diff --git a/go/ql/test/experimental/CWE-321/go.mod b/go/ql/test/experimental/CWE-321/go.mod
index 68e45a0217b9..3d82c675b842 100644
--- a/go/ql/test/experimental/CWE-321/go.mod
+++ b/go/ql/test/experimental/CWE-321/go.mod
@@ -24,7 +24,7 @@ require (
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
- github.com/cespare/xxhash/v2 v2.1.2 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -43,7 +43,7 @@ require (
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/gogf/gf/v2 v2.0.0-rc3 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
@@ -84,13 +84,13 @@ require (
go.opentelemetry.io/otel/sdk v1.0.0 // indirect
go.opentelemetry.io/otel/trace v1.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
- golang.org/x/net v0.8.0 // indirect
- golang.org/x/sys v0.6.0 // indirect
- golang.org/x/text v0.8.0 // indirect
+ golang.org/x/net v0.9.0 // indirect
+ golang.org/x/sys v0.7.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
- google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4 // indirect
- google.golang.org/grpc v1.40.0 // indirect
- google.golang.org/protobuf v1.29.0 // indirect
+ google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+ google.golang.org/grpc v1.56.3 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/.gitignore
new file mode 100644
index 000000000000..fe79e3adda29
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/.gitignore
@@ -0,0 +1,2 @@
+/toml.test
+/toml-test
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/COPYING b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/COPYING
new file mode 100644
index 000000000000..01b5743200b8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/COPYING
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 TOML authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/README.md
new file mode 100644
index 000000000000..3651cfa96092
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/README.md
@@ -0,0 +1,120 @@
+TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
+reflection interface similar to Go's standard library `json` and `xml` packages.
+
+Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0).
+
+Documentation: https://godocs.io/github.com/BurntSushi/toml
+
+See the [releases page](https://github.com/BurntSushi/toml/releases) for a
+changelog; this information is also in the git tag annotations (e.g. `git show
+v0.4.0`).
+
+This library requires Go 1.13 or newer; add it to your go.mod with:
+
+ % go get github.com/BurntSushi/toml@latest
+
+It also comes with a TOML validator CLI tool:
+
+ % go install github.com/BurntSushi/toml/cmd/tomlv@latest
+ % tomlv some-toml-file.toml
+
+### Examples
+For the simplest example, consider some TOML file as just a list of keys and
+values:
+
+```toml
+Age = 25
+Cats = [ "Cauchy", "Plato" ]
+Pi = 3.14
+Perfection = [ 6, 28, 496, 8128 ]
+DOB = 1987-07-05T05:45:00Z
+```
+
+Which can be decoded with:
+
+```go
+type Config struct {
+ Age int
+ Cats []string
+ Pi float64
+ Perfection []int
+ DOB time.Time
+}
+
+var conf Config
+_, err := toml.Decode(tomlData, &conf)
+```
+
+You can also use struct tags if your struct field name doesn't map to a TOML key
+value directly:
+
+```toml
+some_key_NAME = "wat"
+```
+
+```go
+type TOML struct {
+ ObscureKey string `toml:"some_key_NAME"`
+}
+```
+
+Beware that like other decoders **only exported fields** are considered when
+encoding and decoding; private fields are silently ignored.
+
+### Using the `Marshaler` and `encoding.TextUnmarshaler` interfaces
+Here's an example that automatically parses values in a `mail.Address`:
+
+```toml
+contacts = [
+ "Donald Duck ",
+ "Scrooge McDuck ",
+]
+```
+
+Can be decoded with:
+
+```go
+// Create address type which satisfies the encoding.TextUnmarshaler interface.
+type address struct {
+ *mail.Address
+}
+
+func (a *address) UnmarshalText(text []byte) error {
+ var err error
+ a.Address, err = mail.ParseAddress(string(text))
+ return err
+}
+
+// Decode it.
+func decode() {
+ blob := `
+ contacts = [
+ "Donald Duck ",
+ "Scrooge McDuck ",
+ ]
+ `
+
+ var contacts struct {
+ Contacts []address
+ }
+
+ _, err := toml.Decode(blob, &contacts)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, c := range contacts.Contacts {
+ fmt.Printf("%#v\n", c.Address)
+ }
+
+ // Output:
+ // &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"}
+ // &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"}
+}
+```
+
+To target TOML specifically you can implement `UnmarshalTOML` TOML interface in
+a similar way.
+
+### More complex usage
+See the [`_example/`](/_example) directory for a more complex example.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/decode.go
new file mode 100644
index 000000000000..0ca1dc4fee5f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/decode.go
@@ -0,0 +1,602 @@
+package toml
+
+import (
+ "bytes"
+ "encoding"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Unmarshaler is the interface implemented by objects that can unmarshal a
+// TOML description of themselves.
+type Unmarshaler interface {
+ UnmarshalTOML(interface{}) error
+}
+
+// Unmarshal decodes the contents of data in TOML format into a pointer v.
+//
+// See [Decoder] for a description of the decoding process.
+func Unmarshal(data []byte, v interface{}) error {
+ _, err := NewDecoder(bytes.NewReader(data)).Decode(v)
+ return err
+}
+
+// Decode the TOML data in to the pointer v.
+//
+// See [Decoder] for a description of the decoding process.
+func Decode(data string, v interface{}) (MetaData, error) {
+ return NewDecoder(strings.NewReader(data)).Decode(v)
+}
+
+// DecodeFile reads the contents of a file and decodes it with [Decode].
+func DecodeFile(path string, v interface{}) (MetaData, error) {
+ fp, err := os.Open(path)
+ if err != nil {
+ return MetaData{}, err
+ }
+ defer fp.Close()
+ return NewDecoder(fp).Decode(v)
+}
+
+// Primitive is a TOML value that hasn't been decoded into a Go value.
+//
+// This type can be used for any value, which will cause decoding to be delayed.
+// You can use [PrimitiveDecode] to "manually" decode these values.
+//
+// NOTE: The underlying representation of a `Primitive` value is subject to
+// change. Do not rely on it.
+//
+// NOTE: Primitive values are still parsed, so using them will only avoid the
+// overhead of reflection. They can be useful when you don't know the exact type
+// of TOML data until runtime.
+type Primitive struct {
+ undecoded interface{}
+ context Key
+}
+
+// The significand precision for float32 and float64 is 24 and 53 bits; this is
+// the range a natural number can be stored in a float without loss of data.
+const (
+ maxSafeFloat32Int = 16777215 // 2^24-1
+ maxSafeFloat64Int = int64(9007199254740991) // 2^53-1
+)
+
+// Decoder decodes TOML data.
+//
+// TOML tables correspond to Go structs or maps; they can be used
+// interchangeably, but structs offer better type safety.
+//
+// TOML table arrays correspond to either a slice of structs or a slice of maps.
+//
+// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the
+// local timezone.
+//
+// [time.Duration] types are treated as nanoseconds if the TOML value is an
+// integer, or they're parsed with time.ParseDuration() if they're strings.
+//
+// All other TOML types (float, string, int, bool and array) correspond to the
+// obvious Go types.
+//
+// An exception to the above rules is if a type implements the TextUnmarshaler
+// interface, in which case any primitive TOML value (floats, strings, integers,
+// booleans, datetimes) will be converted to a []byte and given to the value's
+// UnmarshalText method. See the Unmarshaler example for a demonstration with
+// email addresses.
+//
+// ### Key mapping
+//
+// TOML keys can map to either keys in a Go map or field names in a Go struct.
+// The special `toml` struct tag can be used to map TOML keys to struct fields
+// that don't match the key name exactly (see the example). A case insensitive
+// match to struct names will be tried if an exact match can't be found.
+//
+// The mapping between TOML values and Go values is loose. That is, there may
+// exist TOML values that cannot be placed into your representation, and there
+// may be parts of your representation that do not correspond to TOML values.
+// This loose mapping can be made stricter by using the IsDefined and/or
+// Undecoded methods on the MetaData returned.
+//
+// This decoder does not handle cyclic types. Decode will not terminate if a
+// cyclic type is passed.
+type Decoder struct {
+ r io.Reader
+}
+
+// NewDecoder creates a new Decoder.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{r: r}
+}
+
+var (
+ unmarshalToml = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
+ unmarshalText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+ primitiveType = reflect.TypeOf((*Primitive)(nil)).Elem()
+)
+
+// Decode TOML data in to the pointer `v`.
+func (dec *Decoder) Decode(v interface{}) (MetaData, error) {
+ rv := reflect.ValueOf(v)
+ if rv.Kind() != reflect.Ptr {
+ s := "%q"
+ if reflect.TypeOf(v) == nil {
+ s = "%v"
+ }
+
+ return MetaData{}, fmt.Errorf("toml: cannot decode to non-pointer "+s, reflect.TypeOf(v))
+ }
+ if rv.IsNil() {
+ return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v))
+ }
+
+ // Check if this is a supported type: struct, map, interface{}, or something
+ // that implements UnmarshalTOML or UnmarshalText.
+ rv = indirect(rv)
+ rt := rv.Type()
+ if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map &&
+ !(rv.Kind() == reflect.Interface && rv.NumMethod() == 0) &&
+ !rt.Implements(unmarshalToml) && !rt.Implements(unmarshalText) {
+ return MetaData{}, fmt.Errorf("toml: cannot decode to type %s", rt)
+ }
+
+ // TODO: parser should read from io.Reader? Or at the very least, make it
+ // read from []byte rather than string
+ data, err := ioutil.ReadAll(dec.r)
+ if err != nil {
+ return MetaData{}, err
+ }
+
+ p, err := parse(string(data))
+ if err != nil {
+ return MetaData{}, err
+ }
+
+ md := MetaData{
+ mapping: p.mapping,
+ keyInfo: p.keyInfo,
+ keys: p.ordered,
+ decoded: make(map[string]struct{}, len(p.ordered)),
+ context: nil,
+ data: data,
+ }
+ return md, md.unify(p.mapping, rv)
+}
+
+// PrimitiveDecode is just like the other Decode* functions, except it decodes a
+// TOML value that has already been parsed. Valid primitive values can *only* be
+// obtained from values filled by the decoder functions, including this method.
+// (i.e., v may contain more [Primitive] values.)
+//
+// Meta data for primitive values is included in the meta data returned by the
+// Decode* functions with one exception: keys returned by the Undecoded method
+// will only reflect keys that were decoded. Namely, any keys hidden behind a
+// Primitive will be considered undecoded. Executing this method will update the
+// undecoded keys in the meta data. (See the example.)
+func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
+ md.context = primValue.context
+ defer func() { md.context = nil }()
+ return md.unify(primValue.undecoded, rvalue(v))
+}
+
+// unify performs a sort of type unification based on the structure of `rv`,
+// which is the client representation.
+//
+// Any type mismatch produces an error. Finding a type that we don't know
+// how to handle produces an unsupported type error.
+func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
+ // Special case. Look for a `Primitive` value.
+ // TODO: #76 would make this superfluous after implemented.
+ if rv.Type() == primitiveType {
+ // Save the undecoded data and the key context into the primitive
+ // value.
+ context := make(Key, len(md.context))
+ copy(context, md.context)
+ rv.Set(reflect.ValueOf(Primitive{
+ undecoded: data,
+ context: context,
+ }))
+ return nil
+ }
+
+ rvi := rv.Interface()
+ if v, ok := rvi.(Unmarshaler); ok {
+ return v.UnmarshalTOML(data)
+ }
+ if v, ok := rvi.(encoding.TextUnmarshaler); ok {
+ return md.unifyText(data, v)
+ }
+
+ // TODO:
+ // The behavior here is incorrect whenever a Go type satisfies the
+ // encoding.TextUnmarshaler interface but also corresponds to a TOML hash or
+ // array. In particular, the unmarshaler should only be applied to primitive
+ // TOML values. But at this point, it will be applied to all kinds of values
+ // and produce an incorrect error whenever those values are hashes or arrays
+ // (including arrays of tables).
+
+ k := rv.Kind()
+
+ if k >= reflect.Int && k <= reflect.Uint64 {
+ return md.unifyInt(data, rv)
+ }
+ switch k {
+ case reflect.Ptr:
+ elem := reflect.New(rv.Type().Elem())
+ err := md.unify(data, reflect.Indirect(elem))
+ if err != nil {
+ return err
+ }
+ rv.Set(elem)
+ return nil
+ case reflect.Struct:
+ return md.unifyStruct(data, rv)
+ case reflect.Map:
+ return md.unifyMap(data, rv)
+ case reflect.Array:
+ return md.unifyArray(data, rv)
+ case reflect.Slice:
+ return md.unifySlice(data, rv)
+ case reflect.String:
+ return md.unifyString(data, rv)
+ case reflect.Bool:
+ return md.unifyBool(data, rv)
+ case reflect.Interface:
+ if rv.NumMethod() > 0 { // Only support empty interfaces are supported.
+ return md.e("unsupported type %s", rv.Type())
+ }
+ return md.unifyAnything(data, rv)
+ case reflect.Float32, reflect.Float64:
+ return md.unifyFloat64(data, rv)
+ }
+ return md.e("unsupported type %s", rv.Kind())
+}
+
+func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
+ tmap, ok := mapping.(map[string]interface{})
+ if !ok {
+ if mapping == nil {
+ return nil
+ }
+ return md.e("type mismatch for %s: expected table but found %T",
+ rv.Type().String(), mapping)
+ }
+
+ for key, datum := range tmap {
+ var f *field
+ fields := cachedTypeFields(rv.Type())
+ for i := range fields {
+ ff := &fields[i]
+ if ff.name == key {
+ f = ff
+ break
+ }
+ if f == nil && strings.EqualFold(ff.name, key) {
+ f = ff
+ }
+ }
+ if f != nil {
+ subv := rv
+ for _, i := range f.index {
+ subv = indirect(subv.Field(i))
+ }
+
+ if isUnifiable(subv) {
+ md.decoded[md.context.add(key).String()] = struct{}{}
+ md.context = append(md.context, key)
+
+ err := md.unify(datum, subv)
+ if err != nil {
+ return err
+ }
+ md.context = md.context[0 : len(md.context)-1]
+ } else if f.name != "" {
+ return md.e("cannot write unexported field %s.%s", rv.Type().String(), f.name)
+ }
+ }
+ }
+ return nil
+}
+
+func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
+ keyType := rv.Type().Key().Kind()
+ if keyType != reflect.String && keyType != reflect.Interface {
+ return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)",
+ keyType, rv.Type())
+ }
+
+ tmap, ok := mapping.(map[string]interface{})
+ if !ok {
+ if tmap == nil {
+ return nil
+ }
+ return md.badtype("map", mapping)
+ }
+ if rv.IsNil() {
+ rv.Set(reflect.MakeMap(rv.Type()))
+ }
+ for k, v := range tmap {
+ md.decoded[md.context.add(k).String()] = struct{}{}
+ md.context = append(md.context, k)
+
+ rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
+
+ err := md.unify(v, indirect(rvval))
+ if err != nil {
+ return err
+ }
+ md.context = md.context[0 : len(md.context)-1]
+
+ rvkey := indirect(reflect.New(rv.Type().Key()))
+
+ switch keyType {
+ case reflect.Interface:
+ rvkey.Set(reflect.ValueOf(k))
+ case reflect.String:
+ rvkey.SetString(k)
+ }
+
+ rv.SetMapIndex(rvkey, rvval)
+ }
+ return nil
+}
+
+func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
+ datav := reflect.ValueOf(data)
+ if datav.Kind() != reflect.Slice {
+ if !datav.IsValid() {
+ return nil
+ }
+ return md.badtype("slice", data)
+ }
+ if l := datav.Len(); l != rv.Len() {
+ return md.e("expected array length %d; got TOML array of length %d", rv.Len(), l)
+ }
+ return md.unifySliceArray(datav, rv)
+}
+
+func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
+ datav := reflect.ValueOf(data)
+ if datav.Kind() != reflect.Slice {
+ if !datav.IsValid() {
+ return nil
+ }
+ return md.badtype("slice", data)
+ }
+ n := datav.Len()
+ if rv.IsNil() || rv.Cap() < n {
+ rv.Set(reflect.MakeSlice(rv.Type(), n, n))
+ }
+ rv.SetLen(n)
+ return md.unifySliceArray(datav, rv)
+}
+
+func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
+ l := data.Len()
+ for i := 0; i < l; i++ {
+ err := md.unify(data.Index(i).Interface(), indirect(rv.Index(i)))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
+ _, ok := rv.Interface().(json.Number)
+ if ok {
+ if i, ok := data.(int64); ok {
+ rv.SetString(strconv.FormatInt(i, 10))
+ } else if f, ok := data.(float64); ok {
+ rv.SetString(strconv.FormatFloat(f, 'f', -1, 64))
+ } else {
+ return md.badtype("string", data)
+ }
+ return nil
+ }
+
+ if s, ok := data.(string); ok {
+ rv.SetString(s)
+ return nil
+ }
+ return md.badtype("string", data)
+}
+
+func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
+ rvk := rv.Kind()
+
+ if num, ok := data.(float64); ok {
+ switch rvk {
+ case reflect.Float32:
+ if num < -math.MaxFloat32 || num > math.MaxFloat32 {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ fallthrough
+ case reflect.Float64:
+ rv.SetFloat(num)
+ default:
+ panic("bug")
+ }
+ return nil
+ }
+
+ if num, ok := data.(int64); ok {
+ if (rvk == reflect.Float32 && (num < -maxSafeFloat32Int || num > maxSafeFloat32Int)) ||
+ (rvk == reflect.Float64 && (num < -maxSafeFloat64Int || num > maxSafeFloat64Int)) {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ rv.SetFloat(float64(num))
+ return nil
+ }
+
+ return md.badtype("float", data)
+}
+
+func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
+ _, ok := rv.Interface().(time.Duration)
+ if ok {
+ // Parse as string duration, and fall back to regular integer parsing
+ // (as nanosecond) if this is not a string.
+ if s, ok := data.(string); ok {
+ dur, err := time.ParseDuration(s)
+ if err != nil {
+ return md.parseErr(errParseDuration{s})
+ }
+ rv.SetInt(int64(dur))
+ return nil
+ }
+ }
+
+ num, ok := data.(int64)
+ if !ok {
+ return md.badtype("integer", data)
+ }
+
+ rvk := rv.Kind()
+ switch {
+ case rvk >= reflect.Int && rvk <= reflect.Int64:
+ if (rvk == reflect.Int8 && (num < math.MinInt8 || num > math.MaxInt8)) ||
+ (rvk == reflect.Int16 && (num < math.MinInt16 || num > math.MaxInt16)) ||
+ (rvk == reflect.Int32 && (num < math.MinInt32 || num > math.MaxInt32)) {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ rv.SetInt(num)
+ case rvk >= reflect.Uint && rvk <= reflect.Uint64:
+ unum := uint64(num)
+ if rvk == reflect.Uint8 && (num < 0 || unum > math.MaxUint8) ||
+ rvk == reflect.Uint16 && (num < 0 || unum > math.MaxUint16) ||
+ rvk == reflect.Uint32 && (num < 0 || unum > math.MaxUint32) {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ rv.SetUint(unum)
+ default:
+ panic("unreachable")
+ }
+ return nil
+}
+
+func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
+ if b, ok := data.(bool); ok {
+ rv.SetBool(b)
+ return nil
+ }
+ return md.badtype("boolean", data)
+}
+
+func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
+ rv.Set(reflect.ValueOf(data))
+ return nil
+}
+
+func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) error {
+ var s string
+ switch sdata := data.(type) {
+ case Marshaler:
+ text, err := sdata.MarshalTOML()
+ if err != nil {
+ return err
+ }
+ s = string(text)
+ case encoding.TextMarshaler:
+ text, err := sdata.MarshalText()
+ if err != nil {
+ return err
+ }
+ s = string(text)
+ case fmt.Stringer:
+ s = sdata.String()
+ case string:
+ s = sdata
+ case bool:
+ s = fmt.Sprintf("%v", sdata)
+ case int64:
+ s = fmt.Sprintf("%d", sdata)
+ case float64:
+ s = fmt.Sprintf("%f", sdata)
+ default:
+ return md.badtype("primitive (string-like)", data)
+ }
+ if err := v.UnmarshalText([]byte(s)); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (md *MetaData) badtype(dst string, data interface{}) error {
+ return md.e("incompatible types: TOML value has type %T; destination has type %s", data, dst)
+}
+
+func (md *MetaData) parseErr(err error) error {
+ k := md.context.String()
+ return ParseError{
+ LastKey: k,
+ Position: md.keyInfo[k].pos,
+ Line: md.keyInfo[k].pos.Line,
+ err: err,
+ input: string(md.data),
+ }
+}
+
+func (md *MetaData) e(format string, args ...interface{}) error {
+ f := "toml: "
+ if len(md.context) > 0 {
+ f = fmt.Sprintf("toml: (last key %q): ", md.context)
+ p := md.keyInfo[md.context.String()].pos
+ if p.Line > 0 {
+ f = fmt.Sprintf("toml: line %d (last key %q): ", p.Line, md.context)
+ }
+ }
+ return fmt.Errorf(f+format, args...)
+}
+
+// rvalue returns a reflect.Value of `v`. All pointers are resolved.
+func rvalue(v interface{}) reflect.Value {
+ return indirect(reflect.ValueOf(v))
+}
+
+// indirect returns the value pointed to by a pointer.
+//
+// Pointers are followed until the value is not a pointer. New values are
+// allocated for each nil pointer.
+//
+// An exception to this rule is if the value satisfies an interface of interest
+// to us (like encoding.TextUnmarshaler).
+func indirect(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Ptr {
+ if v.CanSet() {
+ pv := v.Addr()
+ pvi := pv.Interface()
+ if _, ok := pvi.(encoding.TextUnmarshaler); ok {
+ return pv
+ }
+ if _, ok := pvi.(Unmarshaler); ok {
+ return pv
+ }
+ }
+ return v
+ }
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ return indirect(reflect.Indirect(v))
+}
+
+func isUnifiable(rv reflect.Value) bool {
+ if rv.CanSet() {
+ return true
+ }
+ rvi := rv.Interface()
+ if _, ok := rvi.(encoding.TextUnmarshaler); ok {
+ return true
+ }
+ if _, ok := rvi.(Unmarshaler); ok {
+ return true
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/decode_go116.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/decode_go116.go
new file mode 100644
index 000000000000..086d0b68664f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/decode_go116.go
@@ -0,0 +1,19 @@
+//go:build go1.16
+// +build go1.16
+
+package toml
+
+import (
+ "io/fs"
+)
+
+// DecodeFS reads the contents of a file from [fs.FS] and decodes it with
+// [Decode].
+func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) {
+ fp, err := fsys.Open(path)
+ if err != nil {
+ return MetaData{}, err
+ }
+ defer fp.Close()
+ return NewDecoder(fp).Decode(v)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/deprecated.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/deprecated.go
new file mode 100644
index 000000000000..c6af3f239ddf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/deprecated.go
@@ -0,0 +1,21 @@
+package toml
+
+import (
+ "encoding"
+ "io"
+)
+
+// Deprecated: use encoding.TextMarshaler
+type TextMarshaler encoding.TextMarshaler
+
+// Deprecated: use encoding.TextUnmarshaler
+type TextUnmarshaler encoding.TextUnmarshaler
+
+// Deprecated: use MetaData.PrimitiveDecode.
+func PrimitiveDecode(primValue Primitive, v interface{}) error {
+ md := MetaData{decoded: make(map[string]struct{})}
+ return md.unify(primValue.undecoded, rvalue(v))
+}
+
+// Deprecated: use NewDecoder(reader).Decode(&value).
+func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/doc.go
new file mode 100644
index 000000000000..81a7c0fe9f6d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/doc.go
@@ -0,0 +1,11 @@
+// Package toml implements decoding and encoding of TOML files.
+//
+// This package supports TOML v1.0.0, as specified at https://toml.io
+//
+// There is also support for delaying decoding with the Primitive type, and
+// querying the set of keys in a TOML document with the MetaData type.
+//
+// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator,
+// and can be used to verify if TOML document is valid. It can also be used to
+// print the type of each key.
+package toml
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/encode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/encode.go
new file mode 100644
index 000000000000..930e1d521ac6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/encode.go
@@ -0,0 +1,750 @@
+package toml
+
+import (
+ "bufio"
+ "encoding"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/BurntSushi/toml/internal"
+)
+
+type tomlEncodeError struct{ error }
+
+var (
+ errArrayNilElement = errors.New("toml: cannot encode array with nil element")
+ errNonString = errors.New("toml: cannot encode a map with non-string key type")
+ errNoKey = errors.New("toml: top-level values must be Go maps or structs")
+ errAnything = errors.New("") // used in testing
+)
+
+var dblQuotedReplacer = strings.NewReplacer(
+ "\"", "\\\"",
+ "\\", "\\\\",
+ "\x00", `\u0000`,
+ "\x01", `\u0001`,
+ "\x02", `\u0002`,
+ "\x03", `\u0003`,
+ "\x04", `\u0004`,
+ "\x05", `\u0005`,
+ "\x06", `\u0006`,
+ "\x07", `\u0007`,
+ "\b", `\b`,
+ "\t", `\t`,
+ "\n", `\n`,
+ "\x0b", `\u000b`,
+ "\f", `\f`,
+ "\r", `\r`,
+ "\x0e", `\u000e`,
+ "\x0f", `\u000f`,
+ "\x10", `\u0010`,
+ "\x11", `\u0011`,
+ "\x12", `\u0012`,
+ "\x13", `\u0013`,
+ "\x14", `\u0014`,
+ "\x15", `\u0015`,
+ "\x16", `\u0016`,
+ "\x17", `\u0017`,
+ "\x18", `\u0018`,
+ "\x19", `\u0019`,
+ "\x1a", `\u001a`,
+ "\x1b", `\u001b`,
+ "\x1c", `\u001c`,
+ "\x1d", `\u001d`,
+ "\x1e", `\u001e`,
+ "\x1f", `\u001f`,
+ "\x7f", `\u007f`,
+)
+
+var (
+ marshalToml = reflect.TypeOf((*Marshaler)(nil)).Elem()
+ marshalText = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+ timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
+)
+
+// Marshaler is the interface implemented by types that can marshal themselves
+// into valid TOML.
+type Marshaler interface {
+ MarshalTOML() ([]byte, error)
+}
+
+// Encoder encodes a Go to a TOML document.
+//
+// The mapping between Go values and TOML values should be precisely the same as
+// for [Decode].
+//
+// time.Time is encoded as a RFC 3339 string, and time.Duration as its string
+// representation.
+//
+// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to
+// encoding the value as custom TOML.
+//
+// If you want to write arbitrary binary data then you will need to use
+// something like base64 since TOML does not have any binary types.
+//
+// When encoding TOML hashes (Go maps or structs), keys without any sub-hashes
+// are encoded first.
+//
+// Go maps will be sorted alphabetically by key for deterministic output.
+//
+// The toml struct tag can be used to provide the key name; if omitted the
+// struct field name will be used. If the "omitempty" option is present the
+// following value will be skipped:
+//
+// - arrays, slices, maps, and string with len of 0
+// - struct with all zero values
+// - bool false
+//
+// If omitzero is given all int and float types with a value of 0 will be
+// skipped.
+//
+// Encoding Go values without a corresponding TOML representation will return an
+// error. Examples of this includes maps with non-string keys, slices with nil
+// elements, embedded non-struct types, and nested slices containing maps or
+// structs. (e.g. [][]map[string]string is not allowed but []map[string]string
+// is okay, as is []map[string][]string).
+//
+// NOTE: only exported keys are encoded due to the use of reflection. Unexported
+// keys are silently discarded.
+type Encoder struct {
+ // String to use for a single indentation level; default is two spaces.
+ Indent string
+
+ w *bufio.Writer
+ hasWritten bool // written any output to w yet?
+}
+
+// NewEncoder create a new Encoder.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{
+ w: bufio.NewWriter(w),
+ Indent: " ",
+ }
+}
+
+// Encode writes a TOML representation of the Go value to the [Encoder]'s writer.
+//
+// An error is returned if the value given cannot be encoded to a valid TOML
+// document.
+func (enc *Encoder) Encode(v interface{}) error {
+ rv := eindirect(reflect.ValueOf(v))
+ if err := enc.safeEncode(Key([]string{}), rv); err != nil {
+ return err
+ }
+ return enc.w.Flush()
+}
+
+func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if terr, ok := r.(tomlEncodeError); ok {
+ err = terr.error
+ return
+ }
+ panic(r)
+ }
+ }()
+ enc.encode(key, rv)
+ return nil
+}
+
+func (enc *Encoder) encode(key Key, rv reflect.Value) {
+ // If we can marshal the type to text, then we use that. This prevents the
+ // encoder for handling these types as generic structs (or whatever the
+ // underlying type of a TextMarshaler is).
+ switch {
+ case isMarshaler(rv):
+ enc.writeKeyValue(key, rv, false)
+ return
+ case rv.Type() == primitiveType: // TODO: #76 would make this superfluous after implemented.
+ enc.encode(key, reflect.ValueOf(rv.Interface().(Primitive).undecoded))
+ return
+ }
+
+ k := rv.Kind()
+ switch k {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64,
+ reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
+ enc.writeKeyValue(key, rv, false)
+ case reflect.Array, reflect.Slice:
+ if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
+ enc.eArrayOfTables(key, rv)
+ } else {
+ enc.writeKeyValue(key, rv, false)
+ }
+ case reflect.Interface:
+ if rv.IsNil() {
+ return
+ }
+ enc.encode(key, rv.Elem())
+ case reflect.Map:
+ if rv.IsNil() {
+ return
+ }
+ enc.eTable(key, rv)
+ case reflect.Ptr:
+ if rv.IsNil() {
+ return
+ }
+ enc.encode(key, rv.Elem())
+ case reflect.Struct:
+ enc.eTable(key, rv)
+ default:
+ encPanic(fmt.Errorf("unsupported type for key '%s': %s", key, k))
+ }
+}
+
+// eElement encodes any value that can be an array element.
+func (enc *Encoder) eElement(rv reflect.Value) {
+ switch v := rv.Interface().(type) {
+ case time.Time: // Using TextMarshaler adds extra quotes, which we don't want.
+ format := time.RFC3339Nano
+ switch v.Location() {
+ case internal.LocalDatetime:
+ format = "2006-01-02T15:04:05.999999999"
+ case internal.LocalDate:
+ format = "2006-01-02"
+ case internal.LocalTime:
+ format = "15:04:05.999999999"
+ }
+ switch v.Location() {
+ default:
+ enc.wf(v.Format(format))
+ case internal.LocalDatetime, internal.LocalDate, internal.LocalTime:
+ enc.wf(v.In(time.UTC).Format(format))
+ }
+ return
+ case Marshaler:
+ s, err := v.MarshalTOML()
+ if err != nil {
+ encPanic(err)
+ }
+ if s == nil {
+ encPanic(errors.New("MarshalTOML returned nil and no error"))
+ }
+ enc.w.Write(s)
+ return
+ case encoding.TextMarshaler:
+ s, err := v.MarshalText()
+ if err != nil {
+ encPanic(err)
+ }
+ if s == nil {
+ encPanic(errors.New("MarshalText returned nil and no error"))
+ }
+ enc.writeQuoted(string(s))
+ return
+ case time.Duration:
+ enc.writeQuoted(v.String())
+ return
+ case json.Number:
+ n, _ := rv.Interface().(json.Number)
+
+ if n == "" { /// Useful zero value.
+ enc.w.WriteByte('0')
+ return
+ } else if v, err := n.Int64(); err == nil {
+ enc.eElement(reflect.ValueOf(v))
+ return
+ } else if v, err := n.Float64(); err == nil {
+ enc.eElement(reflect.ValueOf(v))
+ return
+ }
+ encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n))
+ }
+
+ switch rv.Kind() {
+ case reflect.Ptr:
+ enc.eElement(rv.Elem())
+ return
+ case reflect.String:
+ enc.writeQuoted(rv.String())
+ case reflect.Bool:
+ enc.wf(strconv.FormatBool(rv.Bool()))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ enc.wf(strconv.FormatInt(rv.Int(), 10))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ enc.wf(strconv.FormatUint(rv.Uint(), 10))
+ case reflect.Float32:
+ f := rv.Float()
+ if math.IsNaN(f) {
+ enc.wf("nan")
+ } else if math.IsInf(f, 0) {
+ enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)])
+ } else {
+ enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32)))
+ }
+ case reflect.Float64:
+ f := rv.Float()
+ if math.IsNaN(f) {
+ enc.wf("nan")
+ } else if math.IsInf(f, 0) {
+ enc.wf("%cinf", map[bool]byte{true: '-', false: '+'}[math.Signbit(f)])
+ } else {
+ enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64)))
+ }
+ case reflect.Array, reflect.Slice:
+ enc.eArrayOrSliceElement(rv)
+ case reflect.Struct:
+ enc.eStruct(nil, rv, true)
+ case reflect.Map:
+ enc.eMap(nil, rv, true)
+ case reflect.Interface:
+ enc.eElement(rv.Elem())
+ default:
+ encPanic(fmt.Errorf("unexpected type: %T", rv.Interface()))
+ }
+}
+
+// By the TOML spec, all floats must have a decimal with at least one number on
+// either side.
+func floatAddDecimal(fstr string) string {
+ if !strings.Contains(fstr, ".") {
+ return fstr + ".0"
+ }
+ return fstr
+}
+
+func (enc *Encoder) writeQuoted(s string) {
+ enc.wf("\"%s\"", dblQuotedReplacer.Replace(s))
+}
+
+func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
+ length := rv.Len()
+ enc.wf("[")
+ for i := 0; i < length; i++ {
+ elem := eindirect(rv.Index(i))
+ enc.eElement(elem)
+ if i != length-1 {
+ enc.wf(", ")
+ }
+ }
+ enc.wf("]")
+}
+
+func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
+ if len(key) == 0 {
+ encPanic(errNoKey)
+ }
+ for i := 0; i < rv.Len(); i++ {
+ trv := eindirect(rv.Index(i))
+ if isNil(trv) {
+ continue
+ }
+ enc.newline()
+ enc.wf("%s[[%s]]", enc.indentStr(key), key)
+ enc.newline()
+ enc.eMapOrStruct(key, trv, false)
+ }
+}
+
+func (enc *Encoder) eTable(key Key, rv reflect.Value) {
+ if len(key) == 1 {
+ // Output an extra newline between top-level tables.
+ // (The newline isn't written if nothing else has been written though.)
+ enc.newline()
+ }
+ if len(key) > 0 {
+ enc.wf("%s[%s]", enc.indentStr(key), key)
+ enc.newline()
+ }
+ enc.eMapOrStruct(key, rv, false)
+}
+
+func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value, inline bool) {
+ switch rv.Kind() {
+ case reflect.Map:
+ enc.eMap(key, rv, inline)
+ case reflect.Struct:
+ enc.eStruct(key, rv, inline)
+ default:
+ // Should never happen?
+ panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
+ }
+}
+
+func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) {
+ rt := rv.Type()
+ if rt.Key().Kind() != reflect.String {
+ encPanic(errNonString)
+ }
+
+ // Sort keys so that we have deterministic output. And write keys directly
+ // underneath this key first, before writing sub-structs or sub-maps.
+ var mapKeysDirect, mapKeysSub []string
+ for _, mapKey := range rv.MapKeys() {
+ k := mapKey.String()
+ if typeIsTable(tomlTypeOfGo(eindirect(rv.MapIndex(mapKey)))) {
+ mapKeysSub = append(mapKeysSub, k)
+ } else {
+ mapKeysDirect = append(mapKeysDirect, k)
+ }
+ }
+
+ var writeMapKeys = func(mapKeys []string, trailC bool) {
+ sort.Strings(mapKeys)
+ for i, mapKey := range mapKeys {
+ val := eindirect(rv.MapIndex(reflect.ValueOf(mapKey)))
+ if isNil(val) {
+ continue
+ }
+
+ if inline {
+ enc.writeKeyValue(Key{mapKey}, val, true)
+ if trailC || i != len(mapKeys)-1 {
+ enc.wf(", ")
+ }
+ } else {
+ enc.encode(key.add(mapKey), val)
+ }
+ }
+ }
+
+ if inline {
+ enc.wf("{")
+ }
+ writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0)
+ writeMapKeys(mapKeysSub, false)
+ if inline {
+ enc.wf("}")
+ }
+}
+
+const is32Bit = (32 << (^uint(0) >> 63)) == 32
+
+func pointerTo(t reflect.Type) reflect.Type {
+ if t.Kind() == reflect.Ptr {
+ return pointerTo(t.Elem())
+ }
+ return t
+}
+
+func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
+ // Write keys for fields directly under this key first, because if we write
+ // a field that creates a new table then all keys under it will be in that
+ // table (not the one we're writing here).
+ //
+ // Fields is a [][]int: for fieldsDirect this always has one entry (the
+ // struct index). For fieldsSub it contains two entries: the parent field
+ // index from tv, and the field indexes for the fields of the sub.
+ var (
+ rt = rv.Type()
+ fieldsDirect, fieldsSub [][]int
+ addFields func(rt reflect.Type, rv reflect.Value, start []int)
+ )
+ addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
+ for i := 0; i < rt.NumField(); i++ {
+ f := rt.Field(i)
+ isEmbed := f.Anonymous && pointerTo(f.Type).Kind() == reflect.Struct
+ if f.PkgPath != "" && !isEmbed { /// Skip unexported fields.
+ continue
+ }
+ opts := getOptions(f.Tag)
+ if opts.skip {
+ continue
+ }
+
+ frv := eindirect(rv.Field(i))
+
+ // Treat anonymous struct fields with tag names as though they are
+ // not anonymous, like encoding/json does.
+ //
+ // Non-struct anonymous fields use the normal encoding logic.
+ if isEmbed {
+ if getOptions(f.Tag).name == "" && frv.Kind() == reflect.Struct {
+ addFields(frv.Type(), frv, append(start, f.Index...))
+ continue
+ }
+ }
+
+ if typeIsTable(tomlTypeOfGo(frv)) {
+ fieldsSub = append(fieldsSub, append(start, f.Index...))
+ } else {
+ // Copy so it works correct on 32bit archs; not clear why this
+ // is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
+ // This also works fine on 64bit, but 32bit archs are somewhat
+ // rare and this is a wee bit faster.
+ if is32Bit {
+ copyStart := make([]int, len(start))
+ copy(copyStart, start)
+ fieldsDirect = append(fieldsDirect, append(copyStart, f.Index...))
+ } else {
+ fieldsDirect = append(fieldsDirect, append(start, f.Index...))
+ }
+ }
+ }
+ }
+ addFields(rt, rv, nil)
+
+ writeFields := func(fields [][]int) {
+ for _, fieldIndex := range fields {
+ fieldType := rt.FieldByIndex(fieldIndex)
+ fieldVal := eindirect(rv.FieldByIndex(fieldIndex))
+
+ if isNil(fieldVal) { /// Don't write anything for nil fields.
+ continue
+ }
+
+ opts := getOptions(fieldType.Tag)
+ if opts.skip {
+ continue
+ }
+ keyName := fieldType.Name
+ if opts.name != "" {
+ keyName = opts.name
+ }
+
+ if opts.omitempty && enc.isEmpty(fieldVal) {
+ continue
+ }
+ if opts.omitzero && isZero(fieldVal) {
+ continue
+ }
+
+ if inline {
+ enc.writeKeyValue(Key{keyName}, fieldVal, true)
+ if fieldIndex[0] != len(fields)-1 {
+ enc.wf(", ")
+ }
+ } else {
+ enc.encode(key.add(keyName), fieldVal)
+ }
+ }
+ }
+
+ if inline {
+ enc.wf("{")
+ }
+ writeFields(fieldsDirect)
+ writeFields(fieldsSub)
+ if inline {
+ enc.wf("}")
+ }
+}
+
+// tomlTypeOfGo returns the TOML type name of the Go value's type.
+//
+// It is used to determine whether the types of array elements are mixed (which
+// is forbidden). If the Go value is nil, then it is illegal for it to be an
+// array element, and valueIsNil is returned as true.
+//
+// The type may be `nil`, which means no concrete TOML type could be found.
+func tomlTypeOfGo(rv reflect.Value) tomlType {
+ if isNil(rv) || !rv.IsValid() {
+ return nil
+ }
+
+ if rv.Kind() == reflect.Struct {
+ if rv.Type() == timeType {
+ return tomlDatetime
+ }
+ if isMarshaler(rv) {
+ return tomlString
+ }
+ return tomlHash
+ }
+
+ if isMarshaler(rv) {
+ return tomlString
+ }
+
+ switch rv.Kind() {
+ case reflect.Bool:
+ return tomlBool
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64:
+ return tomlInteger
+ case reflect.Float32, reflect.Float64:
+ return tomlFloat
+ case reflect.Array, reflect.Slice:
+ if isTableArray(rv) {
+ return tomlArrayHash
+ }
+ return tomlArray
+ case reflect.Ptr, reflect.Interface:
+ return tomlTypeOfGo(rv.Elem())
+ case reflect.String:
+ return tomlString
+ case reflect.Map:
+ return tomlHash
+ default:
+ encPanic(errors.New("unsupported type: " + rv.Kind().String()))
+ panic("unreachable")
+ }
+}
+
+func isMarshaler(rv reflect.Value) bool {
+ return rv.Type().Implements(marshalText) || rv.Type().Implements(marshalToml)
+}
+
+// isTableArray reports if all entries in the array or slice are a table.
+func isTableArray(arr reflect.Value) bool {
+ if isNil(arr) || !arr.IsValid() || arr.Len() == 0 {
+ return false
+ }
+
+ ret := true
+ for i := 0; i < arr.Len(); i++ {
+ tt := tomlTypeOfGo(eindirect(arr.Index(i)))
+ // Don't allow nil.
+ if tt == nil {
+ encPanic(errArrayNilElement)
+ }
+
+ if ret && !typeEqual(tomlHash, tt) {
+ ret = false
+ }
+ }
+ return ret
+}
+
+type tagOptions struct {
+ skip bool // "-"
+ name string
+ omitempty bool
+ omitzero bool
+}
+
+func getOptions(tag reflect.StructTag) tagOptions {
+ t := tag.Get("toml")
+ if t == "-" {
+ return tagOptions{skip: true}
+ }
+ var opts tagOptions
+ parts := strings.Split(t, ",")
+ opts.name = parts[0]
+ for _, s := range parts[1:] {
+ switch s {
+ case "omitempty":
+ opts.omitempty = true
+ case "omitzero":
+ opts.omitzero = true
+ }
+ }
+ return opts
+}
+
+func isZero(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return rv.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return rv.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return rv.Float() == 0.0
+ }
+ return false
+}
+
+func (enc *Encoder) isEmpty(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
+ return rv.Len() == 0
+ case reflect.Struct:
+ if rv.Type().Comparable() {
+ return reflect.Zero(rv.Type()).Interface() == rv.Interface()
+ }
+ // Need to also check if all the fields are empty, otherwise something
+ // like this with uncomparable types will always return true:
+ //
+ // type a struct{ field b }
+ // type b struct{ s []string }
+ // s := a{field: b{s: []string{"AAA"}}}
+ for i := 0; i < rv.NumField(); i++ {
+ if !enc.isEmpty(rv.Field(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Bool:
+ return !rv.Bool()
+ }
+ return false
+}
+
+func (enc *Encoder) newline() {
+ if enc.hasWritten {
+ enc.wf("\n")
+ }
+}
+
+// Write a key/value pair:
+//
+// key =
+//
+// This is also used for "k = v" in inline tables; so something like this will
+// be written in three calls:
+//
+// ┌───────────────────┐
+// │ ┌───┐ ┌────┐│
+// v v v v vv
+// key = {k = 1, k2 = 2}
+func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
+ if len(key) == 0 {
+ encPanic(errNoKey)
+ }
+ enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
+ enc.eElement(val)
+ if !inline {
+ enc.newline()
+ }
+}
+
+func (enc *Encoder) wf(format string, v ...interface{}) {
+ _, err := fmt.Fprintf(enc.w, format, v...)
+ if err != nil {
+ encPanic(err)
+ }
+ enc.hasWritten = true
+}
+
+func (enc *Encoder) indentStr(key Key) string {
+ return strings.Repeat(enc.Indent, len(key)-1)
+}
+
+func encPanic(err error) {
+ panic(tomlEncodeError{err})
+}
+
+// Resolve any level of pointers to the actual value (e.g. **string → string).
+func eindirect(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
+ if isMarshaler(v) {
+ return v
+ }
+ if v.CanAddr() { /// Special case for marshalers; see #358.
+ if pv := v.Addr(); isMarshaler(pv) {
+ return pv
+ }
+ }
+ return v
+ }
+
+ if v.IsNil() {
+ return v
+ }
+
+ return eindirect(v.Elem())
+}
+
+func isNil(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return rv.IsNil()
+ default:
+ return false
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/error.go
new file mode 100644
index 000000000000..f4f390e647fd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/error.go
@@ -0,0 +1,279 @@
+package toml
+
+import (
+ "fmt"
+ "strings"
+)
+
+// ParseError is returned when there is an error parsing the TOML syntax such as
+// invalid syntax, duplicate keys, etc.
+//
+// In addition to the error message itself, you can also print detailed location
+// information with context by using [ErrorWithPosition]:
+//
+// toml: error: Key 'fruit' was already created and cannot be used as an array.
+//
+// At line 4, column 2-7:
+//
+// 2 | fruit = []
+// 3 |
+// 4 | [[fruit]] # Not allowed
+// ^^^^^
+//
+// [ErrorWithUsage] can be used to print the above with some more detailed usage
+// guidance:
+//
+// toml: error: newlines not allowed within inline tables
+//
+// At line 1, column 18:
+//
+// 1 | x = [{ key = 42 #
+// ^
+//
+// Error help:
+//
+// Inline tables must always be on a single line:
+//
+// table = {key = 42, second = 43}
+//
+// It is invalid to split them over multiple lines like so:
+//
+// # INVALID
+// table = {
+// key = 42,
+// second = 43
+// }
+//
+// Use regular for this:
+//
+// [table]
+// key = 42
+// second = 43
+type ParseError struct {
+ Message string // Short technical message.
+ Usage string // Longer message with usage guidance; may be blank.
+ Position Position // Position of the error
+ LastKey string // Last parsed key, may be blank.
+
+ // Line the error occurred.
+ //
+ // Deprecated: use [Position].
+ Line int
+
+ err error
+ input string
+}
+
+// Position of an error.
+type Position struct {
+ Line int // Line number, starting at 1.
+ Start int // Start of error, as byte offset starting at 0.
+ Len int // Lenght in bytes.
+}
+
+func (pe ParseError) Error() string {
+ msg := pe.Message
+ if msg == "" { // Error from errorf()
+ msg = pe.err.Error()
+ }
+
+ if pe.LastKey == "" {
+ return fmt.Sprintf("toml: line %d: %s", pe.Position.Line, msg)
+ }
+ return fmt.Sprintf("toml: line %d (last key %q): %s",
+ pe.Position.Line, pe.LastKey, msg)
+}
+
+// ErrorWithUsage() returns the error with detailed location context.
+//
+// See the documentation on [ParseError].
+func (pe ParseError) ErrorWithPosition() string {
+ if pe.input == "" { // Should never happen, but just in case.
+ return pe.Error()
+ }
+
+ var (
+ lines = strings.Split(pe.input, "\n")
+ col = pe.column(lines)
+ b = new(strings.Builder)
+ )
+
+ msg := pe.Message
+ if msg == "" {
+ msg = pe.err.Error()
+ }
+
+ // TODO: don't show control characters as literals? This may not show up
+ // well everywhere.
+
+ if pe.Position.Len == 1 {
+ fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d:\n\n",
+ msg, pe.Position.Line, col+1)
+ } else {
+ fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d-%d:\n\n",
+ msg, pe.Position.Line, col, col+pe.Position.Len)
+ }
+ if pe.Position.Line > 2 {
+ fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, lines[pe.Position.Line-3])
+ }
+ if pe.Position.Line > 1 {
+ fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, lines[pe.Position.Line-2])
+ }
+ fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, lines[pe.Position.Line-1])
+ fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col), strings.Repeat("^", pe.Position.Len))
+ return b.String()
+}
+
+// ErrorWithUsage() returns the error with detailed location context and usage
+// guidance.
+//
+// See the documentation on [ParseError].
+func (pe ParseError) ErrorWithUsage() string {
+ m := pe.ErrorWithPosition()
+ if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" {
+ lines := strings.Split(strings.TrimSpace(u.Usage()), "\n")
+ for i := range lines {
+ if lines[i] != "" {
+ lines[i] = " " + lines[i]
+ }
+ }
+ return m + "Error help:\n\n" + strings.Join(lines, "\n") + "\n"
+ }
+ return m
+}
+
+func (pe ParseError) column(lines []string) int {
+ var pos, col int
+ for i := range lines {
+ ll := len(lines[i]) + 1 // +1 for the removed newline
+ if pos+ll >= pe.Position.Start {
+ col = pe.Position.Start - pos
+ if col < 0 { // Should never happen, but just in case.
+ col = 0
+ }
+ break
+ }
+ pos += ll
+ }
+
+ return col
+}
+
+type (
+ errLexControl struct{ r rune }
+ errLexEscape struct{ r rune }
+ errLexUTF8 struct{ b byte }
+ errLexInvalidNum struct{ v string }
+ errLexInvalidDate struct{ v string }
+ errLexInlineTableNL struct{}
+ errLexStringNL struct{}
+ errParseRange struct {
+ i interface{} // int or float
+ size string // "int64", "uint16", etc.
+ }
+ errParseDuration struct{ d string }
+)
+
+func (e errLexControl) Error() string {
+ return fmt.Sprintf("TOML files cannot contain control characters: '0x%02x'", e.r)
+}
+func (e errLexControl) Usage() string { return "" }
+
+func (e errLexEscape) Error() string { return fmt.Sprintf(`invalid escape in string '\%c'`, e.r) }
+func (e errLexEscape) Usage() string { return usageEscape }
+func (e errLexUTF8) Error() string { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) }
+func (e errLexUTF8) Usage() string { return "" }
+func (e errLexInvalidNum) Error() string { return fmt.Sprintf("invalid number: %q", e.v) }
+func (e errLexInvalidNum) Usage() string { return "" }
+func (e errLexInvalidDate) Error() string { return fmt.Sprintf("invalid date: %q", e.v) }
+func (e errLexInvalidDate) Usage() string { return "" }
+func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" }
+func (e errLexInlineTableNL) Usage() string { return usageInlineNewline }
+func (e errLexStringNL) Error() string { return "strings cannot contain newlines" }
+func (e errLexStringNL) Usage() string { return usageStringNewline }
+func (e errParseRange) Error() string { return fmt.Sprintf("%v is out of range for %s", e.i, e.size) }
+func (e errParseRange) Usage() string { return usageIntOverflow }
+func (e errParseDuration) Error() string { return fmt.Sprintf("invalid duration: %q", e.d) }
+func (e errParseDuration) Usage() string { return usageDuration }
+
+const usageEscape = `
+A '\' inside a "-delimited string is interpreted as an escape character.
+
+The following escape sequences are supported:
+\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX
+
+To prevent a '\' from being recognized as an escape character, use either:
+
+- a ' or '''-delimited string; escape characters aren't processed in them; or
+- write two backslashes to get a single backslash: '\\'.
+
+If you're trying to add a Windows path (e.g. "C:\Users\martin") then using '/'
+instead of '\' will usually also work: "C:/Users/martin".
+`
+
+const usageInlineNewline = `
+Inline tables must always be on a single line:
+
+ table = {key = 42, second = 43}
+
+It is invalid to split them over multiple lines like so:
+
+ # INVALID
+ table = {
+ key = 42,
+ second = 43
+ }
+
+Use regular for this:
+
+ [table]
+ key = 42
+ second = 43
+`
+
+const usageStringNewline = `
+Strings must always be on a single line, and cannot span more than one line:
+
+ # INVALID
+ string = "Hello,
+ world!"
+
+Instead use """ or ''' to split strings over multiple lines:
+
+ string = """Hello,
+ world!"""
+`
+
+const usageIntOverflow = `
+This number is too large; this may be an error in the TOML, but it can also be a
+bug in the program that uses too small of an integer.
+
+The maximum and minimum values are:
+
+ size │ lowest │ highest
+ ───────┼────────────────┼──────────
+ int8 │ -128 │ 127
+ int16 │ -32,768 │ 32,767
+ int32 │ -2,147,483,648 │ 2,147,483,647
+ int64 │ -9.2 × 10¹⁷ │ 9.2 × 10¹⁷
+ uint8 │ 0 │ 255
+ uint16 │ 0 │ 65535
+ uint32 │ 0 │ 4294967295
+ uint64 │ 0 │ 1.8 × 10¹⁸
+
+int refers to int32 on 32-bit systems and int64 on 64-bit systems.
+`
+
+const usageDuration = `
+A duration must be as "number", without any spaces. Valid units are:
+
+ ns nanoseconds (billionth of a second)
+ us, µs microseconds (millionth of a second)
+ ms milliseconds (thousands of a second)
+ s seconds
+ m minutes
+ h hours
+
+You can combine multiple units; for example "5m10s" for 5 minutes and 10
+seconds.
+`
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/internal/tz.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/internal/tz.go
new file mode 100644
index 000000000000..022f15bc2b81
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/internal/tz.go
@@ -0,0 +1,36 @@
+package internal
+
+import "time"
+
+// Timezones used for local datetime, date, and time TOML types.
+//
+// The exact way times and dates without a timezone should be interpreted is not
+// well-defined in the TOML specification and left to the implementation. These
+// defaults to current local timezone offset of the computer, but this can be
+// changed by changing these variables before decoding.
+//
+// TODO:
+// Ideally we'd like to offer people the ability to configure the used timezone
+// by setting Decoder.Timezone and Encoder.Timezone; however, this is a bit
+// tricky: the reason we use three different variables for this is to support
+// round-tripping – without these specific TZ names we wouldn't know which
+// format to use.
+//
+// There isn't a good way to encode this right now though, and passing this sort
+// of information also ties in to various related issues such as string format
+// encoding, encoding of comments, etc.
+//
+// So, for the time being, just put this in internal until we can write a good
+// comprehensive API for doing all of this.
+//
+// The reason they're exported is because they're referred from in e.g.
+// internal/tag.
+//
+// Note that this behaviour is valid according to the TOML spec as the exact
+// behaviour is left up to implementations.
+var (
+ localOffset = func() int { _, o := time.Now().Zone(); return o }()
+ LocalDatetime = time.FixedZone("datetime-local", localOffset)
+ LocalDate = time.FixedZone("date-local", localOffset)
+ LocalTime = time.FixedZone("time-local", localOffset)
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/lex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/lex.go
new file mode 100644
index 000000000000..d4d70871d8d7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/lex.go
@@ -0,0 +1,1233 @@
+package toml
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type itemType int
+
+const (
+ itemError itemType = iota
+ itemNIL // used in the parser to indicate no type
+ itemEOF
+ itemText
+ itemString
+ itemRawString
+ itemMultilineString
+ itemRawMultilineString
+ itemBool
+ itemInteger
+ itemFloat
+ itemDatetime
+ itemArray // the start of an array
+ itemArrayEnd
+ itemTableStart
+ itemTableEnd
+ itemArrayTableStart
+ itemArrayTableEnd
+ itemKeyStart
+ itemKeyEnd
+ itemCommentStart
+ itemInlineTableStart
+ itemInlineTableEnd
+)
+
+const eof = 0
+
+type stateFn func(lx *lexer) stateFn
+
+func (p Position) String() string {
+ return fmt.Sprintf("at line %d; start %d; length %d", p.Line, p.Start, p.Len)
+}
+
+type lexer struct {
+ input string
+ start int
+ pos int
+ line int
+ state stateFn
+ items chan item
+
+ // Allow for backing up up to 4 runes. This is necessary because TOML
+ // contains 3-rune tokens (""" and ''').
+ prevWidths [4]int
+ nprev int // how many of prevWidths are in use
+ atEOF bool // If we emit an eof, we can still back up, but it is not OK to call next again.
+
+ // A stack of state functions used to maintain context.
+ //
+ // The idea is to reuse parts of the state machine in various places. For
+ // example, values can appear at the top level or within arbitrarily nested
+ // arrays. The last state on the stack is used after a value has been lexed.
+ // Similarly for comments.
+ stack []stateFn
+}
+
+type item struct {
+ typ itemType
+ val string
+ err error
+ pos Position
+}
+
+func (lx *lexer) nextItem() item {
+ for {
+ select {
+ case item := <-lx.items:
+ return item
+ default:
+ lx.state = lx.state(lx)
+ //fmt.Printf(" STATE %-24s current: %-10s stack: %s\n", lx.state, lx.current(), lx.stack)
+ }
+ }
+}
+
+func lex(input string) *lexer {
+ lx := &lexer{
+ input: input,
+ state: lexTop,
+ items: make(chan item, 10),
+ stack: make([]stateFn, 0, 10),
+ line: 1,
+ }
+ return lx
+}
+
+func (lx *lexer) push(state stateFn) {
+ lx.stack = append(lx.stack, state)
+}
+
+func (lx *lexer) pop() stateFn {
+ if len(lx.stack) == 0 {
+ return lx.errorf("BUG in lexer: no states to pop")
+ }
+ last := lx.stack[len(lx.stack)-1]
+ lx.stack = lx.stack[0 : len(lx.stack)-1]
+ return last
+}
+
+func (lx *lexer) current() string {
+ return lx.input[lx.start:lx.pos]
+}
+
+func (lx lexer) getPos() Position {
+ p := Position{
+ Line: lx.line,
+ Start: lx.start,
+ Len: lx.pos - lx.start,
+ }
+ if p.Len <= 0 {
+ p.Len = 1
+ }
+ return p
+}
+
+func (lx *lexer) emit(typ itemType) {
+ // Needed for multiline strings ending with an incomplete UTF-8 sequence.
+ if lx.start > lx.pos {
+ lx.error(errLexUTF8{lx.input[lx.pos]})
+ return
+ }
+ lx.items <- item{typ: typ, pos: lx.getPos(), val: lx.current()}
+ lx.start = lx.pos
+}
+
+func (lx *lexer) emitTrim(typ itemType) {
+ lx.items <- item{typ: typ, pos: lx.getPos(), val: strings.TrimSpace(lx.current())}
+ lx.start = lx.pos
+}
+
+func (lx *lexer) next() (r rune) {
+ if lx.atEOF {
+ panic("BUG in lexer: next called after EOF")
+ }
+ if lx.pos >= len(lx.input) {
+ lx.atEOF = true
+ return eof
+ }
+
+ if lx.input[lx.pos] == '\n' {
+ lx.line++
+ }
+ lx.prevWidths[3] = lx.prevWidths[2]
+ lx.prevWidths[2] = lx.prevWidths[1]
+ lx.prevWidths[1] = lx.prevWidths[0]
+ if lx.nprev < 4 {
+ lx.nprev++
+ }
+
+ r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
+ if r == utf8.RuneError {
+ lx.error(errLexUTF8{lx.input[lx.pos]})
+ return utf8.RuneError
+ }
+
+ // Note: don't use peek() here, as this calls next().
+ if isControl(r) || (r == '\r' && (len(lx.input)-1 == lx.pos || lx.input[lx.pos+1] != '\n')) {
+ lx.errorControlChar(r)
+ return utf8.RuneError
+ }
+
+ lx.prevWidths[0] = w
+ lx.pos += w
+ return r
+}
+
+// ignore skips over the pending input before this point.
+func (lx *lexer) ignore() {
+ lx.start = lx.pos
+}
+
+// backup steps back one rune. Can be called 4 times between calls to next.
+func (lx *lexer) backup() {
+ if lx.atEOF {
+ lx.atEOF = false
+ return
+ }
+ if lx.nprev < 1 {
+ panic("BUG in lexer: backed up too far")
+ }
+ w := lx.prevWidths[0]
+ lx.prevWidths[0] = lx.prevWidths[1]
+ lx.prevWidths[1] = lx.prevWidths[2]
+ lx.prevWidths[2] = lx.prevWidths[3]
+ lx.nprev--
+
+ lx.pos -= w
+ if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
+ lx.line--
+ }
+}
+
+// accept consumes the next rune if it's equal to `valid`.
+func (lx *lexer) accept(valid rune) bool {
+ if lx.next() == valid {
+ return true
+ }
+ lx.backup()
+ return false
+}
+
+// peek returns but does not consume the next rune in the input.
+func (lx *lexer) peek() rune {
+ r := lx.next()
+ lx.backup()
+ return r
+}
+
+// skip ignores all input that matches the given predicate.
+func (lx *lexer) skip(pred func(rune) bool) {
+ for {
+ r := lx.next()
+ if pred(r) {
+ continue
+ }
+ lx.backup()
+ lx.ignore()
+ return
+ }
+}
+
+// error stops all lexing by emitting an error and returning `nil`.
+//
+// Note that any value that is a character is escaped if it's a special
+// character (newlines, tabs, etc.).
+func (lx *lexer) error(err error) stateFn {
+ if lx.atEOF {
+ return lx.errorPrevLine(err)
+ }
+ lx.items <- item{typ: itemError, pos: lx.getPos(), err: err}
+ return nil
+}
+
+// errorfPrevline is like error(), but sets the position to the last column of
+// the previous line.
+//
+// This is so that unexpected EOF or NL errors don't show on a new blank line.
+func (lx *lexer) errorPrevLine(err error) stateFn {
+ pos := lx.getPos()
+ pos.Line--
+ pos.Len = 1
+ pos.Start = lx.pos - 1
+ lx.items <- item{typ: itemError, pos: pos, err: err}
+ return nil
+}
+
+// errorPos is like error(), but allows explicitly setting the position.
+func (lx *lexer) errorPos(start, length int, err error) stateFn {
+ pos := lx.getPos()
+ pos.Start = start
+ pos.Len = length
+ lx.items <- item{typ: itemError, pos: pos, err: err}
+ return nil
+}
+
+// errorf is like error, and creates a new error.
+func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
+ if lx.atEOF {
+ pos := lx.getPos()
+ pos.Line--
+ pos.Len = 1
+ pos.Start = lx.pos - 1
+ lx.items <- item{typ: itemError, pos: pos, err: fmt.Errorf(format, values...)}
+ return nil
+ }
+ lx.items <- item{typ: itemError, pos: lx.getPos(), err: fmt.Errorf(format, values...)}
+ return nil
+}
+
+func (lx *lexer) errorControlChar(cc rune) stateFn {
+ return lx.errorPos(lx.pos-1, 1, errLexControl{cc})
+}
+
+// lexTop consumes elements at the top level of TOML data.
+func lexTop(lx *lexer) stateFn {
+ r := lx.next()
+ if isWhitespace(r) || isNL(r) {
+ return lexSkip(lx, lexTop)
+ }
+ switch r {
+ case '#':
+ lx.push(lexTop)
+ return lexCommentStart
+ case '[':
+ return lexTableStart
+ case eof:
+ if lx.pos > lx.start {
+ return lx.errorf("unexpected EOF")
+ }
+ lx.emit(itemEOF)
+ return nil
+ }
+
+ // At this point, the only valid item can be a key, so we back up
+ // and let the key lexer do the rest.
+ lx.backup()
+ lx.push(lexTopEnd)
+ return lexKeyStart
+}
+
+// lexTopEnd is entered whenever a top-level item has been consumed. (A value
+// or a table.) It must see only whitespace, and will turn back to lexTop
+// upon a newline. If it sees EOF, it will quit the lexer successfully.
+func lexTopEnd(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == '#':
+ // a comment will read to a newline for us.
+ lx.push(lexTop)
+ return lexCommentStart
+ case isWhitespace(r):
+ return lexTopEnd
+ case isNL(r):
+ lx.ignore()
+ return lexTop
+ case r == eof:
+ lx.emit(itemEOF)
+ return nil
+ }
+ return lx.errorf(
+ "expected a top-level item to end with a newline, comment, or EOF, but got %q instead",
+ r)
+}
+
+// lexTable lexes the beginning of a table. Namely, it makes sure that
+// it starts with a character other than '.' and ']'.
+// It assumes that '[' has already been consumed.
+// It also handles the case that this is an item in an array of tables.
+// e.g., '[[name]]'.
+func lexTableStart(lx *lexer) stateFn {
+ if lx.peek() == '[' {
+ lx.next()
+ lx.emit(itemArrayTableStart)
+ lx.push(lexArrayTableEnd)
+ } else {
+ lx.emit(itemTableStart)
+ lx.push(lexTableEnd)
+ }
+ return lexTableNameStart
+}
+
+func lexTableEnd(lx *lexer) stateFn {
+ lx.emit(itemTableEnd)
+ return lexTopEnd
+}
+
+func lexArrayTableEnd(lx *lexer) stateFn {
+ if r := lx.next(); r != ']' {
+ return lx.errorf("expected end of table array name delimiter ']', but got %q instead", r)
+ }
+ lx.emit(itemArrayTableEnd)
+ return lexTopEnd
+}
+
+func lexTableNameStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == ']' || r == eof:
+ return lx.errorf("unexpected end of table name (table names cannot be empty)")
+ case r == '.':
+ return lx.errorf("unexpected table separator (table names cannot be empty)")
+ case r == '"' || r == '\'':
+ lx.ignore()
+ lx.push(lexTableNameEnd)
+ return lexQuotedName
+ default:
+ lx.push(lexTableNameEnd)
+ return lexBareName
+ }
+}
+
+// lexTableNameEnd reads the end of a piece of a table name, optionally
+// consuming whitespace.
+func lexTableNameEnd(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexTableNameEnd
+ case r == '.':
+ lx.ignore()
+ return lexTableNameStart
+ case r == ']':
+ return lx.pop()
+ default:
+ return lx.errorf("expected '.' or ']' to end table name, but got %q instead", r)
+ }
+}
+
+// lexBareName lexes one part of a key or table.
+//
+// It assumes that at least one valid character for the table has already been
+// read.
+//
+// Lexes only one part, e.g. only 'a' inside 'a.b'.
+func lexBareName(lx *lexer) stateFn {
+ r := lx.next()
+ if isBareKeyChar(r) {
+ return lexBareName
+ }
+ lx.backup()
+ lx.emit(itemText)
+ return lx.pop()
+}
+
+// lexBareName lexes one part of a key or table.
+//
+// It assumes that at least one valid character for the table has already been
+// read.
+//
+// Lexes only one part, e.g. only '"a"' inside '"a".b'.
+func lexQuotedName(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexValue)
+ case r == '"':
+ lx.ignore() // ignore the '"'
+ return lexString
+ case r == '\'':
+ lx.ignore() // ignore the "'"
+ return lexRawString
+ case r == eof:
+ return lx.errorf("unexpected EOF; expected value")
+ default:
+ return lx.errorf("expected value but found %q instead", r)
+ }
+}
+
+// lexKeyStart consumes all key parts until a '='.
+func lexKeyStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == '=' || r == eof:
+ return lx.errorf("unexpected '=': key name appears blank")
+ case r == '.':
+ return lx.errorf("unexpected '.': keys cannot start with a '.'")
+ case r == '"' || r == '\'':
+ lx.ignore()
+ fallthrough
+ default: // Bare key
+ lx.emit(itemKeyStart)
+ return lexKeyNameStart
+ }
+}
+
+func lexKeyNameStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == '=' || r == eof:
+ return lx.errorf("unexpected '='")
+ case r == '.':
+ return lx.errorf("unexpected '.'")
+ case r == '"' || r == '\'':
+ lx.ignore()
+ lx.push(lexKeyEnd)
+ return lexQuotedName
+ default:
+ lx.push(lexKeyEnd)
+ return lexBareName
+ }
+}
+
+// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
+// separator).
+func lexKeyEnd(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexSkip(lx, lexKeyEnd)
+ case r == eof:
+ return lx.errorf("unexpected EOF; expected key separator '='")
+ case r == '.':
+ lx.ignore()
+ return lexKeyNameStart
+ case r == '=':
+ lx.emit(itemKeyEnd)
+ return lexSkip(lx, lexValue)
+ default:
+ return lx.errorf("expected '.' or '=', but got %q instead", r)
+ }
+}
+
+// lexValue starts the consumption of a value anywhere a value is expected.
+// lexValue will ignore whitespace.
+// After a value is lexed, the last state on the next is popped and returned.
+func lexValue(lx *lexer) stateFn {
+ // We allow whitespace to precede a value, but NOT newlines.
+ // In array syntax, the array states are responsible for ignoring newlines.
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexValue)
+ case isDigit(r):
+ lx.backup() // avoid an extra state and use the same as above
+ return lexNumberOrDateStart
+ }
+ switch r {
+ case '[':
+ lx.ignore()
+ lx.emit(itemArray)
+ return lexArrayValue
+ case '{':
+ lx.ignore()
+ lx.emit(itemInlineTableStart)
+ return lexInlineTableValue
+ case '"':
+ if lx.accept('"') {
+ if lx.accept('"') {
+ lx.ignore() // Ignore """
+ return lexMultilineString
+ }
+ lx.backup()
+ }
+ lx.ignore() // ignore the '"'
+ return lexString
+ case '\'':
+ if lx.accept('\'') {
+ if lx.accept('\'') {
+ lx.ignore() // Ignore """
+ return lexMultilineRawString
+ }
+ lx.backup()
+ }
+ lx.ignore() // ignore the "'"
+ return lexRawString
+ case '.': // special error case, be kind to users
+ return lx.errorf("floats must start with a digit, not '.'")
+ case 'i', 'n':
+ if (lx.accept('n') && lx.accept('f')) || (lx.accept('a') && lx.accept('n')) {
+ lx.emit(itemFloat)
+ return lx.pop()
+ }
+ case '-', '+':
+ return lexDecimalNumberStart
+ }
+ if unicode.IsLetter(r) {
+ // Be permissive here; lexBool will give a nice error if the
+ // user wrote something like
+ // x = foo
+ // (i.e. not 'true' or 'false' but is something else word-like.)
+ lx.backup()
+ return lexBool
+ }
+ if r == eof {
+ return lx.errorf("unexpected EOF; expected value")
+ }
+ return lx.errorf("expected value but found %q instead", r)
+}
+
+// lexArrayValue consumes one value in an array. It assumes that '[' or ','
+// have already been consumed. All whitespace and newlines are ignored.
+func lexArrayValue(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r) || isNL(r):
+ return lexSkip(lx, lexArrayValue)
+ case r == '#':
+ lx.push(lexArrayValue)
+ return lexCommentStart
+ case r == ',':
+ return lx.errorf("unexpected comma")
+ case r == ']':
+ return lexArrayEnd
+ }
+
+ lx.backup()
+ lx.push(lexArrayValueEnd)
+ return lexValue
+}
+
+// lexArrayValueEnd consumes everything between the end of an array value and
+// the next value (or the end of the array): it ignores whitespace and newlines
+// and expects either a ',' or a ']'.
+func lexArrayValueEnd(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isWhitespace(r) || isNL(r):
+ return lexSkip(lx, lexArrayValueEnd)
+ case r == '#':
+ lx.push(lexArrayValueEnd)
+ return lexCommentStart
+ case r == ',':
+ lx.ignore()
+ return lexArrayValue // move on to the next value
+ case r == ']':
+ return lexArrayEnd
+ default:
+ return lx.errorf("expected a comma (',') or array terminator (']'), but got %s", runeOrEOF(r))
+ }
+}
+
+// lexArrayEnd finishes the lexing of an array.
+// It assumes that a ']' has just been consumed.
+func lexArrayEnd(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemArrayEnd)
+ return lx.pop()
+}
+
+// lexInlineTableValue consumes one key/value pair in an inline table.
+// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
+func lexInlineTableValue(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexInlineTableValue)
+ case isNL(r):
+ return lx.errorPrevLine(errLexInlineTableNL{})
+ case r == '#':
+ lx.push(lexInlineTableValue)
+ return lexCommentStart
+ case r == ',':
+ return lx.errorf("unexpected comma")
+ case r == '}':
+ return lexInlineTableEnd
+ }
+ lx.backup()
+ lx.push(lexInlineTableValueEnd)
+ return lexKeyStart
+}
+
+// lexInlineTableValueEnd consumes everything between the end of an inline table
+// key/value pair and the next pair (or the end of the table):
+// it ignores whitespace and expects either a ',' or a '}'.
+func lexInlineTableValueEnd(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexSkip(lx, lexInlineTableValueEnd)
+ case isNL(r):
+ return lx.errorPrevLine(errLexInlineTableNL{})
+ case r == '#':
+ lx.push(lexInlineTableValueEnd)
+ return lexCommentStart
+ case r == ',':
+ lx.ignore()
+ lx.skip(isWhitespace)
+ if lx.peek() == '}' {
+ return lx.errorf("trailing comma not allowed in inline tables")
+ }
+ return lexInlineTableValue
+ case r == '}':
+ return lexInlineTableEnd
+ default:
+ return lx.errorf("expected a comma or an inline table terminator '}', but got %s instead", runeOrEOF(r))
+ }
+}
+
+func runeOrEOF(r rune) string {
+ if r == eof {
+ return "end of file"
+ }
+ return "'" + string(r) + "'"
+}
+
+// lexInlineTableEnd finishes the lexing of an inline table.
+// It assumes that a '}' has just been consumed.
+func lexInlineTableEnd(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemInlineTableEnd)
+ return lx.pop()
+}
+
+// lexString consumes the inner contents of a string. It assumes that the
+// beginning '"' has already been consumed and ignored.
+func lexString(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == eof:
+ return lx.errorf(`unexpected EOF; expected '"'`)
+ case isNL(r):
+ return lx.errorPrevLine(errLexStringNL{})
+ case r == '\\':
+ lx.push(lexString)
+ return lexStringEscape
+ case r == '"':
+ lx.backup()
+ lx.emit(itemString)
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ return lexString
+}
+
+// lexMultilineString consumes the inner contents of a string. It assumes that
+// the beginning '"""' has already been consumed and ignored.
+func lexMultilineString(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ default:
+ return lexMultilineString
+ case eof:
+ return lx.errorf(`unexpected EOF; expected '"""'`)
+ case '\\':
+ return lexMultilineStringEscape
+ case '"':
+ /// Found " → try to read two more "".
+ if lx.accept('"') {
+ if lx.accept('"') {
+ /// Peek ahead: the string can contain " and "", including at the
+ /// end: """str"""""
+ /// 6 or more at the end, however, is an error.
+ if lx.peek() == '"' {
+ /// Check if we already lexed 5 's; if so we have 6 now, and
+ /// that's just too many man!
+ ///
+ /// Second check is for the edge case:
+ ///
+ /// two quotes allowed.
+ /// vv
+ /// """lol \""""""
+ /// ^^ ^^^---- closing three
+ /// escaped
+ ///
+ /// But ugly, but it works
+ if strings.HasSuffix(lx.current(), `"""""`) && !strings.HasSuffix(lx.current(), `\"""""`) {
+ return lx.errorf(`unexpected '""""""'`)
+ }
+ lx.backup()
+ lx.backup()
+ return lexMultilineString
+ }
+
+ lx.backup() /// backup: don't include the """ in the item.
+ lx.backup()
+ lx.backup()
+ lx.emit(itemMultilineString)
+ lx.next() /// Read over ''' again and discard it.
+ lx.next()
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ lx.backup()
+ }
+ return lexMultilineString
+ }
+}
+
+// lexRawString consumes a raw string. Nothing can be escaped in such a string.
+// It assumes that the beginning "'" has already been consumed and ignored.
+func lexRawString(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ default:
+ return lexRawString
+ case r == eof:
+ return lx.errorf(`unexpected EOF; expected "'"`)
+ case isNL(r):
+ return lx.errorPrevLine(errLexStringNL{})
+ case r == '\'':
+ lx.backup()
+ lx.emit(itemRawString)
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+}
+
+// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
+// a string. It assumes that the beginning ''' has already been consumed and
+// ignored.
+func lexMultilineRawString(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ default:
+ return lexMultilineRawString
+ case eof:
+ return lx.errorf(`unexpected EOF; expected "'''"`)
+ case '\'':
+ /// Found ' → try to read two more ''.
+ if lx.accept('\'') {
+ if lx.accept('\'') {
+ /// Peek ahead: the string can contain ' and '', including at the
+ /// end: '''str'''''
+ /// 6 or more at the end, however, is an error.
+ if lx.peek() == '\'' {
+ /// Check if we already lexed 5 's; if so we have 6 now, and
+ /// that's just too many man!
+ if strings.HasSuffix(lx.current(), "'''''") {
+ return lx.errorf(`unexpected "''''''"`)
+ }
+ lx.backup()
+ lx.backup()
+ return lexMultilineRawString
+ }
+
+ lx.backup() /// backup: don't include the ''' in the item.
+ lx.backup()
+ lx.backup()
+ lx.emit(itemRawMultilineString)
+ lx.next() /// Read over ''' again and discard it.
+ lx.next()
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ lx.backup()
+ }
+ return lexMultilineRawString
+ }
+}
+
+// lexMultilineStringEscape consumes an escaped character. It assumes that the
+// preceding '\\' has already been consumed.
+func lexMultilineStringEscape(lx *lexer) stateFn {
+ if isNL(lx.next()) { /// \ escaping newline.
+ return lexMultilineString
+ }
+ lx.backup()
+ lx.push(lexMultilineString)
+ return lexStringEscape(lx)
+}
+
+func lexStringEscape(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ case 'b':
+ fallthrough
+ case 't':
+ fallthrough
+ case 'n':
+ fallthrough
+ case 'f':
+ fallthrough
+ case 'r':
+ fallthrough
+ case '"':
+ fallthrough
+ case ' ', '\t':
+ // Inside """ .. """ strings you can use \ to escape newlines, and any
+ // amount of whitespace can be between the \ and \n.
+ fallthrough
+ case '\\':
+ return lx.pop()
+ case 'u':
+ return lexShortUnicodeEscape
+ case 'U':
+ return lexLongUnicodeEscape
+ }
+ return lx.error(errLexEscape{r})
+}
+
+func lexShortUnicodeEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 4; i++ {
+ r = lx.next()
+ if !isHexadecimal(r) {
+ return lx.errorf(
+ `expected four hexadecimal digits after '\u', but got %q instead`,
+ lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+func lexLongUnicodeEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 8; i++ {
+ r = lx.next()
+ if !isHexadecimal(r) {
+ return lx.errorf(
+ `expected eight hexadecimal digits after '\U', but got %q instead`,
+ lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+// lexNumberOrDateStart processes the first character of a value which begins
+// with a digit. It exists to catch values starting with '0', so that
+// lexBaseNumberOrDate can differentiate base prefixed integers from other
+// types.
+func lexNumberOrDateStart(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ case '0':
+ return lexBaseNumberOrDate
+ }
+
+ if !isDigit(r) {
+ // The only way to reach this state is if the value starts
+ // with a digit, so specifically treat anything else as an
+ // error.
+ return lx.errorf("expected a digit but got %q", r)
+ }
+
+ return lexNumberOrDate
+}
+
+// lexNumberOrDate consumes either an integer, float or datetime.
+func lexNumberOrDate(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexNumberOrDate
+ }
+ switch r {
+ case '-', ':':
+ return lexDatetime
+ case '_':
+ return lexDecimalNumber
+ case '.', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDatetime consumes a Datetime, to a first approximation.
+// The parser validates that it matches one of the accepted formats.
+func lexDatetime(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexDatetime
+ }
+ switch r {
+ case '-', ':', 'T', 't', ' ', '.', 'Z', 'z', '+':
+ return lexDatetime
+ }
+
+ lx.backup()
+ lx.emitTrim(itemDatetime)
+ return lx.pop()
+}
+
+// lexHexInteger consumes a hexadecimal integer after seeing the '0x' prefix.
+func lexHexInteger(lx *lexer) stateFn {
+ r := lx.next()
+ if isHexadecimal(r) {
+ return lexHexInteger
+ }
+ switch r {
+ case '_':
+ return lexHexInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexOctalInteger consumes an octal integer after seeing the '0o' prefix.
+func lexOctalInteger(lx *lexer) stateFn {
+ r := lx.next()
+ if isOctal(r) {
+ return lexOctalInteger
+ }
+ switch r {
+ case '_':
+ return lexOctalInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexBinaryInteger consumes a binary integer after seeing the '0b' prefix.
+func lexBinaryInteger(lx *lexer) stateFn {
+ r := lx.next()
+ if isBinary(r) {
+ return lexBinaryInteger
+ }
+ switch r {
+ case '_':
+ return lexBinaryInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDecimalNumber consumes a decimal float or integer.
+func lexDecimalNumber(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexDecimalNumber
+ }
+ switch r {
+ case '.', 'e', 'E':
+ return lexFloat
+ case '_':
+ return lexDecimalNumber
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDecimalNumber consumes the first digit of a number beginning with a sign.
+// It assumes the sign has already been consumed. Values which start with a sign
+// are only allowed to be decimal integers or floats.
+//
+// The special "nan" and "inf" values are also recognized.
+func lexDecimalNumberStart(lx *lexer) stateFn {
+ r := lx.next()
+
+ // Special error cases to give users better error messages
+ switch r {
+ case 'i':
+ if !lx.accept('n') || !lx.accept('f') {
+ return lx.errorf("invalid float: '%s'", lx.current())
+ }
+ lx.emit(itemFloat)
+ return lx.pop()
+ case 'n':
+ if !lx.accept('a') || !lx.accept('n') {
+ return lx.errorf("invalid float: '%s'", lx.current())
+ }
+ lx.emit(itemFloat)
+ return lx.pop()
+ case '0':
+ p := lx.peek()
+ switch p {
+ case 'b', 'o', 'x':
+ return lx.errorf("cannot use sign with non-decimal numbers: '%s%c'", lx.current(), p)
+ }
+ case '.':
+ return lx.errorf("floats must start with a digit, not '.'")
+ }
+
+ if isDigit(r) {
+ return lexDecimalNumber
+ }
+
+ return lx.errorf("expected a digit but got %q", r)
+}
+
+// lexBaseNumberOrDate differentiates between the possible values which
+// start with '0'. It assumes that before reaching this state, the initial '0'
+// has been consumed.
+func lexBaseNumberOrDate(lx *lexer) stateFn {
+ r := lx.next()
+ // Note: All datetimes start with at least two digits, so we don't
+ // handle date characters (':', '-', etc.) here.
+ if isDigit(r) {
+ return lexNumberOrDate
+ }
+ switch r {
+ case '_':
+ // Can only be decimal, because there can't be an underscore
+ // between the '0' and the base designator, and dates can't
+ // contain underscores.
+ return lexDecimalNumber
+ case '.', 'e', 'E':
+ return lexFloat
+ case 'b':
+ r = lx.peek()
+ if !isBinary(r) {
+ lx.errorf("not a binary number: '%s%c'", lx.current(), r)
+ }
+ return lexBinaryInteger
+ case 'o':
+ r = lx.peek()
+ if !isOctal(r) {
+ lx.errorf("not an octal number: '%s%c'", lx.current(), r)
+ }
+ return lexOctalInteger
+ case 'x':
+ r = lx.peek()
+ if !isHexadecimal(r) {
+ lx.errorf("not a hexidecimal number: '%s%c'", lx.current(), r)
+ }
+ return lexHexInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexFloat consumes the elements of a float. It allows any sequence of
+// float-like characters, so floats emitted by the lexer are only a first
+// approximation and must be validated by the parser.
+func lexFloat(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexFloat
+ }
+ switch r {
+ case '_', '.', '-', '+', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemFloat)
+ return lx.pop()
+}
+
+// lexBool consumes a bool string: 'true' or 'false.
+func lexBool(lx *lexer) stateFn {
+ var rs []rune
+ for {
+ r := lx.next()
+ if !unicode.IsLetter(r) {
+ lx.backup()
+ break
+ }
+ rs = append(rs, r)
+ }
+ s := string(rs)
+ switch s {
+ case "true", "false":
+ lx.emit(itemBool)
+ return lx.pop()
+ }
+ return lx.errorf("expected value but found %q instead", s)
+}
+
+// lexCommentStart begins the lexing of a comment. It will emit
+// itemCommentStart and consume no characters, passing control to lexComment.
+func lexCommentStart(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemCommentStart)
+ return lexComment
+}
+
+// lexComment lexes an entire comment. It assumes that '#' has been consumed.
+// It will consume *up to* the first newline character, and pass control
+// back to the last state on the stack.
+func lexComment(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isNL(r) || r == eof:
+ lx.backup()
+ lx.emit(itemText)
+ return lx.pop()
+ default:
+ return lexComment
+ }
+}
+
+// lexSkip ignores all slurped input and moves on to the next state.
+func lexSkip(lx *lexer, nextState stateFn) stateFn {
+ lx.ignore()
+ return nextState
+}
+
+func (s stateFn) String() string {
+ name := runtime.FuncForPC(reflect.ValueOf(s).Pointer()).Name()
+ if i := strings.LastIndexByte(name, '.'); i > -1 {
+ name = name[i+1:]
+ }
+ if s == nil {
+ name = ""
+ }
+ return name + "()"
+}
+
+func (itype itemType) String() string {
+ switch itype {
+ case itemError:
+ return "Error"
+ case itemNIL:
+ return "NIL"
+ case itemEOF:
+ return "EOF"
+ case itemText:
+ return "Text"
+ case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
+ return "String"
+ case itemBool:
+ return "Bool"
+ case itemInteger:
+ return "Integer"
+ case itemFloat:
+ return "Float"
+ case itemDatetime:
+ return "DateTime"
+ case itemTableStart:
+ return "TableStart"
+ case itemTableEnd:
+ return "TableEnd"
+ case itemKeyStart:
+ return "KeyStart"
+ case itemKeyEnd:
+ return "KeyEnd"
+ case itemArray:
+ return "Array"
+ case itemArrayEnd:
+ return "ArrayEnd"
+ case itemCommentStart:
+ return "CommentStart"
+ case itemInlineTableStart:
+ return "InlineTableStart"
+ case itemInlineTableEnd:
+ return "InlineTableEnd"
+ }
+ panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
+}
+
+func (item item) String() string {
+ return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
+}
+
+func isWhitespace(r rune) bool { return r == '\t' || r == ' ' }
+func isNL(r rune) bool { return r == '\n' || r == '\r' }
+func isControl(r rune) bool { // Control characters except \t, \r, \n
+ switch r {
+ case '\t', '\r', '\n':
+ return false
+ default:
+ return (r >= 0x00 && r <= 0x1f) || r == 0x7f
+ }
+}
+func isDigit(r rune) bool { return r >= '0' && r <= '9' }
+func isBinary(r rune) bool { return r == '0' || r == '1' }
+func isOctal(r rune) bool { return r >= '0' && r <= '7' }
+func isHexadecimal(r rune) bool {
+ return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')
+}
+func isBareKeyChar(r rune) bool {
+ return (r >= 'A' && r <= 'Z') ||
+ (r >= 'a' && r <= 'z') ||
+ (r >= '0' && r <= '9') ||
+ r == '_' || r == '-'
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/meta.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/meta.go
new file mode 100644
index 000000000000..71847a04158c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/meta.go
@@ -0,0 +1,121 @@
+package toml
+
+import (
+ "strings"
+)
+
+// MetaData allows access to meta information about TOML data that's not
+// accessible otherwise.
+//
+// It allows checking if a key is defined in the TOML data, whether any keys
+// were undecoded, and the TOML type of a key.
+type MetaData struct {
+ context Key // Used only during decoding.
+
+ keyInfo map[string]keyInfo
+ mapping map[string]interface{}
+ keys []Key
+ decoded map[string]struct{}
+ data []byte // Input file; for errors.
+}
+
+// IsDefined reports if the key exists in the TOML data.
+//
+// The key should be specified hierarchically, for example to access the TOML
+// key "a.b.c" you would use IsDefined("a", "b", "c"). Keys are case sensitive.
+//
+// Returns false for an empty key.
+func (md *MetaData) IsDefined(key ...string) bool {
+ if len(key) == 0 {
+ return false
+ }
+
+ var (
+ hash map[string]interface{}
+ ok bool
+ hashOrVal interface{} = md.mapping
+ )
+ for _, k := range key {
+ if hash, ok = hashOrVal.(map[string]interface{}); !ok {
+ return false
+ }
+ if hashOrVal, ok = hash[k]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// Type returns a string representation of the type of the key specified.
+//
+// Type will return the empty string if given an empty key or a key that does
+// not exist. Keys are case sensitive.
+func (md *MetaData) Type(key ...string) string {
+ if ki, ok := md.keyInfo[Key(key).String()]; ok {
+ return ki.tomlType.typeString()
+ }
+ return ""
+}
+
+// Keys returns a slice of every key in the TOML data, including key groups.
+//
+// Each key is itself a slice, where the first element is the top of the
+// hierarchy and the last is the most specific. The list will have the same
+// order as the keys appeared in the TOML data.
+//
+// All keys returned are non-empty.
+func (md *MetaData) Keys() []Key {
+ return md.keys
+}
+
+// Undecoded returns all keys that have not been decoded in the order in which
+// they appear in the original TOML document.
+//
+// This includes keys that haven't been decoded because of a [Primitive] value.
+// Once the Primitive value is decoded, the keys will be considered decoded.
+//
+// Also note that decoding into an empty interface will result in no decoding,
+// and so no keys will be considered decoded.
+//
+// In this sense, the Undecoded keys correspond to keys in the TOML document
+// that do not have a concrete type in your representation.
+func (md *MetaData) Undecoded() []Key {
+ undecoded := make([]Key, 0, len(md.keys))
+ for _, key := range md.keys {
+ if _, ok := md.decoded[key.String()]; !ok {
+ undecoded = append(undecoded, key)
+ }
+ }
+ return undecoded
+}
+
+// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get
+// values of this type.
+type Key []string
+
+func (k Key) String() string {
+ ss := make([]string, len(k))
+ for i := range k {
+ ss[i] = k.maybeQuoted(i)
+ }
+ return strings.Join(ss, ".")
+}
+
+func (k Key) maybeQuoted(i int) string {
+ if k[i] == "" {
+ return `""`
+ }
+ for _, c := range k[i] {
+ if !isBareKeyChar(c) {
+ return `"` + dblQuotedReplacer.Replace(k[i]) + `"`
+ }
+ }
+ return k[i]
+}
+
+func (k Key) add(piece string) Key {
+ newKey := make(Key, len(k)+1)
+ copy(newKey, k)
+ newKey[len(k)] = piece
+ return newKey
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/parse.go
new file mode 100644
index 000000000000..d2542d6f926f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/parse.go
@@ -0,0 +1,781 @@
+package toml
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+
+ "github.com/BurntSushi/toml/internal"
+)
+
+type parser struct {
+ lx *lexer
+ context Key // Full key for the current hash in scope.
+ currentKey string // Base key name for everything except hashes.
+ pos Position // Current position in the TOML file.
+
+ ordered []Key // List of keys in the order that they appear in the TOML data.
+
+ keyInfo map[string]keyInfo // Map keyname → info about the TOML key.
+ mapping map[string]interface{} // Map keyname → key value.
+ implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names").
+}
+
+type keyInfo struct {
+ pos Position
+ tomlType tomlType
+}
+
+func parse(data string) (p *parser, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if pErr, ok := r.(ParseError); ok {
+ pErr.input = data
+ err = pErr
+ return
+ }
+ panic(r)
+ }
+ }()
+
+ // Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString()
+ // which mangles stuff.
+ if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") {
+ data = data[2:]
+ }
+
+ // Examine first few bytes for NULL bytes; this probably means it's a UTF-16
+ // file (second byte in surrogate pair being NULL). Again, do this here to
+ // avoid having to deal with UTF-8/16 stuff in the lexer.
+ ex := 6
+ if len(data) < 6 {
+ ex = len(data)
+ }
+ if i := strings.IndexRune(data[:ex], 0); i > -1 {
+ return nil, ParseError{
+ Message: "files cannot contain NULL bytes; probably using UTF-16; TOML files must be UTF-8",
+ Position: Position{Line: 1, Start: i, Len: 1},
+ Line: 1,
+ input: data,
+ }
+ }
+
+ p = &parser{
+ keyInfo: make(map[string]keyInfo),
+ mapping: make(map[string]interface{}),
+ lx: lex(data),
+ ordered: make([]Key, 0),
+ implicits: make(map[string]struct{}),
+ }
+ for {
+ item := p.next()
+ if item.typ == itemEOF {
+ break
+ }
+ p.topLevel(item)
+ }
+
+ return p, nil
+}
+
+func (p *parser) panicErr(it item, err error) {
+ panic(ParseError{
+ err: err,
+ Position: it.pos,
+ Line: it.pos.Len,
+ LastKey: p.current(),
+ })
+}
+
+func (p *parser) panicItemf(it item, format string, v ...interface{}) {
+ panic(ParseError{
+ Message: fmt.Sprintf(format, v...),
+ Position: it.pos,
+ Line: it.pos.Len,
+ LastKey: p.current(),
+ })
+}
+
+func (p *parser) panicf(format string, v ...interface{}) {
+ panic(ParseError{
+ Message: fmt.Sprintf(format, v...),
+ Position: p.pos,
+ Line: p.pos.Line,
+ LastKey: p.current(),
+ })
+}
+
+func (p *parser) next() item {
+ it := p.lx.nextItem()
+ //fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.pos.Line, it.val)
+ if it.typ == itemError {
+ if it.err != nil {
+ panic(ParseError{
+ Position: it.pos,
+ Line: it.pos.Line,
+ LastKey: p.current(),
+ err: it.err,
+ })
+ }
+
+ p.panicItemf(it, "%s", it.val)
+ }
+ return it
+}
+
+func (p *parser) nextPos() item {
+ it := p.next()
+ p.pos = it.pos
+ return it
+}
+
+func (p *parser) bug(format string, v ...interface{}) {
+ panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
+}
+
+func (p *parser) expect(typ itemType) item {
+ it := p.next()
+ p.assertEqual(typ, it.typ)
+ return it
+}
+
+func (p *parser) assertEqual(expected, got itemType) {
+ if expected != got {
+ p.bug("Expected '%s' but got '%s'.", expected, got)
+ }
+}
+
+func (p *parser) topLevel(item item) {
+ switch item.typ {
+ case itemCommentStart: // # ..
+ p.expect(itemText)
+ case itemTableStart: // [ .. ]
+ name := p.nextPos()
+
+ var key Key
+ for ; name.typ != itemTableEnd && name.typ != itemEOF; name = p.next() {
+ key = append(key, p.keyString(name))
+ }
+ p.assertEqual(itemTableEnd, name.typ)
+
+ p.addContext(key, false)
+ p.setType("", tomlHash, item.pos)
+ p.ordered = append(p.ordered, key)
+ case itemArrayTableStart: // [[ .. ]]
+ name := p.nextPos()
+
+ var key Key
+ for ; name.typ != itemArrayTableEnd && name.typ != itemEOF; name = p.next() {
+ key = append(key, p.keyString(name))
+ }
+ p.assertEqual(itemArrayTableEnd, name.typ)
+
+ p.addContext(key, true)
+ p.setType("", tomlArrayHash, item.pos)
+ p.ordered = append(p.ordered, key)
+ case itemKeyStart: // key = ..
+ outerContext := p.context
+ /// Read all the key parts (e.g. 'a' and 'b' in 'a.b')
+ k := p.nextPos()
+ var key Key
+ for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
+ key = append(key, p.keyString(k))
+ }
+ p.assertEqual(itemKeyEnd, k.typ)
+
+ /// The current key is the last part.
+ p.currentKey = key[len(key)-1]
+
+ /// All the other parts (if any) are the context; need to set each part
+ /// as implicit.
+ context := key[:len(key)-1]
+ for i := range context {
+ p.addImplicitContext(append(p.context, context[i:i+1]...))
+ }
+
+ /// Set value.
+ vItem := p.next()
+ val, typ := p.value(vItem, false)
+ p.set(p.currentKey, val, typ, vItem.pos)
+ p.ordered = append(p.ordered, p.context.add(p.currentKey))
+
+ /// Remove the context we added (preserving any context from [tbl] lines).
+ p.context = outerContext
+ p.currentKey = ""
+ default:
+ p.bug("Unexpected type at top level: %s", item.typ)
+ }
+}
+
+// Gets a string for a key (or part of a key in a table name).
+func (p *parser) keyString(it item) string {
+ switch it.typ {
+ case itemText:
+ return it.val
+ case itemString, itemMultilineString,
+ itemRawString, itemRawMultilineString:
+ s, _ := p.value(it, false)
+ return s.(string)
+ default:
+ p.bug("Unexpected key type: %s", it.typ)
+ }
+ panic("unreachable")
+}
+
+var datetimeRepl = strings.NewReplacer(
+ "z", "Z",
+ "t", "T",
+ " ", "T")
+
+// value translates an expected value from the lexer into a Go value wrapped
+// as an empty interface.
+func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) {
+ switch it.typ {
+ case itemString:
+ return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it)
+ case itemMultilineString:
+ return p.replaceEscapes(it, stripFirstNewline(p.stripEscapedNewlines(it.val))), p.typeOfPrimitive(it)
+ case itemRawString:
+ return it.val, p.typeOfPrimitive(it)
+ case itemRawMultilineString:
+ return stripFirstNewline(it.val), p.typeOfPrimitive(it)
+ case itemInteger:
+ return p.valueInteger(it)
+ case itemFloat:
+ return p.valueFloat(it)
+ case itemBool:
+ switch it.val {
+ case "true":
+ return true, p.typeOfPrimitive(it)
+ case "false":
+ return false, p.typeOfPrimitive(it)
+ default:
+ p.bug("Expected boolean value, but got '%s'.", it.val)
+ }
+ case itemDatetime:
+ return p.valueDatetime(it)
+ case itemArray:
+ return p.valueArray(it)
+ case itemInlineTableStart:
+ return p.valueInlineTable(it, parentIsArray)
+ default:
+ p.bug("Unexpected value type: %s", it.typ)
+ }
+ panic("unreachable")
+}
+
+func (p *parser) valueInteger(it item) (interface{}, tomlType) {
+ if !numUnderscoresOK(it.val) {
+ p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val)
+ }
+ if numHasLeadingZero(it.val) {
+ p.panicItemf(it, "Invalid integer %q: cannot have leading zeroes", it.val)
+ }
+
+ num, err := strconv.ParseInt(it.val, 0, 64)
+ if err != nil {
+ // Distinguish integer values. Normally, it'd be a bug if the lexer
+ // provides an invalid integer, but it's possible that the number is
+ // out of range of valid values (which the lexer cannot determine).
+ // So mark the former as a bug but the latter as a legitimate user
+ // error.
+ if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
+ p.panicErr(it, errParseRange{i: it.val, size: "int64"})
+ } else {
+ p.bug("Expected integer value, but got '%s'.", it.val)
+ }
+ }
+ return num, p.typeOfPrimitive(it)
+}
+
+func (p *parser) valueFloat(it item) (interface{}, tomlType) {
+ parts := strings.FieldsFunc(it.val, func(r rune) bool {
+ switch r {
+ case '.', 'e', 'E':
+ return true
+ }
+ return false
+ })
+ for _, part := range parts {
+ if !numUnderscoresOK(part) {
+ p.panicItemf(it, "Invalid float %q: underscores must be surrounded by digits", it.val)
+ }
+ }
+ if len(parts) > 0 && numHasLeadingZero(parts[0]) {
+ p.panicItemf(it, "Invalid float %q: cannot have leading zeroes", it.val)
+ }
+ if !numPeriodsOK(it.val) {
+ // As a special case, numbers like '123.' or '1.e2',
+ // which are valid as far as Go/strconv are concerned,
+ // must be rejected because TOML says that a fractional
+ // part consists of '.' followed by 1+ digits.
+ p.panicItemf(it, "Invalid float %q: '.' must be followed by one or more digits", it.val)
+ }
+ val := strings.Replace(it.val, "_", "", -1)
+ if val == "+nan" || val == "-nan" { // Go doesn't support this, but TOML spec does.
+ val = "nan"
+ }
+ num, err := strconv.ParseFloat(val, 64)
+ if err != nil {
+ if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
+ p.panicErr(it, errParseRange{i: it.val, size: "float64"})
+ } else {
+ p.panicItemf(it, "Invalid float value: %q", it.val)
+ }
+ }
+ return num, p.typeOfPrimitive(it)
+}
+
+var dtTypes = []struct {
+ fmt string
+ zone *time.Location
+}{
+ {time.RFC3339Nano, time.Local},
+ {"2006-01-02T15:04:05.999999999", internal.LocalDatetime},
+ {"2006-01-02", internal.LocalDate},
+ {"15:04:05.999999999", internal.LocalTime},
+}
+
+func (p *parser) valueDatetime(it item) (interface{}, tomlType) {
+ it.val = datetimeRepl.Replace(it.val)
+ var (
+ t time.Time
+ ok bool
+ err error
+ )
+ for _, dt := range dtTypes {
+ t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
+ if err == nil {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ p.panicItemf(it, "Invalid TOML Datetime: %q.", it.val)
+ }
+ return t, p.typeOfPrimitive(it)
+}
+
+func (p *parser) valueArray(it item) (interface{}, tomlType) {
+ p.setType(p.currentKey, tomlArray, it.pos)
+
+ var (
+ types []tomlType
+
+ // Initialize to a non-nil empty slice. This makes it consistent with
+ // how S = [] decodes into a non-nil slice inside something like struct
+ // { S []string }. See #338
+ array = []interface{}{}
+ )
+ for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
+ if it.typ == itemCommentStart {
+ p.expect(itemText)
+ continue
+ }
+
+ val, typ := p.value(it, true)
+ array = append(array, val)
+ types = append(types, typ)
+
+ // XXX: types isn't used here, we need it to record the accurate type
+ // information.
+ //
+ // Not entirely sure how to best store this; could use "key[0]",
+ // "key[1]" notation, or maybe store it on the Array type?
+ }
+ return array, tomlArray
+}
+
+func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tomlType) {
+ var (
+ hash = make(map[string]interface{})
+ outerContext = p.context
+ outerKey = p.currentKey
+ )
+
+ p.context = append(p.context, p.currentKey)
+ prevContext := p.context
+ p.currentKey = ""
+
+ p.addImplicit(p.context)
+ p.addContext(p.context, parentIsArray)
+
+ /// Loop over all table key/value pairs.
+ for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
+ if it.typ == itemCommentStart {
+ p.expect(itemText)
+ continue
+ }
+
+ /// Read all key parts.
+ k := p.nextPos()
+ var key Key
+ for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
+ key = append(key, p.keyString(k))
+ }
+ p.assertEqual(itemKeyEnd, k.typ)
+
+ /// The current key is the last part.
+ p.currentKey = key[len(key)-1]
+
+ /// All the other parts (if any) are the context; need to set each part
+ /// as implicit.
+ context := key[:len(key)-1]
+ for i := range context {
+ p.addImplicitContext(append(p.context, context[i:i+1]...))
+ }
+
+ /// Set the value.
+ val, typ := p.value(p.next(), false)
+ p.set(p.currentKey, val, typ, it.pos)
+ p.ordered = append(p.ordered, p.context.add(p.currentKey))
+ hash[p.currentKey] = val
+
+ /// Restore context.
+ p.context = prevContext
+ }
+ p.context = outerContext
+ p.currentKey = outerKey
+ return hash, tomlHash
+}
+
+// numHasLeadingZero checks if this number has leading zeroes, allowing for '0',
+// +/- signs, and base prefixes.
+func numHasLeadingZero(s string) bool {
+ if len(s) > 1 && s[0] == '0' && !(s[1] == 'b' || s[1] == 'o' || s[1] == 'x') { // Allow 0b, 0o, 0x
+ return true
+ }
+ if len(s) > 2 && (s[0] == '-' || s[0] == '+') && s[1] == '0' {
+ return true
+ }
+ return false
+}
+
+// numUnderscoresOK checks whether each underscore in s is surrounded by
+// characters that are not underscores.
+func numUnderscoresOK(s string) bool {
+ switch s {
+ case "nan", "+nan", "-nan", "inf", "-inf", "+inf":
+ return true
+ }
+ accept := false
+ for _, r := range s {
+ if r == '_' {
+ if !accept {
+ return false
+ }
+ }
+
+ // isHexadecimal is a superset of all the permissable characters
+ // surrounding an underscore.
+ accept = isHexadecimal(r)
+ }
+ return accept
+}
+
+// numPeriodsOK checks whether every period in s is followed by a digit.
+func numPeriodsOK(s string) bool {
+ period := false
+ for _, r := range s {
+ if period && !isDigit(r) {
+ return false
+ }
+ period = r == '.'
+ }
+ return !period
+}
+
+// Set the current context of the parser, where the context is either a hash or
+// an array of hashes, depending on the value of the `array` parameter.
+//
+// Establishing the context also makes sure that the key isn't a duplicate, and
+// will create implicit hashes automatically.
+func (p *parser) addContext(key Key, array bool) {
+ var ok bool
+
+ // Always start at the top level and drill down for our context.
+ hashContext := p.mapping
+ keyContext := make(Key, 0)
+
+ // We only need implicit hashes for key[0:-1]
+ for _, k := range key[0 : len(key)-1] {
+ _, ok = hashContext[k]
+ keyContext = append(keyContext, k)
+
+ // No key? Make an implicit hash and move on.
+ if !ok {
+ p.addImplicit(keyContext)
+ hashContext[k] = make(map[string]interface{})
+ }
+
+ // If the hash context is actually an array of tables, then set
+ // the hash context to the last element in that array.
+ //
+ // Otherwise, it better be a table, since this MUST be a key group (by
+ // virtue of it not being the last element in a key).
+ switch t := hashContext[k].(type) {
+ case []map[string]interface{}:
+ hashContext = t[len(t)-1]
+ case map[string]interface{}:
+ hashContext = t
+ default:
+ p.panicf("Key '%s' was already created as a hash.", keyContext)
+ }
+ }
+
+ p.context = keyContext
+ if array {
+ // If this is the first element for this array, then allocate a new
+ // list of tables for it.
+ k := key[len(key)-1]
+ if _, ok := hashContext[k]; !ok {
+ hashContext[k] = make([]map[string]interface{}, 0, 4)
+ }
+
+ // Add a new table. But make sure the key hasn't already been used
+ // for something else.
+ if hash, ok := hashContext[k].([]map[string]interface{}); ok {
+ hashContext[k] = append(hash, make(map[string]interface{}))
+ } else {
+ p.panicf("Key '%s' was already created and cannot be used as an array.", key)
+ }
+ } else {
+ p.setValue(key[len(key)-1], make(map[string]interface{}))
+ }
+ p.context = append(p.context, key[len(key)-1])
+}
+
+// set calls setValue and setType.
+func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) {
+ p.setValue(key, val)
+ p.setType(key, typ, pos)
+
+}
+
+// setValue sets the given key to the given value in the current context.
+// It will make sure that the key hasn't already been defined, account for
+// implicit key groups.
+func (p *parser) setValue(key string, value interface{}) {
+ var (
+ tmpHash interface{}
+ ok bool
+ hash = p.mapping
+ keyContext Key
+ )
+ for _, k := range p.context {
+ keyContext = append(keyContext, k)
+ if tmpHash, ok = hash[k]; !ok {
+ p.bug("Context for key '%s' has not been established.", keyContext)
+ }
+ switch t := tmpHash.(type) {
+ case []map[string]interface{}:
+ // The context is a table of hashes. Pick the most recent table
+ // defined as the current hash.
+ hash = t[len(t)-1]
+ case map[string]interface{}:
+ hash = t
+ default:
+ p.panicf("Key '%s' has already been defined.", keyContext)
+ }
+ }
+ keyContext = append(keyContext, key)
+
+ if _, ok := hash[key]; ok {
+ // Normally redefining keys isn't allowed, but the key could have been
+ // defined implicitly and it's allowed to be redefined concretely. (See
+ // the `valid/implicit-and-explicit-after.toml` in toml-test)
+ //
+ // But we have to make sure to stop marking it as an implicit. (So that
+ // another redefinition provokes an error.)
+ //
+ // Note that since it has already been defined (as a hash), we don't
+ // want to overwrite it. So our business is done.
+ if p.isArray(keyContext) {
+ p.removeImplicit(keyContext)
+ hash[key] = value
+ return
+ }
+ if p.isImplicit(keyContext) {
+ p.removeImplicit(keyContext)
+ return
+ }
+
+ // Otherwise, we have a concrete key trying to override a previous
+ // key, which is *always* wrong.
+ p.panicf("Key '%s' has already been defined.", keyContext)
+ }
+
+ hash[key] = value
+}
+
+// setType sets the type of a particular value at a given key. It should be
+// called immediately AFTER setValue.
+//
+// Note that if `key` is empty, then the type given will be applied to the
+// current context (which is either a table or an array of tables).
+func (p *parser) setType(key string, typ tomlType, pos Position) {
+ keyContext := make(Key, 0, len(p.context)+1)
+ keyContext = append(keyContext, p.context...)
+ if len(key) > 0 { // allow type setting for hashes
+ keyContext = append(keyContext, key)
+ }
+ // Special case to make empty keys ("" = 1) work.
+ // Without it it will set "" rather than `""`.
+ // TODO: why is this needed? And why is this only needed here?
+ if len(keyContext) == 0 {
+ keyContext = Key{""}
+ }
+ p.keyInfo[keyContext.String()] = keyInfo{tomlType: typ, pos: pos}
+}
+
+// Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and
+// "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly).
+func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} }
+func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) }
+func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok }
+func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray }
+func (p *parser) addImplicitContext(key Key) {
+ p.addImplicit(key)
+ p.addContext(key, false)
+}
+
+// current returns the full key name of the current context.
+func (p *parser) current() string {
+ if len(p.currentKey) == 0 {
+ return p.context.String()
+ }
+ if len(p.context) == 0 {
+ return p.currentKey
+ }
+ return fmt.Sprintf("%s.%s", p.context, p.currentKey)
+}
+
+func stripFirstNewline(s string) string {
+ if len(s) > 0 && s[0] == '\n' {
+ return s[1:]
+ }
+ if len(s) > 1 && s[0] == '\r' && s[1] == '\n' {
+ return s[2:]
+ }
+ return s
+}
+
+// Remove newlines inside triple-quoted strings if a line ends with "\".
+func (p *parser) stripEscapedNewlines(s string) string {
+ split := strings.Split(s, "\n")
+ if len(split) < 1 {
+ return s
+ }
+
+ escNL := false // Keep track of the last non-blank line was escaped.
+ for i, line := range split {
+ line = strings.TrimRight(line, " \t\r")
+
+ if len(line) == 0 || line[len(line)-1] != '\\' {
+ split[i] = strings.TrimRight(split[i], "\r")
+ if !escNL && i != len(split)-1 {
+ split[i] += "\n"
+ }
+ continue
+ }
+
+ escBS := true
+ for j := len(line) - 1; j >= 0 && line[j] == '\\'; j-- {
+ escBS = !escBS
+ }
+ if escNL {
+ line = strings.TrimLeft(line, " \t\r")
+ }
+ escNL = !escBS
+
+ if escBS {
+ split[i] += "\n"
+ continue
+ }
+
+ if i == len(split)-1 {
+ p.panicf("invalid escape: '\\ '")
+ }
+
+ split[i] = line[:len(line)-1] // Remove \
+ if len(split)-1 > i {
+ split[i+1] = strings.TrimLeft(split[i+1], " \t\r")
+ }
+ }
+ return strings.Join(split, "")
+}
+
+func (p *parser) replaceEscapes(it item, str string) string {
+ replaced := make([]rune, 0, len(str))
+ s := []byte(str)
+ r := 0
+ for r < len(s) {
+ if s[r] != '\\' {
+ c, size := utf8.DecodeRune(s[r:])
+ r += size
+ replaced = append(replaced, c)
+ continue
+ }
+ r += 1
+ if r >= len(s) {
+ p.bug("Escape sequence at end of string.")
+ return ""
+ }
+ switch s[r] {
+ default:
+ p.bug("Expected valid escape code after \\, but got %q.", s[r])
+ case ' ', '\t':
+ p.panicItemf(it, "invalid escape: '\\%c'", s[r])
+ case 'b':
+ replaced = append(replaced, rune(0x0008))
+ r += 1
+ case 't':
+ replaced = append(replaced, rune(0x0009))
+ r += 1
+ case 'n':
+ replaced = append(replaced, rune(0x000A))
+ r += 1
+ case 'f':
+ replaced = append(replaced, rune(0x000C))
+ r += 1
+ case 'r':
+ replaced = append(replaced, rune(0x000D))
+ r += 1
+ case '"':
+ replaced = append(replaced, rune(0x0022))
+ r += 1
+ case '\\':
+ replaced = append(replaced, rune(0x005C))
+ r += 1
+ case 'u':
+ // At this point, we know we have a Unicode escape of the form
+ // `uXXXX` at [r, r+5). (Because the lexer guarantees this
+ // for us.)
+ escaped := p.asciiEscapeToUnicode(it, s[r+1:r+5])
+ replaced = append(replaced, escaped)
+ r += 5
+ case 'U':
+ // At this point, we know we have a Unicode escape of the form
+ // `uXXXX` at [r, r+9). (Because the lexer guarantees this
+ // for us.)
+ escaped := p.asciiEscapeToUnicode(it, s[r+1:r+9])
+ replaced = append(replaced, escaped)
+ r += 9
+ }
+ }
+ return string(replaced)
+}
+
+func (p *parser) asciiEscapeToUnicode(it item, bs []byte) rune {
+ s := string(bs)
+ hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
+ if err != nil {
+ p.bug("Could not parse '%s' as a hexadecimal number, but the lexer claims it's OK: %s", s, err)
+ }
+ if !utf8.ValidRune(rune(hex)) {
+ p.panicItemf(it, "Escaped character '\\u%s' is not valid UTF-8.", s)
+ }
+ return rune(hex)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/type_fields.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/type_fields.go
new file mode 100644
index 000000000000..254ca82e5494
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/type_fields.go
@@ -0,0 +1,242 @@
+package toml
+
+// Struct field handling is adapted from code in encoding/json:
+//
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the Go distribution.
+
+import (
+ "reflect"
+ "sort"
+ "sync"
+)
+
+// A field represents a single field found in a struct.
+type field struct {
+ name string // the name of the field (`toml` tag included)
+ tag bool // whether field has a `toml` tag
+ index []int // represents the depth of an anonymous field
+ typ reflect.Type // the type of the field
+}
+
+// byName sorts field by name, breaking ties with depth,
+// then breaking ties with "name came from toml tag", then
+// breaking ties with index sequence.
+type byName []field
+
+func (x byName) Len() int { return len(x) }
+
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byName) Less(i, j int) bool {
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
+ }
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+}
+
+// byIndex sorts field by index sequence.
+type byIndex []field
+
+func (x byIndex) Len() int { return len(x) }
+
+func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byIndex) Less(i, j int) bool {
+ for k, xik := range x[i].index {
+ if k >= len(x[j].index) {
+ return false
+ }
+ if xik != x[j].index[k] {
+ return xik < x[j].index[k]
+ }
+ }
+ return len(x[i].index) < len(x[j].index)
+}
+
+// typeFields returns a list of fields that TOML should recognize for the given
+// type. The algorithm is breadth-first search over the set of structs to
+// include - the top struct and then any reachable anonymous structs.
+func typeFields(t reflect.Type) []field {
+ // Anonymous fields to explore at the current level and the next.
+ current := []field{}
+ next := []field{{typ: t}}
+
+ // Count of queued names for current level and the next.
+ var count map[reflect.Type]int
+ var nextCount map[reflect.Type]int
+
+ // Types already visited at an earlier level.
+ visited := map[reflect.Type]bool{}
+
+ // Fields found.
+ var fields []field
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, map[reflect.Type]int{}
+
+ for _, f := range current {
+ if visited[f.typ] {
+ continue
+ }
+ visited[f.typ] = true
+
+ // Scan f.typ for fields to include.
+ for i := 0; i < f.typ.NumField(); i++ {
+ sf := f.typ.Field(i)
+ if sf.PkgPath != "" && !sf.Anonymous { // unexported
+ continue
+ }
+ opts := getOptions(sf.Tag)
+ if opts.skip {
+ continue
+ }
+ index := make([]int, len(f.index)+1)
+ copy(index, f.index)
+ index[len(f.index)] = i
+
+ ft := sf.Type
+ if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+ // Follow pointer.
+ ft = ft.Elem()
+ }
+
+ // Record found field and index sequence.
+ if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
+ tagged := opts.name != ""
+ name := opts.name
+ if name == "" {
+ name = sf.Name
+ }
+ fields = append(fields, field{name, tagged, index, ft})
+ if count[f.typ] > 1 {
+ // If there were multiple instances, add a second,
+ // so that the annihilation code will see a duplicate.
+ // It only cares about the distinction between 1 or 2,
+ // so don't bother generating any more copies.
+ fields = append(fields, fields[len(fields)-1])
+ }
+ continue
+ }
+
+ // Record new anonymous struct to explore in next round.
+ nextCount[ft]++
+ if nextCount[ft] == 1 {
+ f := field{name: ft.Name(), index: index, typ: ft}
+ next = append(next, f)
+ }
+ }
+ }
+ }
+
+ sort.Sort(byName(fields))
+
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with TOML tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
+ out := fields[:0]
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.name
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.name != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
+ continue
+ }
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
+ }
+ }
+
+ fields = out
+ sort.Sort(byIndex(fields))
+
+ return fields
+}
+
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// TOML tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []field) (field, bool) {
+ // The fields are sorted in increasing index-length order. The winner
+ // must therefore be one with the shortest index length. Drop all
+ // longer entries, which is easy: just truncate the slice.
+ length := len(fields[0].index)
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if len(f.index) > length {
+ fields = fields[:i]
+ break
+ }
+ if f.tag {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return field{}, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return field{}, false
+ }
+ return fields[0], true
+}
+
+var fieldCache struct {
+ sync.RWMutex
+ m map[reflect.Type][]field
+}
+
+// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
+func cachedTypeFields(t reflect.Type) []field {
+ fieldCache.RLock()
+ f := fieldCache.m[t]
+ fieldCache.RUnlock()
+ if f != nil {
+ return f
+ }
+
+ // Compute fields without lock.
+ // Might duplicate effort but won't hold other computations back.
+ f = typeFields(t)
+ if f == nil {
+ f = []field{}
+ }
+
+ fieldCache.Lock()
+ if fieldCache.m == nil {
+ fieldCache.m = map[reflect.Type][]field{}
+ }
+ fieldCache.m[t] = f
+ fieldCache.Unlock()
+ return f
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/type_toml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/type_toml.go
new file mode 100644
index 000000000000..4e90d77373b9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/BurntSushi/toml/type_toml.go
@@ -0,0 +1,70 @@
+package toml
+
+// tomlType represents any Go type that corresponds to a TOML type.
+// While the first draft of the TOML spec has a simplistic type system that
+// probably doesn't need this level of sophistication, we seem to be militating
+// toward adding real composite types.
+type tomlType interface {
+ typeString() string
+}
+
+// typeEqual accepts any two types and returns true if they are equal.
+func typeEqual(t1, t2 tomlType) bool {
+ if t1 == nil || t2 == nil {
+ return false
+ }
+ return t1.typeString() == t2.typeString()
+}
+
+func typeIsTable(t tomlType) bool {
+ return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
+}
+
+type tomlBaseType string
+
+func (btype tomlBaseType) typeString() string {
+ return string(btype)
+}
+
+func (btype tomlBaseType) String() string {
+ return btype.typeString()
+}
+
+var (
+ tomlInteger tomlBaseType = "Integer"
+ tomlFloat tomlBaseType = "Float"
+ tomlDatetime tomlBaseType = "Datetime"
+ tomlString tomlBaseType = "String"
+ tomlBool tomlBaseType = "Bool"
+ tomlArray tomlBaseType = "Array"
+ tomlHash tomlBaseType = "Hash"
+ tomlArrayHash tomlBaseType = "ArrayHash"
+)
+
+// typeOfPrimitive returns a tomlType of any primitive value in TOML.
+// Primitive values are: Integer, Float, Datetime, String and Bool.
+//
+// Passing a lexer item other than the following will cause a BUG message
+// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
+func (p *parser) typeOfPrimitive(lexItem item) tomlType {
+ switch lexItem.typ {
+ case itemInteger:
+ return tomlInteger
+ case itemFloat:
+ return tomlFloat
+ case itemDatetime:
+ return tomlDatetime
+ case itemString:
+ return tomlString
+ case itemMultilineString:
+ return tomlString
+ case itemRawString:
+ return tomlString
+ case itemRawMultilineString:
+ return tomlString
+ case itemBool:
+ return tomlBool
+ }
+ p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
+ panic("unreachable")
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/LICENSE
new file mode 100644
index 000000000000..95d674b685f8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 CloudyKit
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/README.md
new file mode 100644
index 000000000000..2078fd2fb035
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/README.md
@@ -0,0 +1,2 @@
+# fastprinter
+FastPrinter supports write values in io.Writer without allocation
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/decimal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/decimal.go
new file mode 100644
index 000000000000..078297fe614c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/decimal.go
@@ -0,0 +1,369 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Multiprecision decimal numbers.
+// For floating-point formatting only; not general purpose.
+// Only operations are assign and (binary) left/right shift.
+// Can do binary floating point in multiprecision decimal precisely
+// because 2 divides 10; cannot do decimal floating point
+// in multiprecision binary precisely.
+
+package fastprinter
+
+type decimal struct {
+ d [800]byte // digits, big-endian representation
+ nd int // number of digits used
+ dp int // decimal point
+ neg bool
+ trunc bool // discarded nonzero digits beyond d[:nd]
+}
+
+// trim trailing zeros from number.
+// (They are meaningless; the decimal point is tracked
+// independent of the number of digits.)
+func trim(a *decimal) {
+ for a.nd > 0 && a.d[a.nd-1] == '0' {
+ a.nd--
+ }
+ if a.nd == 0 {
+ a.dp = 0
+ }
+}
+
+// Assign v to a.
+func (a *decimal) Assign(v uint64) {
+ var buf [24]byte
+
+ // Write reversed decimal in buf.
+ n := 0
+ for v > 0 {
+ v1 := v / 10
+ v -= 10 * v1
+ buf[n] = byte(v + '0')
+ n++
+ v = v1
+ }
+
+ // Reverse again to produce forward decimal in a.d.
+ a.nd = 0
+ for n--; n >= 0; n-- {
+ a.d[a.nd] = buf[n]
+ a.nd++
+ }
+ a.dp = a.nd
+ trim(a)
+}
+
+// Maximum shift that we can do in one pass without overflow.
+// A uint has 32 or 64 bits, and we have to be able to accommodate 9<> 63)
+const maxShift = uintSize - 4
+
+// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow.
+func rightShift(a *decimal, k uint) {
+ r := 0 // read pointer
+ w := 0 // write pointer
+
+ // Pick up enough leading digits to cover first shift.
+ var n uint
+ for ; n>>k == 0; r++ {
+ if r >= a.nd {
+ if n == 0 {
+ // a == 0; shouldn't get here, but handle anyway.
+ a.nd = 0
+ return
+ }
+ for n>>k == 0 {
+ n = n * 10
+ r++
+ }
+ break
+ }
+ c := uint(a.d[r])
+ n = n*10 + c - '0'
+ }
+ a.dp -= r - 1
+
+ // Pick up a digit, put down a digit.
+ for ; r < a.nd; r++ {
+ c := uint(a.d[r])
+ dig := n >> k
+ n -= dig << k
+ a.d[w] = byte(dig + '0')
+ w++
+ n = n*10 + c - '0'
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ dig := n >> k
+ n -= dig << k
+ if w < len(a.d) {
+ a.d[w] = byte(dig + '0')
+ w++
+ } else if dig > 0 {
+ a.trunc = true
+ }
+ n = n * 10
+ }
+
+ a.nd = w
+ trim(a)
+}
+
+// Cheat sheet for left shift: table indexed by shift count giving
+// number of new digits that will be introduced by that shift.
+//
+// For example, leftcheats[4] = {2, "625"}. That means that
+// if we are shifting by 4 (multiplying by 16), it will add 2 digits
+// when the string prefix is "625" through "999", and one fewer digit
+// if the string prefix is "000" through "624".
+//
+// Credit for this trick goes to Ken.
+
+type leftCheat struct {
+ delta int // number of new digits
+ cutoff string // minus one digit if original < a.
+}
+
+var leftcheats = []leftCheat{
+ // Leading digits of 1/2^i = 5^i.
+ // 5^23 is not an exact 64-bit floating point number,
+ // so have to use bc for the math.
+ // Go up to 60 to be large enough for 32bit and 64bit platforms.
+ /*
+ seq 60 | sed 's/^/5^/' | bc |
+ awk 'BEGIN{ print "\t{ 0, \"\" }," }
+ {
+ log2 = log(2)/log(10)
+ printf("\t{ %d, \"%s\" },\t// * %d\n",
+ int(log2*NR+1), $0, 2**NR)
+ }'
+ */
+ {0, ""},
+ {1, "5"}, // * 2
+ {1, "25"}, // * 4
+ {1, "125"}, // * 8
+ {2, "625"}, // * 16
+ {2, "3125"}, // * 32
+ {2, "15625"}, // * 64
+ {3, "78125"}, // * 128
+ {3, "390625"}, // * 256
+ {3, "1953125"}, // * 512
+ {4, "9765625"}, // * 1024
+ {4, "48828125"}, // * 2048
+ {4, "244140625"}, // * 4096
+ {4, "1220703125"}, // * 8192
+ {5, "6103515625"}, // * 16384
+ {5, "30517578125"}, // * 32768
+ {5, "152587890625"}, // * 65536
+ {6, "762939453125"}, // * 131072
+ {6, "3814697265625"}, // * 262144
+ {6, "19073486328125"}, // * 524288
+ {7, "95367431640625"}, // * 1048576
+ {7, "476837158203125"}, // * 2097152
+ {7, "2384185791015625"}, // * 4194304
+ {7, "11920928955078125"}, // * 8388608
+ {8, "59604644775390625"}, // * 16777216
+ {8, "298023223876953125"}, // * 33554432
+ {8, "1490116119384765625"}, // * 67108864
+ {9, "7450580596923828125"}, // * 134217728
+ {9, "37252902984619140625"}, // * 268435456
+ {9, "186264514923095703125"}, // * 536870912
+ {10, "931322574615478515625"}, // * 1073741824
+ {10, "4656612873077392578125"}, // * 2147483648
+ {10, "23283064365386962890625"}, // * 4294967296
+ {10, "116415321826934814453125"}, // * 8589934592
+ {11, "582076609134674072265625"}, // * 17179869184
+ {11, "2910383045673370361328125"}, // * 34359738368
+ {11, "14551915228366851806640625"}, // * 68719476736
+ {12, "72759576141834259033203125"}, // * 137438953472
+ {12, "363797880709171295166015625"}, // * 274877906944
+ {12, "1818989403545856475830078125"}, // * 549755813888
+ {13, "9094947017729282379150390625"}, // * 1099511627776
+ {13, "45474735088646411895751953125"}, // * 2199023255552
+ {13, "227373675443232059478759765625"}, // * 4398046511104
+ {13, "1136868377216160297393798828125"}, // * 8796093022208
+ {14, "5684341886080801486968994140625"}, // * 17592186044416
+ {14, "28421709430404007434844970703125"}, // * 35184372088832
+ {14, "142108547152020037174224853515625"}, // * 70368744177664
+ {15, "710542735760100185871124267578125"}, // * 140737488355328
+ {15, "3552713678800500929355621337890625"}, // * 281474976710656
+ {15, "17763568394002504646778106689453125"}, // * 562949953421312
+ {16, "88817841970012523233890533447265625"}, // * 1125899906842624
+ {16, "444089209850062616169452667236328125"}, // * 2251799813685248
+ {16, "2220446049250313080847263336181640625"}, // * 4503599627370496
+ {16, "11102230246251565404236316680908203125"}, // * 9007199254740992
+ {17, "55511151231257827021181583404541015625"}, // * 18014398509481984
+ {17, "277555756156289135105907917022705078125"}, // * 36028797018963968
+ {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936
+ {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872
+ {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744
+ {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
+ {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
+}
+
+// Is the leading prefix of b lexicographically less than s?
+func prefixIsLessThan(b []byte, s string) bool {
+ for i := 0; i < len(s); i++ {
+ if i >= len(b) {
+ return true
+ }
+ if b[i] != s[i] {
+ return b[i] < s[i]
+ }
+ }
+ return false
+}
+
+// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow.
+func leftShift(a *decimal, k uint) {
+ delta := leftcheats[k].delta
+ if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
+ delta--
+ }
+
+ r := a.nd // read index
+ w := a.nd + delta // write index
+
+ // Pick up a digit, put down a digit.
+ var n uint
+ for r--; r >= 0; r-- {
+ n += (uint(a.d[r]) - '0') << k
+ quo := n / 10
+ rem := n - 10*quo
+ w--
+ if w < len(a.d) {
+ a.d[w] = byte(rem + '0')
+ } else if rem != 0 {
+ a.trunc = true
+ }
+ n = quo
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ quo := n / 10
+ rem := n - 10*quo
+ w--
+ if w < len(a.d) {
+ a.d[w] = byte(rem + '0')
+ } else if rem != 0 {
+ a.trunc = true
+ }
+ n = quo
+ }
+
+ a.nd += delta
+ if a.nd >= len(a.d) {
+ a.nd = len(a.d)
+ }
+ a.dp += delta
+ trim(a)
+}
+
+// Binary shift left (k > 0) or right (k < 0).
+func (a *decimal) Shift(k int) {
+ switch {
+ case a.nd == 0:
+ // nothing to do: a == 0
+ case k > 0:
+ for k > maxShift {
+ leftShift(a, maxShift)
+ k -= maxShift
+ }
+ leftShift(a, uint(k))
+ case k < 0:
+ for k < -maxShift {
+ rightShift(a, maxShift)
+ k += maxShift
+ }
+ rightShift(a, uint(-k))
+ }
+}
+
+// If we chop a at nd digits, should we round up?
+func shouldRoundUp(a *decimal, nd int) bool {
+ if nd < 0 || nd >= a.nd {
+ return false
+ }
+ if a.d[nd] == '5' && nd+1 == a.nd {
+ // exactly halfway - round to even
+ // if we truncated, a little higher than what's recorded - always round up
+ if a.trunc {
+ return true
+ }
+ return nd > 0 && (a.d[nd-1]-'0')%2 != 0
+ }
+ // not halfway - digit tells all
+ return a.d[nd] >= '5'
+}
+
+// Round a to nd digits (or fewer).
+// If nd is zero, it means we're rounding
+// just to the left of the digits, as in
+// 0.09 -> 0.1.
+func (a *decimal) Round(nd int) {
+ if nd < 0 || nd >= a.nd {
+ return
+ }
+ if shouldRoundUp(a, nd) {
+ a.RoundUp(nd)
+ } else {
+ a.RoundDown(nd)
+ }
+}
+
+// Round a down to nd digits (or fewer).
+func (a *decimal) RoundDown(nd int) {
+ if nd < 0 || nd >= a.nd {
+ return
+ }
+ a.nd = nd
+ trim(a)
+}
+
+// Round a up to nd digits (or fewer).
+func (a *decimal) RoundUp(nd int) {
+ if nd < 0 || nd >= a.nd {
+ return
+ }
+
+ // round up
+ for i := nd - 1; i >= 0; i-- {
+ c := a.d[i]
+ if c < '9' {
+ // can stop after this digit
+ a.d[i]++
+ a.nd = i + 1
+ return
+ }
+ }
+
+ // Number is all 9s.
+ // Change to single 1 with adjusted decimal point.
+ a.d[0] = '1'
+ a.nd = 1
+ a.dp++
+}
+
+// Extract integer part, rounded appropriately.
+// No guarantees about overflow.
+func (a *decimal) RoundedInteger() uint64 {
+ if a.dp > 20 {
+ return 0xFFFFFFFFFFFFFFFF
+ }
+ var i int
+ n := uint64(0)
+ for i = 0; i < a.dp && i < a.nd; i++ {
+ n = n*10 + uint64(a.d[i]-'0')
+ }
+ for ; i < a.dp; i++ {
+ n *= 10
+ }
+ if shouldRoundUp(a, a.dp) {
+ n++
+ }
+ return n
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/extfloat.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/extfloat.go
new file mode 100644
index 000000000000..b9cb2e354f15
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/extfloat.go
@@ -0,0 +1,668 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fastprinter
+
+// An extFloat represents an extended floating-point number, with more
+// precision than a float64. It does not try to save bits: the
+// number represented by the structure is mant*(2^exp), with a negative
+// sign if neg is true.
+type extFloat struct {
+ mant uint64
+ exp int
+ neg bool
+}
+
+// Powers of ten taken from double-conversion library.
+// http://code.google.com/p/double-conversion/
+const (
+ firstPowerOfTen = -348
+ stepPowerOfTen = 8
+)
+
+var smallPowersOfTen = [...]extFloat{
+ {1 << 63, -63, false}, // 1
+ {0xa << 60, -60, false}, // 1e1
+ {0x64 << 57, -57, false}, // 1e2
+ {0x3e8 << 54, -54, false}, // 1e3
+ {0x2710 << 50, -50, false}, // 1e4
+ {0x186a0 << 47, -47, false}, // 1e5
+ {0xf4240 << 44, -44, false}, // 1e6
+ {0x989680 << 40, -40, false}, // 1e7
+}
+
+var powersOfTen = [...]extFloat{
+ {0xfa8fd5a0081c0288, -1220, false}, // 10^-348
+ {0xbaaee17fa23ebf76, -1193, false}, // 10^-340
+ {0x8b16fb203055ac76, -1166, false}, // 10^-332
+ {0xcf42894a5dce35ea, -1140, false}, // 10^-324
+ {0x9a6bb0aa55653b2d, -1113, false}, // 10^-316
+ {0xe61acf033d1a45df, -1087, false}, // 10^-308
+ {0xab70fe17c79ac6ca, -1060, false}, // 10^-300
+ {0xff77b1fcbebcdc4f, -1034, false}, // 10^-292
+ {0xbe5691ef416bd60c, -1007, false}, // 10^-284
+ {0x8dd01fad907ffc3c, -980, false}, // 10^-276
+ {0xd3515c2831559a83, -954, false}, // 10^-268
+ {0x9d71ac8fada6c9b5, -927, false}, // 10^-260
+ {0xea9c227723ee8bcb, -901, false}, // 10^-252
+ {0xaecc49914078536d, -874, false}, // 10^-244
+ {0x823c12795db6ce57, -847, false}, // 10^-236
+ {0xc21094364dfb5637, -821, false}, // 10^-228
+ {0x9096ea6f3848984f, -794, false}, // 10^-220
+ {0xd77485cb25823ac7, -768, false}, // 10^-212
+ {0xa086cfcd97bf97f4, -741, false}, // 10^-204
+ {0xef340a98172aace5, -715, false}, // 10^-196
+ {0xb23867fb2a35b28e, -688, false}, // 10^-188
+ {0x84c8d4dfd2c63f3b, -661, false}, // 10^-180
+ {0xc5dd44271ad3cdba, -635, false}, // 10^-172
+ {0x936b9fcebb25c996, -608, false}, // 10^-164
+ {0xdbac6c247d62a584, -582, false}, // 10^-156
+ {0xa3ab66580d5fdaf6, -555, false}, // 10^-148
+ {0xf3e2f893dec3f126, -529, false}, // 10^-140
+ {0xb5b5ada8aaff80b8, -502, false}, // 10^-132
+ {0x87625f056c7c4a8b, -475, false}, // 10^-124
+ {0xc9bcff6034c13053, -449, false}, // 10^-116
+ {0x964e858c91ba2655, -422, false}, // 10^-108
+ {0xdff9772470297ebd, -396, false}, // 10^-100
+ {0xa6dfbd9fb8e5b88f, -369, false}, // 10^-92
+ {0xf8a95fcf88747d94, -343, false}, // 10^-84
+ {0xb94470938fa89bcf, -316, false}, // 10^-76
+ {0x8a08f0f8bf0f156b, -289, false}, // 10^-68
+ {0xcdb02555653131b6, -263, false}, // 10^-60
+ {0x993fe2c6d07b7fac, -236, false}, // 10^-52
+ {0xe45c10c42a2b3b06, -210, false}, // 10^-44
+ {0xaa242499697392d3, -183, false}, // 10^-36
+ {0xfd87b5f28300ca0e, -157, false}, // 10^-28
+ {0xbce5086492111aeb, -130, false}, // 10^-20
+ {0x8cbccc096f5088cc, -103, false}, // 10^-12
+ {0xd1b71758e219652c, -77, false}, // 10^-4
+ {0x9c40000000000000, -50, false}, // 10^4
+ {0xe8d4a51000000000, -24, false}, // 10^12
+ {0xad78ebc5ac620000, 3, false}, // 10^20
+ {0x813f3978f8940984, 30, false}, // 10^28
+ {0xc097ce7bc90715b3, 56, false}, // 10^36
+ {0x8f7e32ce7bea5c70, 83, false}, // 10^44
+ {0xd5d238a4abe98068, 109, false}, // 10^52
+ {0x9f4f2726179a2245, 136, false}, // 10^60
+ {0xed63a231d4c4fb27, 162, false}, // 10^68
+ {0xb0de65388cc8ada8, 189, false}, // 10^76
+ {0x83c7088e1aab65db, 216, false}, // 10^84
+ {0xc45d1df942711d9a, 242, false}, // 10^92
+ {0x924d692ca61be758, 269, false}, // 10^100
+ {0xda01ee641a708dea, 295, false}, // 10^108
+ {0xa26da3999aef774a, 322, false}, // 10^116
+ {0xf209787bb47d6b85, 348, false}, // 10^124
+ {0xb454e4a179dd1877, 375, false}, // 10^132
+ {0x865b86925b9bc5c2, 402, false}, // 10^140
+ {0xc83553c5c8965d3d, 428, false}, // 10^148
+ {0x952ab45cfa97a0b3, 455, false}, // 10^156
+ {0xde469fbd99a05fe3, 481, false}, // 10^164
+ {0xa59bc234db398c25, 508, false}, // 10^172
+ {0xf6c69a72a3989f5c, 534, false}, // 10^180
+ {0xb7dcbf5354e9bece, 561, false}, // 10^188
+ {0x88fcf317f22241e2, 588, false}, // 10^196
+ {0xcc20ce9bd35c78a5, 614, false}, // 10^204
+ {0x98165af37b2153df, 641, false}, // 10^212
+ {0xe2a0b5dc971f303a, 667, false}, // 10^220
+ {0xa8d9d1535ce3b396, 694, false}, // 10^228
+ {0xfb9b7cd9a4a7443c, 720, false}, // 10^236
+ {0xbb764c4ca7a44410, 747, false}, // 10^244
+ {0x8bab8eefb6409c1a, 774, false}, // 10^252
+ {0xd01fef10a657842c, 800, false}, // 10^260
+ {0x9b10a4e5e9913129, 827, false}, // 10^268
+ {0xe7109bfba19c0c9d, 853, false}, // 10^276
+ {0xac2820d9623bf429, 880, false}, // 10^284
+ {0x80444b5e7aa7cf85, 907, false}, // 10^292
+ {0xbf21e44003acdd2d, 933, false}, // 10^300
+ {0x8e679c2f5e44ff8f, 960, false}, // 10^308
+ {0xd433179d9c8cb841, 986, false}, // 10^316
+ {0x9e19db92b4e31ba9, 1013, false}, // 10^324
+ {0xeb96bf6ebadf77d9, 1039, false}, // 10^332
+ {0xaf87023b9bf0ee6b, 1066, false}, // 10^340
+}
+
+// floatBits returns the bits of the float64 that best approximates
+// the extFloat passed as receiver. Overflow is set to true if
+// the resulting float64 is ±Inf.
+func (f *extFloat) floatBits(flt *floatInfo) (bits uint64, overflow bool) {
+ f.Normalize()
+
+ exp := f.exp + 63
+
+ // Exponent too small.
+ if exp < flt.bias+1 {
+ n := flt.bias + 1 - exp
+ f.mant >>= uint(n)
+ exp += n
+ }
+
+ // Extract 1+flt.mantbits bits from the 64-bit mantissa.
+ mant := f.mant >> (63 - flt.mantbits)
+ if f.mant&(1<<(62-flt.mantbits)) != 0 {
+ // Round up.
+ mant += 1
+ }
+
+ // Rounding might have added a bit; shift down.
+ if mant == 2<>= 1
+ exp++
+ }
+
+ // Infinities.
+ if exp-flt.bias >= 1<>uint(-f.exp))<>= uint(-f.exp)
+ f.exp = 0
+ return *f, *f
+ }
+ expBiased := exp - flt.bias
+
+ upper = extFloat{mant: 2*f.mant + 1, exp: f.exp - 1, neg: f.neg}
+ if mant != 1<>(64-32) == 0 {
+ mant <<= 32
+ exp -= 32
+ }
+ if mant>>(64-16) == 0 {
+ mant <<= 16
+ exp -= 16
+ }
+ if mant>>(64-8) == 0 {
+ mant <<= 8
+ exp -= 8
+ }
+ if mant>>(64-4) == 0 {
+ mant <<= 4
+ exp -= 4
+ }
+ if mant>>(64-2) == 0 {
+ mant <<= 2
+ exp -= 2
+ }
+ if mant>>(64-1) == 0 {
+ mant <<= 1
+ exp -= 1
+ }
+ shift = uint(f.exp - exp)
+ f.mant, f.exp = mant, exp
+ return
+}
+
+// Multiply sets f to the product f*g: the result is correctly rounded,
+// but not normalized.
+func (f *extFloat) Multiply(g extFloat) {
+ fhi, flo := f.mant>>32, uint64(uint32(f.mant))
+ ghi, glo := g.mant>>32, uint64(uint32(g.mant))
+
+ // Cross products.
+ cross1 := fhi * glo
+ cross2 := flo * ghi
+
+ // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
+ f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
+ rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
+ // Round up.
+ rem += (1 << 31)
+
+ f.mant += (rem >> 32)
+ f.exp = f.exp + g.exp + 64
+}
+
+var uint64pow10 = [...]uint64{
+ 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// AssignDecimal sets f to an approximate value mantissa*10^exp. It
+// reports whether the value represented by f is guaranteed to be the
+// best approximation of d after being rounded to a float64 or
+// float32 depending on flt.
+func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) {
+ const uint64digits = 19
+ const errorscale = 8
+ errors := 0 // An upper bound for error, computed in errorscale*ulp.
+ if trunc {
+ // the decimal number was truncated.
+ errors += errorscale / 2
+ }
+
+ f.mant = mantissa
+ f.exp = 0
+ f.neg = neg
+
+ // Multiply by powers of ten.
+ i := (exp10 - firstPowerOfTen) / stepPowerOfTen
+ if exp10 < firstPowerOfTen || i >= len(powersOfTen) {
+ return false
+ }
+ adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen
+
+ // We multiply by exp%step
+ if adjExp < uint64digits && mantissa < uint64pow10[uint64digits-adjExp] {
+ // We can multiply the mantissa exactly.
+ f.mant *= uint64pow10[adjExp]
+ f.Normalize()
+ } else {
+ f.Normalize()
+ f.Multiply(smallPowersOfTen[adjExp])
+ errors += errorscale / 2
+ }
+
+ // We multiply by 10 to the exp - exp%step.
+ f.Multiply(powersOfTen[i])
+ if errors > 0 {
+ errors += 1
+ }
+ errors += errorscale / 2
+
+ // Normalize
+ shift := f.Normalize()
+ errors <<= shift
+
+ // Now f is a good approximation of the decimal.
+ // Check whether the error is too large: that is, if the mantissa
+ // is perturbated by the error, the resulting float64 will change.
+ // The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits.
+ //
+ // In many cases the approximation will be good enough.
+ denormalExp := flt.bias - 63
+ var extrabits uint
+ if f.exp <= denormalExp {
+ // f.mant * 2^f.exp is smaller than 2^(flt.bias+1).
+ extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+ } else {
+ extrabits = uint(63 - flt.mantbits)
+ }
+
+ halfway := uint64(1) << (extrabits - 1)
+ mant_extra := f.mant & (1< expMax:
+ i--
+ default:
+ break Loop
+ }
+ }
+ // Apply the desired decimal shift on f. It will have exponent
+ // in the desired range. This is multiplication by 10^-exp10.
+ f.Multiply(powersOfTen[i])
+
+ return -(firstPowerOfTen + i*stepPowerOfTen), i
+}
+
+// frexp10Many applies a common shift by a power of ten to a, b, c.
+func frexp10Many(a, b, c *extFloat) (exp10 int) {
+ exp10, i := c.frexp10()
+ a.Multiply(powersOfTen[i])
+ b.Multiply(powersOfTen[i])
+ return
+}
+
+// FixedDecimal stores in d the first n significant digits
+// of the decimal representation of f. It returns false
+// if it cannot be sure of the answer.
+func (f *extFloat) FixedDecimal(d *decimalSlice, n int) bool {
+ if f.mant == 0 {
+ d.nd = 0
+ d.dp = 0
+ d.neg = f.neg
+ return true
+ }
+ if n == 0 {
+ panic("strconv: internal error: extFloat.FixedDecimal called with n == 0")
+ }
+ // Multiply by an appropriate power of ten to have a reasonable
+ // number to process.
+ f.Normalize()
+ exp10, _ := f.frexp10()
+
+ shift := uint(-f.exp)
+ integer := uint32(f.mant >> shift)
+ fraction := f.mant - (uint64(integer) << shift)
+ ε := uint64(1) // ε is the uncertainty we have on the mantissa of f.
+
+ // Write exactly n digits to d.
+ needed := n // how many digits are left to write.
+ integerDigits := 0 // the number of decimal digits of integer.
+ pow10 := uint64(1) // the power of ten by which f was scaled.
+ for i, pow := 0, uint64(1); i < 20; i++ {
+ if pow > uint64(integer) {
+ integerDigits = i
+ break
+ }
+ pow *= 10
+ }
+ rest := integer
+ if integerDigits > needed {
+ // the integral part is already large, trim the last digits.
+ pow10 = uint64pow10[integerDigits-needed]
+ integer /= uint32(pow10)
+ rest -= integer * uint32(pow10)
+ } else {
+ rest = 0
+ }
+
+ // Write the digits of integer: the digits of rest are omitted.
+ var buf [32]byte
+ pos := len(buf)
+ for v := integer; v > 0; {
+ v1 := v / 10
+ v -= 10 * v1
+ pos--
+ buf[pos] = byte(v + '0')
+ v = v1
+ }
+ for i := pos; i < len(buf); i++ {
+ d.d[i-pos] = buf[i]
+ }
+ nd := len(buf) - pos
+ d.nd = nd
+ d.dp = integerDigits + exp10
+ needed -= nd
+
+ if needed > 0 {
+ if rest != 0 || pow10 != 1 {
+ panic("strconv: internal error, rest != 0 but needed > 0")
+ }
+ // Emit digits for the fractional part. Each time, 10*fraction
+ // fits in a uint64 without overflow.
+ for needed > 0 {
+ fraction *= 10
+ ε *= 10 // the uncertainty scales as we multiply by ten.
+ if 2*ε > 1<> shift
+ d.d[nd] = byte(digit + '0')
+ fraction -= digit << shift
+ nd++
+ needed--
+ }
+ d.nd = nd
+ }
+
+ // We have written a truncation of f (a numerator / 10^d.dp). The remaining part
+ // can be interpreted as a small number (< 1) to be added to the last digit of the
+ // numerator.
+ //
+ // If rest > 0, the amount is:
+ // (rest< 0 guarantees that pow10 << shift does not overflow a uint64.
+ //
+ // If rest = 0, pow10 == 1 and the amount is
+ // fraction / (1 << shift)
+ // fraction being known with a ±ε uncertainty.
+ //
+ // We pass this information to the rounding routine for adjustment.
+
+ ok := adjustLastDigitFixed(d, uint64(rest)<= 0; i-- {
+ if d.d[i] != '0' {
+ d.nd = i + 1
+ break
+ }
+ }
+ return true
+}
+
+// adjustLastDigitFixed assumes d contains the representation of the integral part
+// of some number, whose fractional part is num / (den << shift). The numerator
+// num is only known up to an uncertainty of size ε, assumed to be less than
+// (den << shift)/2.
+//
+// It will increase the last digit by one to account for correct rounding, typically
+// when the fractional part is greater than 1/2, and will return false if ε is such
+// that no correct answer can be given.
+func adjustLastDigitFixed(d *decimalSlice, num, den uint64, shift uint, ε uint64) bool {
+ if num > den< den< den< (den< den<= 0; i-- {
+ if d.d[i] == '9' {
+ d.nd--
+ } else {
+ break
+ }
+ }
+ if i < 0 {
+ d.d[0] = '1'
+ d.nd = 1
+ d.dp++
+ } else {
+ d.d[i]++
+ }
+ return true
+ }
+ return false
+}
+
+// ShortestDecimal stores in d the shortest decimal representation of f
+// which belongs to the open interval (lower, upper), where f is supposed
+// to lie. It returns false whenever the result is unsure. The implementation
+// uses the Grisu3 algorithm.
+func (f *extFloat) ShortestDecimal(d *decimalSlice, lower, upper *extFloat) bool {
+ if f.mant == 0 {
+ d.nd = 0
+ d.dp = 0
+ d.neg = f.neg
+ return true
+ }
+ if f.exp == 0 && *lower == *f && *lower == *upper {
+ // an exact integer.
+ var buf [24]byte
+ n := len(buf) - 1
+ for v := f.mant; v > 0; {
+ v1 := v / 10
+ v -= 10 * v1
+ buf[n] = byte(v + '0')
+ n--
+ v = v1
+ }
+ nd := len(buf) - n - 1
+ for i := 0; i < nd; i++ {
+ d.d[i] = buf[n+1+i]
+ }
+ d.nd, d.dp = nd, nd
+ for d.nd > 0 && d.d[d.nd-1] == '0' {
+ d.nd--
+ }
+ if d.nd == 0 {
+ d.dp = 0
+ }
+ d.neg = f.neg
+ return true
+ }
+ upper.Normalize()
+ // Uniformize exponents.
+ if f.exp > upper.exp {
+ f.mant <<= uint(f.exp - upper.exp)
+ f.exp = upper.exp
+ }
+ if lower.exp > upper.exp {
+ lower.mant <<= uint(lower.exp - upper.exp)
+ lower.exp = upper.exp
+ }
+
+ exp10 := frexp10Many(lower, f, upper)
+ // Take a safety margin due to rounding in frexp10Many, but we lose precision.
+ upper.mant++
+ lower.mant--
+
+ // The shortest representation of f is either rounded up or down, but
+ // in any case, it is a truncation of upper.
+ shift := uint(-upper.exp)
+ integer := uint32(upper.mant >> shift)
+ fraction := upper.mant - (uint64(integer) << shift)
+
+ // How far we can go down from upper until the result is wrong.
+ allowance := upper.mant - lower.mant
+ // How far we should go to get a very precise result.
+ targetDiff := upper.mant - f.mant
+
+ // Count integral digits: there are at most 10.
+ var integerDigits int
+ for i, pow := 0, uint64(1); i < 20; i++ {
+ if pow > uint64(integer) {
+ integerDigits = i
+ break
+ }
+ pow *= 10
+ }
+ for i := 0; i < integerDigits; i++ {
+ pow := uint64pow10[integerDigits-i-1]
+ digit := integer / uint32(pow)
+ d.d[i] = byte(digit + '0')
+ integer -= digit * uint32(pow)
+ // evaluate whether we should stop.
+ if currentDiff := uint64(integer)<> shift)
+ d.d[d.nd] = byte(digit + '0')
+ d.nd++
+ fraction -= uint64(digit) << shift
+ if fraction < allowance*multiplier {
+ // We are in the admissible range. Note that if allowance is about to
+ // overflow, that is, allowance > 2^64/10, the condition is automatically
+ // true due to the limited range of fraction.
+ return adjustLastDigit(d,
+ fraction, targetDiff*multiplier, allowance*multiplier,
+ 1< maxDiff-ulpBinary {
+ // we went too far
+ return false
+ }
+ if d.nd == 1 && d.d[0] == '0' {
+ // the number has actually reached zero.
+ d.nd = 0
+ d.dp = 0
+ }
+ return true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/float.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/float.go
new file mode 100644
index 000000000000..f0aa5ffe649e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/float.go
@@ -0,0 +1,278 @@
+// MIT License
+//
+// Copyright (c) 2017 José Santos
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package fastprinter
+
+import (
+ "io"
+ "math"
+)
+
+type floatInfo struct {
+ mantbits uint
+ expbits uint
+ bias int
+}
+
+var (
+ float64info = floatInfo{52, 11, -1023}
+ floatNaN = []byte("Nan")
+ floatNinf = []byte("-Inf")
+ floatPinf = []byte("+Inf")
+ pool_floatBuffer = newByteSliceBufferPool(800)
+)
+
+func PrintFloat(w io.Writer, f float64) (int, error) {
+ return PrintFloatPrecision(w, f, -1)
+}
+
+func PrintFloatPrecision(dst io.Writer, val float64, prec int) (int, error) {
+ var bits uint64
+ var flt *floatInfo
+
+ bits = math.Float64bits(val)
+ flt = &float64info
+
+ neg := bits>>(flt.expbits+flt.mantbits) != 0
+ exp := int(bits>>flt.mantbits) & (1< 2^(exp-mantbits),
+ // or equivalently log2(10)*(dp-nd) > exp-mantbits.
+ // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
+ minexp := flt.bias + 1 // minimum possible exponent
+ if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
+ // The number is already shortest.
+ return
+ }
+
+ // d = mant << (exp - mantbits)
+ // Next highest floating point number is mant+1 << exp-mantbits.
+ // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1.
+ upper := new(decimal)
+ upper.Assign(mant*2 + 1)
+ upper.Shift(exp - int(flt.mantbits) - 1)
+
+ // d = mant << (exp - mantbits)
+ // Next lowest floating point number is mant-1 << exp-mantbits,
+ // unless mant-1 drops the significant bit and exp is not the minimum exp,
+ // in which case the next lowest is mant*2-1 << exp-mantbits-1.
+ // Either way, call it mantlo << explo-mantbits.
+ // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1.
+ var mantlo uint64
+ var explo int
+ if mant > 1< 0 {
+ m := min(d.nd, d.dp)
+ copy(a.bytes[i:], d.d[:m])
+ i += m
+ for ; m < d.dp; m++ {
+ a.bytes[i] = '0'
+ i++
+ }
+ } else {
+ a.bytes[i] = '0'
+ i++
+ }
+
+ // fraction
+ if prec > 0 {
+ a.bytes[i] = '.'
+ i++
+ for j := 0; j < prec; j++ {
+ ch := byte('0')
+ if j := d.dp + j; 0 <= j && j < d.nd {
+ ch = d.d[j]
+ }
+ a.bytes[i] = ch
+ i++
+ }
+ }
+ n, err = dst.Write(a.bytes[0:i])
+ pool_floatBuffer.Put(a)
+ return
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/printers.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/printers.go
new file mode 100644
index 000000000000..8a427c86bd0e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/fastprinter/printers.go
@@ -0,0 +1,225 @@
+// MIT License
+//
+// Copyright (c) 2017 José Santos
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package fastprinter
+
+import (
+ "fmt"
+ "io"
+ "reflect"
+ "sync"
+)
+
+const (
+ stringBufferSize = 4096
+ integerBufferSize = 20
+)
+
+var (
+ _trueBytes = ([]byte)("true")
+ _falseBytes = ([]byte)("false")
+
+ pool_integerBuffer = newByteSliceBufferPool(integerBufferSize)
+ pool_stringBuffer = newByteSliceBufferPool(stringBufferSize)
+
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+)
+
+type byteSliceBuffer struct {
+ bytes []byte
+}
+
+func newByteSliceBufferPool(size int) sync.Pool {
+ return sync.Pool{
+ New: func() interface{} {
+ return &byteSliceBuffer{make([]byte, size, size)}
+ },
+ }
+}
+
+func Print(w io.Writer, i interface{}) (int, error) {
+ return PrintValue(w, reflect.ValueOf(i))
+}
+
+func PrintPtr(w io.Writer, i interface{}) (int, error) {
+ return PrintValue(w, reflect.ValueOf(i).Elem())
+}
+
+func PrintBool(w io.Writer, b bool) (int, error) {
+ if b {
+ return w.Write(_trueBytes)
+ }
+ return w.Write(_falseBytes)
+}
+
+func PrintString(ww io.Writer, st string) (c int, err error) {
+ if st == "" {
+ return 0, nil
+ }
+
+ numI := len(st) / stringBufferSize
+ nextBucket := 0
+ written := 0
+
+ a := pool_stringBuffer.Get().(*byteSliceBuffer)
+ for i := 0; i < numI; i++ {
+ copy(a.bytes[:], st[nextBucket:nextBucket+stringBufferSize])
+ nextBucket += stringBufferSize
+ written, err = ww.Write(a.bytes[:])
+ c += written
+ if err != nil {
+ return
+ }
+ }
+
+ smallBucket := len(st) % stringBufferSize
+ if smallBucket > 0 {
+ copy(a.bytes[:], st[nextBucket:])
+ written, err = ww.Write(a.bytes[:smallBucket])
+ c += written
+ }
+ pool_stringBuffer.Put(a)
+ return
+}
+
+func PrintUint(w io.Writer, i uint64) (int, error) {
+ return formatBits(w, i, false)
+}
+
+func PrintInt(w io.Writer, i int64) (int, error) {
+ return formatBits(w, uint64(i), i < 0)
+}
+
+// formatBits computes the string representation of u in the given base.
+// If neg is set, u is treated as negative int64 value.
+// Extracted from std package strconv
+func formatBits(dst io.Writer, u uint64, neg bool) (int, error) {
+
+ var a = pool_integerBuffer.Get().(*byteSliceBuffer)
+
+ i := integerBufferSize
+
+ if neg {
+ u = -u
+ }
+
+ // common case: use constants for / because
+ // the compiler can optimize it into a multiply+shift
+
+ if ^uintptr(0)>>32 == 0 {
+ for u > uint64(^uintptr(0)) {
+ q := u / 1e9
+ us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
+ for j := 9; j > 0; j-- {
+ i--
+ qs := us / 10
+ a.bytes[i] = byte(us - qs*10 + '0')
+ us = qs
+ }
+ u = q
+ }
+ }
+
+ // u guaranteed to fit into a uintptr
+ us := uintptr(u)
+ for us >= 10 {
+ i--
+ q := us / 10
+ a.bytes[i] = byte(us - q*10 + '0')
+ us = q
+ }
+ // u < 10
+ i--
+ a.bytes[i] = byte(us + '0')
+
+ // add sign, if any
+ if neg {
+ i--
+ a.bytes[i] = '-'
+ }
+ counter, err := dst.Write(a.bytes[i:])
+ pool_integerBuffer.Put(a)
+ return counter, err
+}
+
+// PrintValue prints a reflect.Value
+func PrintValue(w io.Writer, v reflect.Value) (int, error) {
+ v = maybeDereference(v, 2)
+
+ if v.Type().Implements(fmtStringerType) {
+ return PrintString(w, v.Interface().(fmt.Stringer).String())
+ }
+
+ if v.Type().Implements(errorType) {
+ return PrintString(w, v.Interface().(error).Error())
+ }
+
+ k := v.Kind()
+
+ if k == reflect.String {
+ return PrintString(w, v.String())
+ }
+
+ if k >= reflect.Int && k <= reflect.Int64 {
+ return PrintInt(w, v.Int())
+ }
+
+ if k >= reflect.Uint && k <= reflect.Uint64 {
+ return PrintUint(w, v.Uint())
+ }
+
+ if k == reflect.Float64 || k == reflect.Float32 {
+ return PrintFloat(w, v.Float())
+ }
+
+ if k == reflect.Bool {
+ return PrintBool(w, v.Bool())
+ }
+
+ if k == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 {
+ return w.Write(v.Bytes())
+ }
+
+ return fmt.Fprint(w, v.Interface())
+}
+
+// dereference a certain depth of pointer indirection
+func maybeDereference(v reflect.Value, depth int) reflect.Value {
+ if depth <= 0 {
+ return v
+ }
+
+ if !v.IsValid() {
+ return v
+ }
+
+ if v.Kind() != reflect.Ptr || v.IsNil() {
+ return v
+ }
+
+ if v.Type().Implements(fmtStringerType) || v.Type().Implements(errorType) {
+ return v
+ }
+
+ return maybeDereference(reflect.Indirect(v), depth-1)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/.gitignore
new file mode 100644
index 000000000000..3d725761b024
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+.idea
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/.travis.yml
new file mode 100644
index 000000000000..33ee6b243d52
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+ - "1.13.x"
+ - "1.14.x"
+ - "1.15.x"
+ - "tip"
+
+script:
+ - env GO111MODULE=on go test -v ./...
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/LICENSE
new file mode 100644
index 000000000000..8dada3edaf50
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/README.md
new file mode 100644
index 000000000000..af6af767899c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/README.md
@@ -0,0 +1,47 @@
+# Jet Template Engine for Go
+
+[![Build Status](https://travis-ci.org/CloudyKit/jet.svg?branch=master)](https://travis-ci.org/CloudyKit/jet) [![Build status](https://ci.appveyor.com/api/projects/status/5g4whw3c6518vvku?svg=true)](https://ci.appveyor.com/project/CloudyKit/jet) [![Join the chat at https://gitter.im/CloudyKit/jet](https://badges.gitter.im/CloudyKit/jet.svg)](https://gitter.im/CloudyKit/jet)
+
+Jet is a template engine developed to be easy to use, powerful, dynamic, yet secure and very fast.
+
+* simple and familiar syntax
+* supports template inheritance (`extends`) and composition (`block`/`yield`, `import`, `include`)
+* descriptive error messages with filename and line number
+* auto-escaping
+* simple C-like expressions
+* very fast execution – Jet can execute templates faster than some pre-compiled template engines
+* very light in terms of allocations and memory footprint
+
+## v6
+
+Version 6 brings major improvements to the Go API. Make sure to read through the [breaking changes](./docs/changes.md) before making the jump.
+
+## Docs
+
+- [Go API](https://beta.pkg.go.dev/github.com/CloudyKit/jet/v6#section-documentation)
+- [Syntax Reference](./docs/syntax.md)
+- [Built-ins](./docs/builtins.md)
+- [Wiki](https://github.com/CloudyKit/jet/wiki) (some things are out of date)
+
+## Example application
+
+An example to-do application is available in [examples/todos](./examples/todos). Clone the repository, then (in the repository root) do:
+```
+ $ cd examples/todos; go run main.go
+```
+
+## IntelliJ Plugin
+
+If you use IntelliJ there is a plugin available at https://github.com/jhsx/GoJetPlugin.
+There is also a very good Go plugin for IntelliJ – see https://github.com/go-lang-plugin-org/go-lang-idea-plugin.
+GoJetPlugin + Go-lang-idea-plugin = happiness!
+
+## Contributing
+
+All contributions are welcome – if you find a bug please report it.
+
+## Contributors
+
+- José Santos (@jhsx)
+- Daniel Lohse (@annismckenzie)
+- Alexander Willing (@sauerbraten)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/appveyor.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/appveyor.yml
new file mode 100644
index 000000000000..8bd81243a4b5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/appveyor.yml
@@ -0,0 +1,35 @@
+version: "{build}"
+
+image: Visual Studio 2019
+
+# scripts that are called at very beginning, before repo cloning
+init:
+ - git config --global core.autocrlf true
+
+clone_folder: c:\gopath\src\github.com\CloudyKit\jet
+
+environment:
+ GOPATH: c:\gopath
+ GO111MODULE: on
+ matrix:
+ - GOVERSION: 113
+ - GOVERSION: 114
+ - GOVERSION: 115
+
+install:
+ - set PATH=%GOPATH%\bin;c:\go%GOVERSION%\bin;%PATH%
+ - set GOROOT=c:\go%GOVERSION%
+ - echo %PATH%
+ - echo %GOPATH%
+ - go version
+ - go env
+
+build: off
+
+test_script:
+ - go test -v ./...
+ - cd examples/asset_packaging/
+ - go generate
+ - go run -tags=deploy_build main.go --run-and-exit
+ - go build -tags=deploy_build -o bin/app.exe main.go
+ - .\bin\app.exe --run-and-exit
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/cache.go
new file mode 100644
index 000000000000..9f6815233e9f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/cache.go
@@ -0,0 +1,34 @@
+package jet
+
+import "sync"
+
+// Cache is the interface Jet uses to store and retrieve parsed templates.
+type Cache interface {
+
+ // Get fetches a template from the cache. If Get returns nil, the same path with a different extension will be tried.
+ // If Get() returns nil for all configured extensions, the same path and extensions will be tried on the Set's Loader.
+ Get(templatePath string) *Template
+
+ // Put places the result of parsing a template "file"/string in the cache.
+ Put(templatePath string, t *Template)
+}
+
+// cache is the cache used by default in a new Set.
+type cache struct {
+ m sync.Map
+}
+
+// compile-time check that cache implements Cache
+var _ Cache = (*cache)(nil)
+
+func (c *cache) Get(templatePath string) *Template {
+ _t, ok := c.m.Load(templatePath)
+ if !ok {
+ return nil
+ }
+ return _t.(*Template)
+}
+
+func (c *cache) Put(templatePath string, t *Template) {
+ c.m.Store(templatePath, t)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/constructors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/constructors.go
new file mode 100644
index 000000000000..d0f023bc27e8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/constructors.go
@@ -0,0 +1,244 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+func (t *Template) newSliceExpr(pos Pos, line int, base, index, endIndex Expression) *SliceExprNode {
+ return &SliceExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeSliceExpr, Pos: pos, Line: line}, Index: index, Base: base, EndIndex: endIndex}
+}
+
+func (t *Template) newIndexExpr(pos Pos, line int, base, index Expression) *IndexExprNode {
+ return &IndexExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIndexExpr, Pos: pos, Line: line}, Index: index, Base: base}
+}
+
+func (t *Template) newTernaryExpr(pos Pos, line int, boolean, left, right Expression) *TernaryExprNode {
+ return &TernaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeTernaryExpr, Pos: pos, Line: line}, Boolean: boolean, Left: left, Right: right}
+}
+
+func (t *Template) newSet(pos Pos, line int, isLet, isIndexExprGetLookup bool, left, right []Expression) *SetNode {
+ return &SetNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeSet, Pos: pos, Line: line}, Let: isLet, IndexExprGetLookup: isIndexExprGetLookup, Left: left, Right: right}
+}
+
+func (t *Template) newCallExpr(pos Pos, line int, expr Expression) *CallExprNode {
+ return &CallExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeCallExpr, Pos: pos, Line: line}, BaseExpr: expr}
+}
+func (t *Template) newNotExpr(pos Pos, line int, expr Expression) *NotExprNode {
+ return &NotExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNotExpr, Pos: pos, Line: line}, Expr: expr}
+}
+func (t *Template) newNumericComparativeExpr(pos Pos, line int, left, right Expression, item item) *NumericComparativeExprNode {
+ return &NumericComparativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNumericComparativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newComparativeExpr(pos Pos, line int, left, right Expression, item item) *ComparativeExprNode {
+ return &ComparativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeComparativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newLogicalExpr(pos Pos, line int, left, right Expression, item item) *LogicalExprNode {
+ return &LogicalExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeLogicalExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newMultiplicativeExpr(pos Pos, line int, left, right Expression, item item) *MultiplicativeExprNode {
+ return &MultiplicativeExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeMultiplicativeExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newAdditiveExpr(pos Pos, line int, left, right Expression, item item) *AdditiveExprNode {
+ return &AdditiveExprNode{binaryExprNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeAdditiveExpr, Pos: pos, Line: line}, Operator: item, Left: left, Right: right}}
+}
+
+func (t *Template) newList(pos Pos) *ListNode {
+ return &ListNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeList, Pos: pos}}
+}
+
+func (t *Template) newText(pos Pos, text string) *TextNode {
+ return &TextNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeText, Pos: pos}, Text: []byte(text)}
+}
+
+func (t *Template) newPipeline(pos Pos, line int) *PipeNode {
+ return &PipeNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodePipe, Pos: pos, Line: line}}
+}
+
+func (t *Template) newAction(pos Pos, line int) *ActionNode {
+ return &ActionNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeAction, Pos: pos, Line: line}}
+}
+
+func (t *Template) newCommand(pos Pos) *CommandNode {
+ return &CommandNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeCommand, Pos: pos}}
+}
+
+func (t *Template) newNil(pos Pos) *NilNode {
+ return &NilNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNil, Pos: pos}}
+}
+
+func (t *Template) newField(pos Pos, ident string) *FieldNode {
+ return &FieldNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeField, Pos: pos}, Ident: strings.Split(ident[1:], ".")} //[1:] to drop leading period
+}
+
+func (t *Template) newChain(pos Pos, node Node) *ChainNode {
+ return &ChainNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeChain, Pos: pos}, Node: node}
+}
+
+func (t *Template) newBool(pos Pos, true bool) *BoolNode {
+ return &BoolNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeBool, Pos: pos}, True: true}
+}
+
+func (t *Template) newString(pos Pos, orig, text string) *StringNode {
+ return &StringNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeString, Pos: pos}, Quoted: orig, Text: text}
+}
+
+func (t *Template) newEnd(pos Pos) *endNode {
+ return &endNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeEnd, Pos: pos}}
+}
+
+func (t *Template) newContent(pos Pos) *contentNode {
+ return &contentNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeContent, Pos: pos}}
+}
+
+func (t *Template) newElse(pos Pos, line int) *elseNode {
+ return &elseNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeElse, Pos: pos, Line: line}}
+}
+
+func (t *Template) newIf(pos Pos, line int, set *SetNode, pipe Expression, list, elseList *ListNode) *IfNode {
+ return &IfNode{BranchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIf, Pos: pos, Line: line}, Set: set, Expression: pipe, List: list, ElseList: elseList}}
+}
+
+func (t *Template) newRange(pos Pos, line int, set *SetNode, pipe Expression, list, elseList *ListNode) *RangeNode {
+ return &RangeNode{BranchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeRange, Pos: pos, Line: line}, Set: set, Expression: pipe, List: list, ElseList: elseList}}
+}
+
+func (t *Template) newBlock(pos Pos, line int, name string, parameters *BlockParameterList, pipe Expression, listNode, contentListNode *ListNode) *BlockNode {
+ return &BlockNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeBlock, Line: line, Pos: pos}, Name: name, Parameters: parameters, Expression: pipe, List: listNode, Content: contentListNode}
+}
+
+func (t *Template) newYield(pos Pos, line int, name string, bplist *BlockParameterList, pipe Expression, content *ListNode, isContent bool) *YieldNode {
+ return &YieldNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeYield, Pos: pos, Line: line}, Name: name, Parameters: bplist, Expression: pipe, Content: content, IsContent: isContent}
+}
+
+func (t *Template) newInclude(pos Pos, line int, name, context Expression) *IncludeNode {
+ return &IncludeNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeInclude, Pos: pos, Line: line}, Name: name, Context: context}
+}
+
+func (t *Template) newReturn(pos Pos, line int, pipe Expression) *ReturnNode {
+ return &ReturnNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeReturn, Pos: pos, Line: line}, Value: pipe}
+}
+
+func (t *Template) newTry(pos Pos, line int, list *ListNode, catch *catchNode) *TryNode {
+ return &TryNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeTry, Pos: pos, Line: line}, List: list, Catch: catch}
+}
+
+func (t *Template) newCatch(pos Pos, line int, errVar *IdentifierNode, list *ListNode) *catchNode {
+ return &catchNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: nodeCatch, Pos: pos, Line: line}, Err: errVar, List: list}
+}
+
+func (t *Template) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
+ n := &NumberNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeNumber, Pos: pos}, Text: text}
+ // todo: optimize
+ switch typ {
+ case itemCharConstant:
+ _rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
+ if err != nil {
+ return nil, err
+ }
+ if tail != "'" {
+ return nil, fmt.Errorf("malformed character constant: %s", text)
+ }
+ n.Int64 = int64(_rune)
+ n.IsInt = true
+ n.Uint64 = uint64(_rune)
+ n.IsUint = true
+ n.Float64 = float64(_rune) //odd but those are the rules.
+ n.IsFloat = true
+ return n, nil
+ case itemComplex:
+ //fmt.Sscan can parse the pair, so let it do the work.
+ if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
+ return nil, err
+ }
+ n.IsComplex = true
+ n.simplifyComplex()
+ return n, nil
+ }
+ //Imaginary constants can only be complex unless they are zero.
+ if len(text) > 0 && text[len(text)-1] == 'i' {
+ f, err := strconv.ParseFloat(text[:len(text)-1], 64)
+ if err == nil {
+ n.IsComplex = true
+ n.Complex128 = complex(0, f)
+ n.simplifyComplex()
+ return n, nil
+ }
+ }
+ // Do integer test first so we get 0x123 etc.
+ u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
+ if err == nil {
+ n.IsUint = true
+ n.Uint64 = u
+ }
+ i, err := strconv.ParseInt(text, 0, 64)
+ if err == nil {
+ n.IsInt = true
+ n.Int64 = i
+ if i == 0 {
+ n.IsUint = true // in case of -0.
+ n.Uint64 = u
+ }
+ }
+ // If an integer extraction succeeded, promote the float.
+ if n.IsInt {
+ n.IsFloat = true
+ n.Float64 = float64(n.Int64)
+ } else if n.IsUint {
+ n.IsFloat = true
+ n.Float64 = float64(n.Uint64)
+ } else {
+ f, err := strconv.ParseFloat(text, 64)
+ if err == nil {
+ // If we parsed it as a float but it looks like an integer,
+ // it's a huge number too large to fit in an int. Reject it.
+ if !strings.ContainsAny(text, ".eE") {
+ return nil, fmt.Errorf("integer overflow: %q", text)
+ }
+ n.IsFloat = true
+ n.Float64 = f
+ // If a floating-point extraction succeeded, extract the int if needed.
+ if !n.IsInt && float64(int64(f)) == f {
+ n.IsInt = true
+ n.Int64 = int64(f)
+ }
+ if !n.IsUint && float64(uint64(f)) == f {
+ n.IsUint = true
+ n.Uint64 = uint64(f)
+ }
+ }
+ }
+
+ if !n.IsInt && !n.IsUint && !n.IsFloat {
+ return nil, fmt.Errorf("illegal number syntax: %q", text)
+ }
+
+ return n, nil
+}
+
+func (t *Template) newIdentifier(ident string, pos Pos, line int) *IdentifierNode {
+ return &IdentifierNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeIdentifier, Pos: pos, Line: line}, Ident: ident}
+}
+
+func (t *Template) newUnderscore(pos Pos, line int) *UnderscoreNode {
+ return &UnderscoreNode{NodeBase: NodeBase{TemplatePath: t.Name, NodeType: NodeUnderscore, Pos: pos, Line: line}}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/default.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/default.go
new file mode 100644
index 000000000000..4c26e7f065b4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/default.go
@@ -0,0 +1,235 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "html"
+ "io"
+ "io/ioutil"
+ "net/url"
+ "reflect"
+ "strings"
+ "text/template"
+)
+
+var defaultVariables map[string]reflect.Value
+
+func init() {
+ defaultVariables = map[string]reflect.Value{
+ "lower": reflect.ValueOf(strings.ToLower),
+ "upper": reflect.ValueOf(strings.ToUpper),
+ "hasPrefix": reflect.ValueOf(strings.HasPrefix),
+ "hasSuffix": reflect.ValueOf(strings.HasSuffix),
+ "repeat": reflect.ValueOf(strings.Repeat),
+ "replace": reflect.ValueOf(strings.Replace),
+ "split": reflect.ValueOf(strings.Split),
+ "trimSpace": reflect.ValueOf(strings.TrimSpace),
+ "html": reflect.ValueOf(html.EscapeString),
+ "url": reflect.ValueOf(url.QueryEscape),
+ "safeHtml": reflect.ValueOf(SafeWriter(template.HTMLEscape)),
+ "safeJs": reflect.ValueOf(SafeWriter(template.JSEscape)),
+ "raw": reflect.ValueOf(SafeWriter(unsafePrinter)),
+ "unsafe": reflect.ValueOf(SafeWriter(unsafePrinter)),
+ "writeJson": reflect.ValueOf(jsonRenderer),
+ "json": reflect.ValueOf(json.Marshal),
+ "map": reflect.ValueOf(newMap),
+ "slice": reflect.ValueOf(newSlice),
+ "array": reflect.ValueOf(newSlice),
+ "isset": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
+ a.RequireNumOfArguments("isset", 1, -1)
+ for i := 0; i < a.NumOfArguments(); i++ {
+ if !a.IsSet(i) {
+ return valueBoolFALSE
+ }
+ }
+ return valueBoolTRUE
+ })),
+ "len": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
+ a.RequireNumOfArguments("len", 1, 1)
+
+ expression := a.Get(0)
+ if !expression.IsValid() {
+ a.Panicf("len(): argument is not a valid value")
+ }
+ if expression.Kind() == reflect.Ptr || expression.Kind() == reflect.Interface {
+ expression = expression.Elem()
+ }
+
+ switch expression.Kind() {
+ case reflect.Array, reflect.Chan, reflect.Slice, reflect.Map, reflect.String:
+ return reflect.ValueOf(expression.Len())
+ case reflect.Struct:
+ return reflect.ValueOf(expression.NumField())
+ }
+
+ a.Panicf("len(): invalid value type %s", expression.Type())
+ return reflect.Value{}
+ })),
+ "includeIfExists": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
+ a.RequireNumOfArguments("includeIfExists", 1, 2)
+ t, err := a.runtime.set.GetTemplate(a.Get(0).String())
+ // If template exists but returns an error then panic instead of failing silently
+ if t != nil && err != nil {
+ panic(fmt.Errorf("including %s: %w", a.Get(0).String(), err))
+ }
+ if err != nil {
+ return hiddenFalse
+ }
+
+ a.runtime.newScope()
+ defer a.runtime.releaseScope()
+
+ a.runtime.blocks = t.processedBlocks
+ root := t.Root
+ if t.extends != nil {
+ root = t.extends.Root
+ }
+
+ if a.NumOfArguments() > 1 {
+ c := a.runtime.context
+ defer func() { a.runtime.context = c }()
+ a.runtime.context = a.Get(1)
+ }
+
+ a.runtime.executeList(root)
+
+ return hiddenTrue
+ })),
+ "exec": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
+ a.RequireNumOfArguments("exec", 1, 2)
+ t, err := a.runtime.set.GetTemplate(a.Get(0).String())
+ if err != nil {
+ panic(fmt.Errorf("exec(%s, %v): %w", a.Get(0), a.Get(1), err))
+ }
+
+ a.runtime.newScope()
+ defer a.runtime.releaseScope()
+
+ w := a.runtime.Writer
+ defer func() { a.runtime.Writer = w }()
+ a.runtime.Writer = ioutil.Discard
+
+ a.runtime.blocks = t.processedBlocks
+ root := t.Root
+ if t.extends != nil {
+ root = t.extends.Root
+ }
+
+ if a.NumOfArguments() > 1 {
+ c := a.runtime.context
+ defer func() { a.runtime.context = c }()
+ a.runtime.context = a.Get(1)
+ }
+ result = a.runtime.executeList(root)
+
+ return result
+ })),
+ "ints": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
+ var from, to int64
+ err := a.ParseInto(&from, &to)
+ if err != nil {
+ panic(err)
+ }
+ // check to > from
+ if to <= from {
+ panic(errors.New("invalid range for ints ranger: 'from' must be smaller than 'to'"))
+ }
+ return reflect.ValueOf(newIntsRanger(from, to))
+ })),
+ "dump": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
+ switch numArgs := a.NumOfArguments(); numArgs {
+ case 0:
+ // no arguments were provided, dump all; do not recurse over parents
+ return dumpAll(a, 0)
+ case 1:
+ if arg := a.Get(0); arg.Kind() == reflect.Float64 {
+ // dump all, maybe walk into parents
+ return dumpAll(a, int(arg.Float()))
+ }
+ fallthrough
+ default:
+ // one or more arguments were provided, grab them and check they are all strings
+ ids := make([]string, numArgs)
+ for i := range ids {
+ arg := a.Get(i)
+ if arg.Kind() != reflect.String {
+ panic(fmt.Errorf("dump: expected argument %d to be a string, but got a %T", i, arg.Interface()))
+ }
+ ids = append(ids, arg.String())
+ }
+ return dumpIdentified(a.runtime, ids)
+ }
+ })),
+ }
+}
+
+type hiddenBool bool
+
+func (m hiddenBool) Render(r *Runtime) { /* render nothing -> hidden */ }
+
+var hiddenTrue = reflect.ValueOf(hiddenBool(true))
+var hiddenFalse = reflect.ValueOf(hiddenBool(false))
+
+func jsonRenderer(v interface{}) RendererFunc {
+ return func(r *Runtime) {
+ err := json.NewEncoder(r.Writer).Encode(v)
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+
+func unsafePrinter(w io.Writer, b []byte) {
+ w.Write(b)
+}
+
+// SafeWriter is a function that writes bytes directly to the render output, without going through Jet's auto-escaping phase.
+// Use/implement this if content should be escaped differently or not at all (see raw/unsafe builtins).
+type SafeWriter func(io.Writer, []byte)
+
+var stringType = reflect.TypeOf("")
+
+var newMap = Func(func(a Arguments) reflect.Value {
+ if a.NumOfArguments()%2 > 0 {
+ panic("map(): incomplete key-value pair (even number of arguments required)")
+ }
+
+ m := reflect.ValueOf(make(map[string]interface{}, a.NumOfArguments()/2))
+
+ for i := 0; i < a.NumOfArguments(); i += 2 {
+ key := a.Get(i)
+ if !key.IsValid() {
+ a.Panicf("map(): key argument at position %d is not a valid value!", i)
+ }
+ if !key.Type().ConvertibleTo(stringType) {
+ a.Panicf("map(): can't use %+v as string key: %s is not convertible to string", key, key.Type())
+ }
+ key = key.Convert(stringType)
+ m.SetMapIndex(a.Get(i), a.Get(i+1))
+ }
+
+ return m
+})
+
+var newSlice = Func(func(a Arguments) reflect.Value {
+ arr := make([]interface{}, a.NumOfArguments())
+ for i := 0; i < a.NumOfArguments(); i++ {
+ arr[i] = a.Get(i).Interface()
+ }
+ return reflect.ValueOf(arr)
+})
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/dump.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/dump.go
new file mode 100644
index 000000000000..559c0b38c7c1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/dump.go
@@ -0,0 +1,108 @@
+package jet
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+)
+
+// dumpAll returns
+// - everything in Runtime.context
+// - everything in Runtime.variables
+// - everything in Runtime.set.globals
+// - everything in Runtime.blocks
+func dumpAll(a Arguments, depth int) reflect.Value {
+ var b bytes.Buffer
+ var vars VarMap
+
+ ctx := a.runtime.context
+ fmt.Fprintln(&b, "Context:")
+ fmt.Fprintf(&b, "\t%s %#v\n", ctx.Type(), ctx)
+
+ dumpScopeVars(&b, a.runtime.scope, 0)
+ dumpScopeVarsToDepth(&b, a.runtime.parent, depth)
+
+ vars = a.runtime.set.globals
+ for i, name := range vars.SortedKeys() {
+ if i == 0 {
+ fmt.Fprintln(&b, "Globals:")
+ }
+ val := vars[name]
+ fmt.Fprintf(&b, "\t%s:=%#v // %s\n", name, val, val.Type())
+ }
+
+ blockKeys := a.runtime.scope.sortedBlocks()
+ fmt.Fprintln(&b, "Blocks:")
+ for _, k := range blockKeys {
+ block := a.runtime.blocks[k]
+ dumpBlock(&b, block)
+ }
+
+ return reflect.ValueOf(b.String())
+}
+
+// dumpScopeVarsToDepth prints all variables in the scope, and all parent scopes,
+// to the limit of maxDepth.
+func dumpScopeVarsToDepth(w io.Writer, scope *scope, maxDepth int) {
+ for i := 1; i <= maxDepth; i++ {
+ if scope == nil {
+ break // do not panic if something bad happens
+ }
+ dumpScopeVars(w, scope, i)
+ scope = scope.parent
+ }
+}
+
+// dumpScopeVars prints all variables in the scope.
+func dumpScopeVars(w io.Writer, scope *scope, lvl int) {
+ if scope == nil {
+ return // do not panic if something bad happens
+ }
+ if lvl == 0 {
+ fmt.Fprint(w, "Variables in current scope:\n")
+ } else {
+ fmt.Fprintf(w, "Variables in scope %d level(s) up:\n", lvl)
+ }
+ vars := scope.variables
+ for _, k := range vars.SortedKeys() {
+ fmt.Fprintf(w, "\t%s=%#v\n", k, vars[k])
+ }
+}
+
+// dumpIdentified accepts a runtime and slice of names.
+// Then, it prints all variables and blocks in the runtime, with names equal to one of the names
+// in the slice.
+func dumpIdentified(rnt *Runtime, ids []string) reflect.Value {
+ var b bytes.Buffer
+ for _, id := range ids {
+ dumpFindVar(&b, rnt, id)
+ dumpFindBlock(&b, rnt, id)
+
+ }
+ return reflect.ValueOf(b.String())
+}
+
+// dumpFindBlock finds the block by name, prints the header of the block, and name of the template in which it was defined.
+func dumpFindBlock(w io.Writer, rnt *Runtime, name string) {
+ if block, ok := rnt.scope.blocks[name]; ok {
+ dumpBlock(w, block)
+ }
+}
+
+// dumpBlock prints header of the block, and template in which the block was first defined.
+func dumpBlock(w io.Writer, block *BlockNode) {
+ if block == nil {
+ return
+ }
+ fmt.Fprintf(w, "\tblock %s(%s), from %s\n", block.Name, block.Parameters.String(), block.TemplatePath)
+}
+
+// dumpFindBlock finds the variable by name, and prints the variable, if it is in the runtime.
+func dumpFindVar(w io.Writer, rnt *Runtime, name string) {
+ val, err := rnt.resolve(name)
+ if err != nil {
+ return
+ }
+ fmt.Fprintf(w, "\t%s:=%#v // %s\n", name, val, val.Type())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/eval.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/eval.go
new file mode 100644
index 000000000000..42155e38dbb7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/eval.go
@@ -0,0 +1,1717 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/CloudyKit/fastprinter"
+)
+
+var (
+ funcType = reflect.TypeOf(Func(nil))
+ stringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+ rangerType = reflect.TypeOf((*Ranger)(nil)).Elem()
+ rendererType = reflect.TypeOf((*Renderer)(nil)).Elem()
+ safeWriterType = reflect.TypeOf(SafeWriter(nil))
+ pool_State = sync.Pool{
+ New: func() interface{} {
+ return &Runtime{scope: &scope{}, escapeeWriter: new(escapeeWriter)}
+ },
+ }
+)
+
+// Renderer is used to detect if a value has its own rendering logic. If the value an action evaluates to implements this
+// interface, it will not be printed using github.com/CloudyKit/fastprinter, instead, its Render() method will be called
+// and is responsible for writing the value to the render output.
+type Renderer interface {
+ Render(*Runtime)
+}
+
+// RendererFunc func implementing interface Renderer
+type RendererFunc func(*Runtime)
+
+func (renderer RendererFunc) Render(r *Runtime) {
+ renderer(r)
+}
+
+type escapeeWriter struct {
+ Writer io.Writer
+ escapee SafeWriter
+ set *Set
+}
+
+func (w *escapeeWriter) Write(b []byte) (int, error) {
+ if w.set.escapee == nil {
+ w.Writer.Write(b)
+ } else {
+ w.set.escapee(w.Writer, b)
+ }
+ return 0, nil
+}
+
+// Runtime this type holds the state of the execution of an template
+type Runtime struct {
+ *escapeeWriter
+ *scope
+ content func(*Runtime, Expression)
+
+ context reflect.Value
+}
+
+// Context returns the current context value
+func (r *Runtime) Context() reflect.Value {
+ return r.context
+}
+
+func (st *Runtime) newScope() {
+ st.scope = &scope{parent: st.scope, variables: make(VarMap), blocks: st.blocks}
+}
+
+func (st *Runtime) releaseScope() {
+ st.scope = st.scope.parent
+}
+
+type scope struct {
+ parent *scope
+ variables VarMap
+ blocks map[string]*BlockNode
+}
+
+func (s scope) sortedBlocks() []string {
+ r := make([]string, 0, len(s.blocks))
+ for k := range s.blocks {
+ r = append(r, k)
+ }
+ sort.Strings(r)
+ return r
+}
+
+// YieldBlock yields a block in the current context, will panic if the context is not available
+func (st *Runtime) YieldBlock(name string, context interface{}) {
+ block, has := st.getBlock(name)
+
+ if has == false {
+ panic(fmt.Errorf("Block %q was not found!!", name))
+ }
+
+ if context != nil {
+ current := st.context
+ st.context = reflect.ValueOf(context)
+ st.executeList(block.List)
+ st.context = current
+ }
+
+ st.executeList(block.List)
+}
+
+func (st *scope) getBlock(name string) (block *BlockNode, has bool) {
+ block, has = st.blocks[name]
+ for !has && st.parent != nil {
+ st = st.parent
+ block, has = st.blocks[name]
+ }
+ return
+}
+
+func (state *Runtime) setValue(name string, val reflect.Value) error {
+ // try changing existing variable in current or parent scope
+ sc := state.scope
+ for sc != nil {
+ if _, ok := sc.variables[name]; ok {
+ sc.variables[name] = val
+ return nil
+ }
+ sc = sc.parent
+ }
+
+ return fmt.Errorf("could not assign %q = %v because variable %q is uninitialised", name, val, name)
+}
+
+// LetGlobal sets or initialises a variable in the top-most template scope.
+func (state *Runtime) LetGlobal(name string, val interface{}) {
+ sc := state.scope
+
+ // walk up to top-most valid scope
+ for sc.parent != nil && sc.parent.variables != nil {
+ sc = sc.parent
+ }
+
+ sc.variables[name] = reflect.ValueOf(val)
+}
+
+// Set sets an existing variable in the template scope it lives in.
+func (state *Runtime) Set(name string, val interface{}) error {
+ return state.setValue(name, reflect.ValueOf(val))
+}
+
+// Let initialises a variable in the current template scope (possibly shadowing an existing variable of the same name in a parent scope).
+func (state *Runtime) Let(name string, val interface{}) {
+ state.scope.variables[name] = reflect.ValueOf(val)
+}
+
+// SetOrLet calls Set() (if a variable with the given name is visible from the current scope) or Let() (if there is no variable with the given name in the current or any parent scope).
+func (state *Runtime) SetOrLet(name string, val interface{}) {
+ _, err := state.resolve(name)
+ if err != nil {
+ state.Let(name, val)
+ } else {
+ state.Set(name, val)
+ }
+}
+
+// Resolve resolves a value from the execution context.
+func (state *Runtime) resolve(name string) (reflect.Value, error) {
+ if name == "." {
+ return state.context, nil
+ }
+
+ // try current, then parent variable scopes
+ sc := state.scope
+ for sc != nil {
+ v, ok := sc.variables[name]
+ if ok {
+ return indirectEface(v), nil
+ }
+ sc = sc.parent
+ }
+
+ // try globals
+ state.set.gmx.RLock()
+ v, ok := state.set.globals[name]
+ state.set.gmx.RUnlock()
+ if ok {
+ return indirectEface(v), nil
+ }
+
+ // try default variables
+ v, ok = defaultVariables[name]
+ if ok {
+ return indirectEface(v), nil
+ }
+
+ return reflect.Value{}, fmt.Errorf("identifier %q not available in current (%+v) or parent scope, global, or default variables", name, state.scope.variables)
+}
+
+// Resolve calls resolve() and ignores any errors, meaning it may return a zero reflect.Value.
+func (state *Runtime) Resolve(name string) reflect.Value {
+ v, _ := state.resolve(name)
+ return v
+}
+
+// Resolve calls resolve() and panics if there is an error.
+func (state *Runtime) MustResolve(name string) reflect.Value {
+ v, err := state.resolve(name)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+func (st *Runtime) recover(err *error) {
+ // reset state scope and context just to be safe (they might not be cleared properly if there was a panic while using the state)
+ st.scope = &scope{}
+ st.context = reflect.Value{}
+ pool_State.Put(st)
+ if recovered := recover(); recovered != nil {
+ var ok bool
+ if _, ok = recovered.(runtime.Error); ok {
+ panic(recovered)
+ }
+ *err, ok = recovered.(error)
+ if !ok {
+ panic(recovered)
+ }
+ }
+}
+
+func (st *Runtime) executeSet(left Expression, right reflect.Value) {
+ typ := left.Type()
+ if typ == NodeIdentifier {
+ err := st.setValue(left.(*IdentifierNode).Ident, right)
+ if err != nil {
+ left.error(err)
+ }
+ return
+ }
+ var value reflect.Value
+ var fields []string
+ if typ == NodeChain {
+ chain := left.(*ChainNode)
+ value = st.evalPrimaryExpressionGroup(chain.Node)
+ fields = chain.Field
+ } else {
+ fields = left.(*FieldNode).Ident
+ value = st.context
+ }
+ lef := len(fields) - 1
+ for i := 0; i < lef; i++ {
+ var err error
+ value, err = resolveIndex(value, reflect.Value{}, fields[i])
+ if err != nil {
+ left.errorf("%v", err)
+ }
+ }
+
+RESTART:
+ switch value.Kind() {
+ case reflect.Ptr:
+ value = value.Elem()
+ goto RESTART
+ case reflect.Struct:
+ value = value.FieldByName(fields[lef])
+ if !value.IsValid() {
+ left.errorf("identifier %q is not available in the current scope", fields[lef])
+ }
+ value.Set(right)
+ case reflect.Map:
+ value.SetMapIndex(reflect.ValueOf(&fields[lef]).Elem(), right)
+ }
+}
+
+func (st *Runtime) executeSetList(set *SetNode) {
+ if set.IndexExprGetLookup {
+ value := st.evalPrimaryExpressionGroup(set.Right[0])
+ if set.Left[0].Type() != NodeUnderscore {
+ st.executeSet(set.Left[0], value)
+ }
+ if set.Left[1].Type() != NodeUnderscore {
+ if value.IsValid() {
+ st.executeSet(set.Left[1], valueBoolTRUE)
+ } else {
+ st.executeSet(set.Left[1], valueBoolFALSE)
+ }
+ }
+ } else {
+ for i := 0; i < len(set.Left); i++ {
+ value := st.evalPrimaryExpressionGroup(set.Right[i])
+ if set.Left[i].Type() != NodeUnderscore {
+ st.executeSet(set.Left[i], value)
+ }
+ }
+ }
+}
+
+func (st *Runtime) executeLetList(set *SetNode) {
+ if set.IndexExprGetLookup {
+ value := st.evalPrimaryExpressionGroup(set.Right[0])
+ if set.Left[0].Type() != NodeUnderscore {
+ st.variables[set.Left[0].(*IdentifierNode).Ident] = value
+ }
+ if set.Left[1].Type() != NodeUnderscore {
+ if value.IsValid() {
+ st.variables[set.Left[1].(*IdentifierNode).Ident] = valueBoolTRUE
+ } else {
+ st.variables[set.Left[1].(*IdentifierNode).Ident] = valueBoolFALSE
+ }
+ }
+ } else {
+ for i := 0; i < len(set.Left); i++ {
+ value := st.evalPrimaryExpressionGroup(set.Right[i])
+ if set.Left[i].Type() != NodeUnderscore {
+ st.variables[set.Left[i].(*IdentifierNode).Ident] = value
+ }
+ }
+ }
+}
+
+func (st *Runtime) executeYieldBlock(block *BlockNode, blockParam, yieldParam *BlockParameterList, expression Expression, content *ListNode) {
+
+ needNewScope := len(blockParam.List) > 0 || len(yieldParam.List) > 0
+ if needNewScope {
+ st.newScope()
+ for i := 0; i < len(yieldParam.List); i++ {
+ p := &yieldParam.List[i]
+
+ if p.Expression == nil {
+ block.errorf("missing name for block parameter '%s'", blockParam.List[i].Identifier)
+ }
+
+ st.variables[p.Identifier] = st.evalPrimaryExpressionGroup(p.Expression)
+ }
+ for i := 0; i < len(blockParam.List); i++ {
+ p := &blockParam.List[i]
+ if _, found := st.variables[p.Identifier]; !found {
+ if p.Expression == nil {
+ st.variables[p.Identifier] = valueBoolFALSE
+ } else {
+ st.variables[p.Identifier] = st.evalPrimaryExpressionGroup(p.Expression)
+ }
+ }
+ }
+ }
+
+ mycontent := st.content
+ if content != nil {
+ myscope := st.scope
+ st.content = func(st *Runtime, expression Expression) {
+ outscope := st.scope
+ outcontent := st.content
+
+ st.scope = myscope
+ st.content = mycontent
+
+ if expression != nil {
+ context := st.context
+ st.context = st.evalPrimaryExpressionGroup(expression)
+ st.executeList(content)
+ st.context = context
+ } else {
+ st.executeList(content)
+ }
+
+ st.scope = outscope
+ st.content = outcontent
+ }
+ }
+
+ if expression != nil {
+ context := st.context
+ st.context = st.evalPrimaryExpressionGroup(expression)
+ st.executeList(block.List)
+ st.context = context
+ } else {
+ st.executeList(block.List)
+ }
+
+ st.content = mycontent
+ if needNewScope {
+ st.releaseScope()
+ }
+}
+
+func (st *Runtime) executeList(list *ListNode) (returnValue reflect.Value) {
+ inNewScope := false // to use just one scope for multiple actions with variable declarations
+
+ for i := 0; i < len(list.Nodes); i++ {
+ node := list.Nodes[i]
+ switch node.Type() {
+
+ case NodeText:
+ node := node.(*TextNode)
+ _, err := st.Writer.Write(node.Text)
+ if err != nil {
+ node.error(err)
+ }
+ case NodeAction:
+ node := node.(*ActionNode)
+ if node.Set != nil {
+ if node.Set.Let {
+ if !inNewScope {
+ st.newScope()
+ inNewScope = true
+ defer st.releaseScope()
+ }
+ st.executeLetList(node.Set)
+ } else {
+ st.executeSetList(node.Set)
+ }
+ }
+ if node.Pipe != nil {
+ v, safeWriter := st.evalPipelineExpression(node.Pipe)
+ if !safeWriter && v.IsValid() {
+ if v.Type().Implements(rendererType) {
+ v.Interface().(Renderer).Render(st)
+ } else {
+ _, err := fastprinter.PrintValue(st.escapeeWriter, v)
+ if err != nil {
+ node.error(err)
+ }
+ }
+ }
+ }
+ case NodeIf:
+ node := node.(*IfNode)
+ var isLet bool
+ if node.Set != nil {
+ if node.Set.Let {
+ isLet = true
+ st.newScope()
+ st.executeLetList(node.Set)
+ } else {
+ st.executeSetList(node.Set)
+ }
+ }
+
+ if isTrue(st.evalPrimaryExpressionGroup(node.Expression)) {
+ returnValue = st.executeList(node.List)
+ } else if node.ElseList != nil {
+ returnValue = st.executeList(node.ElseList)
+ }
+ if isLet {
+ st.releaseScope()
+ }
+ case NodeRange:
+ node := node.(*RangeNode)
+ var expression reflect.Value
+
+ isSet := node.Set != nil
+ isLet := false
+ keyVarSlot := 0
+ valVarSlot := -1
+
+ context := st.context
+
+ if isSet {
+ if len(node.Set.Left) > 1 {
+ valVarSlot = 1
+ }
+ expression = st.evalPrimaryExpressionGroup(node.Set.Right[0])
+ if node.Set.Let {
+ isLet = true
+ st.newScope()
+ }
+ } else {
+ expression = st.evalPrimaryExpressionGroup(node.Expression)
+ }
+
+ ranger, cleanup, err := getRanger(expression)
+ if err != nil {
+ node.error(err)
+ }
+ if !ranger.ProvidesIndex() {
+ if isSet && len(node.Set.Left) > 1 {
+ // two-vars assignment with ranger that doesn't provide an index
+ node.error(errors.New("two-var range over ranger that does not provide an index"))
+ } else if isSet {
+ keyVarSlot, valVarSlot = -1, 0
+ }
+ }
+
+ indexValue, rangeValue, end := ranger.Range()
+ if !end {
+ for !end && !returnValue.IsValid() {
+ if isSet {
+ if isLet {
+ if keyVarSlot >= 0 {
+ st.variables[node.Set.Left[keyVarSlot].String()] = indexValue
+ }
+ if valVarSlot >= 0 {
+ st.variables[node.Set.Left[valVarSlot].String()] = rangeValue
+ }
+ } else {
+ if keyVarSlot >= 0 {
+ st.executeSet(node.Set.Left[keyVarSlot], indexValue)
+ }
+ if valVarSlot >= 0 {
+ st.executeSet(node.Set.Left[valVarSlot], rangeValue)
+ }
+ }
+ }
+ if valVarSlot < 0 {
+ st.context = rangeValue
+ }
+ returnValue = st.executeList(node.List)
+ indexValue, rangeValue, end = ranger.Range()
+ }
+ } else if node.ElseList != nil {
+ returnValue = st.executeList(node.ElseList)
+ }
+ cleanup()
+ st.context = context
+ if isLet {
+ st.releaseScope()
+ }
+ case NodeTry:
+ node := node.(*TryNode)
+ returnValue = st.executeTry(node)
+ case NodeYield:
+ node := node.(*YieldNode)
+ if node.IsContent {
+ if st.content != nil {
+ st.content(st, node.Expression)
+ }
+ } else {
+ block, has := st.getBlock(node.Name)
+ if has == false || block == nil {
+ node.errorf("unresolved block %q!!", node.Name)
+ }
+ st.executeYieldBlock(block, block.Parameters, node.Parameters, node.Expression, node.Content)
+ }
+ case NodeBlock:
+ node := node.(*BlockNode)
+ block, has := st.getBlock(node.Name)
+ if has == false {
+ block = node
+ }
+ st.executeYieldBlock(block, block.Parameters, block.Parameters, block.Expression, block.Content)
+ case NodeInclude:
+ node := node.(*IncludeNode)
+ returnValue = st.executeInclude(node)
+ case NodeReturn:
+ node := node.(*ReturnNode)
+ returnValue = st.evalPrimaryExpressionGroup(node.Value)
+ }
+ }
+
+ return returnValue
+}
+
+func (st *Runtime) executeTry(try *TryNode) (returnValue reflect.Value) {
+ writer := st.Writer
+ buf := new(bytes.Buffer)
+
+ defer func() {
+ r := recover()
+
+ // copy buffered render output to writer only if no panic occured
+ if r == nil {
+ io.Copy(writer, buf)
+ } else {
+ // st.Writer is already set to its original value since the later defer ran first
+ if try.Catch != nil {
+ if try.Catch.Err != nil {
+ st.newScope()
+ st.scope.variables[try.Catch.Err.Ident] = reflect.ValueOf(r)
+ }
+ if try.Catch.List != nil {
+ returnValue = st.executeList(try.Catch.List)
+ }
+ if try.Catch.Err != nil {
+ st.releaseScope()
+ }
+ }
+ }
+ }()
+
+ st.Writer = buf
+ defer func() { st.Writer = writer }()
+
+ return st.executeList(try.List)
+}
+
+func (st *Runtime) executeInclude(node *IncludeNode) (returnValue reflect.Value) {
+ var templatePath string
+ name := st.evalPrimaryExpressionGroup(node.Name)
+ if !name.IsValid() {
+ node.errorf("evaluating name of template to include: name is not a valid value")
+ }
+ if name.Type().Implements(stringerType) {
+ templatePath = name.String()
+ } else if name.Kind() == reflect.String {
+ templatePath = name.String()
+ } else {
+ node.errorf("evaluating name of template to include: unexpected expression type %q", getTypeString(name))
+ }
+
+ t, err := st.set.getSiblingTemplate(templatePath, node.TemplatePath, true)
+ if err != nil {
+ node.error(err)
+ return reflect.Value{}
+ }
+
+ st.newScope()
+ defer st.releaseScope()
+
+ st.blocks = t.processedBlocks
+
+ var context reflect.Value
+ if node.Context != nil {
+ context = st.context
+ defer func() { st.context = context }()
+ st.context = st.evalPrimaryExpressionGroup(node.Context)
+ }
+
+ Root := t.Root
+ for t.extends != nil {
+ t = t.extends
+ Root = t.Root
+ }
+
+ return st.executeList(Root)
+}
+
+var (
+ valueBoolTRUE = reflect.ValueOf(true)
+ valueBoolFALSE = reflect.ValueOf(false)
+)
+
+func (st *Runtime) evalPrimaryExpressionGroup(node Expression) reflect.Value {
+ switch node.Type() {
+ case NodeAdditiveExpr:
+ return st.evalAdditiveExpression(node.(*AdditiveExprNode))
+ case NodeMultiplicativeExpr:
+ return st.evalMultiplicativeExpression(node.(*MultiplicativeExprNode))
+ case NodeComparativeExpr:
+ return st.evalComparativeExpression(node.(*ComparativeExprNode))
+ case NodeNumericComparativeExpr:
+ return st.evalNumericComparativeExpression(node.(*NumericComparativeExprNode))
+ case NodeLogicalExpr:
+ return st.evalLogicalExpression(node.(*LogicalExprNode))
+ case NodeNotExpr:
+ return reflect.ValueOf(!isTrue(st.evalPrimaryExpressionGroup(node.(*NotExprNode).Expr)))
+ case NodeTernaryExpr:
+ node := node.(*TernaryExprNode)
+ if isTrue(st.evalPrimaryExpressionGroup(node.Boolean)) {
+ return st.evalPrimaryExpressionGroup(node.Left)
+ }
+ return st.evalPrimaryExpressionGroup(node.Right)
+ case NodeCallExpr:
+ node := node.(*CallExprNode)
+ baseExpr := st.evalBaseExpressionGroup(node.BaseExpr)
+ if baseExpr.Kind() != reflect.Func {
+ node.errorf("node %q is not func kind %q", node.BaseExpr, baseExpr.Type())
+ }
+ ret, err := st.evalCallExpression(baseExpr, node.CallArgs)
+ if err != nil {
+ node.error(err)
+ }
+ return ret
+ case NodeIndexExpr:
+ node := node.(*IndexExprNode)
+ base := st.evalPrimaryExpressionGroup(node.Base)
+ index := st.evalPrimaryExpressionGroup(node.Index)
+
+ resolved, err := resolveIndex(base, index, "")
+ if err != nil {
+ node.error(err)
+ }
+ return resolved
+ case NodeSliceExpr:
+ node := node.(*SliceExprNode)
+ baseExpression := st.evalPrimaryExpressionGroup(node.Base)
+
+ var index, length int
+ if node.Index != nil {
+ indexExpression := st.evalPrimaryExpressionGroup(node.Index)
+ if canNumber(indexExpression.Kind()) {
+ index = int(castInt64(indexExpression))
+ } else {
+ node.Index.errorf("non numeric value in index expression kind %s", indexExpression.Kind().String())
+ }
+ }
+
+ if node.EndIndex != nil {
+ indexExpression := st.evalPrimaryExpressionGroup(node.EndIndex)
+ if canNumber(indexExpression.Kind()) {
+ length = int(castInt64(indexExpression))
+ } else {
+ node.EndIndex.errorf("non numeric value in index expression kind %s", indexExpression.Kind().String())
+ }
+ } else {
+ length = baseExpression.Len()
+ }
+
+ return baseExpression.Slice(index, length)
+ }
+ return st.evalBaseExpressionGroup(node)
+}
+
+// notNil returns false when v.IsValid() == false
+// or when v's kind can be nil and v.IsNil() == true
+func notNil(v reflect.Value) bool {
+ if !v.IsValid() {
+ return false
+ }
+ switch v.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return !v.IsNil()
+ default:
+ return true
+ }
+}
+
+func (st *Runtime) isSet(node Node) (ok bool) {
+ defer func() {
+ if r := recover(); r != nil {
+ // something panicked while evaluating node
+ ok = false
+ }
+ }()
+
+ nodeType := node.Type()
+
+ switch nodeType {
+ case NodeIndexExpr:
+ node := node.(*IndexExprNode)
+ if !st.isSet(node.Base) || !st.isSet(node.Index) {
+ return false
+ }
+
+ base := st.evalPrimaryExpressionGroup(node.Base)
+ index := st.evalPrimaryExpressionGroup(node.Index)
+
+ resolved, err := resolveIndex(base, index, "")
+ return err == nil && notNil(resolved)
+ case NodeIdentifier:
+ value, err := st.resolve(node.String())
+ return err == nil && notNil(value)
+ case NodeField:
+ node := node.(*FieldNode)
+ resolved := st.context
+ for i := 0; i < len(node.Ident); i++ {
+ var err error
+ resolved, err = resolveIndex(resolved, reflect.Value{}, node.Ident[i])
+ if err != nil || !notNil(resolved) {
+ return false
+ }
+ }
+ case NodeChain:
+ node := node.(*ChainNode)
+ resolved, err := st.evalChainNodeExpression(node)
+ return err == nil && notNil(resolved)
+ default:
+ //todo: maybe work some edge cases
+ if !(nodeType > beginExpressions && nodeType < endExpressions) {
+ node.errorf("unexpected %q node in isset clause", node)
+ }
+ }
+ return true
+}
+
+func (st *Runtime) evalNumericComparativeExpression(node *NumericComparativeExprNode) reflect.Value {
+ left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+ isTrue := false
+ kind := left.Kind()
+
+ // if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
+ // this is necessary for expressions like 4*1.23
+ needFloatPromotion := !isFloat(kind) && isFloat(right.Kind())
+
+ switch node.Operator.typ {
+ case itemGreat:
+ if isInt(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Int()) > right.Float()
+ } else {
+ isTrue = left.Int() > toInt(right)
+ }
+ } else if isFloat(kind) {
+ isTrue = left.Float() > toFloat(right)
+ } else if isUint(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Uint()) > right.Float()
+ } else {
+ isTrue = left.Uint() > toUint(right)
+ }
+ } else {
+ node.Left.errorf("a non numeric value in numeric comparative expression")
+ }
+ case itemGreatEquals:
+ if isInt(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Int()) >= right.Float()
+ } else {
+ isTrue = left.Int() >= toInt(right)
+ }
+ } else if isFloat(kind) {
+ isTrue = left.Float() >= toFloat(right)
+ } else if isUint(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Uint()) >= right.Float()
+ } else {
+ isTrue = left.Uint() >= toUint(right)
+ }
+ } else {
+ node.Left.errorf("a non numeric value in numeric comparative expression")
+ }
+ case itemLess:
+ if isInt(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Int()) < right.Float()
+ } else {
+ isTrue = left.Int() < toInt(right)
+ }
+ } else if isFloat(kind) {
+ isTrue = left.Float() < toFloat(right)
+ } else if isUint(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Uint()) < right.Float()
+ } else {
+ isTrue = left.Uint() < toUint(right)
+ }
+ } else {
+ node.Left.errorf("a non numeric value in numeric comparative expression")
+ }
+ case itemLessEquals:
+ if isInt(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Int()) <= right.Float()
+ } else {
+ isTrue = left.Int() <= toInt(right)
+ }
+ } else if isFloat(kind) {
+ isTrue = left.Float() <= toFloat(right)
+ } else if isUint(kind) {
+ if needFloatPromotion {
+ isTrue = float64(left.Uint()) <= right.Float()
+ } else {
+ isTrue = left.Uint() <= toUint(right)
+ }
+ } else {
+ node.Left.errorf("a non numeric value in numeric comparative expression")
+ }
+ }
+ return reflect.ValueOf(isTrue)
+}
+
+func (st *Runtime) evalLogicalExpression(node *LogicalExprNode) reflect.Value {
+ truthy := isTrue(st.evalPrimaryExpressionGroup(node.Left))
+ if node.Operator.typ == itemAnd {
+ truthy = truthy && isTrue(st.evalPrimaryExpressionGroup(node.Right))
+ } else {
+ truthy = truthy || isTrue(st.evalPrimaryExpressionGroup(node.Right))
+ }
+ return reflect.ValueOf(truthy)
+}
+
+func (st *Runtime) evalComparativeExpression(node *ComparativeExprNode) reflect.Value {
+ left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+ equal := checkEquality(left, right)
+ if node.Operator.typ == itemNotEquals {
+ return reflect.ValueOf(!equal)
+ }
+ return reflect.ValueOf(equal)
+}
+
+func toInt(v reflect.Value) int64 {
+ if !v.IsValid() {
+ panic(fmt.Errorf("invalid value can't be converted to int64"))
+ }
+ kind := v.Kind()
+ if isInt(kind) {
+ return v.Int()
+ } else if isFloat(kind) {
+ return int64(v.Float())
+ } else if isUint(kind) {
+ return int64(v.Uint())
+ } else if kind == reflect.String {
+ n, e := strconv.ParseInt(v.String(), 10, 0)
+ if e != nil {
+ panic(e)
+ }
+ return n
+ } else if kind == reflect.Bool {
+ if v.Bool() {
+ return 0
+ }
+ return 1
+ }
+ panic(fmt.Errorf("type: %q can't be converted to int64", v.Type()))
+}
+
+func toUint(v reflect.Value) uint64 {
+ if !v.IsValid() {
+ panic(fmt.Errorf("invalid value can't be converted to uint64"))
+ }
+ kind := v.Kind()
+ if isUint(kind) {
+ return v.Uint()
+ } else if isInt(kind) {
+ return uint64(v.Int())
+ } else if isFloat(kind) {
+ return uint64(v.Float())
+ } else if kind == reflect.String {
+ n, e := strconv.ParseUint(v.String(), 10, 0)
+ if e != nil {
+ panic(e)
+ }
+ return n
+ } else if kind == reflect.Bool {
+ if v.Bool() {
+ return 0
+ }
+ return 1
+ }
+ panic(fmt.Errorf("type: %q can't be converted to uint64", v.Type()))
+}
+
+func toFloat(v reflect.Value) float64 {
+ if !v.IsValid() {
+ panic(fmt.Errorf("invalid value can't be converted to float64"))
+ }
+ kind := v.Kind()
+ if isFloat(kind) {
+ return v.Float()
+ } else if isInt(kind) {
+ return float64(v.Int())
+ } else if isUint(kind) {
+ return float64(v.Uint())
+ } else if kind == reflect.String {
+ n, e := strconv.ParseFloat(v.String(), 0)
+ if e != nil {
+ panic(e)
+ }
+ return n
+ } else if kind == reflect.Bool {
+ if v.Bool() {
+ return 0
+ }
+ return 1
+ }
+ panic(fmt.Errorf("type: %q can't be converted to float64", v.Type()))
+}
+
+func (st *Runtime) evalMultiplicativeExpression(node *MultiplicativeExprNode) reflect.Value {
+ left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+ kind := left.Kind()
+ // if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
+ // this is necessary for expressions like 4*1.23
+ needFloatPromotion := !isFloat(kind) && isFloat(right.Kind())
+ switch node.Operator.typ {
+ case itemMul:
+ if isInt(kind) {
+ if needFloatPromotion {
+ // do the promotion and calculates
+ left = reflect.ValueOf(float64(left.Int()) * right.Float())
+ } else {
+ // do not need float promotion
+ left = reflect.ValueOf(left.Int() * toInt(right))
+ }
+ } else if isFloat(kind) {
+ left = reflect.ValueOf(left.Float() * toFloat(right))
+ } else if isUint(kind) {
+ if needFloatPromotion {
+ left = reflect.ValueOf(float64(left.Uint()) * right.Float())
+ } else {
+ left = reflect.ValueOf(left.Uint() * toUint(right))
+ }
+ } else {
+ node.Left.errorf("a non numeric value in multiplicative expression")
+ }
+ case itemDiv:
+ if isInt(kind) {
+ if needFloatPromotion {
+ left = reflect.ValueOf(float64(left.Int()) / right.Float())
+ } else {
+ left = reflect.ValueOf(left.Int() / toInt(right))
+ }
+ } else if isFloat(kind) {
+ left = reflect.ValueOf(left.Float() / toFloat(right))
+ } else if isUint(kind) {
+ if needFloatPromotion {
+ left = reflect.ValueOf(float64(left.Uint()) / right.Float())
+ } else {
+ left = reflect.ValueOf(left.Uint() / toUint(right))
+ }
+ } else {
+ node.Left.errorf("a non numeric value in multiplicative expression")
+ }
+ case itemMod:
+ if isInt(kind) {
+ left = reflect.ValueOf(left.Int() % toInt(right))
+ } else if isFloat(kind) {
+ left = reflect.ValueOf(int64(left.Float()) % toInt(right))
+ } else if isUint(kind) {
+ left = reflect.ValueOf(left.Uint() % toUint(right))
+ } else {
+ node.Left.errorf("a non numeric value in multiplicative expression")
+ }
+ }
+ return left
+}
+
+func (st *Runtime) evalAdditiveExpression(node *AdditiveExprNode) reflect.Value {
+ isAdditive := node.Operator.typ == itemAdd
+ if node.Left == nil {
+ right := st.evalPrimaryExpressionGroup(node.Right)
+ if !right.IsValid() {
+ node.errorf("right side of additive expression is invalid value")
+ }
+ kind := right.Kind()
+ // todo: optimize
+ if isInt(kind) {
+ if isAdditive {
+ return reflect.ValueOf(+right.Int())
+ } else {
+ return reflect.ValueOf(-right.Int())
+ }
+ } else if isUint(kind) {
+ if isAdditive {
+ return right
+ } else {
+ return reflect.ValueOf(-int64(right.Uint()))
+ }
+ } else if isFloat(kind) {
+ if isAdditive {
+ return reflect.ValueOf(+right.Float())
+ } else {
+ return reflect.ValueOf(-right.Float())
+ }
+ }
+ node.Left.errorf("additive expression: right side %s (%s) is not a numeric value (no left side)", node.Right, getTypeString(right))
+ }
+
+ left, right := st.evalPrimaryExpressionGroup(node.Left), st.evalPrimaryExpressionGroup(node.Right)
+ if !left.IsValid() {
+ node.errorf("left side of additive expression is invalid value")
+ }
+ if !right.IsValid() {
+ node.errorf("right side of additive expression is invalid value")
+ }
+ kind := left.Kind()
+ // if the left value is not a float and the right is, we need to promote the left value to a float before the calculation
+ // this is necessary for expressions like 4+1.23
+ needFloatPromotion := !isFloat(kind) && kind != reflect.String && isFloat(right.Kind())
+ if needFloatPromotion {
+ if isInt(kind) {
+ if isAdditive {
+ left = reflect.ValueOf(float64(left.Int()) + right.Float())
+ } else {
+ left = reflect.ValueOf(float64(left.Int()) - right.Float())
+ }
+ } else if isUint(kind) {
+ if isAdditive {
+ left = reflect.ValueOf(float64(left.Uint()) + right.Float())
+ } else {
+ left = reflect.ValueOf(float64(left.Uint()) - right.Float())
+ }
+ } else {
+ node.Left.errorf("additive expression: left side (%s (%s) needs float promotion but neither int nor uint)", node.Left, getTypeString(left))
+ }
+ } else {
+ if isInt(kind) {
+ if isAdditive {
+ left = reflect.ValueOf(left.Int() + toInt(right))
+ } else {
+ left = reflect.ValueOf(left.Int() - toInt(right))
+ }
+ } else if isFloat(kind) {
+ if isAdditive {
+ left = reflect.ValueOf(left.Float() + toFloat(right))
+ } else {
+ left = reflect.ValueOf(left.Float() - toFloat(right))
+ }
+ } else if isUint(kind) {
+ if isAdditive {
+ left = reflect.ValueOf(left.Uint() + toUint(right))
+ } else {
+ left = reflect.ValueOf(left.Uint() - toUint(right))
+ }
+ } else if kind == reflect.String {
+ if !isAdditive {
+ node.Right.errorf("minus signal is not allowed with strings")
+ }
+ // converts []byte (and alias types of []byte) to string
+ if right.Kind() == reflect.Slice && right.Type().Elem().Kind() == reflect.Uint8 {
+ right = right.Convert(left.Type())
+ }
+ left = reflect.ValueOf(left.String() + fmt.Sprint(right))
+ } else {
+ node.Left.errorf("additive expression: left side %s (%s) is not a numeric value", node.Left, getTypeString(left))
+ }
+ }
+
+ return left
+}
+
+func getTypeString(value reflect.Value) string {
+ if value.IsValid() {
+ return value.Type().String()
+ }
+ return ""
+}
+
+func (st *Runtime) evalBaseExpressionGroup(node Node) reflect.Value {
+ switch node.Type() {
+ case NodeNil:
+ return reflect.ValueOf(nil)
+ case NodeBool:
+ if node.(*BoolNode).True {
+ return valueBoolTRUE
+ }
+ return valueBoolFALSE
+ case NodeString:
+ return reflect.ValueOf(&node.(*StringNode).Text).Elem()
+ case NodeIdentifier:
+ resolved, err := st.resolve(node.(*IdentifierNode).Ident)
+ if err != nil {
+ node.error(err)
+ }
+ return resolved
+ case NodeField:
+ node := node.(*FieldNode)
+ resolved := st.context
+ for i := 0; i < len(node.Ident); i++ {
+ field, err := resolveIndex(resolved, reflect.Value{}, node.Ident[i])
+ if err != nil {
+ node.errorf("%v", err)
+ }
+ if !field.IsValid() {
+ node.errorf("there is no field or method '%s' in %s (.%s)", node.Ident[i], getTypeString(resolved), strings.Join(node.Ident, "."))
+ }
+ resolved = field
+ }
+ return resolved
+ case NodeChain:
+ resolved, err := st.evalChainNodeExpression(node.(*ChainNode))
+ if err != nil {
+ node.error(err)
+ }
+ return resolved
+ case NodeNumber:
+ node := node.(*NumberNode)
+ if node.IsFloat {
+ return reflect.ValueOf(&node.Float64).Elem()
+ }
+
+ if node.IsInt {
+ return reflect.ValueOf(&node.Int64).Elem()
+ }
+
+ if node.IsUint {
+ return reflect.ValueOf(&node.Uint64).Elem()
+ }
+ }
+ node.errorf("unexpected node type %s in unary expression evaluating", node)
+ return reflect.Value{}
+}
+
+func (st *Runtime) evalCallExpression(baseExpr reflect.Value, args CallArgs) (reflect.Value, error) {
+ return st.evalPipeCallExpression(baseExpr, args, nil)
+}
+
+func (st *Runtime) evalPipeCallExpression(baseExpr reflect.Value, args CallArgs, pipedArg *reflect.Value) (reflect.Value, error) {
+ if !baseExpr.IsValid() {
+ return reflect.Value{}, errors.New("base of call expression is invalid value")
+ }
+ if funcType.AssignableTo(baseExpr.Type()) {
+ return baseExpr.Interface().(Func)(Arguments{runtime: st, args: args, pipedVal: pipedArg}), nil
+ }
+
+ argValues, err := st.evaluateArgs(baseExpr.Type(), args, pipedArg)
+ if err != nil {
+ return reflect.Value{}, fmt.Errorf("call expression: %v", err)
+ }
+
+ var returns = baseExpr.Call(argValues)
+ if len(returns) == 0 {
+ return reflect.Value{}, nil
+ }
+
+ return returns[0], nil
+}
+
+func (st *Runtime) evalCommandExpression(node *CommandNode) (reflect.Value, bool) {
+ term := st.evalPrimaryExpressionGroup(node.BaseExpr)
+ if term.IsValid() && node.Exprs != nil {
+ if term.Kind() == reflect.Func {
+ if term.Type() == safeWriterType {
+ st.evalSafeWriter(term, node)
+ return reflect.Value{}, true
+ }
+ ret, err := st.evalCallExpression(term, node.CallArgs)
+ if err != nil {
+ node.BaseExpr.error(err)
+ }
+ return ret, false
+ }
+ node.Exprs[0].errorf("command %q has arguments but is %s, not a function", node.Exprs[0], term.Type())
+ }
+ return term, false
+}
+
+func (st *Runtime) evalChainNodeExpression(node *ChainNode) (reflect.Value, error) {
+ resolved := st.evalPrimaryExpressionGroup(node.Node)
+
+ for i := 0; i < len(node.Field); i++ {
+ field, err := resolveIndex(resolved, reflect.Value{}, node.Field[i])
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if !field.IsValid() {
+ if resolved.Kind() == reflect.Map && i == len(node.Field)-1 {
+ // return reflect.Zero(resolved.Type().Elem()), nil
+ return reflect.Value{}, nil
+ }
+ return reflect.Value{}, fmt.Errorf("there is no field or method '%s' in %s (%s)", node.Field[i], getTypeString(resolved), node)
+ }
+ resolved = field
+ }
+
+ return resolved, nil
+}
+
+type escapeWriter struct {
+ rawWriter io.Writer
+ safeWriter SafeWriter
+}
+
+func (w *escapeWriter) Write(b []byte) (int, error) {
+ w.safeWriter(w.rawWriter, b)
+ return 0, nil
+}
+
+func (st *Runtime) evalSafeWriter(term reflect.Value, node *CommandNode, v ...reflect.Value) {
+ sw := &escapeWriter{rawWriter: st.Writer, safeWriter: term.Interface().(SafeWriter)}
+ for i := 0; i < len(v); i++ {
+ fastprinter.PrintValue(sw, v[i])
+ }
+ for i := 0; i < len(node.Exprs); i++ {
+ fastprinter.PrintValue(sw, st.evalPrimaryExpressionGroup(node.Exprs[i]))
+ }
+}
+
+func (st *Runtime) evalCommandPipeExpression(node *CommandNode, value reflect.Value) (reflect.Value, bool) {
+ term := st.evalPrimaryExpressionGroup(node.BaseExpr)
+ if !term.IsValid() {
+ node.errorf("base expression of command pipe node is invalid value")
+ }
+ if term.Kind() != reflect.Func {
+ node.BaseExpr.errorf("pipe command %q must be a function, but is %s", node.BaseExpr, term.Type())
+ }
+
+ if term.Type() == safeWriterType {
+ st.evalSafeWriter(term, node, value)
+ return reflect.Value{}, true
+ }
+
+ ret, err := st.evalPipeCallExpression(term, node.CallArgs, &value)
+ if err != nil {
+ node.BaseExpr.error(err)
+ }
+ return ret, false
+}
+
+func (st *Runtime) evalPipelineExpression(node *PipeNode) (value reflect.Value, safeWriter bool) {
+ value, safeWriter = st.evalCommandExpression(node.Cmds[0])
+ for i := 1; i < len(node.Cmds); i++ {
+ if safeWriter {
+ node.Cmds[i].errorf("unexpected command %s, writer command should be the last command", node.Cmds[i])
+ }
+ value, safeWriter = st.evalCommandPipeExpression(node.Cmds[i], value)
+ }
+ return
+}
+
+func (st *Runtime) evaluateArgs(fnType reflect.Type, args CallArgs, pipedArg *reflect.Value) ([]reflect.Value, error) {
+ numArgs := len(args.Exprs)
+ if !args.HasPipeSlot && pipedArg != nil {
+ numArgs++
+ }
+ numArgsRequired := fnType.NumIn()
+ isVariadic := fnType.IsVariadic()
+ if isVariadic {
+ numArgsRequired--
+ if numArgs < numArgsRequired {
+ return nil, fmt.Errorf("%s needs at least %d arguments, but have %d", fnType, numArgsRequired, numArgs)
+ }
+ } else {
+ if numArgs != numArgsRequired {
+ return nil, fmt.Errorf("%s needs %d arguments, but have %d", fnType, numArgsRequired, numArgs)
+ }
+ }
+
+ argValues := make([]reflect.Value, numArgs)
+ slot := 0 // index in argument values (evaluated expressions combined with piped argument if applicable)
+
+ if !args.HasPipeSlot && pipedArg != nil {
+ in := fnType.In(slot)
+ if !(*pipedArg).IsValid() {
+ return nil, fmt.Errorf("piped first argument for %s is not a valid value", fnType)
+ }
+ if !(*pipedArg).Type().AssignableTo(in) {
+ *pipedArg = (*pipedArg).Convert(in)
+ }
+ argValues[slot] = *pipedArg
+ slot++
+ }
+
+ i := 0 // index in parsed argument expression list
+
+ for slot < numArgsRequired {
+ in := fnType.In(slot)
+ var term reflect.Value
+ if args.Exprs[i].Type() == NodeUnderscore {
+ term = *pipedArg
+ } else {
+ term = st.evalPrimaryExpressionGroup(args.Exprs[i])
+ }
+ if !term.IsValid() {
+ return nil, fmt.Errorf("argument for position %d in %s is not a valid value", slot, fnType)
+ }
+ if !term.Type().AssignableTo(in) {
+ term = term.Convert(in)
+ }
+ argValues[slot] = term
+ i++
+ slot++
+ }
+
+ if isVariadic {
+ in := fnType.In(numArgsRequired).Elem()
+ for i < len(args.Exprs) {
+ var term reflect.Value
+ if args.Exprs[i].Type() == NodeUnderscore {
+ term = *pipedArg
+ } else {
+ term = st.evalPrimaryExpressionGroup(args.Exprs[i])
+ }
+ if !term.IsValid() {
+ return nil, fmt.Errorf("argument for position %d in %s is not a valid value", slot, fnType)
+ }
+ if !term.Type().AssignableTo(in) {
+ term = term.Convert(in)
+ }
+ argValues[slot] = term
+ i++
+ slot++
+ }
+ }
+
+ return argValues, nil
+}
+
+func isUint(kind reflect.Kind) bool {
+ return kind >= reflect.Uint && kind <= reflect.Uint64
+}
+func isInt(kind reflect.Kind) bool {
+ return kind >= reflect.Int && kind <= reflect.Int64
+}
+func isFloat(kind reflect.Kind) bool {
+ return kind == reflect.Float32 || kind == reflect.Float64
+}
+
+// checkEquality of two reflect values in the semantic of the jet runtime
+func checkEquality(v1, v2 reflect.Value) bool {
+ v1 = indirectInterface(v1)
+ v2 = indirectInterface(v2)
+
+ if !v1.IsValid() || !v2.IsValid() {
+ return v1.IsValid() == v2.IsValid()
+ }
+
+ v1Type := v1.Type()
+ v2Type := v2.Type()
+
+ // fast path
+ if v1Type != v2Type && !v2Type.AssignableTo(v1Type) && !v2Type.ConvertibleTo(v1Type) {
+ return false
+ }
+
+ kind := v1.Kind()
+ if isInt(kind) {
+ return v1.Int() == toInt(v2)
+ }
+ if isFloat(kind) {
+ return v1.Float() == toFloat(v2)
+ }
+ if isUint(kind) {
+ return v1.Uint() == toUint(v2)
+ }
+
+ switch kind {
+ case reflect.Bool:
+ return v1.Bool() == isTrue(v2)
+ case reflect.String:
+ return v1.String() == v2.String()
+ case reflect.Array:
+ vlen := v1.Len()
+ if vlen == v2.Len() {
+ return false
+ }
+ for i := 0; i < vlen; i++ {
+ if !checkEquality(v1.Index(i), v2.Index(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Slice:
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
+
+ vlen := v1.Len()
+ if vlen != v2.Len() {
+ return false
+ }
+
+ if v1.CanAddr() && v2.CanAddr() && v1.Pointer() == v2.Pointer() {
+ return true
+ }
+
+ for i := 0; i < vlen; i++ {
+ if !checkEquality(v1.Index(i), v2.Index(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Interface:
+ if v1.IsNil() || v2.IsNil() {
+ return v1.IsNil() == v2.IsNil()
+ }
+ return checkEquality(v1.Elem(), v2.Elem())
+ case reflect.Ptr:
+ return v1.Pointer() == v2.Pointer()
+ case reflect.Struct:
+ numField := v1.NumField()
+ for i, n := 0, numField; i < n; i++ {
+ if !checkEquality(v1.Field(i), v2.Field(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Map:
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
+ if v1.Len() != v2.Len() {
+ return false
+ }
+ if v1.Pointer() == v2.Pointer() {
+ return true
+ }
+ for _, k := range v1.MapKeys() {
+ val1 := v1.MapIndex(k)
+ val2 := v2.MapIndex(k)
+ if !val1.IsValid() || !val2.IsValid() || !checkEquality(v1.MapIndex(k), v2.MapIndex(k)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Func:
+ return v1.IsNil() && v2.IsNil()
+ default:
+ // Normal equality suffices
+ return v1.Interface() == v2.Interface()
+ }
+}
+
+func isTrue(v reflect.Value) bool {
+ return v.IsValid() && !v.IsZero()
+}
+
+func canNumber(kind reflect.Kind) bool {
+ return isInt(kind) || isUint(kind) || isFloat(kind)
+}
+
+func castInt64(v reflect.Value) int64 {
+ kind := v.Kind()
+ switch {
+ case isInt(kind):
+ return v.Int()
+ case isUint(kind):
+ return int64(v.Uint())
+ case isFloat(kind):
+ return int64(v.Float())
+ }
+ return 0
+}
+
+var cachedStructsMutex = sync.RWMutex{}
+var cachedStructsFieldIndex = map[reflect.Type]map[string][]int{}
+
+// from text/template's exec.go:
+//
+// indirect returns the item at the end of indirection, and a bool to indicate
+// if it's nil. If the returned bool is true, the returned value's kind will be
+// either a pointer or interface.
+func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+ for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
+ if v.IsNil() {
+ return v, true
+ }
+ }
+ return v, false
+}
+
+// indirectInterface returns the concrete value in an interface value, or else v itself.
+// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x):
+// the fact that x was an interface value is forgotten.
+func indirectInterface(v reflect.Value) reflect.Value {
+ if v.Kind() == reflect.Interface {
+ return v.Elem()
+ }
+ return v
+}
+
+// indirectEface is the same as indirectInterface, but only indirects through v if its type
+// is the empty interface and its value is not nil.
+func indirectEface(v reflect.Value) reflect.Value {
+ if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 && !v.IsNil() {
+ return v.Elem()
+ }
+ return v
+}
+
+// mostly copied from text/template's evalField() (exec.go):
+//
+// The index to use to access v can be specified in either index or indexAsStr.
+// Which parameter is filled depends on the call path up to when a particular
+// call to resolveIndex is made and whether that call site already has access
+// to a reflect.Value for the index or just a string identifier.
+//
+// While having both options makes the implementation of this function more
+// complex, it improves the memory allocation story for the most common
+// execution paths when executing a template, such as when accessing a field
+// element.
+func resolveIndex(v, index reflect.Value, indexAsStr string) (reflect.Value, error) {
+ if !v.IsValid() {
+ return reflect.Value{}, fmt.Errorf("there is no field or method '%s' in %s (%s)", index, v, getTypeString(v))
+ }
+
+ v, isNil := indirect(v)
+ if v.Kind() == reflect.Interface && isNil {
+ // Calling a method on a nil interface can't work. The
+ // MethodByName method call below would panic.
+ return reflect.Value{}, fmt.Errorf("nil pointer evaluating %s.%s", v.Type(), index)
+ }
+
+ // Handle the caller passing either index or indexAsStr.
+ indexIsStr := indexAsStr != ""
+ indexAsValue := func() reflect.Value { return index }
+ if indexIsStr {
+ // indexAsStr was specified, so make the indexAsValue function
+ // obtain the corresponding reflect.Value. This is only used in
+ // some code paths, and since it causes an allocation, a
+ // function is used instead of always extracting the
+ // reflect.Value.
+ indexAsValue = func() reflect.Value {
+ return reflect.ValueOf(indexAsStr)
+ }
+ } else {
+ // index was specified, so extract the string value if the index
+ // is in fact a string.
+ indexIsStr = index.Kind() == reflect.String
+ if indexIsStr {
+ indexAsStr = index.String()
+ }
+ }
+
+ // Unless it's an interface, need to get to a value of type *T to guarantee
+ // we see all methods of T and *T.
+ if indexIsStr {
+ ptr := v
+ if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Ptr && ptr.CanAddr() {
+ ptr = ptr.Addr()
+ }
+ if method := ptr.MethodByName(indexAsStr); method.IsValid() {
+ return method, nil
+ }
+ }
+
+ // It's not a method on v; so now:
+ // - if v is array/slice/string, use index as numeric index
+ // - if v is a struct, use index as field name
+ // - if v is a map, use index as key
+ // - if v is (still) a pointer, indexing will fail but we check for nil to get a useful error
+ switch v.Kind() {
+ case reflect.Array, reflect.Slice, reflect.String:
+ indexVal := indexAsValue()
+ x, err := indexArg(indexVal, v.Len())
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ return indirectEface(v.Index(x)), nil
+ case reflect.Struct:
+ if !indexIsStr {
+ return reflect.Value{}, fmt.Errorf("can't use %s (%s, not string) as field name in struct type %s", index, indexAsValue().Type(), v.Type())
+ }
+ typ := v.Type()
+ key := indexAsStr
+
+ // Fast path: use the struct cache to avoid allocations.
+ cachedStructsMutex.RLock()
+ cache, ok := cachedStructsFieldIndex[typ]
+ cachedStructsMutex.RUnlock()
+ if !ok {
+ cachedStructsMutex.Lock()
+ if cache, ok = cachedStructsFieldIndex[typ]; !ok {
+ cache = make(map[string][]int)
+ buildCache(typ, cache, nil)
+ cachedStructsFieldIndex[typ] = cache
+ }
+ cachedStructsMutex.Unlock()
+ }
+ if id, ok := cache[key]; ok {
+ return v.FieldByIndex(id), nil
+ }
+
+ // Slow path: use reflect directly
+ tField, ok := typ.FieldByName(key)
+ if ok {
+ field := v.FieldByIndex(tField.Index)
+ if tField.PkgPath != "" { // field is unexported
+ return reflect.Value{}, fmt.Errorf("%s is an unexported field of struct type %s", indexAsStr, v.Type())
+ }
+ return indirectEface(field), nil
+ }
+ return reflect.Value{}, fmt.Errorf("can't use %s as field name in struct type %s", indexAsStr, v.Type())
+ case reflect.Map:
+ // If it's a map, attempt to use the field name as a key.
+ indexVal := indexAsValue()
+ if !indexVal.Type().ConvertibleTo(v.Type().Key()) {
+ return reflect.Value{}, fmt.Errorf("can't use %s (%s) as key for map of type %s", indexAsStr, indexVal.Type(), v.Type())
+ }
+ index = indexVal.Convert(v.Type().Key()) // noop in most cases, but not expensive
+ return indirectEface(v.MapIndex(indexVal)), nil
+ case reflect.Ptr:
+ etyp := v.Type().Elem()
+ if etyp.Kind() == reflect.Struct && indexIsStr {
+ if _, ok := etyp.FieldByName(indexAsStr); !ok {
+ // If there's no such field, say "can't evaluate"
+ // instead of "nil pointer evaluating".
+ break
+ }
+ }
+ if isNil {
+ return reflect.Value{}, fmt.Errorf("nil pointer evaluating %s.%s", v.Type(), index)
+ }
+ }
+ return reflect.Value{}, fmt.Errorf("can't evaluate index %s (%s) in type %s", index, indexAsStr, getTypeString(v))
+}
+
+// from Go's text/template's funcs.go:
+//
+// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible.
+func indexArg(index reflect.Value, cap int) (int, error) {
+ var x int64
+ switch index.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ x = index.Int()
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ x = int64(index.Uint())
+ case reflect.Float32, reflect.Float64:
+ x = int64(index.Float())
+ case reflect.Invalid:
+ return 0, fmt.Errorf("cannot index slice/array/string with nil")
+ default:
+ return 0, fmt.Errorf("cannot index slice/array/string with type %s", getTypeString(index))
+ }
+ if int(x) < 0 || int(x) >= cap {
+ return 0, fmt.Errorf("index out of range: %d", x)
+ }
+ return int(x), nil
+}
+
+func buildCache(typ reflect.Type, cache map[string][]int, parent []int) {
+ numFields := typ.NumField()
+ max := len(parent) + 1
+
+ for i := 0; i < numFields; i++ {
+
+ index := make([]int, max)
+ copy(index, parent)
+ index[len(parent)] = i
+
+ field := typ.Field(i)
+ if field.Anonymous {
+ typ := field.Type
+ if typ.Kind() == reflect.Struct {
+ buildCache(typ, cache, index)
+ }
+ }
+ cache[field.Name] = index
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/exec.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/exec.go
new file mode 100644
index 000000000000..8ea74e8d750e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/exec.go
@@ -0,0 +1,75 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Jet is a fast and dynamic template engine for the Go programming language, set of features
+// includes very fast template execution, a dynamic and flexible language, template inheritance, low number of allocations,
+// special interfaces to allow even further optimizations.
+
+package jet
+
+import (
+ "io"
+ "reflect"
+ "sort"
+)
+
+type VarMap map[string]reflect.Value
+
+// SortedKeys returns a sorted slice of VarMap keys
+func (scope VarMap) SortedKeys() []string {
+ keys := make([]string, 0, len(scope))
+ for k := range scope {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+func (scope VarMap) Set(name string, v interface{}) VarMap {
+ scope[name] = reflect.ValueOf(v)
+ return scope
+}
+
+func (scope VarMap) SetFunc(name string, v Func) VarMap {
+ scope[name] = reflect.ValueOf(v)
+ return scope
+}
+
+func (scope VarMap) SetWriter(name string, v SafeWriter) VarMap {
+ scope[name] = reflect.ValueOf(v)
+ return scope
+}
+
+// Execute executes the template into w.
+func (t *Template) Execute(w io.Writer, variables VarMap, data interface{}) (err error) {
+ st := pool_State.Get().(*Runtime)
+ defer st.recover(&err)
+
+ st.blocks = t.processedBlocks
+ st.variables = variables
+ st.set = t.set
+ st.Writer = w
+
+ // resolve extended template
+ for t.extends != nil {
+ t = t.extends
+ }
+
+ if data != nil {
+ st.context = reflect.ValueOf(data)
+ }
+
+ st.executeList(t.Root)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/func.go
new file mode 100644
index 000000000000..dae185ff37c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/func.go
@@ -0,0 +1,176 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "fmt"
+ "reflect"
+ "time"
+)
+
+// Arguments holds the arguments passed to jet.Func.
+type Arguments struct {
+ runtime *Runtime
+ args CallArgs
+ pipedVal *reflect.Value
+}
+
+// IsSet checks whether an argument is set or not. It behaves like the build-in isset function.
+func (a *Arguments) IsSet(argumentIndex int) bool {
+ if argumentIndex < len(a.args.Exprs) {
+ if a.args.Exprs[argumentIndex].Type() == NodeUnderscore {
+ return a.pipedVal != nil
+ }
+ return a.runtime.isSet(a.args.Exprs[argumentIndex])
+ }
+ if len(a.args.Exprs) == 0 && argumentIndex == 0 {
+ return a.pipedVal != nil
+ }
+ return false
+}
+
+// Get gets an argument by index.
+func (a *Arguments) Get(argumentIndex int) reflect.Value {
+ if argumentIndex < len(a.args.Exprs) {
+ if a.args.Exprs[argumentIndex].Type() == NodeUnderscore {
+ return *a.pipedVal
+ }
+ return a.runtime.evalPrimaryExpressionGroup(a.args.Exprs[argumentIndex])
+ }
+ if len(a.args.Exprs) == 0 && argumentIndex == 0 {
+ return *a.pipedVal
+ }
+ return reflect.Value{}
+}
+
+// Panicf panics with formatted error message.
+func (a *Arguments) Panicf(format string, v ...interface{}) {
+ panic(fmt.Errorf(format, v...))
+}
+
+// RequireNumOfArguments panics if the number of arguments is not in the range specified by min and max.
+// In case there is no minimum pass -1, in case there is no maximum pass -1 respectively.
+func (a *Arguments) RequireNumOfArguments(funcname string, min, max int) {
+ num := a.NumOfArguments()
+ if min >= 0 && num < min {
+ a.Panicf("unexpected number of arguments in a call to %s", funcname)
+ } else if max >= 0 && num > max {
+ a.Panicf("unexpected number of arguments in a call to %s", funcname)
+ }
+}
+
+// NumOfArguments returns the number of arguments
+func (a *Arguments) NumOfArguments() int {
+ num := len(a.args.Exprs)
+ if a.pipedVal != nil && !a.args.HasPipeSlot {
+ return num + 1
+ }
+ return num
+}
+
+// Runtime get the Runtime context
+func (a *Arguments) Runtime() *Runtime {
+ return a.runtime
+}
+
+// ParseInto parses the arguments into the provided pointers. It returns an error if the number of pointers passed in does not
+// equal the number of arguments, if any argument's value is invalid according to Go's reflect package, if an argument can't
+// be used as the value the pointer passed in at the corresponding position points to, or if an unhandled pointer type is encountered.
+// Allowed pointer types are pointers to interface{}, int, int64, float64, bool, string, time.Time, reflect.Value, []interface{},
+// map[string]interface{}. If a pointer to a reflect.Value is passed in, the argument be assigned as-is to the value pointed to. For
+// pointers to int or float types, type conversion is performed automatically if necessary.
+func (a *Arguments) ParseInto(ptrs ...interface{}) error {
+ if len(ptrs) < a.NumOfArguments() {
+ return fmt.Errorf("have %d arguments, but only %d pointers to parse into", a.NumOfArguments(), len(ptrs))
+ }
+
+ for i := 0; i < a.NumOfArguments(); i++ {
+ arg, ptr := indirectEface(a.Get(i)), ptrs[i]
+ ok := false
+
+ if !arg.IsValid() {
+ return fmt.Errorf("argument at position %d is not a valid value", i)
+ }
+
+ switch p := ptr.(type) {
+ case *reflect.Value:
+ *p, ok = arg, true
+ case *int:
+ switch arg.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ *p, ok = int(arg.Int()), true
+ case reflect.Float32, reflect.Float64:
+ *p, ok = int(arg.Float()), true
+ default:
+ return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+ }
+ case *int64:
+ switch arg.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ *p, ok = arg.Int(), true
+ case reflect.Float32, reflect.Float64:
+ *p, ok = int64(arg.Float()), true
+ default:
+ return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+ }
+ case *float64:
+ switch arg.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ *p, ok = float64(arg.Int()), true
+ case reflect.Float32, reflect.Float64:
+ *p, ok = arg.Float(), true
+ default:
+ return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+ }
+ }
+
+ if ok {
+ continue
+ }
+
+ if !arg.CanInterface() {
+ return fmt.Errorf("argument at position %d can't be accessed via Interface()", i)
+ }
+ val := arg.Interface()
+
+ switch p := ptr.(type) {
+ case *interface{}:
+ *p, ok = val, true
+ case *bool:
+ *p, ok = val.(bool)
+ case *string:
+ *p, ok = val.(string)
+ case *time.Time:
+ *p, ok = val.(time.Time)
+ case *[]interface{}:
+ *p, ok = val.([]interface{})
+ case *map[string]interface{}:
+ *p, ok = val.(map[string]interface{})
+ default:
+ return fmt.Errorf("trying to parse %v into %v: unhandled value type %T", arg, p, val)
+ }
+
+ if !ok {
+ return fmt.Errorf("could not parse %v (%s) into %v (%T)", arg, arg.Type(), ptr, ptr)
+ }
+ }
+
+ return nil
+}
+
+// Func function implementing this type is called directly, which is faster than calling through reflect.
+// If a function is being called many times in the execution of a template, you may consider implementing
+// a wrapper for that function implementing a Func.
+type Func func(Arguments) reflect.Value
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/lex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/lex.go
new file mode 100644
index 000000000000..dc37b6cf982c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/lex.go
@@ -0,0 +1,754 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+ typ itemType // The type of this item.
+ pos Pos // The starting position, in bytes, of this item in the input string.
+ val string // The value of this item.
+}
+
+func (i item) String() string {
+ switch {
+ case i.typ == itemEOF:
+ return "EOF"
+ case i.typ == itemError:
+ return i.val
+ case i.typ > itemKeyword:
+ return fmt.Sprintf("<%s>", i.val)
+ case len(i.val) > 10:
+ return fmt.Sprintf("%.10q...", i.val)
+ }
+ return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex items.
+type itemType int
+
+const (
+ itemError itemType = iota // error occurred; value is text of error
+ itemBool // boolean constant
+ itemChar // printable ASCII character; grab bag for comma etc.
+ itemCharConstant // character constant
+ itemComplex // complex constant (1+2i); imaginary is just a number
+ itemEOF
+ itemField // alphanumeric identifier starting with '.'
+ itemIdentifier // alphanumeric identifier not starting with '.'
+ itemLeftDelim // left action delimiter
+ itemLeftParen // '(' inside action
+ itemNumber // simple number, including imaginary
+ itemPipe // pipe symbol
+ itemRawString // raw quoted string (includes quotes)
+ itemRightDelim // right action delimiter
+ itemRightParen // ')' inside action
+ itemSpace // run of spaces separating arguments
+ itemString // quoted string (includes quotes)
+ itemText // plain text
+ itemAssign
+ itemEquals
+ itemNotEquals
+ itemGreat
+ itemGreatEquals
+ itemLess
+ itemLessEquals
+ itemComma
+ itemSemicolon
+ itemAdd
+ itemMinus
+ itemMul
+ itemDiv
+ itemMod
+ itemColon
+ itemTernary
+ itemLeftBrackets
+ itemRightBrackets
+ itemUnderscore
+ // Keywords appear after all the rest.
+ itemKeyword // used only to delimit the keywords
+ itemExtends
+ itemImport
+ itemInclude
+ itemBlock
+ itemEnd
+ itemYield
+ itemContent
+ itemIf
+ itemElse
+ itemRange
+ itemTry
+ itemCatch
+ itemReturn
+ itemAnd
+ itemOr
+ itemNot
+ itemNil
+ itemMSG
+ itemTrans
+)
+
+var key = map[string]itemType{
+ "extends": itemExtends,
+ "import": itemImport,
+
+ "include": itemInclude,
+ "block": itemBlock,
+ "end": itemEnd,
+ "yield": itemYield,
+ "content": itemContent,
+
+ "if": itemIf,
+ "else": itemElse,
+
+ "range": itemRange,
+
+ "try": itemTry,
+ "catch": itemCatch,
+
+ "return": itemReturn,
+
+ "and": itemAnd,
+ "or": itemOr,
+ "not": itemNot,
+
+ "nil": itemNil,
+
+ "msg": itemMSG,
+ "trans": itemTrans,
+}
+
+const eof = -1
+
+const (
+ defaultLeftDelim = "{{"
+ defaultRightDelim = "}}"
+ leftComment = "{*"
+ rightComment = "*}"
+ leftTrimMarker = "- "
+ rightTrimMarker = " -"
+ trimMarkerLen = Pos(len(leftTrimMarker))
+)
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+ name string // the name of the input; used only for error reports
+ input string // the string being scanned
+ state stateFn // the next lexing function to enter
+ pos Pos // current position in the input
+ start Pos // start position of this item
+ width Pos // width of last rune read from input
+ lastPos Pos // position of most recent item returned by nextItem
+ items chan item // channel of scanned items
+ parenDepth int // nesting depth of ( ) exprs
+ lastType itemType
+ leftDelim string
+ rightDelim string
+ trimRightDelim string
+}
+
+func (l *lexer) setDelimiters(leftDelim, rightDelim string) {
+ if leftDelim != "" {
+ l.leftDelim = leftDelim
+ }
+ if rightDelim != "" {
+ l.rightDelim = rightDelim
+ }
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() rune {
+ if int(l.pos) >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+ l.width = Pos(w)
+ l.pos += l.width
+ return r
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() rune {
+ r := l.next()
+ l.backup()
+ return r
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+ l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+ l.lastType = t
+ l.items <- item{t, l.start, l.input[l.start:l.pos]}
+ l.start = l.pos
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+ l.start = l.pos
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+ if strings.IndexRune(valid, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+ for strings.IndexRune(valid, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+// lineNumber reports which line we're on, based on the position of
+// the previous item returned by nextItem. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+ return 1 + strings.Count(l.input[:l.lastPos], "\n")
+}
+
+// errorf returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.nextItem.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+ return nil
+}
+
+// nextItem returns the next item from the input.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) nextItem() item {
+ item := <-l.items
+ l.lastPos = item.pos
+ return item
+}
+
+// drain drains the output so the lexing goroutine will exit.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) drain() {
+ for range l.items {
+ }
+}
+
+// lex creates a new scanner for the input string.
+func lex(name, input string, run bool) *lexer {
+ l := &lexer{
+ name: name,
+ input: input,
+ items: make(chan item),
+ leftDelim: defaultLeftDelim,
+ rightDelim: defaultRightDelim,
+ trimRightDelim: rightTrimMarker + defaultRightDelim,
+ }
+ if run {
+ l.run()
+ }
+ return l
+}
+
+// run runs the state machine for the lexer.
+func (l *lexer) run() {
+ go func() {
+ for l.state = lexText; l.state != nil; {
+ l.state = l.state(l)
+ }
+ close(l.items)
+ }()
+}
+
+// state functions
+func lexText(l *lexer) stateFn {
+ for {
+ // without breaking the API, this seems like a reasonable workaround to correctly parse comments
+ i := strings.IndexByte(l.input[l.pos:], l.leftDelim[0]) // index of suspected left delimiter
+ ic := strings.IndexByte(l.input[l.pos:], leftComment[0]) // index of suspected left comment marker
+ if ic > -1 && ic < i { // use whichever is lower for future lexing
+ i = ic
+ }
+ // if no token is found, skip till the end of template
+ if i == -1 {
+ l.pos = Pos(len(l.input))
+ break
+ } else {
+ l.pos += Pos(i)
+ if strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
+ ld := Pos(len(l.leftDelim))
+ trimLength := Pos(0)
+ if strings.HasPrefix(l.input[l.pos+ld:], leftTrimMarker) {
+ trimLength = rightTrimLength(l.input[l.start:l.pos])
+ }
+ l.pos -= trimLength
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.pos += trimLength
+ l.ignore()
+ return lexLeftDelim
+ }
+ if strings.HasPrefix(l.input[l.pos:], leftComment) {
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ return lexComment
+ }
+ }
+ if l.next() == eof {
+ break
+ }
+ }
+ // Correctly reached EOF.
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.emit(itemEOF)
+ return nil
+}
+
+func lexLeftDelim(l *lexer) stateFn {
+ l.pos += Pos(len(l.leftDelim))
+ l.emit(itemLeftDelim)
+ trimSpace := strings.HasPrefix(l.input[l.pos:], leftTrimMarker)
+ if trimSpace {
+ l.pos += trimMarkerLen
+ l.ignore()
+ }
+ l.parenDepth = 0
+ return lexInsideAction
+}
+
+// lexComment scans a comment. The left comment marker is known to be present.
+func lexComment(l *lexer) stateFn {
+ l.pos += Pos(len(leftComment))
+ i := strings.Index(l.input[l.pos:], rightComment)
+ if i < 0 {
+ return l.errorf("unclosed comment")
+ }
+ l.pos += Pos(i + len(rightComment))
+ l.ignore()
+ return lexText
+}
+
+// lexRightDelim scans the right delimiter, which is known to be present.
+func lexRightDelim(l *lexer) stateFn {
+ trimSpace := strings.HasPrefix(l.input[l.pos:], rightTrimMarker)
+ if trimSpace {
+ l.pos += trimMarkerLen
+ l.ignore()
+ }
+ l.pos += Pos(len(l.rightDelim))
+ l.emit(itemRightDelim)
+ if trimSpace {
+ l.pos += leftTrimLength(l.input[l.pos:])
+ l.ignore()
+ }
+ return lexText
+}
+
+// lexInsideAction scans the elements inside action delimiters.
+func lexInsideAction(l *lexer) stateFn {
+ // Either number, quoted string, or identifier.
+ // Spaces separate arguments; runs of spaces turn into itemSpace.
+ // Pipe symbols separate and are emitted.
+ delim, _ := l.atRightDelim()
+ if delim {
+ if l.parenDepth == 0 {
+ return lexRightDelim
+ }
+ return l.errorf("unclosed left parenthesis")
+ }
+ switch r := l.next(); {
+ case r == eof:
+ return l.errorf("unclosed action")
+ case isSpace(r):
+ return lexSpace
+ case r == ',':
+ l.emit(itemComma)
+ case r == ';':
+ l.emit(itemSemicolon)
+ case r == '*':
+ l.emit(itemMul)
+ case r == '/':
+ l.emit(itemDiv)
+ case r == '%':
+ l.emit(itemMod)
+ case r == '-':
+
+ if r := l.peek(); '0' <= r && r <= '9' &&
+ itemAdd != l.lastType &&
+ itemMinus != l.lastType &&
+ itemNumber != l.lastType &&
+ itemIdentifier != l.lastType &&
+ itemString != l.lastType &&
+ itemRawString != l.lastType &&
+ itemCharConstant != l.lastType &&
+ itemBool != l.lastType &&
+ itemField != l.lastType &&
+ itemChar != l.lastType &&
+ itemTrans != l.lastType {
+ l.backup()
+ return lexNumber
+ }
+ l.emit(itemMinus)
+ case r == '+':
+ if r := l.peek(); '0' <= r && r <= '9' &&
+ itemAdd != l.lastType &&
+ itemMinus != l.lastType &&
+ itemNumber != l.lastType &&
+ itemIdentifier != l.lastType &&
+ itemString != l.lastType &&
+ itemRawString != l.lastType &&
+ itemCharConstant != l.lastType &&
+ itemBool != l.lastType &&
+ itemField != l.lastType &&
+ itemChar != l.lastType &&
+ itemTrans != l.lastType {
+ l.backup()
+ return lexNumber
+ }
+ l.emit(itemAdd)
+ case r == '?':
+ l.emit(itemTernary)
+ case r == '&':
+ if l.next() == '&' {
+ l.emit(itemAnd)
+ } else {
+ l.backup()
+ }
+ case r == '<':
+ if l.next() == '=' {
+ l.emit(itemLessEquals)
+ } else {
+ l.backup()
+ l.emit(itemLess)
+ }
+ case r == '>':
+ if l.next() == '=' {
+ l.emit(itemGreatEquals)
+ } else {
+ l.backup()
+ l.emit(itemGreat)
+ }
+ case r == '!':
+ if l.next() == '=' {
+ l.emit(itemNotEquals)
+ } else {
+ l.backup()
+ l.emit(itemNot)
+ }
+
+ case r == '=':
+ if l.next() == '=' {
+ l.emit(itemEquals)
+ } else {
+ l.backup()
+ l.emit(itemAssign)
+ }
+ case r == ':':
+ if l.next() == '=' {
+ l.emit(itemAssign)
+ } else {
+ l.backup()
+ l.emit(itemColon)
+ }
+ case r == '|':
+ if l.next() == '|' {
+ l.emit(itemOr)
+ } else {
+ l.backup()
+ l.emit(itemPipe)
+ }
+ case r == '"':
+ return lexQuote
+ case r == '`':
+ return lexRawQuote
+ case r == '\'':
+ return lexChar
+ case r == '.':
+ // special look-ahead for ".field" so we don't break l.backup().
+ if l.pos < Pos(len(l.input)) {
+ r := l.input[l.pos]
+ if r < '0' || '9' < r {
+ return lexField
+ }
+ }
+ fallthrough // '.' can start a number.
+ case '0' <= r && r <= '9':
+ l.backup()
+ return lexNumber
+ case r == '_':
+ if !isAlphaNumeric(l.peek()) {
+ l.emit(itemUnderscore)
+ return lexInsideAction
+ }
+ fallthrough // no space? must be the start of an identifier
+ case isAlphaNumeric(r):
+ l.backup()
+ return lexIdentifier
+ case r == '[':
+ l.emit(itemLeftBrackets)
+ case r == ']':
+ l.emit(itemRightBrackets)
+ case r == '(':
+ l.emit(itemLeftParen)
+ l.parenDepth++
+ case r == ')':
+ l.emit(itemRightParen)
+ l.parenDepth--
+ if l.parenDepth < 0 {
+ return l.errorf("unexpected right paren %#U", r)
+ }
+ case r <= unicode.MaxASCII && unicode.IsPrint(r):
+ l.emit(itemChar)
+ default:
+ return l.errorf("unrecognized character in action: %#U", r)
+ }
+ return lexInsideAction
+}
+
+// lexSpace scans a run of space characters.
+// One space has already been seen.
+func lexSpace(l *lexer) stateFn {
+ var numSpaces int
+ for isSpace(l.peek()) {
+ numSpaces++
+ l.next()
+ }
+ if strings.HasPrefix(l.input[l.pos-1:], l.trimRightDelim) {
+ l.backup()
+ if numSpaces == 1 {
+ return lexRightDelim
+ }
+ }
+ l.emit(itemSpace)
+ return lexInsideAction
+}
+
+// lexIdentifier scans an alphanumeric.
+func lexIdentifier(l *lexer) stateFn {
+Loop:
+ for {
+ switch r := l.next(); {
+ case isAlphaNumeric(r):
+ // absorb.
+ default:
+ l.backup()
+ word := l.input[l.start:l.pos]
+ if !l.atTerminator() {
+ return l.errorf("bad character %#U", r)
+ }
+ switch {
+ case key[word] > itemKeyword:
+ l.emit(key[word])
+ case word[0] == '.':
+ l.emit(itemField)
+ case word == "true", word == "false":
+ l.emit(itemBool)
+ default:
+ l.emit(itemIdentifier)
+ }
+ break Loop
+ }
+ }
+ return lexInsideAction
+}
+
+// lexField scans a field: .Alphanumeric.
+// The . has been scanned.
+func lexField(l *lexer) stateFn {
+
+ if l.atTerminator() {
+ // Nothing interesting follows -> "." or "$".
+ l.emit(itemIdentifier)
+ return lexInsideAction
+ }
+
+ var r rune
+ for {
+ r = l.next()
+ if !isAlphaNumeric(r) {
+ l.backup()
+ break
+ }
+ }
+ if !l.atTerminator() {
+ return l.errorf("bad character %#U", r)
+ }
+ l.emit(itemField)
+ return lexInsideAction
+}
+
+// atTerminator reports whether the input is at valid termination character to
+// appear after an identifier. Breaks .X.Y into two pieces. Also catches cases
+// like "$x+2" not being acceptable without a space, in case we decide one
+// day to implement arithmetic.
+func (l *lexer) atTerminator() bool {
+ r := l.peek()
+ if isSpace(r) {
+ return true
+ }
+ switch r {
+ case eof, '.', ',', '|', ':', ')', '=', '(', ';', '?', '[', ']', '+', '-', '/', '%', '*', '&', '!', '<', '>':
+ return true
+ }
+ // Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
+ // succeed but should fail) but only in extremely rare cases caused by willfully
+ // bad choice of delimiter.
+ if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
+ return true
+ }
+ return false
+}
+
+// lexChar scans a character constant. The initial quote is already
+// scanned. Syntax checking is done by the parser.
+func lexChar(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated character constant")
+ case '\'':
+ break Loop
+ }
+ }
+ l.emit(itemCharConstant)
+ return lexInsideAction
+}
+
+// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
+// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
+// and "089" - but when it's wrong the input is invalid and the parser (via
+// strconv) will notice.
+func lexNumber(l *lexer) stateFn {
+ if !l.scanNumber() {
+ return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+ }
+
+ l.emit(itemNumber)
+ return lexInsideAction
+}
+
+func (l *lexer) scanNumber() bool {
+ // Optional leading sign.
+ l.accept("+-")
+ // Is it hex?
+ digits := "0123456789"
+ if l.accept("0") && l.accept("xX") {
+ digits = "0123456789abcdefABCDEF"
+ }
+ l.acceptRun(digits)
+ if l.accept(".") {
+ l.acceptRun(digits)
+ }
+ if l.accept("eE") {
+ l.accept("+-")
+ l.acceptRun("0123456789")
+ }
+ //Is it imaginary?
+ l.accept("i")
+ //Next thing mustn't be alphanumeric.
+ if isAlphaNumeric(l.peek()) {
+ l.next()
+ return false
+ }
+ return true
+}
+
+// lexQuote scans a quoted string.
+func lexQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated quoted string")
+ case '"':
+ break Loop
+ }
+ }
+ l.emit(itemString)
+ return lexInsideAction
+}
+
+// lexRawQuote scans a raw quoted string.
+func lexRawQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case eof:
+ return l.errorf("unterminated raw quoted string")
+ case '`':
+ break Loop
+ }
+ }
+ l.emit(itemRawString)
+ return lexInsideAction
+}
+
+// isSpace reports whether r is a space character.
+func isSpace(r rune) bool {
+ return r == ' ' || r == '\t' || r == '\r' || r == '\n'
+}
+
+// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumeric(r rune) bool {
+ return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}
+
+// rightTrimLength returns the length of the spaces at the end of the string.
+func rightTrimLength(s string) Pos {
+ return Pos(len(s) - len(strings.TrimRightFunc(s, isSpace)))
+}
+
+// leftTrimLength returns the length of the spaces at the beginning of the string.
+func leftTrimLength(s string) Pos {
+ return Pos(len(s) - len(strings.TrimLeftFunc(s, isSpace)))
+}
+
+// atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker.
+func (l *lexer) atRightDelim() (delim, trimSpaces bool) {
+ if strings.HasPrefix(l.input[l.pos:], l.trimRightDelim) { // With trim marker.
+ return true, true
+ }
+ if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker.
+ return true, false
+ }
+ return false, false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/loader.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/loader.go
new file mode 100644
index 000000000000..0231da8487a4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/loader.go
@@ -0,0 +1,146 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "sync"
+)
+
+// Loader is a minimal interface required for loading templates.
+//
+// Jet will build an absolute path (with slash delimiters) before looking up templates by resolving paths in extends/import/include statements:
+//
+// - `{{ extends "/bar.jet" }}` will make Jet look up `/bar.jet` in the Loader unchanged, no matter where it occurs (since it's an absolute path)
+// - `{{ include("\views\bar.jet") }}` will make Jet look up `/views/bar.jet` in the Loader, no matter where it occurs
+// - `{{ import "bar.jet" }}` in `/views/foo.jet` will result in a lookup of `/views/bar.jet`
+// - `{{ extends "./bar.jet" }}` in `/views/foo.jet` will result in a lookup of `/views/bar.jet`
+// - `{{ import "../views\bar.jet" }}` in `/views/foo.jet` will result in a lookup of `/views/bar.jet`
+// - `{{ include("../bar.jet") }}` in `/views/foo.jet` will result in a lookup of `/bar.jet`
+// - `{{ import "../views/../bar.jet" }}` in `/views/foo.jet` will result in a lookup of `/bar.jet`
+//
+// This means that the same template will always be looked up using the same path.
+//
+// Jet will also try appending multiple file endings for convenience: `{{ extends "/bar" }}` will lookup `/bar`, `/bar.jet`,
+// `/bar.html.jet` and `/bar.jet.html` (in that order). To avoid unneccessary lookups, use the full file name in your templates (so the first lookup
+// is always a hit, or override this list of extensions using Set.SetExtensions().
+type Loader interface {
+ // Exists returns whether or not a template exists under the requested path.
+ Exists(templatePath string) bool
+
+ // Open returns the template's contents or an error if something went wrong.
+ // Calls to Open() will always be preceded by a call to Exists() with the same `templatePath`.
+ // It is the caller's duty to close the template.
+ Open(templatePath string) (io.ReadCloser, error)
+}
+
+// OSFileSystemLoader implements Loader interface using OS file system (os.File).
+type OSFileSystemLoader struct {
+ dir string
+}
+
+// compile time check that we implement Loader
+var _ Loader = (*OSFileSystemLoader)(nil)
+
+// NewOSFileSystemLoader returns an initialized OSFileSystemLoader.
+func NewOSFileSystemLoader(dirPath string) *OSFileSystemLoader {
+ return &OSFileSystemLoader{
+ dir: filepath.FromSlash(dirPath),
+ }
+}
+
+// Exists returns true if a file is found under the template path after converting it to a file path
+// using the OS's path seperator and joining it with the loader's directory path.
+func (l *OSFileSystemLoader) Exists(templatePath string) bool {
+ templatePath = filepath.Join(l.dir, filepath.FromSlash(templatePath))
+ stat, err := os.Stat(templatePath)
+ if err == nil && !stat.IsDir() {
+ return true
+ }
+ return false
+}
+
+// Open returns the result of `os.Open()` on the file located using the same logic as Exists().
+func (l *OSFileSystemLoader) Open(templatePath string) (io.ReadCloser, error) {
+ return os.Open(filepath.Join(l.dir, filepath.FromSlash(templatePath)))
+}
+
+// InMemLoader is a simple in-memory loader storing template contents in a simple map.
+// InMemLoader normalizes paths passed to its methods by converting any input path to a slash-delimited path,
+// turning it into an absolute path by prepending a "/" if neccessary, and cleaning it (see path.Clean()).
+// It is safe for concurrent use.
+type InMemLoader struct {
+ lock sync.RWMutex
+ files map[string][]byte
+}
+
+// compile time check that we implement Loader
+var _ Loader = (*InMemLoader)(nil)
+
+// NewInMemLoader return a new InMemLoader.
+func NewInMemLoader() *InMemLoader {
+ return &InMemLoader{
+ files: map[string][]byte{},
+ }
+}
+
+func (l *InMemLoader) normalize(templatePath string) string {
+ templatePath = filepath.ToSlash(templatePath)
+ return path.Join("/", templatePath)
+}
+
+// Open returns a template's contents, or an error if no template was added under this path using Set().
+func (l *InMemLoader) Open(templatePath string) (io.ReadCloser, error) {
+ templatePath = l.normalize(templatePath)
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ f, ok := l.files[templatePath]
+ if !ok {
+ return nil, fmt.Errorf("%s does not exist", templatePath)
+ }
+
+ return ioutil.NopCloser(bytes.NewReader(f)), nil
+}
+
+// Exists returns whether or not a template is indexed under this path.
+func (l *InMemLoader) Exists(templatePath string) bool {
+ templatePath = l.normalize(templatePath)
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ _, ok := l.files[templatePath]
+ return ok
+}
+
+// Set adds a template to the loader.
+func (l *InMemLoader) Set(templatePath, contents string) {
+ templatePath = l.normalize(templatePath)
+ l.lock.Lock()
+ defer l.lock.Unlock()
+ l.files[templatePath] = []byte(contents)
+}
+
+// Delete removes whatever contents are stored under the given path.
+func (l *InMemLoader) Delete(templatePath string) {
+ templatePath = l.normalize(templatePath)
+ l.lock.Lock()
+ defer l.lock.Unlock()
+ delete(l.files, templatePath)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/node.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/node.go
new file mode 100644
index 000000000000..819dd37d8e32
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/node.go
@@ -0,0 +1,713 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "bytes"
+ "fmt"
+ "path/filepath"
+)
+
+var textFormat = "%s" //Changed to "%q" in tests for better error messages.
+
+type Node interface {
+ Type() NodeType
+ String() string
+ Position() Pos
+ line() int
+ error(error)
+ errorf(string, ...interface{})
+}
+
+type Expression interface {
+ Node
+}
+
+// Pos represents a byte position in the original input text from which
+// this template was parsed.
+type Pos int
+
+func (p Pos) Position() Pos {
+ return p
+}
+
+// NodeType identifies the type of a parse tree node.
+type NodeType int
+
+type NodeBase struct {
+ TemplatePath string
+ Line int
+ NodeType
+ Pos
+}
+
+func (node *NodeBase) line() int {
+ return node.Line
+}
+
+func (node *NodeBase) error(err error) {
+ node.errorf("%s", err)
+}
+
+func (node *NodeBase) errorf(format string, v ...interface{}) {
+ panic(fmt.Errorf("Jet Runtime Error (%q:%d): %s", filepath.ToSlash(node.TemplatePath), node.Line, fmt.Sprintf(format, v...)))
+}
+
+// Type returns itself and provides an easy default implementation
+// for embedding in a Node. Embedded in all non-trivial Nodes.
+func (t NodeType) Type() NodeType {
+ return t
+}
+
+const (
+ NodeText NodeType = iota //Plain text.
+ NodeAction //A non-control action such as a field evaluation.
+ NodeChain //A sequence of field accesses.
+ NodeCommand //An element of a pipeline.
+ NodeField //A field or method name.
+ NodeIdentifier //An identifier; always a function name.
+ NodeUnderscore //An underscore (discard in assignment, or slot in argument list for piped value)
+ NodeList //A list of Nodes.
+ NodePipe //A pipeline of commands.
+ NodeSet
+ //NodeWith //A with action.
+ NodeInclude
+ NodeBlock
+ nodeEnd //An end action. Not added to tree.
+ NodeYield
+ nodeContent
+ NodeIf //An if action.
+ nodeElse //An else action. Not added to tree.
+ NodeRange //A range action.
+ NodeTry
+ nodeCatch
+ NodeReturn
+ beginExpressions
+ NodeString //A string constant.
+ NodeNil //An untyped nil constant.
+ NodeNumber //A numerical constant.
+ NodeBool //A boolean constant.
+ NodeAdditiveExpr
+ NodeMultiplicativeExpr
+ NodeComparativeExpr
+ NodeNumericComparativeExpr
+ NodeLogicalExpr
+ NodeCallExpr
+ NodeNotExpr
+ NodeTernaryExpr
+ NodeIndexExpr
+ NodeSliceExpr
+ endExpressions
+)
+
+// Nodes.
+
+// ListNode holds a sequence of nodes.
+type ListNode struct {
+ NodeBase
+ Nodes []Node //The element nodes in lexical order.
+}
+
+func (l *ListNode) append(n Node) {
+ l.Nodes = append(l.Nodes, n)
+}
+
+func (l *ListNode) String() string {
+ b := new(bytes.Buffer)
+ for _, n := range l.Nodes {
+ fmt.Fprint(b, n)
+ }
+ return b.String()
+}
+
+// TextNode holds plain text.
+type TextNode struct {
+ NodeBase
+ Text []byte
+}
+
+func (t *TextNode) String() string {
+ return fmt.Sprintf(textFormat, t.Text)
+}
+
+// PipeNode holds a pipeline with optional declaration
+type PipeNode struct {
+ NodeBase //The line number in the input. Deprecated: Kept for compatibility.
+ Cmds []*CommandNode //The commands in lexical order.
+}
+
+func (p *PipeNode) append(command *CommandNode) {
+ p.Cmds = append(p.Cmds, command)
+}
+
+func (p *PipeNode) String() string {
+ s := ""
+ for i, c := range p.Cmds {
+ if i > 0 {
+ s += " | "
+ }
+ s += c.String()
+ }
+ return s
+}
+
+// ActionNode holds an action (something bounded by delimiters).
+// Control actions have their own nodes; ActionNode represents simple
+// ones such as field evaluations and parenthesized pipelines.
+type ActionNode struct {
+ NodeBase
+ Set *SetNode
+ Pipe *PipeNode
+}
+
+func (a *ActionNode) String() string {
+ if a.Set != nil {
+ if a.Pipe == nil {
+ return fmt.Sprintf("{{%s}}", a.Set)
+ }
+ return fmt.Sprintf("{{%s;%s}}", a.Set, a.Pipe)
+ }
+ return fmt.Sprintf("{{%s}}", a.Pipe)
+}
+
+// CommandNode holds a command (a pipeline inside an evaluating action).
+type CommandNode struct {
+ NodeBase
+ CallExprNode
+}
+
+func (c *CommandNode) append(arg Node) {
+ c.Exprs = append(c.Exprs, arg)
+}
+
+func (c *CommandNode) String() string {
+ if c.Exprs == nil {
+ return c.BaseExpr.String()
+ }
+
+ arguments := ""
+ for i, expr := range c.Exprs {
+ if i > 0 {
+ arguments += ", "
+ }
+ arguments += expr.String()
+ }
+ return fmt.Sprintf("%s(%s)", c.BaseExpr, arguments)
+}
+
+// IdentifierNode holds an identifier.
+type IdentifierNode struct {
+ NodeBase
+ Ident string //The identifier's name.
+}
+
+func (i *IdentifierNode) String() string {
+ return i.Ident
+}
+
+// UnderscoreNode is used for one of two things:
+// - signals to discard the corresponding right side of an assignment
+// - tells Jet where in a pipelined function call to inject the piped value
+type UnderscoreNode struct {
+ NodeBase
+}
+
+func (i *UnderscoreNode) String() string {
+ return "_"
+}
+
+// NilNode holds the special identifier 'nil' representing an untyped nil constant.
+type NilNode struct {
+ NodeBase
+}
+
+func (n *NilNode) String() string {
+ return "nil"
+}
+
+// FieldNode holds a field (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The period is dropped from each ident.
+type FieldNode struct {
+ NodeBase
+ Ident []string //The identifiers in lexical order.
+}
+
+func (f *FieldNode) String() string {
+ s := ""
+ for _, id := range f.Ident {
+ s += "." + id
+ }
+ return s
+}
+
+// ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The periods are dropped from each ident.
+type ChainNode struct {
+ NodeBase
+ Node Node
+ Field []string //The identifiers in lexical order.
+}
+
+// Add adds the named field (which should start with a period) to the end of the chain.
+func (c *ChainNode) Add(field string) {
+ if len(field) == 0 || field[0] != '.' {
+ panic("no dot in field")
+ }
+ field = field[1:] //Remove leading dot.
+ if field == "" {
+ panic("empty field")
+ }
+ c.Field = append(c.Field, field)
+}
+
+func (c *ChainNode) String() string {
+ s := c.Node.String()
+ if _, ok := c.Node.(*PipeNode); ok {
+ s = "(" + s + ")"
+ }
+ for _, field := range c.Field {
+ s += "." + field
+ }
+ return s
+}
+
+// BoolNode holds a boolean constant.
+type BoolNode struct {
+ NodeBase
+ True bool //The value of the boolean constant.
+}
+
+func (b *BoolNode) String() string {
+ if b.True {
+ return "true"
+ }
+ return "false"
+}
+
+// NumberNode holds a number: signed or unsigned integer, float, or complex.
+// The value is parsed and stored under all the types that can represent the value.
+// This simulates in a small amount of code the behavior of Go's ideal constants.
+type NumberNode struct {
+ NodeBase
+
+ IsInt bool //Number has an integral value.
+ IsUint bool //Number has an unsigned integral value.
+ IsFloat bool //Number has a floating-point value.
+ IsComplex bool //Number is complex.
+ Int64 int64 //The signed integer value.
+ Uint64 uint64 //The unsigned integer value.
+ Float64 float64 //The floating-point value.
+ Complex128 complex128 //The complex value.
+ Text string //The original textual representation from the input.
+}
+
+// simplifyComplex pulls out any other types that are represented by the complex number.
+// These all require that the imaginary part be zero.
+func (n *NumberNode) simplifyComplex() {
+ n.IsFloat = imag(n.Complex128) == 0
+ if n.IsFloat {
+ n.Float64 = real(n.Complex128)
+ n.IsInt = float64(int64(n.Float64)) == n.Float64
+ if n.IsInt {
+ n.Int64 = int64(n.Float64)
+ }
+ n.IsUint = float64(uint64(n.Float64)) == n.Float64
+ if n.IsUint {
+ n.Uint64 = uint64(n.Float64)
+ }
+ }
+}
+
+func (n *NumberNode) String() string {
+ return n.Text
+}
+
+// StringNode holds a string constant. The value has been "unquoted".
+type StringNode struct {
+ NodeBase
+
+ Quoted string //The original text of the string, with quotes.
+ Text string //The string, after quote processing.
+}
+
+func (s *StringNode) String() string {
+ return s.Quoted
+}
+
+// endNode represents an {{end}} action.
+// It does not appear in the final parse tree.
+type endNode struct {
+ NodeBase
+}
+
+func (e *endNode) String() string {
+ return "{{end}}"
+}
+
+// endNode represents an {{end}} action.
+// It does not appear in the final parse tree.
+type contentNode struct {
+ NodeBase
+}
+
+func (e *contentNode) String() string {
+ return "{{content}}"
+}
+
+// elseNode represents an {{else}} action. Does not appear in the final tree.
+type elseNode struct {
+ NodeBase //The line number in the input. Deprecated: Kept for compatibility.
+}
+
+func (e *elseNode) String() string {
+ return "{{else}}"
+}
+
+// SetNode represents a set action, ident( ',' ident)* '=' expression ( ',' expression )*
+type SetNode struct {
+ NodeBase
+ Let bool
+ IndexExprGetLookup bool
+ Left []Expression
+ Right []Expression
+}
+
+func (set *SetNode) String() string {
+ var s = ""
+
+ for i, v := range set.Left {
+ if i > 0 {
+ s += ", "
+ }
+ s += v.String()
+ }
+
+ if set.Let {
+ s += ":="
+ } else {
+ s += "="
+ }
+
+ for i, v := range set.Right {
+ if i > 0 {
+ s += ", "
+ }
+ s += v.String()
+ }
+
+ return s
+}
+
+// BranchNode is the common representation of if, range, and with.
+type BranchNode struct {
+ NodeBase
+ Set *SetNode
+ Expression Expression
+ List *ListNode
+ ElseList *ListNode
+}
+
+func (b *BranchNode) String() string {
+
+ if b.NodeType == NodeRange {
+ s := ""
+ if b.Set != nil {
+ s = b.Set.String()
+ } else {
+ s = b.Expression.String()
+ }
+
+ if b.ElseList != nil {
+ return fmt.Sprintf("{{range %s}}%s{{else}}%s{{end}}", s, b.List, b.ElseList)
+ }
+ return fmt.Sprintf("{{range %s}}%s{{end}}", s, b.List)
+ } else {
+ s := ""
+ if b.Set != nil {
+ s = b.Set.String() + ";"
+ }
+ if b.ElseList != nil {
+ return fmt.Sprintf("{{if %s%s}}%s{{else}}%s{{end}}", s, b.Expression, b.List, b.ElseList)
+ }
+ return fmt.Sprintf("{{if %s%s}}%s{{end}}", s, b.Expression, b.List)
+ }
+}
+
+// IfNode represents an {{if}} action and its commands.
+type IfNode struct {
+ BranchNode
+}
+
+// RangeNode represents a {{range}} action and its commands.
+type RangeNode struct {
+ BranchNode
+}
+
+type BlockParameter struct {
+ Identifier string
+ Expression Expression
+}
+
+type BlockParameterList struct {
+ NodeBase
+ List []BlockParameter
+}
+
+func (bplist *BlockParameterList) Param(name string) (Expression, int) {
+ for i := 0; i < len(bplist.List); i++ {
+ param := &bplist.List[i]
+ if param.Identifier == name {
+ return param.Expression, i
+ }
+ }
+ return nil, -1
+}
+
+func (bplist *BlockParameterList) String() (str string) {
+ buff := bytes.NewBuffer(nil)
+ for _, bp := range bplist.List {
+ if bp.Identifier == "" {
+ fmt.Fprintf(buff, "%s,", bp.Expression)
+ } else {
+ if bp.Expression == nil {
+ fmt.Fprintf(buff, "%s,", bp.Identifier)
+ } else {
+ fmt.Fprintf(buff, "%s=%s,", bp.Identifier, bp.Expression)
+ }
+ }
+ }
+ if buff.Len() > 0 {
+ str = buff.String()[0 : buff.Len()-1]
+ }
+ return
+}
+
+// BlockNode represents a {{block }} action.
+type BlockNode struct {
+ NodeBase //The line number in the input. Deprecated: Kept for compatibility.
+ Name string //The name of the template (unquoted).
+
+ Parameters *BlockParameterList
+ Expression Expression //The command to evaluate as dot for the template.
+
+ List *ListNode
+ Content *ListNode
+}
+
+func (t *BlockNode) String() string {
+ if t.Content != nil {
+ if t.Expression == nil {
+ return fmt.Sprintf("{{block %s(%s)}}%s{{content}}%s{{end}}", t.Name, t.Parameters, t.List, t.Content)
+ }
+ return fmt.Sprintf("{{block %s(%s) %s}}%s{{content}}%s{{end}}", t.Name, t.Parameters, t.Expression, t.List, t.Content)
+ }
+ if t.Expression == nil {
+ return fmt.Sprintf("{{block %s(%s)}}%s{{end}}", t.Name, t.Parameters, t.List)
+ }
+ return fmt.Sprintf("{{block %s(%s) %s}}%s{{end}}", t.Name, t.Parameters, t.Expression, t.List)
+}
+
+// YieldNode represents a {{yield}} action
+type YieldNode struct {
+ NodeBase //The line number in the input. Deprecated: Kept for compatibility.
+ Name string //The name of the template (unquoted).
+ Parameters *BlockParameterList
+ Expression Expression //The command to evaluate as dot for the template.
+ Content *ListNode
+ IsContent bool
+}
+
+func (t *YieldNode) String() string {
+ if t.IsContent {
+ if t.Expression == nil {
+ return "{{yield content}}"
+ }
+ return fmt.Sprintf("{{yield content %s}}", t.Expression)
+ }
+
+ if t.Content != nil {
+ if t.Expression == nil {
+ return fmt.Sprintf("{{yield %s(%s) content}}%s{{end}}", t.Name, t.Parameters, t.Content)
+ }
+ return fmt.Sprintf("{{yield %s(%s) %s content}}%s{{end}}", t.Name, t.Parameters, t.Expression, t.Content)
+ }
+
+ if t.Expression == nil {
+ return fmt.Sprintf("{{yield %s(%s)}}", t.Name, t.Parameters)
+ }
+ return fmt.Sprintf("{{yield %s(%s) %s}}", t.Name, t.Parameters, t.Expression)
+}
+
+// IncludeNode represents a {{include }} action.
+type IncludeNode struct {
+ NodeBase
+ Name Expression
+ Context Expression
+}
+
+func (t *IncludeNode) String() string {
+ if t.Context == nil {
+ return fmt.Sprintf("{{include %s}}", t.Name)
+ }
+ return fmt.Sprintf("{{include %s %s}}", t.Name, t.Context)
+}
+
+type binaryExprNode struct {
+ NodeBase
+ Operator item
+ Left, Right Expression
+}
+
+func (node *binaryExprNode) String() string {
+ return fmt.Sprintf("%s %s %s", node.Left, node.Operator.val, node.Right)
+}
+
+// AdditiveExprNode represents an add or subtract expression
+// ex: expression ( '+' | '-' ) expression
+type AdditiveExprNode struct {
+ binaryExprNode
+}
+
+// MultiplicativeExprNode represents a multiplication, division, or module expression
+// ex: expression ( '*' | '/' | '%' ) expression
+type MultiplicativeExprNode struct {
+ binaryExprNode
+}
+
+// LogicalExprNode represents a boolean expression, 'and' or 'or'
+// ex: expression ( '&&' | '||' ) expression
+type LogicalExprNode struct {
+ binaryExprNode
+}
+
+// ComparativeExprNode represents a comparative expression
+// ex: expression ( '==' | '!=' ) expression
+type ComparativeExprNode struct {
+ binaryExprNode
+}
+
+// NumericComparativeExprNode represents a numeric comparative expression
+// ex: expression ( '<' | '>' | '<=' | '>=' ) expression
+type NumericComparativeExprNode struct {
+ binaryExprNode
+}
+
+// NotExprNode represents a negate expression
+// ex: '!' expression
+type NotExprNode struct {
+ NodeBase
+ Expr Expression
+}
+
+func (s *NotExprNode) String() string {
+ return fmt.Sprintf("!%s", s.Expr)
+}
+
+type CallArgs struct {
+ Exprs []Expression
+ HasPipeSlot bool
+}
+
+// CallExprNode represents a call expression
+// ex: expression '(' (expression (',' expression)* )? ')'
+type CallExprNode struct {
+ NodeBase
+ BaseExpr Expression
+ CallArgs
+}
+
+func (s *CallExprNode) String() string {
+ arguments := ""
+ for i, expr := range s.Exprs {
+ if i > 0 {
+ arguments += ", "
+ }
+ arguments += expr.String()
+ }
+ return fmt.Sprintf("%s(%s)", s.BaseExpr, arguments)
+}
+
+// TernaryExprNod represents a ternary expression,
+// ex: expression '?' expression ':' expression
+type TernaryExprNode struct {
+ NodeBase
+ Boolean, Left, Right Expression
+}
+
+func (s *TernaryExprNode) String() string {
+ return fmt.Sprintf("%s?%s:%s", s.Boolean, s.Left, s.Right)
+}
+
+type IndexExprNode struct {
+ NodeBase
+ Base Expression
+ Index Expression
+}
+
+func (s *IndexExprNode) String() string {
+ return fmt.Sprintf("%s[%s]", s.Base, s.Index)
+}
+
+type SliceExprNode struct {
+ NodeBase
+ Base Expression
+ Index Expression
+ EndIndex Expression
+}
+
+func (s *SliceExprNode) String() string {
+ var index_string, len_string string
+ if s.Index != nil {
+ index_string = s.Index.String()
+ }
+ if s.EndIndex != nil {
+ len_string = s.EndIndex.String()
+ }
+ return fmt.Sprintf("%s[%s:%s]", s.Base, index_string, len_string)
+}
+
+type ReturnNode struct {
+ NodeBase
+ Value Expression
+}
+
+func (n *ReturnNode) String() string {
+ return fmt.Sprintf("return %v", n.Value)
+}
+
+type TryNode struct {
+ NodeBase
+ List *ListNode
+ Catch *catchNode
+}
+
+func (n *TryNode) String() string {
+ if n.Catch != nil {
+ return fmt.Sprintf("{{try}}%s%s", n.List, n.Catch)
+ }
+ return fmt.Sprintf("{{try}}%s{{end}}", n.List)
+}
+
+type catchNode struct {
+ NodeBase
+ Err *IdentifierNode
+ List *ListNode
+}
+
+func (n *catchNode) String() string {
+ return fmt.Sprintf("{{catch %s}}%s{{end}}", n.Err, n.List)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/parse.go
new file mode 100644
index 000000000000..4f0166d81a88
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/parse.go
@@ -0,0 +1,1059 @@
+// Copyright 2016 José Santos
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jet
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+func unquote(text string) (string, error) {
+ return strconv.Unquote(text)
+}
+
+// Template is the representation of a single parsed template.
+type Template struct {
+ Name string // name of the template represented by the tree.
+ ParseName string // name of the top-level template during parsing, for error messages.
+
+ set *Set
+ extends *Template
+ imports []*Template
+
+ processedBlocks map[string]*BlockNode
+ passedBlocks map[string]*BlockNode
+ Root *ListNode // top-level root of the tree.
+
+ text string // text parsed to create the template (or its parent)
+
+ // Parsing only; cleared after parse.
+ lex *lexer
+ token [3]item // three-token lookahead for parser.
+ peekCount int
+}
+
+func (t *Template) String() (template string) {
+ if t.extends != nil {
+ if len(t.Root.Nodes) > 0 && len(t.imports) == 0 {
+ template += fmt.Sprintf("{{extends %q}}", t.extends.ParseName)
+ } else {
+ template += fmt.Sprintf("{{extends %q}}", t.extends.ParseName)
+ }
+ }
+
+ for k, _import := range t.imports {
+ if t.extends == nil && k == 0 {
+ template += fmt.Sprintf("{{import %q}}", _import.ParseName)
+ } else {
+ template += fmt.Sprintf("\n{{import %q}}", _import.ParseName)
+ }
+ }
+
+ if t.extends != nil || len(t.imports) > 0 {
+ if len(t.Root.Nodes) > 0 {
+ template += "\n" + t.Root.String()
+ }
+ } else {
+ template += t.Root.String()
+ }
+ return
+}
+
+func (t *Template) addBlocks(blocks map[string]*BlockNode) {
+ if len(blocks) == 0 {
+ return
+ }
+ if t.processedBlocks == nil {
+ t.processedBlocks = make(map[string]*BlockNode)
+ }
+ for key, value := range blocks {
+ t.processedBlocks[key] = value
+ }
+}
+
+// next returns the next token.
+func (t *Template) next() item {
+ if t.peekCount > 0 {
+ t.peekCount--
+ } else {
+ t.token[0] = t.lex.nextItem()
+ }
+ return t.token[t.peekCount]
+}
+
+// backup backs the input stream up one token.
+func (t *Template) backup() {
+ t.peekCount++
+}
+
+// backup2 backs the input stream up two tokens.
+// The zeroth token is already there.
+func (t *Template) backup2(t1 item) {
+ t.token[1] = t1
+ t.peekCount = 2
+}
+
+// backup3 backs the input stream up three tokens
+// The zeroth token is already there.
+func (t *Template) backup3(t2, t1 item) {
+ // Reverse order: we're pushing back.
+ t.token[1] = t1
+ t.token[2] = t2
+ t.peekCount = 3
+}
+
+// peek returns but does not consume the next token.
+func (t *Template) peek() item {
+ if t.peekCount > 0 {
+ return t.token[t.peekCount-1]
+ }
+ t.peekCount = 1
+ t.token[0] = t.lex.nextItem()
+ return t.token[0]
+}
+
+// nextNonSpace returns the next non-space token.
+func (t *Template) nextNonSpace() (token item) {
+ for {
+ token = t.next()
+ if token.typ != itemSpace {
+ break
+ }
+ }
+ return token
+}
+
+// peekNonSpace returns but does not consume the next non-space token.
+func (t *Template) peekNonSpace() (token item) {
+ for {
+ token = t.next()
+ if token.typ != itemSpace {
+ break
+ }
+ }
+ t.backup()
+ return token
+}
+
+// errorf formats the error and terminates processing.
+func (t *Template) errorf(format string, args ...interface{}) {
+ t.Root = nil
+ format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format)
+ panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (t *Template) error(err error) {
+ t.errorf("%s", err)
+}
+
+// expect consumes the next token and guarantees it has the required type.
+func (t *Template) expect(expectedType itemType, context, expected string) item {
+ token := t.nextNonSpace()
+ if token.typ != expectedType {
+ t.unexpected(token, context, expected)
+ }
+ return token
+}
+
+func (t *Template) expectRightDelim(context string) item {
+ return t.expect(itemRightDelim, context, "closing delimiter")
+}
+
+// expectOneOf consumes the next token and guarantees it has one of the required types.
+func (t *Template) expectOneOf(expected1, expected2 itemType, context, expectedAs string) item {
+ token := t.nextNonSpace()
+ if token.typ != expected1 && token.typ != expected2 {
+ t.unexpected(token, context, expectedAs)
+ }
+ return token
+}
+
+// unexpected complains about the token and terminates processing.
+func (t *Template) unexpected(token item, context, expected string) {
+ switch {
+ case token.typ == itemImport,
+ token.typ == itemExtends:
+ t.errorf("parsing %s: unexpected keyword '%s' ('%s' statements must be at the beginning of the template)", context, token.val, token.val)
+ case token.typ > itemKeyword:
+ t.errorf("parsing %s: unexpected keyword '%s' (expected %s)", context, token.val, expected)
+ default:
+ t.errorf("parsing %s: unexpected token '%s' (expected %s)", context, token.val, expected)
+ }
+}
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (t *Template) recover(errp *error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ if t != nil {
+ t.lex.drain()
+ t.stopParse()
+ }
+ *errp = e.(error)
+ }
+ return
+}
+
+func (s *Set) parse(name, text string, cacheAfterParsing bool) (t *Template, err error) {
+ t = &Template{
+ Name: name,
+ ParseName: name,
+ text: text,
+ set: s,
+ passedBlocks: make(map[string]*BlockNode),
+ }
+ defer t.recover(&err)
+
+ lexer := lex(name, text, false)
+ lexer.setDelimiters(s.leftDelim, s.rightDelim)
+ lexer.run()
+ t.startParse(lexer)
+ t.parseTemplate(cacheAfterParsing)
+ t.stopParse()
+
+ if t.extends != nil {
+ t.addBlocks(t.extends.processedBlocks)
+ }
+
+ for _, _import := range t.imports {
+ t.addBlocks(_import.processedBlocks)
+ }
+
+ t.addBlocks(t.passedBlocks)
+
+ return t, err
+}
+
+func (t *Template) expectString(context string) string {
+ token := t.expectOneOf(itemString, itemRawString, context, "string literal")
+ s, err := unquote(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ return s
+}
+
+// parse is the top-level parser for a template, essentially the same
+// It runs to EOF.
+func (t *Template) parseTemplate(cacheAfterParsing bool) (next Node) {
+ t.Root = t.newList(t.peek().pos)
+ // {{ extends|import stringLiteral }}
+ for t.peek().typ != itemEOF {
+ delim := t.next()
+ if delim.typ == itemText && strings.TrimSpace(delim.val) == "" {
+ continue //skips empty text nodes
+ }
+ if delim.typ == itemLeftDelim {
+ token := t.nextNonSpace()
+ if token.typ == itemExtends || token.typ == itemImport {
+ s := t.expectString("extends|import")
+ if token.typ == itemExtends {
+ if t.extends != nil {
+ t.errorf("Unexpected extends clause: each template can only extend one template")
+ } else if len(t.imports) > 0 {
+ t.errorf("Unexpected extends clause: the 'extends' clause should come before all import clauses")
+ }
+ var err error
+ t.extends, err = t.set.getSiblingTemplate(s, t.Name, cacheAfterParsing)
+ if err != nil {
+ t.error(err)
+ }
+ } else {
+ tt, err := t.set.getSiblingTemplate(s, t.Name, cacheAfterParsing)
+ if err != nil {
+ t.error(err)
+ }
+ t.imports = append(t.imports, tt)
+ }
+ t.expect(itemRightDelim, "extends|import", "closing delimiter")
+ } else {
+ t.backup2(delim)
+ break
+ }
+ } else {
+ t.backup()
+ break
+ }
+ }
+
+ for t.peek().typ != itemEOF {
+ switch n := t.textOrAction(); n.Type() {
+ case nodeEnd, nodeElse, nodeContent:
+ t.errorf("unexpected %s", n)
+ default:
+ t.Root.append(n)
+ }
+ }
+ return nil
+}
+
+// startParse initializes the parser, using the lexer.
+func (t *Template) startParse(lex *lexer) {
+ t.Root = nil
+ t.lex = lex
+}
+
+// stopParse terminates parsing.
+func (t *Template) stopParse() {
+ t.lex = nil
+}
+
+// IsEmptyTree reports whether this tree (node) is empty of everything but space.
+func IsEmptyTree(n Node) bool {
+ switch n := n.(type) {
+ case nil:
+ return true
+ case *ActionNode:
+ case *IfNode:
+ case *ListNode:
+ for _, node := range n.Nodes {
+ if !IsEmptyTree(node) {
+ return false
+ }
+ }
+ return true
+ case *RangeNode:
+ case *IncludeNode:
+ case *TextNode:
+ return len(bytes.TrimSpace(n.Text)) == 0
+ case *BlockNode:
+ case *YieldNode:
+ default:
+ panic("unknown node: " + n.String())
+ }
+ return false
+}
+
+func (t *Template) blockParametersList(isDeclaring bool, context string) *BlockParameterList {
+ block := &BlockParameterList{}
+
+ t.expect(itemLeftParen, context, "opening parenthesis")
+ for {
+ var expression Expression
+ next := t.nextNonSpace()
+ if next.typ == itemIdentifier {
+ identifier := next.val
+ next2 := t.nextNonSpace()
+ switch next2.typ {
+ case itemComma, itemRightParen:
+ block.List = append(block.List, BlockParameter{Identifier: identifier})
+ next = next2
+ case itemAssign:
+ expression, next = t.parseExpression(context)
+ block.List = append(block.List, BlockParameter{Identifier: identifier, Expression: expression})
+ default:
+ if !isDeclaring {
+ switch next2.typ {
+ case itemComma, itemRightParen:
+ default:
+ t.backup2(next)
+ expression, next = t.parseExpression(context)
+ block.List = append(block.List, BlockParameter{Expression: expression})
+ }
+ } else {
+ t.unexpected(next2, context, "comma, assignment, or closing parenthesis")
+ }
+ }
+ } else if !isDeclaring {
+ switch next.typ {
+ case itemComma, itemRightParen:
+ default:
+ t.backup()
+ expression, next = t.parseExpression(context)
+ block.List = append(block.List, BlockParameter{Expression: expression})
+ }
+ }
+
+ if next.typ != itemComma {
+ t.backup()
+ break
+ }
+ }
+ t.expect(itemRightParen, context, "closing parenthesis")
+ return block
+}
+
+func (t *Template) parseBlock() Node {
+ const context = "block clause"
+ var pipe Expression
+
+ name := t.expect(itemIdentifier, context, "name")
+ bplist := t.blockParametersList(true, context)
+
+ if t.peekNonSpace().typ != itemRightDelim {
+ pipe = t.expression(context, "context")
+ }
+
+ t.expectRightDelim(context)
+
+ list, end := t.itemList(nodeContent, nodeEnd)
+ var contentList *ListNode
+
+ if end.Type() == nodeContent {
+ contentList, end = t.itemList(nodeEnd)
+ }
+
+ block := t.newBlock(name.pos, t.lex.lineNumber(), name.val, bplist, pipe, list, contentList)
+ t.passedBlocks[block.Name] = block
+ return block
+}
+
+func (t *Template) parseYield() Node {
+ const context = "yield clause"
+
+ var (
+ pipe Expression
+ name item
+ bplist *BlockParameterList
+ content *ListNode
+ )
+
+ // parse block name
+ name = t.nextNonSpace()
+ if name.typ == itemContent {
+ // content yield {{yield content}}
+ if t.peekNonSpace().typ != itemRightDelim {
+ pipe = t.expression(context, "content context")
+ }
+ t.expectRightDelim(context)
+ return t.newYield(name.pos, t.lex.lineNumber(), "", nil, pipe, nil, true)
+ } else if name.typ != itemIdentifier {
+ t.unexpected(name, context, "block name")
+ }
+
+ // parse block parameters
+ bplist = t.blockParametersList(false, context)
+
+ // parse optional context & content
+ typ := t.peekNonSpace().typ
+ if typ == itemRightDelim {
+ t.expectRightDelim(context)
+ } else {
+ if typ != itemContent {
+ // parse context expression
+ pipe = t.expression("yield", "context")
+ typ = t.peekNonSpace().typ
+ }
+ if typ == itemRightDelim {
+ t.expectRightDelim(context)
+ } else if typ == itemContent {
+ // parse content from following nodes (until {{end}})
+ t.nextNonSpace()
+ t.expectRightDelim(context)
+ content, _ = t.itemList(nodeEnd)
+ } else {
+ t.unexpected(t.nextNonSpace(), context, "content keyword or closing delimiter")
+ }
+ }
+
+ return t.newYield(name.pos, t.lex.lineNumber(), name.val, bplist, pipe, content, false)
+}
+
+func (t *Template) parseInclude() Node {
+ var context Expression
+ name := t.expression("include", "template name")
+ if t.peekNonSpace().typ != itemRightDelim {
+ context = t.expression("include", "context")
+ }
+ t.expectRightDelim("include invocation")
+ return t.newInclude(name.Position(), t.lex.lineNumber(), name, context)
+}
+
+func (t *Template) parseReturn() Node {
+ value := t.expression("return", "value")
+ t.expectRightDelim("return")
+ return t.newReturn(value.Position(), t.lex.lineNumber(), value)
+}
+
+// itemList:
+// textOrAction*
+// Terminates at any of the given nodes, returned separately.
+func (t *Template) itemList(terminatedBy ...NodeType) (list *ListNode, next Node) {
+ list = t.newList(t.peekNonSpace().pos)
+ for t.peekNonSpace().typ != itemEOF {
+ n := t.textOrAction()
+ for _, terminatorType := range terminatedBy {
+ if n.Type() == terminatorType {
+ return list, n
+ }
+ }
+ list.append(n)
+ }
+ t.errorf("unexpected EOF")
+ return
+}
+
+// textOrAction:
+// text | action
+func (t *Template) textOrAction() Node {
+ switch token := t.nextNonSpace(); token.typ {
+ case itemText:
+ return t.newText(token.pos, token.val)
+ case itemLeftDelim:
+ return t.action()
+ default:
+ t.unexpected(token, "input", "text or action")
+ }
+ return nil
+}
+
+func (t *Template) action() (n Node) {
+ switch token := t.nextNonSpace(); token.typ {
+ case itemInclude:
+ return t.parseInclude()
+ case itemBlock:
+ return t.parseBlock()
+ case itemEnd:
+ return t.endControl()
+ case itemYield:
+ return t.parseYield()
+ case itemContent:
+ return t.contentControl()
+ case itemIf:
+ return t.ifControl()
+ case itemElse:
+ return t.elseControl()
+ case itemRange:
+ return t.rangeControl()
+ case itemTry:
+ return t.parseTry()
+ case itemCatch:
+ return t.parseCatch()
+ case itemReturn:
+ return t.parseReturn()
+ }
+
+ t.backup()
+ action := t.newAction(t.peek().pos, t.lex.lineNumber())
+
+ expr := t.assignmentOrExpression("command")
+ if expr.Type() == NodeSet {
+ action.Set = expr.(*SetNode)
+ expr = nil
+ if t.expectOneOf(itemSemicolon, itemRightDelim, "command", "semicolon or right delimiter").typ == itemSemicolon {
+ expr = t.expression("command", "pipeline base expression")
+ }
+ }
+ if expr != nil {
+ action.Pipe = t.pipeline("command", expr)
+ }
+ return action
+}
+
+func (t *Template) logicalExpression(context string) (Expression, item) {
+ left, endtoken := t.comparativeExpression(context)
+ for endtoken.typ == itemAnd || endtoken.typ == itemOr {
+ right, rightendtoken := t.comparativeExpression(context)
+ left, endtoken = t.newLogicalExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+ }
+ return left, endtoken
+}
+
+func (t *Template) parseExpression(context string) (Expression, item) {
+ expression, endtoken := t.logicalExpression(context)
+ if endtoken.typ == itemTernary {
+ var left, right Expression
+ left, endtoken = t.parseExpression(context)
+ if endtoken.typ != itemColon {
+ t.unexpected(endtoken, "ternary expression", "colon in ternary expression")
+ }
+ right, endtoken = t.parseExpression(context)
+ expression = t.newTernaryExpr(expression.Position(), t.lex.lineNumber(), expression, left, right)
+ }
+ return expression, endtoken
+}
+
+func (t *Template) comparativeExpression(context string) (Expression, item) {
+ left, endtoken := t.numericComparativeExpression(context)
+ for endtoken.typ == itemEquals || endtoken.typ == itemNotEquals {
+ right, rightendtoken := t.numericComparativeExpression(context)
+ left, endtoken = t.newComparativeExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+ }
+ return left, endtoken
+}
+
+func (t *Template) numericComparativeExpression(context string) (Expression, item) {
+ left, endtoken := t.additiveExpression(context)
+ for endtoken.typ >= itemGreat && endtoken.typ <= itemLessEquals {
+ right, rightendtoken := t.additiveExpression(context)
+ left, endtoken = t.newNumericComparativeExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+ }
+ return left, endtoken
+}
+
+func (t *Template) additiveExpression(context string) (Expression, item) {
+ left, endtoken := t.multiplicativeExpression(context)
+ for endtoken.typ == itemAdd || endtoken.typ == itemMinus {
+ right, rightendtoken := t.multiplicativeExpression(context)
+ left, endtoken = t.newAdditiveExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+ }
+ return left, endtoken
+}
+
+func (t *Template) multiplicativeExpression(context string) (left Expression, endtoken item) {
+ left, endtoken = t.unaryExpression(context)
+ for endtoken.typ >= itemMul && endtoken.typ <= itemMod {
+ right, rightendtoken := t.unaryExpression(context)
+ left, endtoken = t.newMultiplicativeExpr(left.Position(), t.lex.lineNumber(), left, right, endtoken), rightendtoken
+ }
+
+ return left, endtoken
+}
+
+func (t *Template) unaryExpression(context string) (Expression, item) {
+ next := t.nextNonSpace()
+ switch next.typ {
+ case itemNot:
+ expr, endToken := t.comparativeExpression(context)
+ return t.newNotExpr(expr.Position(), t.lex.lineNumber(), expr), endToken
+ case itemMinus, itemAdd:
+ return t.newAdditiveExpr(next.pos, t.lex.lineNumber(), nil, t.operand("additive expression"), next), t.nextNonSpace()
+ default:
+ t.backup()
+ }
+ operand := t.operand(context)
+ return operand, t.nextNonSpace()
+}
+
+func (t *Template) assignmentOrExpression(context string) (operand Expression) {
+ t.peekNonSpace()
+ line := t.lex.lineNumber()
+ var right, left []Expression
+
+ var isSet bool
+ var isLet bool
+ var returned item
+ operand, returned = t.parseExpression(context)
+ pos := operand.Position()
+ if returned.typ == itemComma || returned.typ == itemAssign {
+ isSet = true
+ } else {
+ if operand == nil {
+ t.unexpected(returned, context, "operand")
+ }
+ t.backup()
+ return operand
+ }
+
+ if isSet {
+ leftloop:
+ for {
+ switch operand.Type() {
+ case NodeField, NodeChain, NodeIdentifier, NodeUnderscore:
+ left = append(left, operand)
+ default:
+ t.errorf("unexpected node in assign")
+ }
+
+ switch returned.typ {
+ case itemComma:
+ operand, returned = t.parseExpression(context)
+ case itemAssign:
+ isLet = returned.val == ":="
+ break leftloop
+ default:
+ t.unexpected(returned, "assignment", "comma or assignment")
+ }
+ }
+
+ if isLet {
+ for _, operand := range left {
+ if operand.Type() != NodeIdentifier && operand.Type() != NodeUnderscore {
+ t.errorf("unexpected node type %s in variable declaration", operand)
+ }
+ }
+ }
+
+ for {
+ operand, returned = t.parseExpression("assignment")
+ right = append(right, operand)
+ if returned.typ != itemComma {
+ t.backup()
+ break
+ }
+ }
+
+ var isIndexExprGetLookup bool
+
+ if context == "range" {
+ if len(left) > 2 || len(right) > 1 {
+ t.errorf("unexpected number of operands in assign on range")
+ }
+ } else {
+ if len(left) != len(right) {
+ if len(left) == 2 && len(right) == 1 && right[0].Type() == NodeIndexExpr {
+ isIndexExprGetLookup = true
+ } else {
+ t.errorf("unexpected number of operands in assign on range")
+ }
+ }
+ }
+ operand = t.newSet(pos, line, isLet, isIndexExprGetLookup, left, right)
+ return
+
+ }
+ return
+}
+
+func (t *Template) expression(context, as string) Expression {
+ expr, tk := t.parseExpression(context)
+ if expr == nil {
+ t.unexpected(tk, context, as)
+ }
+ t.backup()
+ return expr
+}
+
+func (t *Template) pipeline(context string, baseExprMutate Expression) (pipe *PipeNode) {
+ pos := t.peekNonSpace().pos
+ pipe = t.newPipeline(pos, t.lex.lineNumber())
+
+ if baseExprMutate == nil {
+ pipe.errorf("parsing pipeline: first expression cannot be nil")
+ }
+ pipe.append(t.command(baseExprMutate))
+
+ for {
+ token := t.expectOneOf(itemPipe, itemRightDelim, "pipeline", "pipe or right delimiter")
+ if token.typ == itemRightDelim {
+ break
+ }
+ token = t.nextNonSpace()
+ switch token.typ {
+ case itemField, itemIdentifier:
+ t.backup()
+ pipe.append(t.command(nil))
+ default:
+ t.unexpected(token, "pipeline", "field or identifier")
+ }
+ }
+
+ return
+}
+
+func (t *Template) command(baseExpr Expression) *CommandNode {
+ cmd := t.newCommand(t.peekNonSpace().pos)
+
+ if baseExpr == nil {
+ baseExpr = t.expression("command", "name")
+ }
+
+ if baseExpr.Type() == NodeCallExpr {
+ call := baseExpr.(*CallExprNode)
+ cmd.CallExprNode = *call
+ return cmd
+ }
+
+ cmd.BaseExpr = baseExpr
+
+ next := t.nextNonSpace()
+ switch next.typ {
+ case itemColon:
+ cmd.CallArgs = t.parseArguments()
+ default:
+ t.backup()
+ }
+
+ if cmd.BaseExpr == nil {
+ t.errorf("empty command")
+ }
+
+ return cmd
+}
+
+// operand:
+// term .Field*
+// An operand is a space-separated component of a command,
+// a term possibly followed by field accesses.
+// A nil return means the next item is not an operand.
+func (t *Template) operand(context string) Expression {
+ node := t.term()
+ if node == nil {
+ t.unexpected(t.next(), context, "term")
+ }
+RESET:
+ if t.peek().typ == itemField {
+ chain := t.newChain(t.peek().pos, node)
+ for t.peekNonSpace().typ == itemField {
+ chain.Add(t.next().val)
+ }
+ // Compatibility with original API: If the term is of type NodeField
+ // or NodeVariable, just put more fields on the original.
+ // Otherwise, keep the Chain node.
+ // Obvious parsing errors involving literal values are detected here.
+ // More complex error cases will have to be handled at execution time.
+ switch node.Type() {
+ case NodeField:
+ node = t.newField(chain.Position(), chain.String())
+ case NodeBool, NodeString, NodeNumber, NodeNil:
+ t.errorf("unexpected . after term %q", node.String())
+ default:
+ node = chain
+ }
+ }
+ nodeTYPE := node.Type()
+ if nodeTYPE == NodeIdentifier ||
+ nodeTYPE == NodeCallExpr ||
+ nodeTYPE == NodeField ||
+ nodeTYPE == NodeChain ||
+ nodeTYPE == NodeIndexExpr {
+ switch t.nextNonSpace().typ {
+ case itemLeftParen:
+ callExpr := t.newCallExpr(node.Position(), t.lex.lineNumber(), node)
+ callExpr.CallArgs = t.parseArguments()
+ t.expect(itemRightParen, "call expression", "closing parenthesis")
+ node = callExpr
+ goto RESET
+ case itemLeftBrackets:
+ base := node
+ var index Expression
+ var next item
+
+ //found colon is slice expression
+ if t.peekNonSpace().typ != itemColon {
+ index, next = t.parseExpression("index|slice expression")
+ } else {
+ next = t.nextNonSpace()
+ }
+
+ switch next.typ {
+ case itemColon:
+ var endIndex Expression
+ if t.peekNonSpace().typ != itemRightBrackets {
+ endIndex = t.expression("slice expression", "end indexß")
+ }
+ node = t.newSliceExpr(node.Position(), node.line(), base, index, endIndex)
+ case itemRightBrackets:
+ node = t.newIndexExpr(node.Position(), node.line(), base, index)
+ fallthrough
+ default:
+ t.backup()
+ }
+
+ t.expect(itemRightBrackets, "index expression", "closing bracket")
+ goto RESET
+ default:
+ t.backup()
+ }
+ }
+ return node
+}
+
+func (t *Template) parseArguments() (args CallArgs) {
+ context := "call expression argument list"
+ args.Exprs = []Expression{}
+loop:
+ for {
+ peek := t.peekNonSpace()
+ if peek.typ == itemRightParen {
+ break
+ }
+ var (
+ expr Expression
+ endtoken item
+ )
+ expr, endtoken = t.parseExpression(context)
+ if expr.Type() == NodeUnderscore {
+ // slot for piped argument
+ if args.HasPipeSlot {
+ t.errorf("found two pipe slot markers ('_') for the same function call")
+ }
+ args.HasPipeSlot = true
+ }
+ args.Exprs = append(args.Exprs, expr)
+ switch endtoken.typ {
+ case itemComma:
+ // continue with closing parens (allowed because of multiline syntax) or next arg
+ default:
+ t.backup()
+ break loop
+ }
+ }
+ return
+}
+
+func (t *Template) parseControl(allowElseIf bool, context string) (pos Pos, line int, set *SetNode, expression Expression, list, elseList *ListNode) {
+ line = t.lex.lineNumber()
+
+ expression = t.assignmentOrExpression(context)
+ pos = expression.Position()
+ if expression.Type() == NodeSet {
+ set = expression.(*SetNode)
+ if context != "range" {
+ t.expect(itemSemicolon, context, "semicolon between assignment and expression")
+ expression = t.expression(context, "expression after assignment")
+ } else {
+ expression = nil
+ }
+ }
+
+ t.expectRightDelim(context)
+ var next Node
+ list, next = t.itemList(nodeElse, nodeEnd)
+ if next.Type() == nodeElse {
+ if allowElseIf && t.peek().typ == itemIf {
+ // Special case for "else if". If the "else" is followed immediately by an "if",
+ // the elseControl will have left the "if" token pending. Treat
+ // {{if a}}_{{else if b}}_{{end}}
+ // as
+ // {{if a}}_{{else}}{{if b}}_{{end}}{{end}}.
+ // To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}}
+ // is assumed. This technique works even for long if-else-if chains.
+ t.next() // Consume the "if" token.
+ elseList = t.newList(next.Position())
+ elseList.append(t.ifControl())
+ // Do not consume the next item - only one {{end}} required.
+ } else {
+ elseList, next = t.itemList(nodeEnd)
+ }
+ }
+ return pos, line, set, expression, list, elseList
+}
+
+// If:
+// {{if expression}} itemList {{end}}
+// {{if expression}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Template) ifControl() Node {
+ return t.newIf(t.parseControl(true, "if"))
+}
+
+// Range:
+// {{range expression}} itemList {{end}}
+// {{range expression}} itemList {{else}} itemList {{end}}
+// Range keyword is past.
+func (t *Template) rangeControl() Node {
+ return t.newRange(t.parseControl(false, "range"))
+}
+
+// End:
+// {{end}}
+// End keyword is past.
+func (t *Template) endControl() Node {
+ return t.newEnd(t.expectRightDelim("end").pos)
+}
+
+// Content:
+// {{content}}
+// Content keyword is past.
+func (t *Template) contentControl() Node {
+ return t.newContent(t.expectRightDelim("content").pos)
+}
+
+// Else:
+// {{else}}
+// Else keyword is past.
+func (t *Template) elseControl() Node {
+ // Special case for "else if".
+ peek := t.peekNonSpace()
+ if peek.typ == itemIf {
+ // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
+ return t.newElse(peek.pos, t.lex.lineNumber())
+ }
+ return t.newElse(t.expectRightDelim("else").pos, t.lex.lineNumber())
+}
+
+// Try-catch:
+// {{try}}
+// itemList
+// {{catch }}
+// itemList
+// {{end}}
+// try keyword is past.
+func (t *Template) parseTry() *TryNode {
+ var recov *catchNode
+ line := t.lex.lineNumber()
+ pos := t.expectRightDelim("try").pos
+ list, next := t.itemList(nodeCatch, nodeEnd)
+ if next.Type() == nodeCatch {
+ recov = next.(*catchNode)
+ }
+
+ return t.newTry(pos, line, list, recov)
+}
+
+// catch:
+// {{catch }}
+// itemList
+// {{end}}
+// catch keyword is past.
+func (t *Template) parseCatch() *catchNode {
+ line := t.lex.lineNumber()
+ var errVar *IdentifierNode
+ peek := t.peekNonSpace()
+ if peek.typ != itemRightDelim {
+ _errVar := t.term()
+ if typ := _errVar.Type(); typ != NodeIdentifier {
+ t.errorf("unexpected node type '%s' in catch", typ)
+ }
+ errVar = _errVar.(*IdentifierNode)
+ }
+ t.expectRightDelim("catch")
+ list, _ := t.itemList(nodeEnd)
+ return t.newCatch(peek.pos, line, errVar, list)
+}
+
+// term:
+// literal (number, string, nil, boolean)
+// function (identifier)
+// .
+// .Field
+// variable
+// '(' expression ')'
+// A term is a simple "expression".
+// A nil return means the next item is not a term.
+func (t *Template) term() Node {
+ switch token := t.nextNonSpace(); token.typ {
+ case itemError:
+ t.errorf("%s", token.val)
+ case itemIdentifier:
+ return t.newIdentifier(token.val, token.pos, t.lex.lineNumber())
+ case itemUnderscore:
+ return t.newUnderscore(token.pos, t.lex.lineNumber())
+ case itemNil:
+ return t.newNil(token.pos)
+ case itemField:
+ return t.newField(token.pos, token.val)
+ case itemBool:
+ return t.newBool(token.pos, token.val == "true")
+ case itemCharConstant, itemComplex, itemNumber:
+ number, err := t.newNumber(token.pos, token.val, token.typ)
+ if err != nil {
+ t.error(err)
+ }
+ return number
+ case itemLeftParen:
+ pipe := t.expression("parenthesized expression", "expression")
+ if token := t.next(); token.typ != itemRightParen {
+ t.unexpected(token, "parenthesized expression", "closing parenthesis")
+ }
+ return pipe
+ case itemString, itemRawString:
+ s, err := unquote(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ return t.newString(token.pos, token.val, s)
+ }
+ t.backup()
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/profile.sh b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/profile.sh
new file mode 100644
index 000000000000..46a73caf624c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/profile.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+go test -run="^$" -bench="Range" -benchmem -c -cpuprofile=./pprof.out
+go test -run="^$" -bench="Range" -benchmem -cpuprofile=./pprof.out
+go tool pprof --pdf --focus="$1" jet.test pprof.out >> out.pdf
+rm jet.test
+rm pprof.out
+open out.pdf
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/ranger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/ranger.go
new file mode 100644
index 000000000000..088cef68e7db
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/ranger.go
@@ -0,0 +1,179 @@
+package jet
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "sync"
+)
+
+// Ranger describes an interface for types that iterate over something.
+// Implementing this interface means the ranger will be used when it's
+// encountered on the right hand side of a range's "let" expression.
+type Ranger interface {
+ // Range calls should return a key, a value and a done bool to indicate
+ // whether there are more values to be generated.
+ //
+ // When the done flag is true, then the loop ends.
+ Range() (reflect.Value, reflect.Value, bool)
+
+ // ProvidesIndex should return true if keys are produced during Range()
+ // calls. This call should be idempotent across Range() calls (i.e.
+ // its return value must not change during an iteration).
+ ProvidesIndex() bool
+}
+
+type intsRanger struct {
+ i, val, to int64
+}
+
+var _ Ranger = &intsRanger{}
+
+func (r *intsRanger) Range() (index, value reflect.Value, end bool) {
+ r.i++
+ r.val++
+ end = r.val == r.to
+
+ // The indirection in the ValueOf calls avoids an allocation versus
+ // using the concrete value of 'i' and 'val'. The downside is having
+ // to interpret 'r.i' as "the current value" after Range() returns,
+ // and so it needs to be initialized as -1.
+ index = reflect.ValueOf(&r.i).Elem()
+ value = reflect.ValueOf(&r.val).Elem()
+ return
+}
+
+func (r *intsRanger) ProvidesIndex() bool { return true }
+
+func newIntsRanger(from, to int64) *intsRanger {
+ r := &intsRanger{
+ to: to,
+ i: -1,
+ val: from - 1,
+ }
+ return r
+}
+
+type pooledRanger interface {
+ Ranger
+ Setup(reflect.Value)
+}
+
+type sliceRanger struct {
+ v reflect.Value
+ i int
+}
+
+var _ Ranger = &sliceRanger{}
+var _ pooledRanger = &sliceRanger{}
+
+func (r *sliceRanger) Setup(v reflect.Value) {
+ r.i = 0
+ r.v = v
+}
+
+func (r *sliceRanger) Range() (index, value reflect.Value, end bool) {
+ if r.i == r.v.Len() {
+ end = true
+ return
+ }
+ index = reflect.ValueOf(r.i)
+ value = r.v.Index(r.i)
+ r.i++
+ return
+}
+
+func (r *sliceRanger) ProvidesIndex() bool { return true }
+
+type mapRanger struct {
+ iter *reflect.MapIter
+ hasMore bool
+}
+
+var _ Ranger = &mapRanger{}
+var _ pooledRanger = &mapRanger{}
+
+func (r *mapRanger) Setup(v reflect.Value) {
+ r.iter = v.MapRange()
+ r.hasMore = r.iter.Next()
+}
+
+func (r *mapRanger) Range() (key, value reflect.Value, end bool) {
+ if !r.hasMore {
+ end = true
+ return
+ }
+ key, value = r.iter.Key(), r.iter.Value()
+ r.hasMore = r.iter.Next()
+ return
+}
+
+func (r *mapRanger) ProvidesIndex() bool { return true }
+
+type chanRanger struct {
+ v reflect.Value
+}
+
+var _ Ranger = &chanRanger{}
+var _ pooledRanger = &chanRanger{}
+
+func (r *chanRanger) Setup(v reflect.Value) {
+ r.v = v
+}
+
+func (r *chanRanger) Range() (_, value reflect.Value, end bool) {
+ v, ok := r.v.Recv()
+ value, end = v, !ok
+ return
+}
+
+func (r *chanRanger) ProvidesIndex() bool { return false }
+
+// ranger pooling
+
+var (
+ poolSliceRanger = &sync.Pool{
+ New: func() interface{} {
+ return new(sliceRanger)
+ },
+ }
+
+ poolsByKind = map[reflect.Kind]*sync.Pool{
+ reflect.Slice: poolSliceRanger,
+ reflect.Array: poolSliceRanger,
+ reflect.Map: &sync.Pool{
+ New: func() interface{} {
+ return new(mapRanger)
+ },
+ },
+ reflect.Chan: &sync.Pool{
+ New: func() interface{} {
+ return new(chanRanger)
+ },
+ },
+ }
+)
+
+func getRanger(v reflect.Value) (r Ranger, cleanup func(), err error) {
+ if !v.IsValid() {
+ return nil, nil, errors.New("can't range over invalid value")
+ }
+ t := v.Type()
+ if t.Implements(rangerType) {
+ return v.Interface().(Ranger), func() { /* no cleanup needed */ }, nil
+ }
+
+ v, isNil := indirect(v)
+ if isNil {
+ return nil, nil, fmt.Errorf("cannot range over nil pointer/interface (%s)", t)
+ }
+
+ pool, ok := poolsByKind[v.Kind()]
+ if !ok {
+ return nil, nil, fmt.Errorf("value %v (type %s) is not rangeable", v, t)
+ }
+
+ pr := pool.Get().(pooledRanger)
+ pr.Setup(v)
+ return pr, func() { pool.Put(pr) }, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/set.go b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/set.go
new file mode 100644
index 000000000000..67b787183c60
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/set.go
@@ -0,0 +1,221 @@
+package jet
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "path"
+ "path/filepath"
+ "reflect"
+ "sync"
+ "text/template"
+)
+
+// Set is responsible to load, parse and cache templates.
+// Every Jet template is associated with a Set.
+type Set struct {
+ loader Loader
+ cache Cache
+ escapee SafeWriter // escapee to use at runtime
+ globals VarMap // global scope for this template set
+ gmx *sync.RWMutex // global variables map mutex
+ extensions []string
+ developmentMode bool
+ leftDelim string
+ rightDelim string
+}
+
+// Option is the type of option functions that can be used in NewSet().
+type Option func(*Set)
+
+// NewSet returns a new Set relying on loader. NewSet panics if a nil Loader is passed.
+func NewSet(loader Loader, opts ...Option) *Set {
+ if loader == nil {
+ panic(errors.New("jet: NewSet() must not be called with a nil loader"))
+ }
+
+ s := &Set{
+ loader: loader,
+ cache: &cache{},
+ escapee: template.HTMLEscape,
+ globals: VarMap{},
+ gmx: &sync.RWMutex{},
+ extensions: []string{
+ "", // in case the path is given with the correct extension already
+ ".jet",
+ ".html.jet",
+ ".jet.html",
+ },
+ }
+
+ for _, opt := range opts {
+ opt(s)
+ }
+
+ return s
+}
+
+// WithCache returns an option function that sets the cache to use for template parsing results.
+// Use InDevelopmentMode() to disable caching of parsed templates. By default, Jet uses a
+// concurrency-safe in-memory cache that holds templates forever.
+func WithCache(c Cache) Option {
+ if c == nil {
+ panic(errors.New("jet: WithCache() must not be called with a nil cache"))
+ }
+ return func(s *Set) {
+ s.cache = c
+ }
+}
+
+// WithSafeWriter returns an option function that sets the escaping function to use when executing
+// templates. By default, Jet uses a writer that takes care of HTML escaping. Pass nil to disable escaping.
+func WithSafeWriter(w SafeWriter) Option {
+ return func(s *Set) {
+ s.escapee = w
+ }
+}
+
+// WithDelims returns an option function that sets the delimiters to the specified strings.
+// Parsed templates will inherit the settings. Not setting them leaves them at the default: `{{` and `}}`.
+func WithDelims(left, right string) Option {
+ return func(s *Set) {
+ s.leftDelim = left
+ s.rightDelim = right
+ }
+}
+
+// WithTemplateNameExtensions returns an option function that sets the extensions to try when looking
+// up template names in the cache or loader. Default extensions are `""` (no extension), `".jet"`,
+// `".html.jet"`, `".jet.html"`. Extensions will be tried in the order they are defined in the slice.
+// WithTemplateNameExtensions panics when you pass in a nil or empty slice.
+func WithTemplateNameExtensions(extensions []string) Option {
+ if len(extensions) == 0 {
+ panic(errors.New("jet: WithTemplateNameExtensions() must not be called with a nil or empty slice of extensions"))
+ }
+ return func(s *Set) {
+ s.extensions = extensions
+ }
+}
+
+// InDevelopmentMode returns an option function that toggles development mode on, meaning the cache will
+// always be bypassed and every template lookup will go to the loader.
+func InDevelopmentMode() Option {
+ return func(s *Set) {
+ s.developmentMode = true
+ }
+}
+
+// GetTemplate tries to find (and parse, if not yet parsed) the template at the specified path.
+//
+// For example, GetTemplate("catalog/products.list") with extensions set to []string{"", ".html.jet",".jet"}
+// will try to look for:
+// 1. catalog/products.list
+// 2. catalog/products.list.html.jet
+// 3. catalog/products.list.jet
+// in the set's templates cache, and if it can't find the template it will try to load the same paths via
+// the loader, and, if parsed successfully, cache the template (unless running in development mode).
+func (s *Set) GetTemplate(templatePath string) (t *Template, err error) {
+ return s.getSiblingTemplate(templatePath, "/", true)
+}
+
+func (s *Set) getSiblingTemplate(templatePath, siblingPath string, cacheAfterParsing bool) (t *Template, err error) {
+ templatePath = filepath.ToSlash(templatePath)
+ siblingPath = filepath.ToSlash(siblingPath)
+ if !path.IsAbs(templatePath) {
+ siblingDir := path.Dir(siblingPath)
+ templatePath = path.Join(siblingDir, templatePath)
+ }
+ return s.getTemplate(templatePath, cacheAfterParsing)
+}
+
+// same as GetTemplate, but doesn't cache a template when found through the loader.
+func (s *Set) getTemplate(templatePath string, cacheAfterParsing bool) (t *Template, err error) {
+ if !s.developmentMode {
+ t, found := s.getTemplateFromCache(templatePath)
+ if found {
+ return t, nil
+ }
+ }
+
+ t, err = s.getTemplateFromLoader(templatePath, cacheAfterParsing)
+ if err == nil && cacheAfterParsing && !s.developmentMode {
+ s.cache.Put(templatePath, t)
+ }
+ return t, err
+}
+
+func (s *Set) getTemplateFromCache(templatePath string) (t *Template, ok bool) {
+ // check path with all possible extensions in cache
+ for _, extension := range s.extensions {
+ canonicalPath := templatePath + extension
+ if t := s.cache.Get(canonicalPath); t != nil {
+ return t, true
+ }
+ }
+ return nil, false
+}
+
+func (s *Set) getTemplateFromLoader(templatePath string, cacheAfterParsing bool) (t *Template, err error) {
+ // check path with all possible extensions in loader
+ for _, extension := range s.extensions {
+ canonicalPath := templatePath + extension
+ if found := s.loader.Exists(canonicalPath); found {
+ return s.loadFromFile(canonicalPath, cacheAfterParsing)
+ }
+ }
+ return nil, fmt.Errorf("template %s could not be found", templatePath)
+}
+
+func (s *Set) loadFromFile(templatePath string, cacheAfterParsing bool) (template *Template, err error) {
+ f, err := s.loader.Open(templatePath)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ content, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, err
+ }
+ return s.parse(templatePath, string(content), cacheAfterParsing)
+}
+
+// Parse parses `contents` as if it were located at `templatePath`, but won't put the result into the cache.
+// Any referenced template (e.g. via `extends` or `import` statements) will be tried to be loaded from the cache.
+// If a referenced template has to be loaded and parsed, it will also not be put into the cache after parsing.
+func (s *Set) Parse(templatePath, contents string) (template *Template, err error) {
+ templatePath = filepath.ToSlash(templatePath)
+ switch path.Base(templatePath) {
+ case ".", "/":
+ return nil, errors.New("template path has no base name")
+ }
+ // make sure it's absolute and clean it
+ templatePath = path.Join("/", templatePath)
+
+ return s.parse(templatePath, contents, false)
+}
+
+// AddGlobal adds a global variable into the Set,
+// overriding any value previously set under the specified key.
+// It returns the Set it was called on to allow for method chaining.
+func (s *Set) AddGlobal(key string, i interface{}) *Set {
+ s.gmx.Lock()
+ defer s.gmx.Unlock()
+ s.globals[key] = reflect.ValueOf(i)
+ return s
+}
+
+// LookupGlobal returns the global variable previously set under the specified key.
+// It returns the nil interface and false if no variable exists under that key.
+func (s *Set) LookupGlobal(key string) (val interface{}, found bool) {
+ s.gmx.RLock()
+ defer s.gmx.RUnlock()
+ val, found = s.globals[key]
+ return
+}
+
+// AddGlobalFunc adds a global function into the Set,
+// overriding any function previously set under the specified key.
+// It returns the Set it was called on to allow for method chaining.
+func (s *Set) AddGlobalFunc(key string, fn Func) *Set {
+ return s.AddGlobal(key, fn)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/stress.bash b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/stress.bash
new file mode 100644
index 000000000000..307753f703d1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/CloudyKit/jet/v6/stress.bash
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash -e
+
+go test -c
+# comment above and uncomment below to enable the race builder
+#go test -c -race
+PKG=$(basename $(pwd))
+
+while true ; do
+ export GOMAXPROCS=$[ 1 + $[ RANDOM % 128 ]]
+ ./$PKG.test $@ 2>&1
+done
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/LICENSE.md b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/LICENSE.md
new file mode 100644
index 000000000000..201ef1d9314e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/LICENSE.md
@@ -0,0 +1,27 @@
+Copyright (c) 2015, Joker
+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 jade nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/README.md
new file mode 100644
index 000000000000..ed153f9a55a1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/README.md
@@ -0,0 +1,250 @@
+# Jade.go - template engine for Go (golang)
+Package jade (github.com/Joker/jade) is a simple and fast template engine implementing Jade/Pug template.
+Jade precompiles templates to Go code or generates html/template.
+Now Jade-lang is renamed to [Pug template engine](https://pugjs.org/language/tags.html).
+
+[![GoDoc](https://godoc.org/github.com/Joker/jade?status.svg)](https://pkg.go.dev/github.com/Joker/jade#section-documentation) [![Go Report Card](https://goreportcard.com/badge/github.com/Joker/jade)](https://goreportcard.com/report/github.com/Joker/jade)
+
+## Jade/Pug syntax
+example:
+
+```jade
+//- :go:func Index(pageTitle string, youAreUsingJade bool)
+
+mixin for(golang)
+ #cmd Precompile jade templates to #{golang} code.
+
+doctype html
+html(lang="en")
+ head
+ title= pageTitle
+ script(type='text/javascript').
+ if(question){
+ answer(40 + 2)
+ }
+ body
+ h1 Jade - template engine
+ +for('Go')
+
+ #container.col
+ if youAreUsingJade
+ p You are amazing
+ else
+ p Get on it!
+ p.
+ Jade/Pug is a terse and simple
+ templating language with
+ a #[strong focus] on performance
+ and powerful features.
+```
+
+becomes
+
+```html
+
+
+
+ Jade.go
+
+
+
+ Jade - template engine
+ Precompile jade templates to Go code.
+
+
+
You are amazing
+
+ Jade/Pug is a terse and simple
+ templating language with
+ a focus on performance
+ and powerful features.
+
+
+
+
+```
+
+Here are additional [examples](https://github.com/Joker/jade/tree/master/example) and [test cases](https://github.com/Joker/jade/tree/master/testdata/v2).
+
+## Installation
+Install [jade compiler](https://github.com/Joker/jade/tree/master/cmd/jade)
+```console
+go install github.com/Joker/jade/cmd/jade@latest
+```
+or github.com/Joker/jade package
+```console
+go get -u github.com/Joker/jade
+```
+
+## Example usage
+
+### jade compiler
+```console
+jade -writer -pkg=main hello.jade
+```
+
+jade command[^1] precompiles _hello.jade_ to _hello.jade.go_
+
+`hello.jade`
+```
+:go:func(arg) word string
+doctype 5
+html
+ body
+ p Hello #{word}!
+```
+
+`hello.jade.go`
+```go
+// Code generated by "jade.go"; DO NOT EDIT.
+package main
+
+import "io"
+
+const (
+ hello__0 = `Hello `
+ hello__1 = `!
`
+)
+func Jade_hello(word string, wr io.Writer) {
+ buffer := &WriterAsBuffer{wr}
+ buffer.WriteString(hello__0)
+ WriteEscString(word, buffer)
+ buffer.WriteString(hello__1)
+}
+```
+
+`main.go`
+```go
+package main
+//go:generate jade -pkg=main -writer hello.jade
+
+import "net/http"
+
+func main() {
+ http.HandleFunc("/", func(wr http.ResponseWriter, req *http.Request) {
+ Jade_hello("jade", wr)
+ })
+ http.ListenAndServe(":8080", nil)
+}
+```
+
+output at localhost:8080
+```html
+Hello jade!
+```
+
+### github.com/Joker/jade package
+generate [`html/template`](https://pkg.go.dev/html/template#hdr-Introduction) at runtime
+(This case is slightly slower and doesn't support[^2] all features of Jade.go)
+
+```go
+package main
+
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+
+ "github.com/Joker/hpp" // Prettify HTML
+ "github.com/Joker/jade"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ jadeTpl, _ := jade.Parse("jade", []byte("doctype 5\n html: body: p Hello #{.Word} !"))
+ goTpl, _ := template.New("html").Parse(jadeTpl)
+
+ fmt.Printf("output:%s\n\n", hpp.PrPrint(jadeTpl))
+ goTpl.Execute(w, struct{ Word string }{"jade"})
+}
+
+func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe(":8080", nil)
+}
+```
+
+console output
+```html
+
+
+
+ Hello {{.Word}} !
+
+
+```
+
+output at localhost:8080
+```html
+Hello jade !
+```
+
+## Performance
+The data of chart comes from [SlinSo/goTemplateBenchmark](https://github.com/SlinSo/goTemplateBenchmark).
+![chart](https://user-images.githubusercontent.com/11617/141963788-3bf16698-c41e-4dc7-9f11-80d9473009ad.png)
+
+## Custom filter :go
+This filter is used as helper for command line tool
+(to set imports, function name and parameters).
+Filter may be placed at any nesting level.
+When Jade used as library :go filter is not needed.
+
+### Nested filter :func
+```
+:go:func
+ CustomNameForTemplateFunc(any []int, input string, args map[string]int)
+
+:go:func(name)
+ OnlyCustomNameForTemplateFunc
+
+:go:func(args)
+ (only string, input float32, args uint)
+```
+
+### Nested filter :import
+```
+:go:import
+ "github.com/Joker/jade"
+ github.com/Joker/hpp
+```
+
+#### note
+[^1]:
+ `Usage: ./jade [OPTION]... [FILE]...`
+ ```
+ -basedir string
+ base directory for templates (default "./")
+ -d string
+ directory for generated .go files (default "./")
+ -fmt
+ HTML pretty print output for generated functions
+ -inline
+ inline HTML in generated functions
+ -pkg string
+ package name for generated files (default "jade")
+ -stdbuf
+ use bytes.Buffer [default bytebufferpool.ByteBuffer]
+ -stdlib
+ use stdlib functions
+ -writer
+ use io.Writer for output
+ ```
+[^2]:
+ Runtime `html/template` generation doesn't support the following features:
+ `=>` means it generate the folowing template
+ ```
+ for => "{{/* %s, %s */}}{{ range %s }}"
+ for if => "{{ if gt len %s 0 }}{{/* %s, %s */}}{{ range %s }}"
+
+ multiline code => "{{/* %s */}}"
+ inheritance block => "{{/* block */}}"
+
+ case statement => "{{/* switch %s */}}"
+ when => "{{/* case %s: */}}"
+ default => "{{/* default: */}}"
+ ```
+ You can change this behaviour in [`config.go`](https://github.com/Joker/jade/blob/master/config.go#L24) file.
+ Partly this problem can be solved by [custom](https://pkg.go.dev/text/template#example-Template-Func) functions.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/config.go
new file mode 100644
index 000000000000..5e63083ae3ee
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/config.go
@@ -0,0 +1,372 @@
+package jade
+
+import "io/ioutil"
+
+//go:generate stringer -type=itemType,NodeType -trimprefix=item -output=config_string.go
+
+var TabSize = 4
+var ReadFunc = ioutil.ReadFile
+
+var (
+ golang_mode = false
+ tag__bgn = "<%s%s>"
+ tag__end = "%s>"
+ tag__void = "<%s%s/>"
+ tag__arg_esc = ` %s="{{ print %s }}"`
+ tag__arg_une = ` %s="{{ print %s }}"`
+ tag__arg_str = ` %s="%s"`
+ tag__arg_add = `%s " " %s`
+ tag__arg_bgn = ""
+ tag__arg_end = ""
+
+ cond__if = "{{ if %s }}"
+ cond__unless = "{{ if not %s }}"
+ cond__case = "{{/* switch %s */}}"
+ cond__while = "{{ range %s }}"
+ cond__for = "{{/* %s, %s */}}{{ range %s }}"
+ cond__end = "{{ end }}"
+
+ cond__for_if = "{{ if gt len %s 0 }}{{/* %s, %s */}}{{ range %s }}"
+ code__for_else = "{{ end }}{{ else }}"
+
+ code__longcode = "{{/* %s */}}"
+ code__buffered = "{{ %s }}"
+ code__unescaped = "{{ %s }}"
+ code__else = "{{ else }}"
+ code__else_if = "{{ else if %s }}"
+ code__case_when = "{{/* case %s: */}}"
+ code__case_def = "{{/* default: */}}"
+ code__mix_block = "{{/* block */}}"
+
+ text__str = "%s"
+ text__comment = ""
+
+ mixin__bgn = "\n%s"
+ mixin__end = ""
+ mixin__var_bgn = ""
+ mixin__var = "{{ $%s := %s }}"
+ mixin__var_rest = "{{ $%s := %#v }}"
+ mixin__var_end = "\n"
+ mixin__var_block_bgn = ""
+ mixin__var_block = ""
+ mixin__var_block_end = ""
+)
+
+type ReplaseTokens struct {
+ GolangMode bool
+ TagBgn string
+ TagEnd string
+ TagVoid string
+ TagArgEsc string
+ TagArgUne string
+ TagArgStr string
+ TagArgAdd string
+ TagArgBgn string
+ TagArgEnd string
+
+ CondIf string
+ CondUnless string
+ CondCase string
+ CondWhile string
+ CondFor string
+ CondEnd string
+ CondForIf string
+
+ CodeForElse string
+ CodeLongcode string
+ CodeBuffered string
+ CodeUnescaped string
+ CodeElse string
+ CodeElseIf string
+ CodeCaseWhen string
+ CodeCaseDef string
+ CodeMixBlock string
+
+ TextStr string
+ TextComment string
+
+ MixinBgn string
+ MixinEnd string
+ MixinVarBgn string
+ MixinVar string
+ MixinVarRest string
+ MixinVarEnd string
+ MixinVarBlockBgn string
+ MixinVarBlock string
+ MixinVarBlockEnd string
+}
+
+func Config(c ReplaseTokens) {
+ golang_mode = c.GolangMode
+ if c.TagBgn != "" {
+ tag__bgn = c.TagBgn
+ }
+ if c.TagEnd != "" {
+ tag__end = c.TagEnd
+ }
+ if c.TagVoid != "" {
+ tag__void = c.TagVoid
+ }
+ if c.TagArgEsc != "" {
+ tag__arg_esc = c.TagArgEsc
+ }
+ if c.TagArgUne != "" {
+ tag__arg_une = c.TagArgUne
+ }
+ if c.TagArgStr != "" {
+ tag__arg_str = c.TagArgStr
+ }
+ if c.TagArgAdd != "" {
+ tag__arg_add = c.TagArgAdd
+ }
+ if c.TagArgBgn != "" {
+ tag__arg_bgn = c.TagArgBgn
+ }
+ if c.TagArgEnd != "" {
+ tag__arg_end = c.TagArgEnd
+ }
+ if c.CondIf != "" {
+ cond__if = c.CondIf
+ }
+ if c.CondUnless != "" {
+ cond__unless = c.CondUnless
+ }
+ if c.CondCase != "" {
+ cond__case = c.CondCase
+ }
+ if c.CondWhile != "" {
+ cond__while = c.CondWhile
+ }
+ if c.CondFor != "" {
+ cond__for = c.CondFor
+ }
+ if c.CondEnd != "" {
+ cond__end = c.CondEnd
+ }
+ if c.CondForIf != "" {
+ cond__for_if = c.CondForIf
+ }
+ if c.CodeForElse != "" {
+ code__for_else = c.CodeForElse
+ }
+ if c.CodeLongcode != "" {
+ code__longcode = c.CodeLongcode
+ }
+ if c.CodeBuffered != "" {
+ code__buffered = c.CodeBuffered
+ }
+ if c.CodeUnescaped != "" {
+ code__unescaped = c.CodeUnescaped
+ }
+ if c.CodeElse != "" {
+ code__else = c.CodeElse
+ }
+ if c.CodeElseIf != "" {
+ code__else_if = c.CodeElseIf
+ }
+ if c.CodeCaseWhen != "" {
+ code__case_when = c.CodeCaseWhen
+ }
+ if c.CodeCaseDef != "" {
+ code__case_def = c.CodeCaseDef
+ }
+ if c.CodeMixBlock != "" {
+ code__mix_block = c.CodeMixBlock
+ }
+ if c.TextStr != "" {
+ text__str = c.TextStr
+ }
+ if c.TextComment != "" {
+ text__comment = c.TextComment
+ }
+ if c.MixinBgn != "" {
+ mixin__bgn = c.MixinBgn
+ }
+ if c.MixinEnd != "" {
+ mixin__end = c.MixinEnd
+ }
+ if c.MixinVarBgn != "" {
+ mixin__var_bgn = c.MixinVarBgn
+ }
+ if c.MixinVar != "" {
+ mixin__var = c.MixinVar
+ }
+ if c.MixinVarRest != "" {
+ mixin__var_rest = c.MixinVarRest
+ }
+ if c.MixinVarEnd != "" {
+ mixin__var_end = c.MixinVarEnd
+ }
+ if c.MixinVarBlockBgn != "" {
+ mixin__var_block_bgn = c.MixinVarBlockBgn
+ }
+ if c.MixinVarBlock != "" {
+ mixin__var_block = c.MixinVarBlock
+ }
+ if c.MixinVarBlockEnd != "" {
+ mixin__var_block_end = c.MixinVarBlockEnd
+ }
+}
+
+//
+
+type goFilter struct {
+ Name, Args, Import string
+}
+
+var goFlt goFilter
+
+// global variable access (goFlt)
+func UseGoFilter() *goFilter { return &goFlt }
+
+//
+
+type itemType int8
+
+const (
+ itemError itemType = iota // error occurred; value is text of error
+ itemEOF
+
+ itemEndL
+ itemIdent
+ itemEmptyLine // empty line
+
+ itemText // plain text
+
+ itemComment // html comment
+ itemHTMLTag // html
+ itemDoctype // Doctype tag
+
+ itemDiv // html div for . or #
+ itemTag // html tag
+ itemTagInline // inline tags
+ itemTagEnd // for
+ itemTagVoid // self-closing tags
+ itemTagVoidInline // inline + self-closing tags
+
+ itemID // id attribute
+ itemClass // class attribute
+
+ itemAttrStart
+ itemAttrEnd
+ itemAttr
+ itemAttrSpace
+ itemAttrComma
+ itemAttrEqual
+ itemAttrEqualUn
+
+ itemFilter
+ itemFilterSubf
+ itemFilterArgs
+ itemFilterText
+
+ // itemKeyword // used only to delimit the keywords
+
+ itemInclude
+ itemExtends
+ itemBlock
+ itemBlockAppend
+ itemBlockPrepend
+ itemMixin
+ itemMixinCall
+ itemMixinBlock
+
+ itemCode
+ itemCodeBuffered
+ itemCodeUnescaped
+
+ itemIf
+ itemElse
+ itemElseIf
+ itemUnless
+
+ itemEach
+ itemWhile
+ itemFor
+ itemForIfNotContain
+ itemForElse
+
+ itemCase
+ itemCaseWhen
+ itemCaseDefault
+)
+
+var key = map[string]itemType{
+ "include": itemInclude,
+ "extends": itemExtends,
+ "block": itemBlock,
+ "append": itemBlockAppend,
+ "prepend": itemBlockPrepend,
+ "mixin": itemMixin,
+
+ "if": itemIf,
+ "else": itemElse,
+ "unless": itemUnless,
+ "for": itemFor,
+ "each": itemEach,
+ "while": itemWhile,
+ "case": itemCase,
+ "when": itemCaseWhen,
+ "default": itemCaseDefault,
+
+ "doctype": itemDoctype,
+
+ "a": itemTagInline,
+ "abbr": itemTagInline,
+ "acronym": itemTagInline,
+ "b": itemTagInline,
+ "code": itemTagInline,
+ "em": itemTagInline,
+ "font": itemTagInline,
+ "i": itemTagInline,
+ "ins": itemTagInline,
+ "kbd": itemTagInline,
+ "map": itemTagInline,
+ "samp": itemTagInline,
+ "small": itemTagInline,
+ "span": itemTagInline,
+ "strong": itemTagInline,
+ "sub": itemTagInline,
+ "sup": itemTagInline,
+
+ "area": itemTagVoid,
+ "base": itemTagVoid,
+ "col": itemTagVoid,
+ "command": itemTagVoid,
+ "embed": itemTagVoid,
+ "hr": itemTagVoid,
+ "input": itemTagVoid,
+ "keygen": itemTagVoid,
+ "link": itemTagVoid,
+ "meta": itemTagVoid,
+ "param": itemTagVoid,
+ "source": itemTagVoid,
+ "track": itemTagVoid,
+ "wbr": itemTagVoid,
+
+ "br": itemTagVoidInline,
+ "img": itemTagVoidInline,
+}
+
+//
+
+// nodeType identifies the type of a parse tree node.
+type nodeType int8
+
+// Type returns itself and provides an easy default implementation
+// for embedding in a Node. Embedded in all non-trivial Nodes.
+func (t nodeType) Type() nodeType {
+ return t
+}
+
+const (
+ nodeText nodeType = iota
+ nodeList
+ nodeTag
+ nodeCode
+ nodeCond
+ nodeString
+ nodeDoctype
+ nodeMixin
+ nodeBlock
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/config_string.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/config_string.go
new file mode 100644
index 000000000000..04b1e4e3bc26
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/config_string.go
@@ -0,0 +1,27 @@
+// Code generated by "stringer -type=itemType,NodeType -trimprefix=item -output=config_string.go"; DO NOT EDIT.
+
+package jade
+
+import "strconv"
+
+const _itemType_name = "ErrorEOFEndLIdentEmptyLineTextCommentHTMLTagDoctypeDivTagTagInlineTagEndTagVoidTagVoidInlineIDClassAttrStartAttrEndAttrAttrSpaceAttrCommaAttrEqualAttrEqualUnFilterFilterSubfFilterArgsFilterTextIncludeExtendsBlockBlockAppendBlockPrependMixinMixinCallMixinBlockCodeCodeBufferedCodeUnescapedIfElseElseIfUnlessEachWhileForForIfNotContainForElseCaseCaseWhenCaseDefault"
+
+var _itemType_index = [...]uint16{0, 5, 8, 12, 17, 26, 30, 37, 44, 51, 54, 57, 66, 72, 79, 92, 94, 99, 108, 115, 119, 128, 137, 146, 157, 163, 173, 183, 193, 200, 207, 212, 223, 235, 240, 249, 259, 263, 275, 288, 290, 294, 300, 306, 310, 315, 318, 333, 340, 344, 352, 363}
+
+func (i itemType) String() string {
+ if i < 0 || i >= itemType(len(_itemType_index)-1) {
+ return "itemType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _itemType_name[_itemType_index[i]:_itemType_index[i+1]]
+}
+
+const _NodeType_name = "nodeTextNodeListNodeTagNodeCodeNodeCondNodeStringNodeDoctypeNodeMixinNodeBlock"
+
+var _NodeType_index = [...]uint8{0, 8, 16, 23, 31, 39, 49, 60, 69, 78}
+
+func (i nodeType) String() string {
+ if i < 0 || i >= nodeType(len(_NodeType_index)-1) {
+ return "NodeType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _NodeType_name[_NodeType_index[i]:_NodeType_index[i+1]]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_lex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_lex.go
new file mode 100644
index 000000000000..f7ad342911ac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_lex.go
@@ -0,0 +1,679 @@
+package jade
+
+import (
+ "strings"
+)
+
+func lexIndents(l *lexer) stateFn {
+ d := l.indents()
+ if d == -1 {
+ l.depth = 0
+ l.emit(itemEmptyLine)
+ } else {
+ l.depth = d
+ l.emit(itemIdent)
+ }
+ return lexTags
+}
+func (l *lexer) indents() (depth int) {
+ for {
+ switch l.next() {
+ case ' ':
+ depth += 1
+ case '\t':
+ depth += TabSize
+ case '\r':
+ // skip
+ case '\n':
+ return -1
+ default:
+ l.backup()
+ return
+ }
+ }
+}
+
+func lexEndLine(l *lexer) stateFn {
+ switch r := l.next(); {
+ case r == '\r':
+ if l.next() == '\n' {
+ l.emit(itemEndL)
+ return lexIndents
+ }
+ return l.errorf("lexTags: standalone '\\r' ")
+ case r == '\n':
+ l.emit(itemEndL)
+ return lexIndents
+ case r == eof:
+ l.depth = 0
+ l.emit(itemEOF)
+ return nil
+ default:
+ return l.errorf("lexEndLine: unexpected token %#U `%s`", r, string(r))
+ }
+}
+
+// lexTags scans tags.
+func lexTags(l *lexer) stateFn {
+ switch r := l.next(); {
+
+ case isEndOfLine(r), r == eof:
+ l.backup()
+ return lexEndLine
+ case r == ' ' || r == '\t':
+ l.backup()
+ return lexIndents
+ //
+ //
+ case r == '.':
+ n := l.skipSpaces()
+ if n == 0 {
+ l.emit(itemDiv)
+ return lexClass
+ }
+ if n == -1 {
+ l.ignore()
+ return lexLongText
+ }
+ return l.errorf("lexTags: class name cannot start with a space.")
+ case r == '#':
+ l.emit(itemDiv)
+ return lexID
+ case r == ':':
+ l.ignore()
+ if l.emitWordByType(itemFilter) {
+ r = l.next()
+ if r == ':' {
+ l.ignore()
+ l.emitWordByType(itemFilterSubf)
+ r = l.next()
+ }
+ if r == '(' {
+ l.ignore()
+ l.toStopRune(')', true)
+ l.emit(itemFilterArgs)
+ l.next()
+ l.ignore()
+ } else {
+ l.backup()
+ }
+ return lexFilter
+ }
+ return l.errorf("lexTags: expect filter name")
+ case r == '|':
+ r = l.next()
+ if r != ' ' {
+ l.backup()
+ }
+ l.ignore()
+ return lexText
+ case r == '<':
+ l.emitLineByType(itemHTMLTag)
+ return lexEndLine
+ case r == '+':
+ l.skipSpaces()
+ l.ignore()
+ if l.emitWordByType(itemMixinCall) {
+ return lexAfterTag
+ }
+ return l.errorf("lexTags: expect mixin name")
+ case r == '/':
+ return lexComment
+ case r == '-':
+ l.ignore()
+ return lexCode
+ case r == '=':
+ l.skipSpaces()
+ l.ignore()
+ l.emitLineByType(itemCodeBuffered)
+ return lexEndLine
+ case r == '!':
+ np := l.next()
+ if np == '=' {
+ l.skipSpaces()
+ l.ignore()
+ l.emitLineByType(itemCodeUnescaped)
+ return lexEndLine
+ }
+ if np == '!' && l.next() == '!' && l.depth == 0 {
+ l.ignore()
+ if l.skipSpaces() != -1 {
+ l.emitLineByType(itemDoctype)
+ } else {
+ l.emit(itemDoctype)
+ }
+ return lexEndLine
+ }
+ return l.errorf("expect '=' after '!'")
+ case isAlphaNumeric(r):
+ l.backup()
+ return lexTagName
+ default:
+ return l.errorf("lexTags: unexpected token %#U `%s`", r, string(r))
+ }
+}
+
+//
+//
+
+func lexID(l *lexer) stateFn {
+ if l.emitWordByType(itemID) {
+ return lexAfterTag
+ }
+ return l.errorf("lexID: expect id name")
+}
+func lexClass(l *lexer) stateFn {
+ if l.emitWordByType(itemClass) {
+ return lexAfterTag
+ }
+ return l.errorf("lexClass: expect class name")
+}
+
+func lexFilter(l *lexer) stateFn {
+ l.multiline()
+ l.emit(itemFilterText)
+ return lexIndents
+}
+
+func lexCode(l *lexer) stateFn {
+ if l.skipSpaces() == -1 {
+ l.multiline()
+ l.emit(itemCode)
+ return lexIndents
+ } else {
+ l.ignore()
+ l.emitLineByType(itemCode)
+ return lexEndLine
+ }
+}
+func lexComment(l *lexer) stateFn {
+ sp := l.next()
+ tp := l.peek()
+ if sp == '/' {
+ if tp == '-' {
+ l.multiline()
+ l.ignore()
+ return lexIndents
+ } else {
+ l.ignore()
+ l.multiline()
+ l.emit(itemComment)
+ return lexIndents
+ }
+ }
+ return l.errorf("lexComment: unexpected token '%#U' expect '/'", sp)
+}
+
+//
+//
+
+func lexText(l *lexer) stateFn {
+ if l.skipSpaces() == -1 {
+ l.ignore()
+ return lexEndLine
+ }
+ return text(l)
+}
+func lexLongText(l *lexer) stateFn {
+ l.longtext = true
+ return text(l)
+}
+func text(l *lexer) stateFn {
+ for {
+ switch r := l.next(); {
+ case r == '\\':
+ l.next()
+ continue
+ case r == '#':
+ sp := l.peek()
+ if sp == '[' {
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.next()
+ l.next()
+ l.skipSpaces()
+ l.interpolation += 1
+ l.depth += 1
+ // l.emit(itemInterpolation)
+ l.ignore()
+ return lexTags
+ }
+ if sp == '{' {
+ l.interpol(itemCodeBuffered)
+ }
+ // case r == '$':
+ // sp := l.peek()
+ // if sp == '{' {
+ // l.interpol(itemCodeBuffered)
+ // }
+ case r == '!':
+ sp := l.peek()
+ if sp == '{' {
+ l.interpol(itemCodeUnescaped)
+ }
+ case r == ']':
+ if l.interpolation > 0 {
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.next()
+ // l.emit(itemInterpolationEnd)
+ l.ignore()
+ l.interpolation -= 1
+ l.depth -= 1
+ }
+ case r == eof:
+ l.backup()
+ l.emit(itemText)
+ return lexEndLine
+ case r == '\n':
+ if l.longtext {
+ var (
+ indent int
+ pos pos
+ )
+ l.backup()
+ pos = l.pos
+ l.next()
+ indent = l.indents()
+ if indent != -1 {
+ if indent < l.depth {
+ l.pos = pos
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.longtext = false
+ return lexIndents
+ }
+ } else {
+ l.backup()
+ }
+ } else {
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ return lexIndents
+ }
+ }
+ }
+}
+func (l *lexer) interpol(item itemType) {
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.next()
+ l.next()
+ l.skipSpaces()
+ l.ignore()
+Loop:
+ for {
+ switch r := l.next(); {
+ case r == '`':
+ l.toStopRune('`', false)
+ case r == '"':
+ l.toStopRune('"', false)
+ case r == '\'':
+ l.toStopRune('\'', false)
+ case r == '\n', r == eof:
+ l.backup()
+ l.errorf("interpolation error: expect '}'")
+ return
+ case r == '}':
+ break Loop
+ }
+ }
+ l.backup()
+ l.emit(item)
+ l.next()
+ l.ignore()
+}
+
+func lexTagName(l *lexer) stateFn {
+ for {
+ switch r := l.next(); {
+ case isAlphaNumeric(r):
+ // absorb.
+ default:
+ l.backup()
+ word := l.input[l.start:l.pos]
+ if w, ok := key[word]; ok {
+ switch w {
+ case itemElse:
+ l.emit(w)
+ l.skipSpaces()
+ l.ignore()
+ return lexTags
+ case itemDoctype, itemExtends:
+ if l.depth == 0 {
+ ss := l.skipSpaces()
+ l.ignore()
+ if ss != -1 {
+ l.emitLineByType(w)
+ } else if w == itemDoctype {
+ l.emit(w)
+ } else {
+ return l.errorf("lexTagName: itemExtends need path ")
+ }
+ return lexEndLine
+ } else {
+ l.emit(itemTag)
+ }
+ case itemBlock:
+ sp := l.skipSpaces()
+ l.ignore()
+ if sp == -1 {
+ l.emit(itemMixinBlock)
+ } else if strings.HasPrefix(l.input[l.pos:], "prepend ") {
+ l.toStopRune(' ', true)
+ l.skipSpaces()
+ l.ignore()
+ l.emitLineByType(itemBlockPrepend)
+ } else if strings.HasPrefix(l.input[l.pos:], "append ") {
+ l.toStopRune(' ', true)
+ l.skipSpaces()
+ l.ignore()
+ l.emitLineByType(itemBlockAppend)
+ } else {
+ l.emitLineByType(itemBlock)
+ }
+ return lexEndLine
+ case itemBlockAppend, itemBlockPrepend,
+ itemIf, itemUnless, itemCase,
+ itemEach, itemWhile, itemFor,
+ itemInclude:
+
+ l.skipSpaces()
+ l.ignore()
+ l.emitLineByType(w)
+ return lexEndLine
+ case itemMixin:
+ l.skipSpaces()
+ l.ignore()
+ l.emitWordByType(w)
+ return lexAfterTag
+ case itemCaseWhen:
+ l.skipSpaces()
+ l.ignore()
+ l.toStopRune(':', true)
+ l.emit(w)
+ return lexAfterTag
+ default:
+ l.emit(w)
+ }
+ } else {
+ l.emit(itemTag)
+ }
+ return lexAfterTag
+ }
+ }
+}
+
+func lexAfterTag(l *lexer) stateFn {
+ switch r := l.next(); {
+ case r == '(':
+ l.emit(itemAttrStart)
+ return lexAttr
+ case r == '/':
+ l.emit(itemTagEnd)
+ return lexAfterTag
+ case r == ':':
+ l.skipSpaces()
+ l.ignore()
+ l.depth += 1
+ return lexTags
+ case r == ' ' || r == '\t':
+ l.ignore()
+ l.depth += 1
+ return lexText
+ case r == ']':
+ if l.interpolation > 0 {
+ l.ignore()
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.interpolation -= 1
+ l.depth -= 1
+ if l.longtext {
+ return lexLongText
+ } else {
+ return lexText
+ }
+ }
+ return l.errorf("lexAfterTag: %#U", r)
+ case r == '=':
+ l.skipSpaces()
+ l.ignore()
+ l.depth += 1
+ l.emitLineByType(itemCodeBuffered)
+ return lexEndLine
+ case r == '!':
+ if l.next() == '=' {
+ l.skipSpaces()
+ l.ignore()
+ l.depth += 1
+ l.emitLineByType(itemCodeUnescaped)
+ return lexEndLine
+ }
+ return l.errorf("expect '=' after '!'")
+ case r == '#':
+ l.ignore()
+ return lexID
+ case r == '&':
+ l.toStopRune(')', false)
+ l.ignore() // TODO: now ignore div(data-bar="foo")&attributes({'data-foo': 'baz'})
+ return lexAfterTag
+ case r == '.':
+ switch l.skipSpaces() {
+ case 0:
+ l.ignore()
+ return lexClass
+ case -1:
+ if sp := l.next(); sp != eof {
+ l.ignore()
+ l.depth += 1
+ return lexLongText
+ }
+ return lexEndLine
+ default:
+ l.ignore()
+ l.depth += 1
+ return lexText
+ }
+ case isEndOfLine(r), r == eof:
+ l.backup()
+ return lexEndLine
+ default:
+ return l.errorf("lexAfterTag: %#U", r)
+ }
+}
+
+//
+//
+
+func lexAttr(l *lexer) stateFn {
+ b1, b2, b3 := 0, 0, 0
+ for {
+ switch r := l.next(); {
+ case r == '"' || r == '\'':
+ l.toStopRune(r, false)
+ case r == '`':
+ for {
+ r = l.next()
+ if r == '`' {
+ break
+ }
+ }
+ case r == '(':
+ // b1 += 1
+ l.toStopRune(')', false)
+ case r == ')':
+ // b1 -= 1
+ // if b1 == -1 {
+ if b2 != 0 || b3 != 0 {
+ return l.errorf("lexAttrName: mismatched bracket")
+ }
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemAttr)
+ }
+ l.next()
+ l.emit(itemAttrEnd)
+ return lexAfterTag
+ // }
+ case r == '[':
+ b2 += 1
+ case r == ']':
+ b2 -= 1
+ if b2 == -1 {
+ return l.errorf("lexAttrName: mismatched bracket '['")
+ }
+ case r == '{':
+ b3 += 1
+ case r == '}':
+ b3 -= 1
+ if b3 == -1 {
+ return l.errorf("lexAttrName: mismatched bracket '{'")
+ }
+ case r == ' ' || r == '\t':
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemAttr)
+ }
+ l.skipSpaces()
+ l.emit(itemAttrSpace)
+ case r == '=':
+ if l.peek() == '=' {
+ l.toStopRune(' ', true)
+ l.emit(itemAttr)
+ continue
+ }
+ l.backup()
+ l.emit(itemAttr)
+ l.next()
+ l.emit(itemAttrEqual)
+ case r == '!':
+ if l.peek() == '=' {
+ l.backup()
+ l.emit(itemAttr)
+ l.next()
+ l.next()
+ l.emit(itemAttrEqualUn)
+ }
+ case r == ',' || r == '\n':
+ if b1 == 0 && b2 == 0 && b3 == 0 {
+ l.backup()
+ if l.pos > l.start {
+ l.emit(itemAttr)
+ }
+ l.next()
+ l.emit(itemAttrComma)
+ }
+ case r == eof:
+ return l.errorf("lexAttr: expected ')'")
+ }
+ }
+}
+
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+
+func (l *lexer) emitWordByType(item itemType) bool {
+ for {
+ if !isAlphaNumeric(l.next()) {
+ l.backup()
+ break
+ }
+ }
+ if l.pos > l.start {
+ l.emit(item)
+ return true
+ }
+ return false
+}
+
+func (l *lexer) emitLineByType(item itemType) bool {
+ var r rune
+ for {
+ r = l.next()
+ if r == '\n' || r == '\r' || r == eof {
+ l.backup()
+ if l.pos > l.start {
+ l.emit(item)
+ return true
+ }
+ return false
+ }
+ }
+}
+
+//
+
+func (l *lexer) skipSpaces() (out int) {
+ for {
+ switch l.next() {
+ case ' ', '\t':
+ out += 1
+ case '\n', eof:
+ l.backup()
+ return -1
+ default:
+ l.backup()
+ return
+ }
+ }
+}
+
+func (l *lexer) toStopRune(stopRune rune, backup bool) {
+ for {
+ switch r := l.next(); {
+ case r == stopRune:
+ if backup {
+ l.backup()
+ }
+ return
+ case r == eof || r == '\r' || r == '\n':
+ l.backup()
+ return
+ }
+ }
+}
+
+func (l *lexer) multiline() {
+ var (
+ indent int
+ pos pos
+ )
+ for {
+ switch r := l.next(); {
+ case r == '\n':
+ l.backup()
+ pos = l.pos
+ l.next()
+ indent = l.indents()
+ if indent != -1 {
+ if indent <= l.depth {
+ l.pos = pos
+ return
+ }
+ } else {
+ l.backup()
+ }
+ case r == eof:
+ l.backup()
+ return
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_node.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_node.go
new file mode 100644
index 000000000000..4802f8125288
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_node.go
@@ -0,0 +1,711 @@
+package jade
+
+import (
+ "bytes"
+ "fmt"
+ "go/parser"
+ "html"
+ "io"
+ "log"
+ "regexp"
+ "strings"
+)
+
+type tagNode struct {
+ nodeType
+ pos
+ tr *tree
+ Nodes []node
+ AttrName []string
+ AttrCode []string
+ AttrUesc []bool
+ TagName string
+ tagType itemType
+}
+
+func (t *tree) newTag(pos pos, name string, tagType itemType) *tagNode {
+ return &tagNode{tr: t, nodeType: nodeTag, pos: pos, TagName: name, tagType: tagType}
+}
+
+func (l *tagNode) append(n node) {
+ l.Nodes = append(l.Nodes, n)
+}
+
+func (l *tagNode) tree() *tree {
+ return l.tr
+}
+
+func (l *tagNode) attr(a, b string, c bool) {
+ for k, v := range l.AttrName {
+ // add to existing attribute
+ if v == a {
+ l.AttrCode[k] = fmt.Sprintf(tag__arg_add, l.AttrCode[k], b)
+ return
+ }
+ }
+
+ l.AttrName = append(l.AttrName, a)
+ l.AttrCode = append(l.AttrCode, b)
+ l.AttrUesc = append(l.AttrUesc, c)
+}
+
+func (l *tagNode) ifAttrArgBollean() {
+ for k, v := range l.AttrCode {
+ if v == "true" {
+ l.AttrCode[k] = `"` + l.AttrName[k] + `"`
+ } else if v == "false" {
+ l.AttrName = append(l.AttrName[:k], l.AttrName[k+1:]...)
+ l.AttrCode = append(l.AttrCode[:k], l.AttrCode[k+1:]...)
+ l.AttrUesc = append(l.AttrUesc[:k], l.AttrUesc[k+1:]...)
+ }
+ }
+}
+
+// `"aaa'a" + 'b\"bb"b' + 'c'` >>> `"aaa'a" + "b\"bb\"b" + "c"`
+func filterString(in string) string {
+ var (
+ rs = []rune(in)
+ flag, prev rune
+ psn int
+ )
+ for k, r := range rs {
+ // fmt.Println(string(r), " ", r)
+ switch r {
+ case '"':
+ if flag == '\'' && prev != '\\' {
+ rs[k] = 0 // bookmark for replace
+ }
+ if flag == 0 {
+ flag = '"'
+ psn = k
+ } else if r == flag && prev != '\\' {
+ flag = 0
+ }
+ case '\'':
+ if flag == 0 {
+ flag = '\''
+ psn = k
+ } else if r == flag && prev != '\\' {
+ // if k-(psn+1) != 1 {
+ rs[psn] = '"'
+ rs[k] = '"'
+ // }
+ flag = 0
+ }
+ case '`':
+ if flag == 0 {
+ flag = '`'
+ psn = k
+ } else if r == flag {
+ flag = 0
+ }
+ }
+ prev = r
+ }
+ filterPlus(rs)
+ filterJsEsc(rs)
+ out := strings.Replace(string(rs), string(rune(0)), `\"`, -1)
+ out = strings.Replace(out, string(rune(1)), ``, -1)
+ out = strings.Replace(out, string([]rune{2, 2}), "`+", -1)
+ out = strings.Replace(out, string(rune(3)), "+`", -1)
+ return out
+}
+
+// "aaa" + "bbb" >>> "aaabbb"
+func filterPlus(rs []rune) {
+ var (
+ flag, prev rune
+ psn int
+ )
+ for k, r := range rs {
+ switch r {
+ case '"':
+ if flag == 0 {
+ flag = '"'
+ if psn > 0 {
+ for i := psn; i < k+1; i++ {
+ // fmt.Println(string(rs[i]), rs[i])
+ rs[i] = 1
+ }
+ }
+ } else if r == flag && prev != '\\' {
+ psn = k
+ flag = 0
+ }
+ case '`':
+ if flag == 0 {
+ flag = '`'
+ } else if r == flag {
+ flag = 0
+ }
+ case ' ', '+':
+ default:
+ psn = 0
+ }
+ prev = r
+ }
+}
+
+// `aaa ${bbb} ccc` >>> `aaa `+bbb+` ccc`
+func filterJsEsc(rs []rune) {
+ var (
+ flag, prev rune
+ code bool
+ )
+ for k, r := range rs {
+ switch r {
+ case '`':
+ if flag == 0 {
+ flag = '`'
+ } else if r == flag {
+ flag = 0
+ }
+ case '{':
+ if flag == '`' && prev == '$' {
+ rs[k-1] = 2
+ rs[k] = 2
+ code = true
+ }
+ case '}':
+ if flag == '`' && code {
+ rs[k] = 3
+ }
+ }
+ prev = r
+ }
+}
+
+func ifAttrArgString(a string, unesc bool) (string, bool) {
+ var (
+ str = []rune(a)
+ lng = len(str)
+ first = str[0]
+ last = str[lng-1]
+ )
+
+ switch first {
+ case '"', '\'':
+ if first == last {
+ for k, v := range str[1 : lng-1] {
+ if v == first && str[k] != '\\' {
+ return "", false
+ }
+ }
+ if unesc {
+ return string(str[1 : lng-1]), true
+ }
+ return html.EscapeString(string(str[1 : lng-1])), true
+ }
+ case '`':
+ if first == last {
+ if !strings.ContainsAny(string(str[1:lng-1]), "`") {
+ if unesc {
+ return string(str[1 : lng-1]), true
+ }
+ return html.EscapeString(string(str[1 : lng-1])), true
+ }
+ }
+ }
+ return "", false
+}
+
+func ternary(a string) (string, bool) {
+ var (
+ re = regexp.MustCompile(`^(.+)\?(.+):(.+)$`)
+ match = re.FindStringSubmatch(a)
+ )
+ if len(match) == 4 {
+ for _, v := range match[1:4] {
+ if _, err := parser.ParseExpr(v); err != nil {
+ return "", false
+ }
+ }
+ return "ternary(" + match[1] + ", " + match[2] + ", " + match[3] + ")", true
+ }
+ return "", false
+}
+
+func (l *tagNode) String() string {
+ var b = new(bytes.Buffer)
+ l.WriteIn(b)
+ return b.String()
+}
+func (l *tagNode) WriteIn(b io.Writer) {
+ var (
+ attr = new(bytes.Buffer)
+ )
+ l.ifAttrArgBollean()
+
+ if len(l.AttrName) > 0 {
+ fmt.Fprint(attr, tag__arg_bgn)
+ for k, name := range l.AttrName {
+ attrStr := filterString(l.AttrCode[k])
+
+ if arg, ok := ifAttrArgString(attrStr, l.AttrUesc[k]); ok {
+ fmt.Fprintf(attr, tag__arg_str, name, arg)
+
+ } else if !golang_mode {
+ fmt.Fprintf(attr, tag__arg_esc, name, attrStr)
+
+ } else if _, err := parser.ParseExpr(attrStr); err == nil {
+ if l.AttrUesc[k] {
+ fmt.Fprintf(attr, tag__arg_une, name, l.pos, attrStr)
+ } else {
+ fmt.Fprintf(attr, tag__arg_esc, name, l.pos, attrStr)
+ }
+
+ } else if arg, ok := ternary(attrStr); ok {
+ if l.AttrUesc[k] {
+ fmt.Fprintf(attr, tag__arg_une, name, l.pos, arg)
+ } else {
+ fmt.Fprintf(attr, tag__arg_esc, name, l.pos, arg)
+ }
+
+ } else {
+ log.Fatalln("Error tag attribute value ==> ", attrStr)
+ }
+ }
+ fmt.Fprint(attr, tag__arg_end)
+ }
+ switch l.tagType {
+ case itemTagVoid:
+ fmt.Fprintf(b, tag__void, l.TagName, attr)
+ case itemTagVoidInline:
+ fmt.Fprintf(b, tag__void, l.TagName, attr)
+ default:
+ fmt.Fprintf(b, tag__bgn, l.TagName, attr)
+ for _, inner := range l.Nodes {
+ inner.WriteIn(b)
+ }
+ fmt.Fprintf(b, tag__end, l.TagName)
+ }
+}
+
+func (l *tagNode) CopyTag() *tagNode {
+ if l == nil {
+ return l
+ }
+ n := l.tr.newTag(l.pos, l.TagName, l.tagType)
+ n.AttrCode = l.AttrCode
+ n.AttrName = l.AttrName
+ n.AttrUesc = l.AttrUesc
+ for _, elem := range l.Nodes {
+ n.append(elem.Copy())
+ }
+ return n
+}
+
+func (l *tagNode) Copy() node {
+ return l.CopyTag()
+}
+
+//
+//
+
+type condNode struct {
+ nodeType
+ pos
+ tr *tree
+ Nodes []node
+ cond string
+ condType itemType
+}
+
+func (t *tree) newCond(pos pos, cond string, condType itemType) *condNode {
+ return &condNode{tr: t, nodeType: nodeCond, pos: pos, cond: cond, condType: condType}
+}
+
+func (l *condNode) append(n node) {
+ l.Nodes = append(l.Nodes, n)
+}
+
+func (l *condNode) tree() *tree {
+ return l.tr
+}
+
+func (l *condNode) String() string {
+ var b = new(bytes.Buffer)
+ l.WriteIn(b)
+ return b.String()
+}
+func (l *condNode) WriteIn(b io.Writer) {
+ switch l.condType {
+ case itemIf:
+ fmt.Fprintf(b, cond__if, l.cond)
+ case itemUnless:
+ fmt.Fprintf(b, cond__unless, l.cond)
+ case itemCase:
+ fmt.Fprintf(b, cond__case, l.cond)
+ case itemWhile:
+ fmt.Fprintf(b, cond__while, l.cond)
+ case itemFor, itemEach:
+ if k, v, name, ok := l.parseForArgs(); ok {
+ fmt.Fprintf(b, cond__for, k, v, name)
+ } else {
+ fmt.Fprintf(b, "\n{{ Error malformed each: %s }}", l.cond)
+ }
+ case itemForIfNotContain:
+ if k, v, name, ok := l.parseForArgs(); ok {
+ fmt.Fprintf(b, cond__for_if, name, k, v, name)
+ } else {
+ fmt.Fprintf(b, "\n{{ Error malformed each: %s }}", l.cond)
+ }
+ default:
+ fmt.Fprintf(b, "{{ Error Cond %s }}", l.cond)
+ }
+
+ for _, n := range l.Nodes {
+ n.WriteIn(b)
+ }
+
+ fmt.Fprint(b, cond__end)
+}
+
+func (l *condNode) parseForArgs() (k, v, name string, ok bool) {
+ sp := strings.SplitN(l.cond, " in ", 2)
+ if len(sp) != 2 {
+ return
+ }
+ name = strings.Trim(sp[1], " ")
+ re := regexp.MustCompile(`^(\w+)\s*,\s*(\w+)$`)
+ kv := re.FindAllStringSubmatch(strings.Trim(sp[0], " "), -1)
+ if len(kv) == 1 && len(kv[0]) == 3 {
+ k = kv[0][2]
+ v = kv[0][1]
+ ok = true
+ return
+ }
+ r2 := regexp.MustCompile(`^\w+$`)
+ kv2 := r2.FindAllString(strings.Trim(sp[0], " "), -1)
+ if len(kv2) == 1 {
+ k = "_"
+ v = kv2[0]
+ ok = true
+ return
+ }
+ return
+}
+
+func (l *condNode) CopyCond() *condNode {
+ if l == nil {
+ return l
+ }
+ n := l.tr.newCond(l.pos, l.cond, l.condType)
+ for _, elem := range l.Nodes {
+ n.append(elem.Copy())
+ }
+ return n
+}
+
+func (l *condNode) Copy() node {
+ return l.CopyCond()
+}
+
+//
+//
+
+type codeNode struct {
+ nodeType
+ pos
+ tr *tree
+ codeType itemType
+ Code []byte // The text; may span newlines.
+}
+
+func (t *tree) newCode(pos pos, text string, codeType itemType) *codeNode {
+ return &codeNode{tr: t, nodeType: nodeCode, pos: pos, Code: []byte(text), codeType: codeType}
+}
+
+func (t *codeNode) String() string {
+ var b = new(bytes.Buffer)
+ t.WriteIn(b)
+ return b.String()
+}
+func (t *codeNode) WriteIn(b io.Writer) {
+ switch t.codeType {
+ case itemCodeBuffered:
+ if !golang_mode {
+ fmt.Fprintf(b, code__buffered, filterString(string(t.Code)))
+ return
+ }
+ if code, ok := ifAttrArgString(string(t.Code), false); ok {
+ fmt.Fprintf(b, code__buffered, t.pos, `"`+code+`"`)
+ } else {
+ fmt.Fprintf(b, code__buffered, t.pos, filterString(string(t.Code)))
+ }
+ case itemCodeUnescaped:
+ if !golang_mode {
+ fmt.Fprintf(b, code__unescaped, filterString(string(t.Code)))
+ return
+ }
+ fmt.Fprintf(b, code__unescaped, t.pos, filterString(string(t.Code)))
+ case itemCode:
+ fmt.Fprintf(b, code__longcode, filterString(string(t.Code)))
+ case itemElse:
+ fmt.Fprintf(b, code__else)
+ case itemElseIf:
+ fmt.Fprintf(b, code__else_if, filterString(string(t.Code)))
+ case itemForElse:
+ fmt.Fprintf(b, code__for_else)
+ case itemCaseWhen:
+ fmt.Fprintf(b, code__case_when, filterString(string(t.Code)))
+ case itemCaseDefault:
+ fmt.Fprintf(b, code__case_def)
+ case itemMixinBlock:
+ fmt.Fprintf(b, code__mix_block)
+ default:
+ fmt.Fprintf(b, "{{ Error Code %s }}", t.Code)
+ }
+}
+
+func (t *codeNode) tree() *tree {
+ return t.tr
+}
+
+func (t *codeNode) Copy() node {
+ return &codeNode{tr: t.tr, nodeType: nodeCode, pos: t.pos, codeType: t.codeType, Code: append([]byte{}, t.Code...)}
+}
+
+//
+//
+
+type blockNode struct {
+ nodeType
+ pos
+ tr *tree
+ blockType itemType
+ Name string
+}
+
+func (t *tree) newBlock(pos pos, name string, textType itemType) *blockNode {
+ return &blockNode{tr: t, nodeType: nodeBlock, pos: pos, Name: name, blockType: textType}
+}
+
+func (bn *blockNode) String() string {
+ var b = new(bytes.Buffer)
+ bn.WriteIn(b)
+ return b.String()
+}
+func (bn *blockNode) WriteIn(b io.Writer) {
+ var (
+ out_blk = bn.tr.block[bn.Name]
+ out_pre, ok_pre = bn.tr.block[bn.Name+"_prepend"]
+ out_app, ok_app = bn.tr.block[bn.Name+"_append"]
+ )
+ if ok_pre {
+ out_pre.WriteIn(b)
+ }
+ out_blk.WriteIn(b)
+
+ if ok_app {
+ out_app.WriteIn(b)
+ }
+}
+
+func (bn *blockNode) tree() *tree {
+ return bn.tr
+}
+
+func (bn *blockNode) Copy() node {
+ return &blockNode{tr: bn.tr, nodeType: nodeBlock, pos: bn.pos, blockType: bn.blockType, Name: bn.Name}
+}
+
+//
+//
+
+type textNode struct {
+ nodeType
+ pos
+ tr *tree
+ textType itemType
+ Text []byte // The text; may span newlines.
+}
+
+func (t *tree) newText(pos pos, text []byte, textType itemType) *textNode {
+ return &textNode{tr: t, nodeType: nodeText, pos: pos, Text: text, textType: textType}
+}
+
+func (t *textNode) String() string {
+ var b = new(bytes.Buffer)
+ t.WriteIn(b)
+ return b.String()
+}
+func (t *textNode) WriteIn(b io.Writer) {
+ switch t.textType {
+ case itemComment:
+ fmt.Fprintf(b, text__comment, t.Text)
+ default:
+ if !golang_mode {
+ fmt.Fprintf(b, text__str, t.Text)
+ } else {
+ fmt.Fprintf(b, text__str, bytes.Replace(t.Text, []byte("`"), []byte("`+\"`\"+`"), -1))
+ }
+ }
+}
+
+func (t *textNode) tree() *tree {
+ return t.tr
+}
+
+func (t *textNode) Copy() node {
+ return &textNode{tr: t.tr, nodeType: nodeText, pos: t.pos, textType: t.textType, Text: append([]byte{}, t.Text...)}
+}
+
+//
+//
+
+type mixinNode struct {
+ nodeType
+ pos
+ tr *tree
+ Nodes []node
+ AttrName []string
+ AttrCode []string
+ AttrRest []string
+ MixinName string
+ block []node
+ tagType itemType
+}
+
+func (t *tree) newMixin(pos pos) *mixinNode {
+ return &mixinNode{tr: t, nodeType: nodeMixin, pos: pos}
+}
+
+func (l *mixinNode) append(n node) {
+ l.Nodes = append(l.Nodes, n)
+}
+func (l *mixinNode) appendToBlock(n node) {
+ l.block = append(l.block, n)
+}
+
+func (l *mixinNode) attr(a, b string, c bool) {
+ l.AttrName = append(l.AttrName, a)
+ l.AttrCode = append(l.AttrCode, b)
+}
+
+func (l *mixinNode) tree() *tree {
+ return l.tr
+}
+
+func (l *mixinNode) String() string {
+ var b = new(bytes.Buffer)
+ l.WriteIn(b)
+ return b.String()
+}
+func (l *mixinNode) WriteIn(b io.Writer) {
+ var (
+ attr = new(bytes.Buffer)
+ an = len(l.AttrName)
+ rest = len(l.AttrRest)
+ )
+
+ if an > 0 {
+ fmt.Fprintf(attr, mixin__var_bgn)
+ if rest > 0 {
+ // TODO
+ // fmt.Println("-------- ", mixin__var_rest, l.AttrName[an-1], l.AttrRest)
+ fmt.Fprintf(attr, mixin__var_rest, strings.TrimLeft(l.AttrName[an-1], "."), l.AttrRest)
+ l.AttrName = l.AttrName[:an-1]
+ }
+ for k, name := range l.AttrName {
+ fmt.Fprintf(attr, mixin__var, name, filterString(l.AttrCode[k]))
+ }
+ fmt.Fprintf(attr, mixin__var_end)
+ }
+ fmt.Fprintf(b, mixin__bgn, attr)
+
+ if len(l.block) > 0 {
+ b.Write([]byte(mixin__var_block_bgn))
+ for _, n := range l.block {
+ n.WriteIn(b)
+ }
+ b.Write([]byte(mixin__var_block_end))
+ } else {
+ b.Write([]byte(mixin__var_block))
+ }
+
+ for _, n := range l.Nodes {
+ n.WriteIn(b)
+ }
+ fmt.Fprintf(b, mixin__end)
+}
+
+func (l *mixinNode) CopyMixin() *mixinNode {
+ if l == nil {
+ return l
+ }
+ n := l.tr.newMixin(l.pos)
+ for _, elem := range l.Nodes {
+ n.append(elem.Copy())
+ }
+ return n
+}
+
+func (l *mixinNode) Copy() node {
+ return l.CopyMixin()
+}
+
+//
+//
+
+type doctypeNode struct {
+ nodeType
+ pos
+ tr *tree
+ doctype string
+}
+
+func (t *tree) newDoctype(pos pos, text string) *doctypeNode {
+ doc := ""
+ txt := strings.Trim(text, " ")
+ if len(txt) > 0 {
+ sls := strings.SplitN(txt, " ", 2)
+ switch sls[0] {
+ case "5", "html":
+ doc = ``
+ case "xml":
+ doc = ``
+ case "1.1", "xhtml":
+ doc = ``
+ case "basic":
+ doc = ``
+ case "strict":
+ doc = ``
+ case "frameset":
+ doc = ``
+ case "transitional":
+ doc = ``
+ case "mobile":
+ doc = ``
+ case "4", "4strict":
+ doc = ``
+ case "4frameset":
+ doc = ``
+ case "4transitional":
+ doc = ``
+ }
+ if doc == "" {
+ doc = fmt.Sprintf("", txt)
+ } else if doc != "" && len(sls) == 2 {
+ doc = fmt.Sprintf(doc, " "+sls[1])
+ } else {
+ doc = fmt.Sprintf(doc, "")
+ }
+ } else {
+ doc = ``
+ }
+ return &doctypeNode{tr: t, nodeType: nodeDoctype, pos: pos, doctype: doc}
+}
+func (d *doctypeNode) String() string {
+ return fmt.Sprintf(text__str, d.doctype)
+}
+func (d *doctypeNode) WriteIn(b io.Writer) {
+ fmt.Fprintf(b, text__str, d.doctype)
+ // b.Write([]byte(d.doctype))
+}
+func (d *doctypeNode) tree() *tree {
+ return d.tr
+}
+func (d *doctypeNode) Copy() node {
+ return &doctypeNode{tr: d.tr, nodeType: nodeDoctype, pos: d.pos, doctype: d.doctype}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_parse.go
new file mode 100644
index 000000000000..e9a9f6e4c7ad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/jade_parse.go
@@ -0,0 +1,504 @@
+package jade
+
+import (
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func (t *tree) topParse() {
+ t.Root = t.newList(t.peek().pos)
+ var (
+ ext bool
+ token = t.nextNonSpace()
+ )
+ if token.typ == itemExtends {
+ ext = true
+ t.Root.append(t.parseSubFile(token.val))
+ token = t.nextNonSpace()
+ }
+ for {
+ switch token.typ {
+ case itemInclude:
+ t.Root.append(t.parseInclude(token))
+ case itemBlock, itemBlockPrepend, itemBlockAppend:
+ if ext {
+ t.parseBlock(token)
+ } else {
+ t.Root.append(t.parseBlock(token))
+ }
+ case itemMixin:
+ t.mixin[token.val] = t.parseMixin(token)
+ case itemEOF:
+ return
+ case itemExtends:
+ t.errorf(`Declaration of template inheritance ("extends") should be the first thing in the file. There can only be one extends statement per file.`)
+ case itemError:
+ t.errorf("%s line: %d\n", token.val, token.line)
+ default:
+ if ext {
+ t.errorf(`Only import, named blocks and mixins can appear at the top level of an extending template`)
+ }
+ t.Root.append(t.hub(token))
+ }
+ token = t.nextNonSpace()
+ }
+}
+
+func (t *tree) hub(token item) (n node) {
+ for {
+ switch token.typ {
+ case itemDiv:
+ token.val = "div"
+ fallthrough
+ case itemTag, itemTagInline, itemTagVoid, itemTagVoidInline:
+ return t.parseTag(token)
+ case itemText, itemComment, itemHTMLTag:
+ return t.newText(token.pos, []byte(token.val), token.typ)
+ case itemCode, itemCodeBuffered, itemCodeUnescaped, itemMixinBlock:
+ return t.newCode(token.pos, token.val, token.typ)
+ case itemIf, itemUnless:
+ return t.parseIf(token)
+ case itemFor, itemEach, itemWhile:
+ return t.parseFor(token)
+ case itemCase:
+ return t.parseCase(token)
+ case itemBlock, itemBlockPrepend, itemBlockAppend:
+ return t.parseBlock(token)
+ case itemMixinCall:
+ return t.parseMixinUse(token)
+ case itemInclude:
+ return t.parseInclude(token)
+ case itemDoctype:
+ return t.newDoctype(token.pos, token.val)
+ case itemFilter:
+ return t.parseFilter(token)
+ case itemError:
+ t.errorf("Error lex: %s line: %d\n", token.val, token.line)
+ default:
+ t.errorf(`Error hub(): unexpected token "%s" type "%s"`, token.val, token.typ)
+ }
+ }
+}
+
+func (t *tree) parseFilter(tk item) node {
+ var subf, args, text string
+Loop:
+ for {
+ switch token := t.nextNonSpace(); token.typ {
+ case itemFilterSubf:
+ subf = token.val
+ case itemFilterArgs:
+ args = strings.Trim(token.val, " \t\r\n")
+ case itemFilterText:
+ text = strings.Trim(token.val, " \t\r\n")
+ default:
+ break Loop
+ }
+ }
+ t.backup()
+ switch tk.val {
+ case "go":
+ filterGo(subf, args, text)
+ case "markdown", "markdown-it":
+ // TODO: filterMarkdown(subf, args, text)
+ }
+ return t.newList(tk.pos) // for return nothing
+}
+
+func filterGo(subf, args, text string) {
+ switch subf {
+ case "func":
+ goFlt.Name = ""
+ switch args {
+ case "name":
+ goFlt.Name = text
+ case "arg", "args":
+ if goFlt.Args != "" {
+ goFlt.Args += ", " + strings.Trim(text, "()")
+ } else {
+ goFlt.Args = strings.Trim(text, "()")
+ }
+ default:
+ fn := strings.Split(text, "(")
+ if len(fn) == 2 {
+ goFlt.Name = strings.Trim(fn[0], " \t\n)")
+ goFlt.Args = strings.Trim(fn[1], " \t\n)")
+ } else {
+ log.Fatal(":go:func filter error in " + text)
+ }
+ }
+ case "import":
+ goFlt.Import = text
+ }
+}
+
+func (t *tree) parseTag(tk item) node {
+ var (
+ deep = tk.depth
+ tag = t.newTag(tk.pos, tk.val, tk.typ)
+ )
+Loop:
+ for {
+ switch token := t.nextNonSpace(); {
+ case token.depth > deep:
+ if tag.tagType == itemTagVoid || tag.tagType == itemTagVoidInline {
+ break Loop
+ }
+ tag.append(t.hub(token))
+ case token.depth == deep:
+ switch token.typ {
+ case itemClass:
+ tag.attr("class", `"`+token.val+`"`, false)
+ case itemID:
+ tag.attr("id", `"`+token.val+`"`, false)
+ case itemAttrStart:
+ t.parseAttributes(tag, `"`)
+ case itemTagEnd:
+ tag.tagType = itemTagVoid
+ return tag
+ default:
+ break Loop
+ }
+ default:
+ break Loop
+ }
+ }
+ t.backup()
+ return tag
+}
+
+type pAttr interface {
+ attr(string, string, bool)
+}
+
+func (t *tree) parseAttributes(tag pAttr, qw string) {
+ var (
+ aname string
+ equal bool
+ unesc bool
+ stack = make([]string, 0, 4)
+ )
+ for {
+ switch token := t.next(); token.typ {
+ case itemAttrSpace:
+ // skip
+ case itemAttr:
+ switch {
+ case aname == "":
+ aname = token.val
+ case aname != "" && !equal:
+ tag.attr(aname, qw+aname+qw, unesc)
+ aname = token.val
+ case aname != "" && equal:
+ stack = append(stack, token.val)
+ }
+ case itemAttrEqual, itemAttrEqualUn:
+ if token.typ == itemAttrEqual {
+ unesc = false
+ } else {
+ unesc = true
+ }
+ equal = true
+ switch len_stack := len(stack); {
+ case len_stack == 0 && aname != "":
+ // skip
+ case len_stack > 1 && aname != "":
+ tag.attr(aname, strings.Join(stack[:len(stack)-1], " "), unesc)
+
+ aname = stack[len(stack)-1]
+ stack = stack[:0]
+ case len_stack == 1 && aname == "":
+ aname = stack[0]
+ stack = stack[:0]
+ default:
+ t.errorf("unexpected '='")
+ }
+ case itemAttrComma:
+ equal = false
+ switch len_stack := len(stack); {
+ case len_stack > 0 && aname != "":
+ tag.attr(aname, strings.Join(stack, " "), unesc)
+ aname = ""
+ stack = stack[:0]
+ case len_stack == 0 && aname != "":
+ tag.attr(aname, qw+aname+qw, unesc)
+ aname = ""
+ }
+ case itemAttrEnd:
+ switch len_stack := len(stack); {
+ case len_stack > 0 && aname != "":
+ tag.attr(aname, strings.Join(stack, " "), unesc)
+ case len_stack > 0 && aname == "":
+ for _, a := range stack {
+ tag.attr(a, a, unesc)
+ }
+ case len_stack == 0 && aname != "":
+ tag.attr(aname, qw+aname+qw, unesc)
+ }
+ return
+ default:
+ t.errorf("unexpected %s", token.val)
+ }
+ }
+}
+
+func (t *tree) parseIf(tk item) node {
+ var (
+ deep = tk.depth
+ cond = t.newCond(tk.pos, tk.val, tk.typ)
+ )
+Loop:
+ for {
+ switch token := t.nextNonSpace(); {
+ case token.depth > deep:
+ cond.append(t.hub(token))
+ case token.depth == deep:
+ switch token.typ {
+ case itemElse:
+ ni := t.peek()
+ if ni.typ == itemIf {
+ token = t.next()
+ cond.append(t.newCode(token.pos, token.val, itemElseIf))
+ } else {
+ cond.append(t.newCode(token.pos, token.val, token.typ))
+ }
+ default:
+ break Loop
+ }
+ default:
+ break Loop
+ }
+ }
+ t.backup()
+ return cond
+}
+
+func (t *tree) parseFor(tk item) node {
+ var (
+ deep = tk.depth
+ cond = t.newCond(tk.pos, tk.val, tk.typ)
+ )
+Loop:
+ for {
+ switch token := t.nextNonSpace(); {
+ case token.depth > deep:
+ cond.append(t.hub(token))
+ case token.depth == deep:
+ if token.typ == itemElse {
+ cond.condType = itemForIfNotContain
+ cond.append(t.newCode(token.pos, token.val, itemForElse))
+ } else {
+ break Loop
+ }
+ default:
+ break Loop
+ }
+ }
+ t.backup()
+ return cond
+}
+
+func (t *tree) parseCase(tk item) node {
+ var (
+ deep = tk.depth
+ iCase = t.newCond(tk.pos, tk.val, tk.typ)
+ )
+ for {
+ if token := t.nextNonSpace(); token.depth > deep {
+ switch token.typ {
+ case itemCaseWhen, itemCaseDefault:
+ iCase.append(t.newCode(token.pos, token.val, token.typ))
+ default:
+ iCase.append(t.hub(token))
+ }
+ } else {
+ break
+ }
+ }
+ t.backup()
+ return iCase
+}
+
+func (t *tree) parseMixin(tk item) *mixinNode {
+ var (
+ deep = tk.depth
+ mixin = t.newMixin(tk.pos)
+ )
+Loop:
+ for {
+ switch token := t.nextNonSpace(); {
+ case token.depth > deep:
+ mixin.append(t.hub(token))
+ case token.depth == deep:
+ if token.typ == itemAttrStart {
+ t.parseAttributes(mixin, "")
+ } else {
+ break Loop
+ }
+ default:
+ break Loop
+ }
+ }
+ t.backup()
+ return mixin
+}
+
+func (t *tree) parseMixinUse(tk item) node {
+ tMix, ok := t.mixin[tk.val]
+ if !ok {
+ t.errorf(`Mixin "%s" must be declared before use.`, tk.val)
+ }
+ var (
+ deep = tk.depth
+ mixin = tMix.CopyMixin()
+ )
+Loop:
+ for {
+ switch token := t.nextNonSpace(); {
+ case token.depth > deep:
+ mixin.appendToBlock(t.hub(token))
+ case token.depth == deep:
+ if token.typ == itemAttrStart {
+ t.parseAttributes(mixin, "")
+ } else {
+ break Loop
+ }
+ default:
+ break Loop
+ }
+ }
+ t.backup()
+
+ use := len(mixin.AttrName)
+ tpl := len(tMix.AttrName)
+ switch {
+ case use < tpl:
+ i := 0
+ diff := tpl - use
+ mixin.AttrCode = append(mixin.AttrCode, make([]string, diff)...) // Extend slice
+ for index := 0; index < diff; index++ {
+ i = tpl - index - 1
+ if tMix.AttrName[i] != tMix.AttrCode[i] {
+ mixin.AttrCode[i] = tMix.AttrCode[i]
+ } else {
+ mixin.AttrCode[i] = `""`
+ }
+ }
+ mixin.AttrName = tMix.AttrName
+ case use > tpl:
+ if tpl <= 0 {
+ break
+ }
+ if strings.HasPrefix(tMix.AttrName[tpl-1], "...") {
+ mixin.AttrRest = mixin.AttrCode[tpl-1:]
+ }
+ mixin.AttrCode = mixin.AttrCode[:tpl]
+ mixin.AttrName = tMix.AttrName
+ case use == tpl:
+ mixin.AttrName = tMix.AttrName
+ }
+ return mixin
+}
+
+func (t *tree) parseBlock(tk item) *blockNode {
+ block := t.newList(tk.pos)
+ for {
+ token := t.nextNonSpace()
+ if token.depth > tk.depth {
+ block.append(t.hub(token))
+ } else {
+ break
+ }
+ }
+ t.backup()
+ var suf string
+ switch tk.typ {
+ case itemBlockPrepend:
+ suf = "_prepend"
+ case itemBlockAppend:
+ suf = "_append"
+ }
+ t.block[tk.val+suf] = block
+ return t.newBlock(tk.pos, tk.val, tk.typ)
+}
+
+func (t *tree) parseInclude(tk item) *listNode {
+ switch ext := filepath.Ext(tk.val); ext {
+ case ".jade", ".pug", "":
+ return t.parseSubFile(tk.val)
+ case ".js", ".css", ".tpl", ".md":
+ ln := t.newList(tk.pos)
+ ln.append(t.newText(tk.pos, t.read(tk.val), itemText))
+ return ln
+ default:
+ t.errorf(`file extension "%s" is not supported`, ext)
+ return nil
+ }
+}
+
+func (t *tree) parseSubFile(path string) *listNode {
+ var incTree = New(t.resolvePath(path))
+
+ incTree.block = t.block
+ incTree.mixin = t.mixin
+ incTree.fs = t.fs
+
+ _, err := incTree.Parse(t.read(path))
+ if err != nil {
+ d, _ := os.Getwd()
+ t.errorf(`in '%s' subtemplate '%s': parseSubFile() error: %s`, d, path, err)
+ }
+
+ return incTree.Root
+}
+
+func (t *tree) read(path string) []byte {
+ path = t.resolvePath(path)
+ bb, err := readFile(path, t.fs)
+
+ if os.IsNotExist(err) {
+
+ if ext := filepath.Ext(path); ext == "" {
+ if _, er := os.Stat(path + ".jade"); os.IsNotExist(er) {
+ if _, er = os.Stat(path + ".pug"); os.IsNotExist(er) {
+ wd, _ := os.Getwd()
+ t.errorf("in '%s' subtemplate '%s': file path error: '.jade' or '.pug' file required", wd, path)
+ } else {
+ ext = ".pug"
+ }
+ } else {
+ ext = ".jade"
+ }
+ bb, err = readFile(path+ext, t.fs)
+ }
+ }
+ if err != nil {
+ wd, _ := os.Getwd()
+ t.errorf(`%s work dir: %s `, err, wd)
+ }
+ return bb
+}
+
+func (t *tree) resolvePath(path string) string {
+ currentTmplDir, _ := filepath.Split(t.Name)
+ path = filepath.Join(currentTmplDir, path)
+ return filepath.ToSlash(path)
+}
+
+func readFile(fname string, fs http.FileSystem) ([]byte, error) {
+ if fs == nil {
+ return ReadFunc(fname)
+ }
+
+ file, err := fs.Open(fname)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ return ioutil.ReadAll(file)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/lex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/lex.go
new file mode 100644
index 000000000000..3aeb89a6e042
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/lex.go
@@ -0,0 +1,220 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jade
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+ typ itemType // The type of this item.
+ pos pos // The starting position, in bytes, of this item in the input string.
+ val string // The value of this item.
+ line int // The line number at the start of this item.
+ depth int
+}
+
+func (i item) String() string {
+ switch {
+ case i.typ == itemEOF:
+ return "EOF"
+ case i.typ == itemError:
+ return i.val
+ // case i.typ > itemKeyword:
+ // return fmt.Sprintf("<%s>", i.val)
+ case len(i.val) > 10:
+ return fmt.Sprintf("%.10q...", i.val)
+ }
+ return fmt.Sprintf("%q", i.val)
+}
+
+const (
+ eof = -1
+ spaceChars = " \t\r\n" // These are the space characters defined by Go itself.
+)
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+ name string // the name of the input; used only for error reports
+ input string // the string being scanned
+ pos pos // current position in the input
+ start pos // start position of this item
+ width pos // width of last rune read from input
+ items chan item // channel of scanned items
+ line int // 1+number of newlines seen
+
+ depth int // current tag depth
+ interpolation int // interpolation depth
+ longtext bool // long text flag
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() rune {
+ if int(l.pos) >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+ l.width = pos(w)
+ l.pos += l.width
+ if r == '\n' {
+ l.line++
+ }
+ return r
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() rune {
+ r := l.next()
+ l.backup()
+ return r
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+ l.pos -= l.width
+ // Correct newline count.
+ if l.width == 1 && l.input[l.pos] == '\n' {
+ l.line--
+ }
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+ l.items <- item{t, l.start, l.input[l.start:l.pos], l.line, l.depth}
+ // Some items contain text internally. If so, count their newlines.
+ switch t {
+ // case itemText, itemRawString, itemLeftDelim, itemRightDelim:
+ case itemText:
+ l.line += strings.Count(l.input[l.start:l.pos], "\n")
+ }
+ l.start = l.pos
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+ l.line += strings.Count(l.input[l.start:l.pos], "\n")
+ l.start = l.pos
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+ if strings.ContainsRune(valid, l.next()) {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+ for strings.ContainsRune(valid, l.next()) {
+ }
+ l.backup()
+}
+
+// errorf returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.nextItem.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.line, l.depth}
+ return nil
+}
+
+// nextItem returns the next item from the input.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) nextItem() item {
+ return <-l.items
+}
+
+// drain drains the output so the lexing goroutine will exit.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) drain() {
+ for range l.items {
+ }
+}
+
+// lex creates a new scanner for the input string.
+func lex(name string, input []byte) *lexer {
+ l := &lexer{
+ name: name,
+ input: string(input),
+ items: make(chan item),
+ line: 1,
+ }
+ go l.run()
+ return l
+}
+
+func (l *lexer) run() {
+ for state := lexIndents; state != nil; {
+ state = state(l)
+ }
+ close(l.items)
+}
+
+// atTerminator reports whether the input is at valid termination character to
+// appear after an identifier. Breaks .X.Y into two pieces. Also catches cases
+// like "$x+2" not being acceptable without a space, in case we decide one
+// day to implement arithmetic.
+func (l *lexer) atTerminator() bool {
+ r := l.peek()
+ if isSpace(r) || isEndOfLine(r) {
+ return true
+ }
+ switch r {
+ case eof, '.', ',', '|', ':', ')', '(':
+ return true
+ }
+
+ return false
+}
+
+func (l *lexer) scanNumber() bool {
+ // Optional leading sign.
+ l.accept("+-")
+ // Is it hex?
+ digits := "0123456789"
+ if l.accept("0") && l.accept("xX") {
+ digits = "0123456789abcdefABCDEF"
+ }
+ l.acceptRun(digits)
+ if l.accept(".") {
+ l.acceptRun(digits)
+ }
+ if l.accept("eE") {
+ l.accept("+-")
+ l.acceptRun("0123456789")
+ }
+ // Is it imaginary?
+ l.accept("i")
+ // Next thing mustn't be alphanumeric.
+ if isAlphaNumeric(l.peek()) {
+ l.next()
+ return false
+ }
+ return true
+}
+
+// isSpace reports whether r is a space character.
+func isSpace(r rune) bool {
+ return r == ' ' || r == '\t'
+}
+
+// isEndOfLine reports whether r is an end-of-line character.
+func isEndOfLine(r rune) bool {
+ return r == '\r' || r == '\n'
+}
+
+// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumeric(r rune) bool {
+ return r == '_' || r == '-' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/node.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/node.go
new file mode 100644
index 000000000000..24c5123f8962
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/node.go
@@ -0,0 +1,85 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jade
+
+import (
+ "bytes"
+ "io"
+)
+
+// var textFormat = "%s" // Changed to "%q" in tests for better error messages.
+
+// A Node is an element in the parse tree. The interface is trivial.
+// The interface contains an unexported method so that only
+// types local to this package can satisfy it.
+type node interface {
+ Type() nodeType
+ String() string
+ WriteIn(io.Writer)
+ // Copy does a deep copy of the Node and all its components.
+ // To avoid type assertions, some XxxNodes also have specialized
+ // CopyXxx methods that return *XxxNode.
+ Copy() node
+ position() pos // byte position of start of node in full original input string
+ // tree returns the containing *tree.
+ // It is unexported so all implementations of Node are in this package.
+ tree() *tree
+}
+
+// pos represents a byte position in the original input text from which
+// this template was parsed.
+type pos int
+
+func (p pos) position() pos {
+ return p
+}
+
+// Nodes.
+
+// listNode holds a sequence of nodes.
+type listNode struct {
+ nodeType
+ pos
+ tr *tree
+ Nodes []node // The element nodes in lexical order.
+}
+
+func (t *tree) newList(pos pos) *listNode {
+ return &listNode{tr: t, nodeType: nodeList, pos: pos}
+}
+
+func (l *listNode) append(n node) {
+ l.Nodes = append(l.Nodes, n)
+}
+
+func (l *listNode) tree() *tree {
+ return l.tr
+}
+
+func (l *listNode) String() string {
+ b := new(bytes.Buffer)
+ l.WriteIn(b)
+ return b.String()
+}
+func (l *listNode) WriteIn(b io.Writer) {
+ for _, n := range l.Nodes {
+ n.WriteIn(b)
+ }
+}
+
+func (l *listNode) CopyList() *listNode {
+ if l == nil {
+ return l
+ }
+ n := l.tr.newList(l.pos)
+ for _, elem := range l.Nodes {
+ n.append(elem.Copy())
+ }
+ return n
+}
+
+func (l *listNode) Copy() node {
+ return l.CopyList()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/parse.go
new file mode 100644
index 000000000000..8532806f0ff8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/parse.go
@@ -0,0 +1,148 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jade
+
+import (
+ "fmt"
+ "net/http"
+ "runtime"
+)
+
+// Tree is the representation of a single parsed template.
+type tree struct {
+ Name string // name of the template represented by the tree.
+ Root *listNode // top-level root of the tree.
+ text string // text parsed to create the template (or its parent)
+
+ // Parsing only; cleared after parse.
+ lex *lexer
+ token [3]item // three-token lookahead for parser.
+ peekCount int
+
+ mixin map[string]*mixinNode
+ block map[string]*listNode
+
+ fs http.FileSystem // embedded file system
+}
+
+// Copy returns a copy of the Tree. Any parsing state is discarded.
+func (t *tree) Copy() *tree {
+ if t == nil {
+ return nil
+ }
+ return &tree{
+ Name: t.Name,
+ Root: t.Root.CopyList(),
+ text: t.text,
+ }
+}
+
+// next returns the next token.
+func (t *tree) next() item {
+ if t.peekCount > 0 {
+ t.peekCount--
+ } else {
+ t.token[0] = t.lex.nextItem()
+ }
+ return t.token[t.peekCount]
+}
+
+// backup backs the input stream up one token.
+func (t *tree) backup() {
+ t.peekCount++
+}
+
+// backup2 backs the input stream up two tokens.
+// The zeroth token is already there.
+func (t *tree) backup2(t1 item) {
+ t.token[1] = t1
+ t.peekCount = 2
+}
+
+// backup3 backs the input stream up three tokens
+// The zeroth token is already there.
+func (t *tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
+ t.token[1] = t1
+ t.token[2] = t2
+ t.peekCount = 3
+}
+
+// peek returns but does not consume the next token.
+func (t *tree) peek() item {
+ if t.peekCount > 0 {
+ return t.token[t.peekCount-1]
+ }
+ t.peekCount = 1
+ t.token[0] = t.lex.nextItem()
+ return t.token[0]
+}
+
+// nextNonSpace returns the next non-space token.
+func (t *tree) nextNonSpace() (token item) {
+ for {
+ token = t.next()
+ if token.typ != itemIdent && token.typ != itemEndL && token.typ != itemEmptyLine {
+ break
+ }
+ }
+ // fmt.Println("\t\tnextNonSpace", token.val)
+ return token
+}
+
+// peekNonSpace returns but does not consume the next non-space token.
+func (t *tree) peekNonSpace() (token item) {
+ for {
+ token = t.next()
+ if token.typ != itemIdent && token.typ != itemEndL && token.typ != itemEmptyLine {
+ break
+ }
+ }
+ t.backup()
+ return token
+}
+
+// errorf formats the error and terminates processing.
+func (t *tree) errorf(format string, args ...interface{}) {
+ t.Root = nil
+ format = fmt.Sprintf("template:%d: %s", t.token[0].line, format)
+ panic(fmt.Errorf(format, args...))
+}
+
+//
+//
+//
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (t *tree) recover(errp *error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ if t != nil {
+ t.lex.drain()
+ t.lex = nil
+ }
+ *errp = e.(error)
+ }
+}
+
+func (t *tree) Parse(text []byte) (tree *tree, err error) {
+ defer t.recover(&err)
+ t.lex = lex(t.Name, text)
+ t.text = string(text)
+ t.topParse()
+ t.lex = nil
+ return t, nil
+}
+
+// New allocates a new parse tree with the given name.
+func New(name string) *tree {
+ return &tree{
+ Name: name,
+ mixin: map[string]*mixinNode{},
+ block: map[string]*listNode{},
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/template.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/template.go
new file mode 100644
index 000000000000..964425f63bdd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Joker/jade/template.go
@@ -0,0 +1,86 @@
+// Jade.go - template engine. Package implements Jade-lang templates for generating Go html/template output.
+package jade
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+)
+
+/*
+Parse parses the template definition string to construct a representation of the template for execution.
+
+Trivial usage:
+
+ package main
+
+ import (
+ "fmt"
+ "html/template"
+ "net/http"
+
+ "github.com/Joker/jade"
+ )
+
+ func handler(w http.ResponseWriter, r *http.Request) {
+ jadeTpl, _ := jade.Parse("jade", []byte("doctype 5\n html: body: p Hello #{.Word}!"))
+ goTpl, _ := template.New("html").Parse(jadeTpl)
+
+ goTpl.Execute(w, struct{ Word string }{"jade"})
+ }
+
+ func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe(":8080", nil)
+ }
+
+Output:
+
+ Hello jade!
+*/
+func Parse(fname string, text []byte) (string, error) {
+ outTpl, err := New(fname).Parse(text)
+ if err != nil {
+ return "", err
+ }
+ bb := new(bytes.Buffer)
+ outTpl.WriteIn(bb)
+ return bb.String(), nil
+}
+
+// ParseFile parse the jade template file in given filename
+func ParseFile(fname string) (string, error) {
+ text, err := ReadFunc(fname)
+ if err != nil {
+ return "", err
+ }
+ return Parse(fname, text)
+}
+
+// ParseWithFileSystem parse in context of a http.FileSystem (supports embedded files)
+func ParseWithFileSystem(fname string, text []byte, fs http.FileSystem) (str string, err error) {
+ outTpl := New(fname)
+ outTpl.fs = fs
+
+ outTpl, err = outTpl.Parse(text)
+ if err != nil {
+ return "", err
+ }
+
+ bb := new(bytes.Buffer)
+ outTpl.WriteIn(bb)
+ return bb.String(), nil
+}
+
+// ParseFileFromFileSystem parse template file in context of a http.FileSystem (supports embedded files)
+func ParseFileFromFileSystem(fname string, fs http.FileSystem) (str string, err error) {
+ text, err := readFile(fname, fs)
+ if err != nil {
+ return "", err
+ }
+ return ParseWithFileSystem(fname, text, fs)
+}
+
+func (t *tree) WriteIn(b io.Writer) {
+ t.Root.WriteIn(b)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/.gitignore
new file mode 100644
index 000000000000..24a676653dc2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/.gitignore
@@ -0,0 +1,4 @@
+vendor/
+.DS_Store
+.idea
+.vscode/
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/LICENSE
new file mode 100644
index 000000000000..d688cb7ffdb1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Steven Normore
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/README.md
new file mode 100644
index 000000000000..1e7d34d56249
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/README.md
@@ -0,0 +1,42 @@
+goreferrer
+==========
+
+A Go module that analyzes and classifies different kinds of referrer URLs (search, social, ...).
+
+## Example
+
+```go
+package main
+
+import (
+ "fmt"
+
+ "github.com/Shopify/goreferrer"
+)
+
+var urls = []string{
+ "http://ca.search.yahoo.com/search?p=hello",
+ "https://twitter.com/jdoe/status/391149968360103936",
+ "http://yoursite.com/links",
+}
+
+func main() {
+ for _, url := range urls {
+ r := goreferrer.DefaultRules.Parse(url)
+ switch r.Type {
+ case goreferrer.Search:
+ fmt.Printf("Search %s: %s\n", r.Label, r.Query)
+ case goreferrer.Social:
+ fmt.Printf("Social %s\n", r.Label)
+ case goreferrer.Indirect:
+ fmt.Printf("Indirect: %s\n", r.URL)
+ }
+ }
+}
+```
+Result:
+```
+Search Yahoo: hello
+Social Twitter
+Indirect: http://yoursite.com/links
+```
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/default_rules.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/default_rules.go
new file mode 100644
index 000000000000..a646f91e7b90
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/default_rules.go
@@ -0,0 +1,4566 @@
+package goreferrer
+
+import (
+ "strings"
+)
+
+var DefaultRules RuleSet
+
+func init() {
+ domainRules, err := LoadJsonDomainRules(strings.NewReader(defaultRules))
+ if err != nil {
+ panic(err)
+ }
+
+ DefaultRules = RuleSet{
+ DomainRules: domainRules,
+ UaRules: map[string]UaRule{
+ "Twitter": {
+ Url: "twitter://twitter.com",
+ Domain: "twitter",
+ Tld: "com",
+ },
+ "Pinterest": {
+ Url: "pinterest://pinterest.com",
+ Domain: "pinterest",
+ Tld: "com",
+ },
+ "Facebook": {
+ Url: "facebook://facebook.com",
+ Domain: "facebook",
+ Tld: "com",
+ },
+ "FBAV": {
+ Url: "facebook://facebook.com",
+ Domain: "facebook",
+ Tld: "com",
+ },
+ },
+ }
+}
+
+const defaultRules = `
+{
+ "email": {
+ "126 Mail": {
+ "domains": [
+ "mail.126.com"
+ ]
+ },
+ "163 Mail": {
+ "domains": [
+ "mail.163.com"
+ ]
+ },
+ "2degrees": {
+ "domains": [
+ "webmail.2degreesbroadband.co.nz"
+ ]
+ },
+ "Adam Internet": {
+ "domains": [
+ "webmail.adam.com.au"
+ ]
+ },
+ "AOL Mail": {
+ "domains": [
+ "mail.aol.com",
+ "cpw.mail.aol.com"
+ ]
+ },
+ "Xfinity":{
+ "domains": [
+ "web.mail.comcast.net"
+ ]
+ },
+ "Bigpond": {
+ "domains": [
+ "webmail.bigpond.com",
+ "webmail2.bigpond.com",
+ "email.telstra.com",
+ "basic.messaging.bigpond.com"
+ ]
+ },
+ "Commander": {
+ "domains": [
+ "webmail.commander.net.au"
+ ]
+ },
+ "Daum Mail": {
+ "domains": [
+ "mail2.daum.net",
+ "mail.daum.net"
+ ]
+ },
+ "Dodo": {
+ "domains": [
+ "webmail.dodo.com.au"
+ ]
+ },
+ "Freenet": {
+ "domains": [
+ "webmail.freenet.de"
+ ]
+ },
+ "Gmail": {
+ "domains": [
+ "mail.google.com",
+ "inbox.google.com"
+ ]
+ },
+ "iiNet": {
+ "domains": [
+ "webmail.iinet.net.au",
+ "mail.iinet.net.au"
+ ]
+ },
+ "Inbox.com": {
+ "domains": [
+ "inbox.com"
+ ]
+ },
+ "iPrimus": {
+ "domains": [
+ "webmail.iprimus.com.au"
+ ]
+ },
+ "Naver Mail": {
+ "domains": [
+ "mail.naver.com"
+ ]
+ },
+ "Netspace": {
+ "domains": [
+ "webmail.netspace.net.au"
+ ]
+ },
+ "Optus Zoo": {
+ "domains": [
+ "webmail.optuszoo.com.au",
+ "webmail.optusnet.com.au"
+ ]
+ },
+ "Orange Webmail": {
+ "domains": [
+ "orange.fr/webmail"
+ ]
+ },
+ "Outlook.com": {
+ "domains": [
+ "mail.live.com",
+ "outlook.live.com",
+ "blu180.mail.live.com",
+ "col130.mail.live.com",
+ "blu184.mail.live.com",
+ "bay179.mail.live.com",
+ "col131.mail.live.com",
+ "blu179.mail.live.com",
+ "bay180.mail.live.com",
+ "blu182.mail.live.com",
+ "blu181.mail.live.com",
+ "bay182.mail.live.com",
+ "snt149.mail.live.com",
+ "bay181.mail.live.com",
+ "col129.mail.live.com",
+ "snt148.mail.live.com",
+ "snt147.mail.live.com",
+ "snt146.mail.live.com",
+ "snt153.mail.live.com",
+ "snt152.mail.live.com",
+ "snt150.mail.live.com",
+ "snt151.mail.live.com",
+ "col128.mail.live.com",
+ "blu185.mail.live.com",
+ "dub125.mail.live.com",
+ "dub128.mail.live.com",
+ "dub127.mail.live.com",
+ "dub131.mail.live.com",
+ "col125.mail.live.com",
+ "dub130.mail.live.com",
+ "blu172.mail.live.com",
+ "bay169.mail.live.com",
+ "blu175.mail.live.com",
+ "blu173.mail.live.com",
+ "bay176.mail.live.com",
+ "blu176.mail.live.com",
+ "col126.mail.live.com",
+ "col127.mail.live.com",
+ "blu177.mail.live.com",
+ "blu174.mail.live.com",
+ "bay174.mail.live.com",
+ "bay172.mail.live.com",
+ "blu169.mail.live.com",
+ "bay177.mail.live.com",
+ "blu178.mail.live.com",
+ "blu171.mail.live.com",
+ "dub126.mail.live.com",
+ "blu168.mail.live.com",
+ "bay173.mail.live.com",
+ "bay175.mail.live.com",
+ "bay178.mail.live.com",
+ "bay168.mail.live.com",
+ "bay167.mail.live.com",
+ "blu170.mail.live.com",
+ "dub124.mail.live.com",
+ "dub122.mail.live.com",
+ "dub121.mail.live.com",
+ "dub129.mail.live.com",
+ "dub114.mail.live.com",
+ "dub110.mail.live.com",
+ "dub111.mail.live.com",
+ "dub113.mail.live.com",
+ "dub109.mail.live.com",
+ "dub120.mail.live.com",
+ "dub115.mail.live.com",
+ "dub123.mail.live.com",
+ "dub119.mail.live.com",
+ "dub118.mail.live.com",
+ "dub112.mail.live.com",
+ "dub117.mail.live.com",
+ "dub116.mail.live.com",
+ "blu183.mail.live.com"
+ ]
+ },
+ "QQ Mail": {
+ "domains": [
+ "mail.qq.com"
+ ]
+ },
+ "Seznam Mail": {
+ "domains": [
+ "email.seznam.cz"
+ ]
+ },
+ "Virgin": {
+ "domains": [
+ "webmail.virginbroadband.com.au"
+ ]
+ },
+ "Vodafone": {
+ "domains": [
+ "webmail.vodafone.co.nz"
+ ]
+ },
+ "Westnet": {
+ "domains": [
+ "webmail.westnet.com.au"
+ ]
+ },
+ "Yahoo! Mail": {
+ "domains": [
+ "mail.yahoo.net",
+ "mail.yahoo.com",
+ "mail.yahoo.co.uk",
+ "mail.yahoo.co.jp"
+ ]
+ },
+ "Mynet Mail": {
+ "domains": [
+ "mail.mynet.com"
+ ]
+ },
+ "Zoho": {
+ "domains": [
+ "mail.zoho.com"
+ ]
+ },
+ "MailChimp": {
+ "domains": [
+ "list-manage.com",
+ "list-manage1.com",
+ "list-manage2.com",
+ "list-manage3.com",
+ "list-manage4.com",
+ "list-manage5.com",
+ "list-manage6.com",
+ "list-manage7.com",
+ "list-manage8.com",
+ "list-manage9.com"
+ ]
+ }
+ },
+ "search": {
+ "1.cz": {
+ "domains": [
+ "1.cz"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "1&1": {
+ "domains": [
+ "search.1and1.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "1und1": {
+ "domains": [
+ "search.1und1.de"
+ ],
+ "parameters": [
+ "su"
+ ]
+ },
+ "360.cn": {
+ "domains": [
+ "so.360.cn",
+ "www.so.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "ABCs\u00f8k": {
+ "domains": [
+ "abcsolk.no",
+ "verden.abcsok.no"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "AOL": {
+ "domains": [
+ "m.search.aol.com",
+ "search.aol.ca",
+ "www.aol.com",
+ "search.aol.com",
+ "search.aol.it",
+ "aolsearch.aol.com",
+ "aolsearch.com",
+ "www.aolrecherche.aol.fr",
+ "www.aolrecherches.aol.fr",
+ "www.aolimages.aol.fr",
+ "aim.search.aol.com",
+ "www.recherche.aol.fr",
+ "recherche.aol.fr",
+ "find.web.aol.com",
+ "recherche.aol.ca",
+ "aolsearch.aol.co.uk",
+ "search.aol.co.uk",
+ "aolrecherche.aol.fr",
+ "sucheaol.aol.de",
+ "suche.aol.de",
+ "suche.aolsvc.de",
+ "aolbusqueda.aol.com.mx",
+ "alicesuche.aol.de",
+ "alicesuchet.aol.de",
+ "suchet2.aol.de",
+ "search.hp.my.aol.com.au",
+ "search.hp.my.aol.de",
+ "search.hp.my.aol.it",
+ "search-intl.netscape.com"
+ ],
+ "parameters": [
+ "q",
+ "query"
+ ]
+ },
+ "APOLL07": {
+ "domains": [
+ "apollo7.de"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Abacho": {
+ "domains": [
+ "www.abacho.de",
+ "www.abacho.com",
+ "www.abacho.co.uk",
+ "www.se.abacho.com",
+ "www.tr.abacho.com",
+ "www.abacho.at",
+ "www.abacho.fr",
+ "www.abacho.es",
+ "www.abacho.ch",
+ "www.abacho.it"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Acoon": {
+ "domains": [
+ "www.acoon.de"
+ ],
+ "parameters": [
+ "begriff"
+ ]
+ },
+ "Alexa": {
+ "domains": [
+ "alexa.com",
+ "search.toolbars.alexa.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Alice Adsl": {
+ "domains": [
+ "rechercher.aliceadsl.fr"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "AllTheWeb": {
+ "domains": [
+ "www.alltheweb.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Altavista": {
+ "domains": [
+ "www.altavista.com",
+ "search.altavista.com",
+ "listings.altavista.com",
+ "altavista.de",
+ "altavista.fr",
+ "be-nl.altavista.com",
+ "be-fr.altavista.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Apollo Latvia": {
+ "domains": [
+ "apollo.lv/portal/search/"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Amazon": {
+ "domains": [
+ "amazon.com",
+ "amazon.co.uk",
+ "amazon.ca",
+ "amazon.de",
+ "amazon.fr",
+ "amazonaws.com",
+ "amazon.co.jp",
+ "amazon.es",
+ "amazon.it",
+ "amazon.in",
+ "www.amazon.com"
+ ],
+ "parameters": [
+ "keywords",
+ "field-keywords"
+ ]
+ },
+ "Apontador": {
+ "domains": [
+ "apontador.com.br",
+ "www.apontador.com.br"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Aport": {
+ "domains": [
+ "sm.aport.ru"
+ ],
+ "parameters": [
+ "r"
+ ]
+ },
+ "Arcor": {
+ "domains": [
+ "www.arcor.de"
+ ],
+ "parameters": [
+ "Keywords"
+ ]
+ },
+ "Arianna": {
+ "domains": [
+ "arianna.libero.it",
+ "www.arianna.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Ask": {
+ "domains": [
+ "ask.com",
+ "www.ask.com",
+ "web.ask.com",
+ "int.ask.com",
+ "mws.ask.com",
+ "uk.ask.com",
+ "images.ask.com",
+ "ask.reference.com",
+ "www.askkids.com",
+ "iwon.ask.com",
+ "www.ask.co.uk",
+ "www.qbyrd.com",
+ "search-results.com",
+ "uk.search-results.com",
+ "www.search-results.com",
+ "int.search-results.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Ask Toolbar": {
+ "domains": [
+ "search.tb.ask.com"
+ ],
+ "parameters": [
+ "searchfor"
+ ]
+ },
+ "Atlas": {
+ "domains": [
+ "searchatlas.centrum.cz"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Austronaut": {
+ "domains": [
+ "www2.austronaut.at",
+ "www1.astronaut.at"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Babylon": {
+ "domains": [
+ "search.babylon.com",
+ "searchassist.babylon.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Baidu": {
+ "domains": [
+ "www.baidu.com",
+ "www1.baidu.com",
+ "zhidao.baidu.com",
+ "tieba.baidu.com",
+ "news.baidu.com",
+ "web.gougou.com",
+ "m.baidu.com",
+ "image.baidu.com",
+ "tieba.baidu.com",
+ "fanyi.baidu.com",
+ "zhidao.baidu.com",
+ "www.baidu.co.th",
+ "m5.baidu.com",
+ "m.siteapp.baidu.com"
+ ],
+ "parameters": [
+ "wd",
+ "word",
+ "kw",
+ "k"
+ ]
+ },
+ "Biglobe": {
+ "domains": [
+ "cgi.search.biglobe.ne.jp"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Bing": {
+ "domains": [
+ "bing.com",
+ "www.bing.com",
+ "msnbc.msn.com",
+ "dizionario.it.msn.com",
+ "cc.bingj.com",
+ "m.bing.com"
+ ],
+ "parameters": [
+ "q",
+ "Q"
+ ]
+ },
+ "Bing Images": {
+ "domains": [
+ "bing.com/images/search",
+ "www.bing.com/images/search"
+ ],
+ "parameters": [
+ "q",
+ "Q"
+ ]
+ },
+ "Blogdigger": {
+ "domains": [
+ "www.blogdigger.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Blogpulse": {
+ "domains": [
+ "www.blogpulse.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Bluewin": {
+ "domains": [
+ "search.bluewin.ch"
+ ],
+ "parameters": [
+ "searchTerm"
+ ]
+ },
+ "British Telecommunications": {
+ "domains": [
+ "search.bt.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Centrum": {
+ "domains": [
+ "serach.centrum.cz",
+ "morfeo.centrum.cz"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Certified-Toolbar": {
+ "domains": [
+ "search.certified-toolbar.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Charter": {
+ "domains": [
+ "www.charter.net"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Clix": {
+ "domains": [
+ "pesquisa.clix.pt"
+ ],
+ "parameters": [
+ "question"
+ ]
+ },
+ "Comcast": {
+ "domains": [
+ "search.comcast.net",
+ "comcast.net",
+ "xfinity.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Compuserve": {
+ "domains": [
+ "websearch.cs.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Conduit": {
+ "domains": [
+ "search.conduit.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Crawler": {
+ "domains": [
+ "www.crawler.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Cuil": {
+ "domains": [
+ "www.cuil.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Daemon search": {
+ "domains": [
+ "daemon-search.com",
+ "my.daemon-search.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Dalesearch": {
+ "domains": [
+ "www.dalesearch.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "DasOertliche": {
+ "domains": [
+ "www.dasoertliche.de"
+ ],
+ "parameters": [
+ "kw"
+ ]
+ },
+ "DasTelefonbuch": {
+ "domains": [
+ "www1.dastelefonbuch.de"
+ ],
+ "parameters": [
+ "kw"
+ ]
+ },
+ "Daum": {
+ "domains": [
+ "search.daum.net"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Delfi": {
+ "domains": [
+ "otsing.delfi.ee"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Delfi latvia": {
+ "domains": [
+ "smart.delfi.lv"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Digg": {
+ "domains": [
+ "digg.com"
+ ],
+ "parameters": [
+ "s"
+ ]
+ },
+ "Dodo": {
+ "domains": [
+ "google.dodo.com.au"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "DuckDuckGo": {
+ "domains": [
+ "duckduckgo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Ecosia": {
+ "domains": [
+ "ecosia.org"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "El Mundo": {
+ "domains": [
+ "ariadna.elmundo.es"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Eniro": {
+ "domains": [
+ "www.eniro.se"
+ ],
+ "parameters": [
+ "q",
+ "search_word"
+ ]
+ },
+ "Eurip": {
+ "domains": [
+ "www.eurip.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Euroseek": {
+ "domains": [
+ "www.euroseek.com"
+ ],
+ "parameters": [
+ "string"
+ ]
+ },
+ "Everyclick": {
+ "domains": [
+ "www.everyclick.com"
+ ],
+ "parameters": [
+ "keyword"
+ ]
+ },
+ "Exalead": {
+ "domains": [
+ "www.exalead.fr",
+ "www.exalead.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Excite": {
+ "domains": [
+ "search.excite.it",
+ "search.excite.fr",
+ "search.excite.de",
+ "search.excite.co.uk",
+ "serach.excite.es",
+ "search.excite.nl",
+ "msxml.excite.com",
+ "www.excite.co.jp"
+ ],
+ "parameters": [
+ "q",
+ "search"
+ ]
+ },
+ "Fast Browser Search": {
+ "domains": [
+ "www.fastbrowsersearch.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Finderoo": {
+ "domains": [
+ "www.finderoo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Findwide": {
+ "domains": [
+ "search.findwide.com"
+ ],
+ "parameters": [
+ "k"
+ ]
+ },
+ "Fireball": {
+ "domains": [
+ "www.fireball.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Firstfind": {
+ "domains": [
+ "www.firstsfind.com"
+ ],
+ "parameters": [
+ "qry"
+ ]
+ },
+ "Fixsuche": {
+ "domains": [
+ "www.fixsuche.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Flix": {
+ "domains": [
+ "www.flix.de"
+ ],
+ "parameters": [
+ "keyword"
+ ]
+ },
+ "Flyingbird": {
+ "domains": [
+ "inspsearch.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Forestle": {
+ "domains": [
+ "forestle.org",
+ "www.forestle.org",
+ "forestle.mobi"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Francite": {
+ "domains": [
+ "recherche.francite.com"
+ ],
+ "parameters": [
+ "name"
+ ]
+ },
+ "Free": {
+ "domains": [
+ "search.free.fr",
+ "search1-2.free.fr",
+ "search1-1.free.fr"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Freecause": {
+ "domains": [
+ "search.freecause.com"
+ ],
+ "parameters": [
+ "p"
+ ]
+ },
+ "Freenet": {
+ "domains": [
+ "suche.freenet.de"
+ ],
+ "parameters": [
+ "query",
+ "Keywords"
+ ]
+ },
+ "Freshweather": {
+ "domains": [
+ "www.fresh-weather.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "FriendFeed": {
+ "domains": [
+ "friendfeed.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "GAIS": {
+ "domains": [
+ "gais.cs.ccu.edu.tw"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "GMX": {
+ "domains": [
+ "suche.gmx.net"
+ ],
+ "parameters": [
+ "su"
+ ]
+ },
+ "Geona": {
+ "domains": [
+ "geona.net"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Genieo": {
+ "domains": [
+ "search.genieo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Gigablast": {
+ "domains": [
+ "www.gigablast.com",
+ "dir.gigablast.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Globososo": {
+ "domains": [
+ "searches.globososo.com",
+ "search.globososo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Gnadenmeer": {
+ "domains": [
+ "www.gnadenmeer.de"
+ ],
+ "parameters": [
+ "keyword"
+ ]
+ },
+ "Gomeo": {
+ "domains": [
+ "www.gomeo.com"
+ ],
+ "parameters": [
+ "Keywords"
+ ]
+ },
+ "Google": {
+ "domains": [
+ "www.google.com",
+ "www.google.ac",
+ "www.google.ad",
+ "www.google.al",
+ "www.google.com.af",
+ "www.google.com.ag",
+ "www.google.com.ai",
+ "www.google.am",
+ "www.google.it.ao",
+ "www.google.com.ar",
+ "www.google.as",
+ "www.google.at",
+ "www.google.com.au",
+ "www.google.az",
+ "www.google.ba",
+ "www.google.com.bd",
+ "www.google.be",
+ "www.google.bf",
+ "www.google.bg",
+ "www.google.com.bh",
+ "www.google.bi",
+ "www.google.bj",
+ "www.google.com.bn",
+ "www.google.com.bo",
+ "www.google.com.br",
+ "www.google.bs",
+ "www.google.co.bw",
+ "www.google.com.by",
+ "www.google.by",
+ "www.google.com.bz",
+ "www.google.ca",
+ "www.google.com.kh",
+ "www.google.cc",
+ "www.google.cd",
+ "www.google.cf",
+ "www.google.cat",
+ "www.google.cg",
+ "www.google.ch",
+ "www.google.ci",
+ "www.google.co.ck",
+ "www.google.cl",
+ "www.google.cm",
+ "www.google.cn",
+ "www.google.com.co",
+ "www.google.co.cr",
+ "www.google.com.cu",
+ "www.google.cv",
+ "www.google.com.cy",
+ "www.google.cz",
+ "www.google.de",
+ "www.google.dj",
+ "www.google.dk",
+ "www.google.dm",
+ "www.google.com.do",
+ "www.google.dz",
+ "www.google.com.ec",
+ "www.google.ee",
+ "www.google.com.eg",
+ "www.google.es",
+ "www.google.com.et",
+ "www.google.fi",
+ "www.google.com.fj",
+ "www.google.fm",
+ "www.google.fr",
+ "www.google.ga",
+ "www.google.gd",
+ "www.google.ge",
+ "www.google.gf",
+ "www.google.gg",
+ "www.google.com.gh",
+ "www.google.com.gi",
+ "www.google.gl",
+ "www.google.gm",
+ "www.google.gp",
+ "www.google.gr",
+ "www.google.com.gt",
+ "www.google.gy",
+ "www.google.com.hk",
+ "www.google.hn",
+ "www.google.hr",
+ "www.google.ht",
+ "www.google.hu",
+ "www.google.co.id",
+ "www.google.iq",
+ "www.google.ie",
+ "www.google.co.il",
+ "www.google.im",
+ "www.google.co.in",
+ "www.google.io",
+ "www.google.is",
+ "www.google.it",
+ "www.google.je",
+ "www.google.com.jm",
+ "www.google.jo",
+ "www.google.co.jp",
+ "www.google.co.ke",
+ "www.google.com.kh",
+ "www.google.ki",
+ "www.google.kg",
+ "www.google.co.kr",
+ "www.google.com.kw",
+ "www.google.kz",
+ "www.google.la",
+ "www.google.com.lb",
+ "www.google.com.lc",
+ "www.google.li",
+ "www.google.lk",
+ "www.google.co.ls",
+ "www.google.lt",
+ "www.google.lu",
+ "www.google.lv",
+ "www.google.com.ly",
+ "www.google.co.ma",
+ "www.google.md",
+ "www.google.me",
+ "www.google.mg",
+ "www.google.mk",
+ "www.google.ml",
+ "www.google.mn",
+ "www.google.ms",
+ "www.google.com.mt",
+ "www.google.mu",
+ "www.google.mv",
+ "www.google.mw",
+ "www.google.com.mx",
+ "www.google.com.my",
+ "www.google.co.mz",
+ "www.google.com.na",
+ "www.google.ne",
+ "www.google.com.nf",
+ "www.google.com.ng",
+ "www.google.com.ni",
+ "www.google.nl",
+ "www.google.no",
+ "www.google.com.np",
+ "www.google.nr",
+ "www.google.nu",
+ "www.google.co.nz",
+ "www.google.com.om",
+ "www.google.com.pa",
+ "www.google.com.pe",
+ "www.google.com.ph",
+ "www.google.com.pk",
+ "www.google.pl",
+ "www.google.pn",
+ "www.google.com.pr",
+ "www.google.ps",
+ "www.google.pt",
+ "www.google.com.py",
+ "www.google.com.qa",
+ "www.google.ro",
+ "www.google.rs",
+ "www.google.ru",
+ "www.google.rw",
+ "www.google.com.sa",
+ "www.google.com.sb",
+ "www.google.sc",
+ "www.google.se",
+ "www.google.com.sg",
+ "www.google.sh",
+ "www.google.si",
+ "www.google.sk",
+ "www.google.com.sl",
+ "www.google.sn",
+ "www.google.sm",
+ "www.google.so",
+ "www.google.st",
+ "www.google.com.sv",
+ "www.google.td",
+ "www.google.tg",
+ "www.google.co.th",
+ "www.google.com.tj",
+ "www.google.tk",
+ "www.google.tl",
+ "www.google.tm",
+ "www.google.to",
+ "www.google.com.tn",
+ "www.google.com.tr",
+ "www.google.tt",
+ "www.google.tn",
+ "www.google.com.tw",
+ "www.google.co.tz",
+ "www.google.com.ua",
+ "www.google.co.ug",
+ "www.google.ae",
+ "www.google.co.uk",
+ "www.google.us",
+ "www.google.com.uy",
+ "www.google.co.uz",
+ "www.google.com.vc",
+ "www.google.co.ve",
+ "www.google.vg",
+ "www.google.co.vi",
+ "www.google.com.vn",
+ "www.google.vu",
+ "www.google.ws",
+ "www.google.co.za",
+ "www.google.co.zm",
+ "www.google.co.zw",
+ "www.google.com.mm",
+ "www.google.sr",
+ "www.google.com.pg",
+ "www.google.bt",
+ "www.google.ng",
+ "www.google.com.iq",
+ "www.google.co.ao",
+ "google.com",
+ "google.ac",
+ "google.ad",
+ "google.al",
+ "google.com.af",
+ "google.com.ag",
+ "google.com.ai",
+ "google.am",
+ "google.it.ao",
+ "google.com.ar",
+ "google.as",
+ "google.at",
+ "google.com.au",
+ "google.az",
+ "google.ba",
+ "google.com.bd",
+ "google.be",
+ "google.bf",
+ "google.bg",
+ "google.com.bh",
+ "google.bi",
+ "google.bj",
+ "google.com.bn",
+ "google.com.bo",
+ "google.com.br",
+ "google.bs",
+ "google.co.bw",
+ "google.com.by",
+ "google.by",
+ "google.com.bz",
+ "google.ca",
+ "google.com.kh",
+ "google.cc",
+ "google.cd",
+ "google.cf",
+ "google.cat",
+ "google.cg",
+ "google.ch",
+ "google.ci",
+ "google.co.ck",
+ "google.cl",
+ "google.cm",
+ "google.cn",
+ "google.com.co",
+ "google.co.cr",
+ "google.com.cu",
+ "google.cv",
+ "google.com.cy",
+ "google.cz",
+ "google.de",
+ "google.dj",
+ "google.dk",
+ "google.dm",
+ "google.com.do",
+ "google.dz",
+ "google.com.ec",
+ "google.ee",
+ "google.com.eg",
+ "google.es",
+ "google.com.et",
+ "google.fi",
+ "google.com.fj",
+ "google.fm",
+ "google.fr",
+ "google.ga",
+ "google.gd",
+ "google.ge",
+ "google.gf",
+ "google.gg",
+ "google.com.gh",
+ "google.com.gi",
+ "google.gl",
+ "google.gm",
+ "google.gp",
+ "google.gr",
+ "google.com.gt",
+ "google.gy",
+ "google.com.hk",
+ "google.hn",
+ "google.hr",
+ "google.ht",
+ "google.hu",
+ "google.co.id",
+ "google.iq",
+ "google.ie",
+ "google.co.il",
+ "google.im",
+ "google.co.in",
+ "google.io",
+ "google.is",
+ "google.it",
+ "google.je",
+ "google.com.jm",
+ "google.jo",
+ "google.co.jp",
+ "google.co.ke",
+ "google.com.kh",
+ "google.ki",
+ "google.kg",
+ "google.co.kr",
+ "google.com.kw",
+ "google.kz",
+ "google.la",
+ "google.com.lb",
+ "google.com.lc",
+ "google.li",
+ "google.lk",
+ "google.co.ls",
+ "google.lt",
+ "google.lu",
+ "google.lv",
+ "google.com.ly",
+ "google.co.ma",
+ "google.md",
+ "google.me",
+ "google.mg",
+ "google.mk",
+ "google.ml",
+ "google.mn",
+ "google.ms",
+ "google.com.mt",
+ "google.mu",
+ "google.mv",
+ "google.mw",
+ "google.com.mx",
+ "google.com.my",
+ "google.co.mz",
+ "google.com.na",
+ "google.ne",
+ "google.com.nf",
+ "google.com.ng",
+ "google.com.ni",
+ "google.nl",
+ "google.no",
+ "google.com.np",
+ "google.nr",
+ "google.nu",
+ "google.co.nz",
+ "google.com.om",
+ "google.com.pa",
+ "google.com.pe",
+ "google.com.ph",
+ "google.com.pk",
+ "google.pl",
+ "google.pn",
+ "google.com.pr",
+ "google.ps",
+ "google.pt",
+ "google.com.py",
+ "google.com.qa",
+ "google.ro",
+ "google.rs",
+ "google.ru",
+ "google.rw",
+ "google.com.sa",
+ "google.com.sb",
+ "google.sc",
+ "google.se",
+ "google.com.sg",
+ "google.sh",
+ "google.si",
+ "google.sk",
+ "google.com.sl",
+ "google.sn",
+ "google.sm",
+ "google.so",
+ "google.st",
+ "google.com.sv",
+ "google.td",
+ "google.tg",
+ "google.tn",
+ "google.co.th",
+ "google.com.tj",
+ "google.tk",
+ "google.tl",
+ "google.tm",
+ "google.to",
+ "google.com.tn",
+ "google.com.tr",
+ "google.tt",
+ "google.com.tw",
+ "google.co.tz",
+ "google.com.ua",
+ "google.co.ug",
+ "google.ae",
+ "google.co.uk",
+ "google.us",
+ "google.com.uy",
+ "google.co.uz",
+ "google.com.vc",
+ "google.co.ve",
+ "google.vg",
+ "google.co.vi",
+ "google.com.vn",
+ "google.vu",
+ "google.ws",
+ "google.co.za",
+ "google.co.zm",
+ "google.co.zw",
+ "search.avg.com",
+ "isearch.avg.com",
+ "www.cnn.com",
+ "darkoogle.com",
+ "search.darkoogle.com",
+ "search.foxtab.com",
+ "www.gooofullsearch.com",
+ "search.hiyo.com",
+ "search.incredimail.com",
+ "search1.incredimail.com",
+ "search2.incredimail.com",
+ "search3.incredimail.com",
+ "search4.incredimail.com",
+ "search.incredibar.com",
+ "search.sweetim.com",
+ "www.fastweb.it",
+ "search.juno.com",
+ "find.tdc.dk",
+ "searchresults.verizon.com",
+ "search.walla.co.il",
+ "search.alot.com",
+ "www.googleearth.de",
+ "www.googleearth.fr",
+ "webcache.googleusercontent.com",
+ "encrypted.google.com",
+ "googlesyndicatedsearch.com",
+ "www.googleadservices.com"
+ ],
+ "parameters": [
+ "q",
+ "query",
+ "Keywords",
+ "*"
+ ]
+ },
+ "Google Blogsearch": {
+ "domains": [
+ "blogsearch.google.ac",
+ "blogsearch.google.ad",
+ "blogsearch.google.ae",
+ "blogsearch.google.am",
+ "blogsearch.google.as",
+ "blogsearch.google.at",
+ "blogsearch.google.az",
+ "blogsearch.google.ba",
+ "blogsearch.google.be",
+ "blogsearch.google.bf",
+ "blogsearch.google.bg",
+ "blogsearch.google.bi",
+ "blogsearch.google.bj",
+ "blogsearch.google.bs",
+ "blogsearch.google.by",
+ "blogsearch.google.ca",
+ "blogsearch.google.cat",
+ "blogsearch.google.cc",
+ "blogsearch.google.cd",
+ "blogsearch.google.cf",
+ "blogsearch.google.cg",
+ "blogsearch.google.ch",
+ "blogsearch.google.ci",
+ "blogsearch.google.cl",
+ "blogsearch.google.cm",
+ "blogsearch.google.cn",
+ "blogsearch.google.co.bw",
+ "blogsearch.google.co.ck",
+ "blogsearch.google.co.cr",
+ "blogsearch.google.co.id",
+ "blogsearch.google.co.il",
+ "blogsearch.google.co.in",
+ "blogsearch.google.co.jp",
+ "blogsearch.google.co.ke",
+ "blogsearch.google.co.kr",
+ "blogsearch.google.co.ls",
+ "blogsearch.google.co.ma",
+ "blogsearch.google.co.mz",
+ "blogsearch.google.co.nz",
+ "blogsearch.google.co.th",
+ "blogsearch.google.co.tz",
+ "blogsearch.google.co.ug",
+ "blogsearch.google.co.uk",
+ "blogsearch.google.co.uz",
+ "blogsearch.google.co.ve",
+ "blogsearch.google.co.vi",
+ "blogsearch.google.co.za",
+ "blogsearch.google.co.zm",
+ "blogsearch.google.co.zw",
+ "blogsearch.google.com",
+ "blogsearch.google.com.af",
+ "blogsearch.google.com.ag",
+ "blogsearch.google.com.ai",
+ "blogsearch.google.com.ar",
+ "blogsearch.google.com.au",
+ "blogsearch.google.com.bd",
+ "blogsearch.google.com.bh",
+ "blogsearch.google.com.bn",
+ "blogsearch.google.com.bo",
+ "blogsearch.google.com.br",
+ "blogsearch.google.com.by",
+ "blogsearch.google.com.bz",
+ "blogsearch.google.com.co",
+ "blogsearch.google.com.cu",
+ "blogsearch.google.com.cy",
+ "blogsearch.google.com.do",
+ "blogsearch.google.com.ec",
+ "blogsearch.google.com.eg",
+ "blogsearch.google.com.et",
+ "blogsearch.google.com.fj",
+ "blogsearch.google.com.gh",
+ "blogsearch.google.com.gi",
+ "blogsearch.google.com.gt",
+ "blogsearch.google.com.hk",
+ "blogsearch.google.com.jm",
+ "blogsearch.google.com.kh",
+ "blogsearch.google.com.kh",
+ "blogsearch.google.com.kw",
+ "blogsearch.google.com.lb",
+ "blogsearch.google.com.lc",
+ "blogsearch.google.com.ly",
+ "blogsearch.google.com.mt",
+ "blogsearch.google.com.mx",
+ "blogsearch.google.com.my",
+ "blogsearch.google.com.na",
+ "blogsearch.google.com.nf",
+ "blogsearch.google.com.ng",
+ "blogsearch.google.com.ni",
+ "blogsearch.google.com.np",
+ "blogsearch.google.com.om",
+ "blogsearch.google.com.pa",
+ "blogsearch.google.com.pe",
+ "blogsearch.google.com.ph",
+ "blogsearch.google.com.pk",
+ "blogsearch.google.com.pr",
+ "blogsearch.google.com.py",
+ "blogsearch.google.com.qa",
+ "blogsearch.google.com.sa",
+ "blogsearch.google.com.sb",
+ "blogsearch.google.com.sg",
+ "blogsearch.google.com.sl",
+ "blogsearch.google.com.sv",
+ "blogsearch.google.com.tj",
+ "blogsearch.google.com.tn",
+ "blogsearch.google.com.tr",
+ "blogsearch.google.com.tw",
+ "blogsearch.google.com.ua",
+ "blogsearch.google.com.uy",
+ "blogsearch.google.com.vc",
+ "blogsearch.google.com.vn",
+ "blogsearch.google.cv",
+ "blogsearch.google.cz",
+ "blogsearch.google.de",
+ "blogsearch.google.dj",
+ "blogsearch.google.dk",
+ "blogsearch.google.dm",
+ "blogsearch.google.dz",
+ "blogsearch.google.ee",
+ "blogsearch.google.es",
+ "blogsearch.google.fi",
+ "blogsearch.google.fm",
+ "blogsearch.google.fr",
+ "blogsearch.google.ga",
+ "blogsearch.google.gd",
+ "blogsearch.google.ge",
+ "blogsearch.google.gf",
+ "blogsearch.google.gg",
+ "blogsearch.google.gl",
+ "blogsearch.google.gm",
+ "blogsearch.google.gp",
+ "blogsearch.google.gr",
+ "blogsearch.google.gy",
+ "blogsearch.google.hn",
+ "blogsearch.google.hr",
+ "blogsearch.google.ht",
+ "blogsearch.google.hu",
+ "blogsearch.google.ie",
+ "blogsearch.google.im",
+ "blogsearch.google.io",
+ "blogsearch.google.iq",
+ "blogsearch.google.is",
+ "blogsearch.google.it",
+ "blogsearch.google.it.ao",
+ "blogsearch.google.je",
+ "blogsearch.google.jo",
+ "blogsearch.google.kg",
+ "blogsearch.google.ki",
+ "blogsearch.google.kz",
+ "blogsearch.google.la",
+ "blogsearch.google.li",
+ "blogsearch.google.lk",
+ "blogsearch.google.lt",
+ "blogsearch.google.lu",
+ "blogsearch.google.lv",
+ "blogsearch.google.md",
+ "blogsearch.google.me",
+ "blogsearch.google.mg",
+ "blogsearch.google.mk",
+ "blogsearch.google.ml",
+ "blogsearch.google.mn",
+ "blogsearch.google.ms",
+ "blogsearch.google.mu",
+ "blogsearch.google.mv",
+ "blogsearch.google.mw",
+ "blogsearch.google.ne",
+ "blogsearch.google.nl",
+ "blogsearch.google.no",
+ "blogsearch.google.nr",
+ "blogsearch.google.nu",
+ "blogsearch.google.pl",
+ "blogsearch.google.pn",
+ "blogsearch.google.ps",
+ "blogsearch.google.pt",
+ "blogsearch.google.ro",
+ "blogsearch.google.rs",
+ "blogsearch.google.ru",
+ "blogsearch.google.rw",
+ "blogsearch.google.sc",
+ "blogsearch.google.se",
+ "blogsearch.google.sh",
+ "blogsearch.google.si",
+ "blogsearch.google.sk",
+ "blogsearch.google.sm",
+ "blogsearch.google.sn",
+ "blogsearch.google.so",
+ "blogsearch.google.st",
+ "blogsearch.google.td",
+ "blogsearch.google.tg",
+ "blogsearch.google.tk",
+ "blogsearch.google.tl",
+ "blogsearch.google.tm",
+ "blogsearch.google.to",
+ "blogsearch.google.tt",
+ "blogsearch.google.us",
+ "blogsearch.google.vg",
+ "blogsearch.google.vu",
+ "blogsearch.google.ws"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Google Images": {
+ "domains": [
+ "google.ac/imgres",
+ "google.ad/imgres",
+ "google.ae/imgres",
+ "google.am/imgres",
+ "google.as/imgres",
+ "google.at/imgres",
+ "google.az/imgres",
+ "google.ba/imgres",
+ "google.be/imgres",
+ "google.bf/imgres",
+ "google.bg/imgres",
+ "google.bi/imgres",
+ "google.bj/imgres",
+ "google.bs/imgres",
+ "google.by/imgres",
+ "google.ca/imgres",
+ "google.cat/imgres",
+ "google.cc/imgres",
+ "google.cd/imgres",
+ "google.cf/imgres",
+ "google.cg/imgres",
+ "google.ch/imgres",
+ "google.ci/imgres",
+ "google.cl/imgres",
+ "google.cm/imgres",
+ "google.cn/imgres",
+ "google.co.bw/imgres",
+ "google.co.ck/imgres",
+ "google.co.cr/imgres",
+ "google.co.id/imgres",
+ "google.co.il/imgres",
+ "google.co.in/imgres",
+ "google.co.jp/imgres",
+ "google.co.ke/imgres",
+ "google.co.kr/imgres",
+ "google.co.ls/imgres",
+ "google.co.ma/imgres",
+ "google.co.mz/imgres",
+ "google.co.nz/imgres",
+ "google.co.th/imgres",
+ "google.co.tz/imgres",
+ "google.co.ug/imgres",
+ "google.co.uk/imgres",
+ "google.co.uz/imgres",
+ "google.co.ve/imgres",
+ "google.co.vi/imgres",
+ "google.co.za/imgres",
+ "google.co.zm/imgres",
+ "google.co.zw/imgres",
+ "google.com/imgres",
+ "google.com.af/imgres",
+ "google.com.ag/imgres",
+ "google.com.ai/imgres",
+ "google.com.ar/imgres",
+ "google.com.au/imgres",
+ "google.com.bd/imgres",
+ "google.com.bh/imgres",
+ "google.com.bn/imgres",
+ "google.com.bo/imgres",
+ "google.com.br/imgres",
+ "google.com.by/imgres",
+ "google.com.bz/imgres",
+ "google.com.co/imgres",
+ "google.com.cu/imgres",
+ "google.com.cy/imgres",
+ "google.com.do/imgres",
+ "google.com.ec/imgres",
+ "google.com.eg/imgres",
+ "google.com.et/imgres",
+ "google.com.fj/imgres",
+ "google.com.gh/imgres",
+ "google.com.gi/imgres",
+ "google.com.gt/imgres",
+ "google.com.hk/imgres",
+ "google.com.jm/imgres",
+ "google.com.kh/imgres",
+ "google.com.kh/imgres",
+ "google.com.kw/imgres",
+ "google.com.lb/imgres",
+ "google.com.lc/imgres",
+ "google.com.ly/imgres",
+ "google.com.mt/imgres",
+ "google.com.mx/imgres",
+ "google.com.my/imgres",
+ "google.com.na/imgres",
+ "google.com.nf/imgres",
+ "google.com.ng/imgres",
+ "google.com.ni/imgres",
+ "google.com.np/imgres",
+ "google.com.om/imgres",
+ "google.com.pa/imgres",
+ "google.com.pe/imgres",
+ "google.com.ph/imgres",
+ "google.com.pk/imgres",
+ "google.com.pr/imgres",
+ "google.com.py/imgres",
+ "google.com.qa/imgres",
+ "google.com.sa/imgres",
+ "google.com.sb/imgres",
+ "google.com.sg/imgres",
+ "google.com.sl/imgres",
+ "google.com.sv/imgres",
+ "google.com.tj/imgres",
+ "google.com.tn/imgres",
+ "google.com.tr/imgres",
+ "google.com.tw/imgres",
+ "google.com.ua/imgres",
+ "google.com.uy/imgres",
+ "google.com.vc/imgres",
+ "google.com.vn/imgres",
+ "google.cv/imgres",
+ "google.cz/imgres",
+ "google.de/imgres",
+ "google.dj/imgres",
+ "google.dk/imgres",
+ "google.dm/imgres",
+ "google.dz/imgres",
+ "google.ee/imgres",
+ "google.es/imgres",
+ "google.fi/imgres",
+ "google.fm/imgres",
+ "google.fr/imgres",
+ "google.ga/imgres",
+ "google.gd/imgres",
+ "google.ge/imgres",
+ "google.gf/imgres",
+ "google.gg/imgres",
+ "google.gl/imgres",
+ "google.gm/imgres",
+ "google.gp/imgres",
+ "google.gr/imgres",
+ "google.gy/imgres",
+ "google.hn/imgres",
+ "google.hr/imgres",
+ "google.ht/imgres",
+ "google.hu/imgres",
+ "google.ie/imgres",
+ "google.im/imgres",
+ "google.io/imgres",
+ "google.iq/imgres",
+ "google.is/imgres",
+ "google.it/imgres",
+ "google.it.ao/imgres",
+ "google.je/imgres",
+ "google.jo/imgres",
+ "google.kg/imgres",
+ "google.ki/imgres",
+ "google.kz/imgres",
+ "google.la/imgres",
+ "google.li/imgres",
+ "google.lk/imgres",
+ "google.lt/imgres",
+ "google.lu/imgres",
+ "google.lv/imgres",
+ "google.md/imgres",
+ "google.me/imgres",
+ "google.mg/imgres",
+ "google.mk/imgres",
+ "google.ml/imgres",
+ "google.mn/imgres",
+ "google.ms/imgres",
+ "google.mu/imgres",
+ "google.mv/imgres",
+ "google.mw/imgres",
+ "google.ne/imgres",
+ "google.nl/imgres",
+ "google.no/imgres",
+ "google.nr/imgres",
+ "google.nu/imgres",
+ "google.pl/imgres",
+ "google.pn/imgres",
+ "google.ps/imgres",
+ "google.pt/imgres",
+ "google.ro/imgres",
+ "google.rs/imgres",
+ "google.ru/imgres",
+ "google.rw/imgres",
+ "google.sc/imgres",
+ "google.se/imgres",
+ "google.sh/imgres",
+ "google.si/imgres",
+ "google.sk/imgres",
+ "google.sm/imgres",
+ "google.sn/imgres",
+ "google.so/imgres",
+ "google.st/imgres",
+ "google.td/imgres",
+ "google.tg/imgres",
+ "google.tk/imgres",
+ "google.tl/imgres",
+ "google.tm/imgres",
+ "google.to/imgres",
+ "google.tt/imgres",
+ "google.us/imgres",
+ "google.vg/imgres",
+ "google.vu/imgres",
+ "images.google.ws",
+ "images.google.ac",
+ "images.google.ad",
+ "images.google.ae",
+ "images.google.am",
+ "images.google.as",
+ "images.google.at",
+ "images.google.az",
+ "images.google.ba",
+ "images.google.be",
+ "images.google.bf",
+ "images.google.bg",
+ "images.google.bi",
+ "images.google.bj",
+ "images.google.bs",
+ "images.google.by",
+ "images.google.ca",
+ "images.google.cat",
+ "images.google.cc",
+ "images.google.cd",
+ "images.google.cf",
+ "images.google.cg",
+ "images.google.ch",
+ "images.google.ci",
+ "images.google.cl",
+ "images.google.cm",
+ "images.google.cn",
+ "images.google.co.bw",
+ "images.google.co.ck",
+ "images.google.co.cr",
+ "images.google.co.id",
+ "images.google.co.il",
+ "images.google.co.in",
+ "images.google.co.jp",
+ "images.google.co.ke",
+ "images.google.co.kr",
+ "images.google.co.ls",
+ "images.google.co.ma",
+ "images.google.co.mz",
+ "images.google.co.nz",
+ "images.google.co.th",
+ "images.google.co.tz",
+ "images.google.co.ug",
+ "images.google.co.uk",
+ "images.google.co.uz",
+ "images.google.co.ve",
+ "images.google.co.vi",
+ "images.google.co.za",
+ "images.google.co.zm",
+ "images.google.co.zw",
+ "images.google.com",
+ "images.google.com.af",
+ "images.google.com.ag",
+ "images.google.com.ai",
+ "images.google.com.ar",
+ "images.google.com.au",
+ "images.google.com.bd",
+ "images.google.com.bh",
+ "images.google.com.bn",
+ "images.google.com.bo",
+ "images.google.com.br",
+ "images.google.com.by",
+ "images.google.com.bz",
+ "images.google.com.co",
+ "images.google.com.cu",
+ "images.google.com.cy",
+ "images.google.com.do",
+ "images.google.com.ec",
+ "images.google.com.eg",
+ "images.google.com.et",
+ "images.google.com.fj",
+ "images.google.com.gh",
+ "images.google.com.gi",
+ "images.google.com.gt",
+ "images.google.com.hk",
+ "images.google.com.jm",
+ "images.google.com.kh",
+ "images.google.com.kh",
+ "images.google.com.kw",
+ "images.google.com.lb",
+ "images.google.com.lc",
+ "images.google.com.ly",
+ "images.google.com.mt",
+ "images.google.com.mx",
+ "images.google.com.my",
+ "images.google.com.na",
+ "images.google.com.nf",
+ "images.google.com.ng",
+ "images.google.com.ni",
+ "images.google.com.np",
+ "images.google.com.om",
+ "images.google.com.pa",
+ "images.google.com.pe",
+ "images.google.com.ph",
+ "images.google.com.pk",
+ "images.google.com.pr",
+ "images.google.com.py",
+ "images.google.com.qa",
+ "images.google.com.sa",
+ "images.google.com.sb",
+ "images.google.com.sg",
+ "images.google.com.sl",
+ "images.google.com.sv",
+ "images.google.com.tj",
+ "images.google.com.tn",
+ "images.google.com.tr",
+ "images.google.com.tw",
+ "images.google.com.ua",
+ "images.google.com.uy",
+ "images.google.com.vc",
+ "images.google.com.vn",
+ "images.google.cv",
+ "images.google.cz",
+ "images.google.de",
+ "images.google.dj",
+ "images.google.dk",
+ "images.google.dm",
+ "images.google.dz",
+ "images.google.ee",
+ "images.google.es",
+ "images.google.fi",
+ "images.google.fm",
+ "images.google.fr",
+ "images.google.ga",
+ "images.google.gd",
+ "images.google.ge",
+ "images.google.gf",
+ "images.google.gg",
+ "images.google.gl",
+ "images.google.gm",
+ "images.google.gp",
+ "images.google.gr",
+ "images.google.gy",
+ "images.google.hn",
+ "images.google.hr",
+ "images.google.ht",
+ "images.google.hu",
+ "images.google.ie",
+ "images.google.im",
+ "images.google.io",
+ "images.google.iq",
+ "images.google.is",
+ "images.google.it",
+ "images.google.it.ao",
+ "images.google.je",
+ "images.google.jo",
+ "images.google.kg",
+ "images.google.ki",
+ "images.google.kz",
+ "images.google.la",
+ "images.google.li",
+ "images.google.lk",
+ "images.google.lt",
+ "images.google.lu",
+ "images.google.lv",
+ "images.google.md",
+ "images.google.me",
+ "images.google.mg",
+ "images.google.mk",
+ "images.google.ml",
+ "images.google.mn",
+ "images.google.ms",
+ "images.google.mu",
+ "images.google.mv",
+ "images.google.mw",
+ "images.google.ne",
+ "images.google.nl",
+ "images.google.no",
+ "images.google.nr",
+ "images.google.nu",
+ "images.google.pl",
+ "images.google.pn",
+ "images.google.ps",
+ "images.google.pt",
+ "images.google.ro",
+ "images.google.rs",
+ "images.google.ru",
+ "images.google.rw",
+ "images.google.sc",
+ "images.google.se",
+ "images.google.sh",
+ "images.google.si",
+ "images.google.sk",
+ "images.google.sm",
+ "images.google.sn",
+ "images.google.so",
+ "images.google.st",
+ "images.google.td",
+ "images.google.tg",
+ "images.google.tk",
+ "images.google.tl",
+ "images.google.tm",
+ "images.google.to",
+ "images.google.tt",
+ "images.google.us",
+ "images.google.vg",
+ "images.google.vu",
+ "images.google.ws"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Google News": {
+ "domains": [
+ "news.google.ac",
+ "news.google.ad",
+ "news.google.ae",
+ "news.google.am",
+ "news.google.as",
+ "news.google.at",
+ "news.google.az",
+ "news.google.ba",
+ "news.google.be",
+ "news.google.bf",
+ "news.google.bg",
+ "news.google.bi",
+ "news.google.bj",
+ "news.google.bs",
+ "news.google.by",
+ "news.google.ca",
+ "news.google.cat",
+ "news.google.cc",
+ "news.google.cd",
+ "news.google.cf",
+ "news.google.cg",
+ "news.google.ch",
+ "news.google.ci",
+ "news.google.cl",
+ "news.google.cm",
+ "news.google.cn",
+ "news.google.co.bw",
+ "news.google.co.ck",
+ "news.google.co.cr",
+ "news.google.co.id",
+ "news.google.co.il",
+ "news.google.co.in",
+ "news.google.co.jp",
+ "news.google.co.ke",
+ "news.google.co.kr",
+ "news.google.co.ls",
+ "news.google.co.ma",
+ "news.google.co.mz",
+ "news.google.co.nz",
+ "news.google.co.th",
+ "news.google.co.tz",
+ "news.google.co.ug",
+ "news.google.co.uk",
+ "news.google.co.uz",
+ "news.google.co.ve",
+ "news.google.co.vi",
+ "news.google.co.za",
+ "news.google.co.zm",
+ "news.google.co.zw",
+ "news.google.com",
+ "news.google.com.af",
+ "news.google.com.ag",
+ "news.google.com.ai",
+ "news.google.com.ar",
+ "news.google.com.au",
+ "news.google.com.bd",
+ "news.google.com.bh",
+ "news.google.com.bn",
+ "news.google.com.bo",
+ "news.google.com.br",
+ "news.google.com.by",
+ "news.google.com.bz",
+ "news.google.com.co",
+ "news.google.com.cu",
+ "news.google.com.cy",
+ "news.google.com.do",
+ "news.google.com.ec",
+ "news.google.com.eg",
+ "news.google.com.et",
+ "news.google.com.fj",
+ "news.google.com.gh",
+ "news.google.com.gi",
+ "news.google.com.gt",
+ "news.google.com.hk",
+ "news.google.com.jm",
+ "news.google.com.kh",
+ "news.google.com.kh",
+ "news.google.com.kw",
+ "news.google.com.lb",
+ "news.google.com.lc",
+ "news.google.com.ly",
+ "news.google.com.mt",
+ "news.google.com.mx",
+ "news.google.com.my",
+ "news.google.com.na",
+ "news.google.com.nf",
+ "news.google.com.ng",
+ "news.google.com.ni",
+ "news.google.com.np",
+ "news.google.com.om",
+ "news.google.com.pa",
+ "news.google.com.pe",
+ "news.google.com.ph",
+ "news.google.com.pk",
+ "news.google.com.pr",
+ "news.google.com.py",
+ "news.google.com.qa",
+ "news.google.com.sa",
+ "news.google.com.sb",
+ "news.google.com.sg",
+ "news.google.com.sl",
+ "news.google.com.sv",
+ "news.google.com.tj",
+ "news.google.com.tn",
+ "news.google.com.tr",
+ "news.google.com.tw",
+ "news.google.com.ua",
+ "news.google.com.uy",
+ "news.google.com.vc",
+ "news.google.com.vn",
+ "news.google.cv",
+ "news.google.cz",
+ "news.google.de",
+ "news.google.dj",
+ "news.google.dk",
+ "news.google.dm",
+ "news.google.dz",
+ "news.google.ee",
+ "news.google.es",
+ "news.google.fi",
+ "news.google.fm",
+ "news.google.fr",
+ "news.google.ga",
+ "news.google.gd",
+ "news.google.ge",
+ "news.google.gf",
+ "news.google.gg",
+ "news.google.gl",
+ "news.google.gm",
+ "news.google.gp",
+ "news.google.gr",
+ "news.google.gy",
+ "news.google.hn",
+ "news.google.hr",
+ "news.google.ht",
+ "news.google.hu",
+ "news.google.ie",
+ "news.google.im",
+ "news.google.io",
+ "news.google.iq",
+ "news.google.is",
+ "news.google.it",
+ "news.google.it.ao",
+ "news.google.je",
+ "news.google.jo",
+ "news.google.kg",
+ "news.google.ki",
+ "news.google.kz",
+ "news.google.la",
+ "news.google.li",
+ "news.google.lk",
+ "news.google.lt",
+ "news.google.lu",
+ "news.google.lv",
+ "news.google.md",
+ "news.google.me",
+ "news.google.mg",
+ "news.google.mk",
+ "news.google.ml",
+ "news.google.mn",
+ "news.google.ms",
+ "news.google.mu",
+ "news.google.mv",
+ "news.google.mw",
+ "news.google.ne",
+ "news.google.nl",
+ "news.google.no",
+ "news.google.nr",
+ "news.google.nu",
+ "news.google.pl",
+ "news.google.pn",
+ "news.google.ps",
+ "news.google.pt",
+ "news.google.ro",
+ "news.google.rs",
+ "news.google.ru",
+ "news.google.rw",
+ "news.google.sc",
+ "news.google.se",
+ "news.google.sh",
+ "news.google.si",
+ "news.google.sk",
+ "news.google.sm",
+ "news.google.sn",
+ "news.google.so",
+ "news.google.st",
+ "news.google.td",
+ "news.google.tg",
+ "news.google.tk",
+ "news.google.tl",
+ "news.google.tm",
+ "news.google.to",
+ "news.google.tt",
+ "news.google.us",
+ "news.google.vg",
+ "news.google.vu",
+ "news.google.ws"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Google Product Search": {
+ "domains": [
+ "google.ac/products",
+ "google.ad/products",
+ "google.ae/products",
+ "google.am/products",
+ "google.as/products",
+ "google.at/products",
+ "google.az/products",
+ "google.ba/products",
+ "google.be/products",
+ "google.bf/products",
+ "google.bg/products",
+ "google.bi/products",
+ "google.bj/products",
+ "google.bs/products",
+ "google.by/products",
+ "google.ca/products",
+ "google.cat/products",
+ "google.cc/products",
+ "google.cd/products",
+ "google.cf/products",
+ "google.cg/products",
+ "google.ch/products",
+ "google.ci/products",
+ "google.cl/products",
+ "google.cm/products",
+ "google.cn/products",
+ "google.co.bw/products",
+ "google.co.ck/products",
+ "google.co.cr/products",
+ "google.co.id/products",
+ "google.co.il/products",
+ "google.co.in/products",
+ "google.co.jp/products",
+ "google.co.ke/products",
+ "google.co.kr/products",
+ "google.co.ls/products",
+ "google.co.ma/products",
+ "google.co.mz/products",
+ "google.co.nz/products",
+ "google.co.th/products",
+ "google.co.tz/products",
+ "google.co.ug/products",
+ "google.co.uk/products",
+ "google.co.uz/products",
+ "google.co.ve/products",
+ "google.co.vi/products",
+ "google.co.za/products",
+ "google.co.zm/products",
+ "google.co.zw/products",
+ "google.com/products",
+ "google.com.af/products",
+ "google.com.ag/products",
+ "google.com.ai/products",
+ "google.com.ar/products",
+ "google.com.au/products",
+ "google.com.bd/products",
+ "google.com.bh/products",
+ "google.com.bn/products",
+ "google.com.bo/products",
+ "google.com.br/products",
+ "google.com.by/products",
+ "google.com.bz/products",
+ "google.com.co/products",
+ "google.com.cu/products",
+ "google.com.cy/products",
+ "google.com.do/products",
+ "google.com.ec/products",
+ "google.com.eg/products",
+ "google.com.et/products",
+ "google.com.fj/products",
+ "google.com.gh/products",
+ "google.com.gi/products",
+ "google.com.gt/products",
+ "google.com.hk/products",
+ "google.com.jm/products",
+ "google.com.kh/products",
+ "google.com.kh/products",
+ "google.com.kw/products",
+ "google.com.lb/products",
+ "google.com.lc/products",
+ "google.com.ly/products",
+ "google.com.mt/products",
+ "google.com.mx/products",
+ "google.com.my/products",
+ "google.com.na/products",
+ "google.com.nf/products",
+ "google.com.ng/products",
+ "google.com.ni/products",
+ "google.com.np/products",
+ "google.com.om/products",
+ "google.com.pa/products",
+ "google.com.pe/products",
+ "google.com.ph/products",
+ "google.com.pk/products",
+ "google.com.pr/products",
+ "google.com.py/products",
+ "google.com.qa/products",
+ "google.com.sa/products",
+ "google.com.sb/products",
+ "google.com.sg/products",
+ "google.com.sl/products",
+ "google.com.sv/products",
+ "google.com.tj/products",
+ "google.com.tn/products",
+ "google.com.tr/products",
+ "google.com.tw/products",
+ "google.com.ua/products",
+ "google.com.uy/products",
+ "google.com.vc/products",
+ "google.com.vn/products",
+ "google.cv/products",
+ "google.cz/products",
+ "google.de/products",
+ "google.dj/products",
+ "google.dk/products",
+ "google.dm/products",
+ "google.dz/products",
+ "google.ee/products",
+ "google.es/products",
+ "google.fi/products",
+ "google.fm/products",
+ "google.fr/products",
+ "google.ga/products",
+ "google.gd/products",
+ "google.ge/products",
+ "google.gf/products",
+ "google.gg/products",
+ "google.gl/products",
+ "google.gm/products",
+ "google.gp/products",
+ "google.gr/products",
+ "google.gy/products",
+ "google.hn/products",
+ "google.hr/products",
+ "google.ht/products",
+ "google.hu/products",
+ "google.ie/products",
+ "google.im/products",
+ "google.io/products",
+ "google.iq/products",
+ "google.is/products",
+ "google.it/products",
+ "google.it.ao/products",
+ "google.je/products",
+ "google.jo/products",
+ "google.kg/products",
+ "google.ki/products",
+ "google.kz/products",
+ "google.la/products",
+ "google.li/products",
+ "google.lk/products",
+ "google.lt/products",
+ "google.lu/products",
+ "google.lv/products",
+ "google.md/products",
+ "google.me/products",
+ "google.mg/products",
+ "google.mk/products",
+ "google.ml/products",
+ "google.mn/products",
+ "google.ms/products",
+ "google.mu/products",
+ "google.mv/products",
+ "google.mw/products",
+ "google.ne/products",
+ "google.nl/products",
+ "google.no/products",
+ "google.nr/products",
+ "google.nu/products",
+ "google.pl/products",
+ "google.pn/products",
+ "google.ps/products",
+ "google.pt/products",
+ "google.ro/products",
+ "google.rs/products",
+ "google.ru/products",
+ "google.rw/products",
+ "google.sc/products",
+ "google.se/products",
+ "google.sh/products",
+ "google.si/products",
+ "google.sk/products",
+ "google.sm/products",
+ "google.sn/products",
+ "google.so/products",
+ "google.st/products",
+ "google.td/products",
+ "google.tg/products",
+ "google.tk/products",
+ "google.tl/products",
+ "google.tm/products",
+ "google.to/products",
+ "google.tt/products",
+ "google.us/products",
+ "google.vg/products",
+ "google.vu/products",
+ "google.ws/products",
+ "www.google.ac/products",
+ "www.google.ad/products",
+ "www.google.ae/products",
+ "www.google.am/products",
+ "www.google.as/products",
+ "www.google.at/products",
+ "www.google.az/products",
+ "www.google.ba/products",
+ "www.google.be/products",
+ "www.google.bf/products",
+ "www.google.bg/products",
+ "www.google.bi/products",
+ "www.google.bj/products",
+ "www.google.bs/products",
+ "www.google.by/products",
+ "www.google.ca/products",
+ "www.google.cat/products",
+ "www.google.cc/products",
+ "www.google.cd/products",
+ "www.google.cf/products",
+ "www.google.cg/products",
+ "www.google.ch/products",
+ "www.google.ci/products",
+ "www.google.cl/products",
+ "www.google.cm/products",
+ "www.google.cn/products",
+ "www.google.co.bw/products",
+ "www.google.co.ck/products",
+ "www.google.co.cr/products",
+ "www.google.co.id/products",
+ "www.google.co.il/products",
+ "www.google.co.in/products",
+ "www.google.co.jp/products",
+ "www.google.co.ke/products",
+ "www.google.co.kr/products",
+ "www.google.co.ls/products",
+ "www.google.co.ma/products",
+ "www.google.co.mz/products",
+ "www.google.co.nz/products",
+ "www.google.co.th/products",
+ "www.google.co.tz/products",
+ "www.google.co.ug/products",
+ "www.google.co.uk/products",
+ "www.google.co.uz/products",
+ "www.google.co.ve/products",
+ "www.google.co.vi/products",
+ "www.google.co.za/products",
+ "www.google.co.zm/products",
+ "www.google.co.zw/products",
+ "www.google.com/products",
+ "www.google.com.af/products",
+ "www.google.com.ag/products",
+ "www.google.com.ai/products",
+ "www.google.com.ar/products",
+ "www.google.com.au/products",
+ "www.google.com.bd/products",
+ "www.google.com.bh/products",
+ "www.google.com.bn/products",
+ "www.google.com.bo/products",
+ "www.google.com.br/products",
+ "www.google.com.by/products",
+ "www.google.com.bz/products",
+ "www.google.com.co/products",
+ "www.google.com.cu/products",
+ "www.google.com.cy/products",
+ "www.google.com.do/products",
+ "www.google.com.ec/products",
+ "www.google.com.eg/products",
+ "www.google.com.et/products",
+ "www.google.com.fj/products",
+ "www.google.com.gh/products",
+ "www.google.com.gi/products",
+ "www.google.com.gt/products",
+ "www.google.com.hk/products",
+ "www.google.com.jm/products",
+ "www.google.com.kh/products",
+ "www.google.com.kh/products",
+ "www.google.com.kw/products",
+ "www.google.com.lb/products",
+ "www.google.com.lc/products",
+ "www.google.com.ly/products",
+ "www.google.com.mt/products",
+ "www.google.com.mx/products",
+ "www.google.com.my/products",
+ "www.google.com.na/products",
+ "www.google.com.nf/products",
+ "www.google.com.ng/products",
+ "www.google.com.ni/products",
+ "www.google.com.np/products",
+ "www.google.com.om/products",
+ "www.google.com.pa/products",
+ "www.google.com.pe/products",
+ "www.google.com.ph/products",
+ "www.google.com.pk/products",
+ "www.google.com.pr/products",
+ "www.google.com.py/products",
+ "www.google.com.qa/products",
+ "www.google.com.sa/products",
+ "www.google.com.sb/products",
+ "www.google.com.sg/products",
+ "www.google.com.sl/products",
+ "www.google.com.sv/products",
+ "www.google.com.tj/products",
+ "www.google.com.tn/products",
+ "www.google.com.tr/products",
+ "www.google.com.tw/products",
+ "www.google.com.ua/products",
+ "www.google.com.uy/products",
+ "www.google.com.vc/products",
+ "www.google.com.vn/products",
+ "www.google.cv/products",
+ "www.google.cz/products",
+ "www.google.de/products",
+ "www.google.dj/products",
+ "www.google.dk/products",
+ "www.google.dm/products",
+ "www.google.dz/products",
+ "www.google.ee/products",
+ "www.google.es/products",
+ "www.google.fi/products",
+ "www.google.fm/products",
+ "www.google.fr/products",
+ "www.google.ga/products",
+ "www.google.gd/products",
+ "www.google.ge/products",
+ "www.google.gf/products",
+ "www.google.gg/products",
+ "www.google.gl/products",
+ "www.google.gm/products",
+ "www.google.gp/products",
+ "www.google.gr/products",
+ "www.google.gy/products",
+ "www.google.hn/products",
+ "www.google.hr/products",
+ "www.google.ht/products",
+ "www.google.hu/products",
+ "www.google.ie/products",
+ "www.google.im/products",
+ "www.google.io/products",
+ "www.google.iq/products",
+ "www.google.is/products",
+ "www.google.it/products",
+ "www.google.it.ao/products",
+ "www.google.je/products",
+ "www.google.jo/products",
+ "www.google.kg/products",
+ "www.google.ki/products",
+ "www.google.kz/products",
+ "www.google.la/products",
+ "www.google.li/products",
+ "www.google.lk/products",
+ "www.google.lt/products",
+ "www.google.lu/products",
+ "www.google.lv/products",
+ "www.google.md/products",
+ "www.google.me/products",
+ "www.google.mg/products",
+ "www.google.mk/products",
+ "www.google.ml/products",
+ "www.google.mn/products",
+ "www.google.ms/products",
+ "www.google.mu/products",
+ "www.google.mv/products",
+ "www.google.mw/products",
+ "www.google.ne/products",
+ "www.google.nl/products",
+ "www.google.no/products",
+ "www.google.nr/products",
+ "www.google.nu/products",
+ "www.google.pl/products",
+ "www.google.pn/products",
+ "www.google.ps/products",
+ "www.google.pt/products",
+ "www.google.ro/products",
+ "www.google.rs/products",
+ "www.google.ru/products",
+ "www.google.rw/products",
+ "www.google.sc/products",
+ "www.google.se/products",
+ "www.google.sh/products",
+ "www.google.si/products",
+ "www.google.sk/products",
+ "www.google.sm/products",
+ "www.google.sn/products",
+ "www.google.so/products",
+ "www.google.st/products",
+ "www.google.td/products",
+ "www.google.tg/products",
+ "www.google.tk/products",
+ "www.google.tl/products",
+ "www.google.tm/products",
+ "www.google.to/products",
+ "www.google.tt/products",
+ "www.google.us/products",
+ "www.google.vg/products",
+ "www.google.vu/products",
+ "www.google.ws/products"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Google Video": {
+ "domains": [
+ "video.google.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Goyellow.de": {
+ "domains": [
+ "www.goyellow.de"
+ ],
+ "parameters": [
+ "MDN"
+ ]
+ },
+ "Gule Sider": {
+ "domains": [
+ "www.gulesider.no"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "HighBeam": {
+ "domains": [
+ "www.highbeam.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Hit-Parade": {
+ "domains": [
+ "req.-hit-parade.com",
+ "class.hit-parade.com",
+ "www.hit-parade.com"
+ ],
+ "parameters": [
+ "p7"
+ ]
+ },
+ "Holmes": {
+ "domains": [
+ "holmes.ge"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Hooseek.com": {
+ "domains": [
+ "www.hooseek.com"
+ ],
+ "parameters": [
+ "recherche"
+ ]
+ },
+ "Hotbot": {
+ "domains": [
+ "www.hotbot.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Haosou": {
+ "domains": [
+ "www.haosou.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "I-play": {
+ "domains": [
+ "start.iplay.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "I.ua": {
+ "domains": [
+ "search.i.ua"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "ICQ": {
+ "domains": [
+ "www.icq.com",
+ "search.icq.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "IXquick": {
+ "domains": [
+ "ixquick.com",
+ "www.eu.ixquick.com",
+ "ixquick.de",
+ "www.ixquick.de",
+ "us.ixquick.com",
+ "s1.us.ixquick.com",
+ "s2.us.ixquick.com",
+ "s3.us.ixquick.com",
+ "s4.us.ixquick.com",
+ "s5.us.ixquick.com",
+ "eu.ixquick.com",
+ "s8-eu.ixquick.com",
+ "s1-eu.ixquick.de"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Icerockeet": {
+ "domains": [
+ "blogs.icerocket.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Ilse": {
+ "domains": [
+ "www.ilse.nl"
+ ],
+ "parameters": [
+ "search_for"
+ ]
+ },
+ "InfoSpace": {
+ "domains": [
+ "infospace.com",
+ "dogpile.com",
+ "www.dogpile.com",
+ "metacrawler.com",
+ "webfetch.com",
+ "webcrawler.com",
+ "search.kiwee.com",
+ "isearch.babylon.com",
+ "start.facemoods.com",
+ "search.magnetic.com",
+ "search.searchcompletion.com",
+ "clusty.com"
+ ],
+ "parameters": [
+ "q",
+ "s"
+ ]
+ },
+ "Inbox": {
+ "domains": [
+ "inbox.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Inbox.com": {
+ "domains": [
+ "inbox.com/search/"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Info": {
+ "domains": [
+ "info.com"
+ ],
+ "parameters": [
+ "qkw"
+ ]
+ },
+ "Interia": {
+ "domains": [
+ "www.google.interia.pl"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Jungle Key": {
+ "domains": [
+ "junglekey.com",
+ "junglekey.fr"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Jungle Spider": {
+ "domains": [
+ "www.jungle-spider.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Jyxo": {
+ "domains": [
+ "jyxo.1188.cz"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Kataweb": {
+ "domains": [
+ "www.kataweb.it"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Kvasir": {
+ "domains": [
+ "www.kvasir.no"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "La Toile Du Quebec Via Google": {
+ "domains": [
+ "www.toile.com",
+ "web.toile.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Latne": {
+ "domains": [
+ "www.latne.lv"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Lo.st": {
+ "domains": [
+ "lo.st"
+ ],
+ "parameters": [
+ "x_query"
+ ]
+ },
+ "Looksmart": {
+ "domains": [
+ "www.looksmart.com"
+ ],
+ "parameters": [
+ "key"
+ ]
+ },
+ "Lycos": {
+ "domains": [
+ "search.lycos.com",
+ "www.lycos.com",
+ "lycos.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Mail.ru": {
+ "domains": [
+ "go.mail.ru"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Mamma": {
+ "domains": [
+ "www.mamma.com",
+ "mamma75.mamma.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Marktplaats": {
+ "domains": [
+ "www.marktplaats.nl"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Maxwebsearch": {
+ "domains": [
+ "maxwebsearch.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Meinestadt": {
+ "domains": [
+ "www.meinestadt.de"
+ ],
+ "parameters": [
+ "words"
+ ]
+ },
+ "Meta": {
+ "domains": [
+ "meta.ua"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "MetaCrawler.de": {
+ "domains": [
+ "s1.metacrawler.de",
+ "s2.metacrawler.de",
+ "s3.metacrawler.de"
+ ],
+ "parameters": [
+ "qry"
+ ]
+ },
+ "Metager": {
+ "domains": [
+ "meta.rrzn.uni-hannover.de",
+ "www.metager.de"
+ ],
+ "parameters": [
+ "eingabe"
+ ]
+ },
+ "Metager2": {
+ "domains": [
+ "metager2.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Mister Wong": {
+ "domains": [
+ "www.mister-wong.com",
+ "www.mister-wong.de"
+ ],
+ "parameters": [
+ "Keywords"
+ ]
+ },
+ "Monstercrawler": {
+ "domains": [
+ "www.monstercrawler.com"
+ ],
+ "parameters": [
+ "qry"
+ ]
+ },
+ "Mozbot": {
+ "domains": [
+ "www.mozbot.fr",
+ "www.mozbot.co.uk",
+ "www.mozbot.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "MySearch": {
+ "domains": [
+ "www.mysearch.com",
+ "ms114.mysearch.com",
+ "ms146.mysearch.com",
+ "kf.mysearch.myway.com",
+ "ki.mysearch.myway.com",
+ "search.myway.com",
+ "search.mywebsearch.com"
+ ],
+ "parameters": [
+ "searchfor",
+ "searchFor"
+ ]
+ },
+ "Najdi": {
+ "domains": [
+ "www.najdi.si"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Nate": {
+ "domains": [
+ "search.nate.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Naver": {
+ "domains": [
+ "search.naver.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Naver Images": {
+ "domains": [
+ "image.search.naver.com",
+ "imagesearch.naver.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Needtofind": {
+ "domains": [
+ "ko.search.need2find.com"
+ ],
+ "parameters": [
+ "searchfor"
+ ]
+ },
+ "Neti": {
+ "domains": [
+ "www.neti.ee"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Nifty": {
+ "domains": [
+ "search.nifty.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Nigma": {
+ "domains": [
+ "nigma.ru"
+ ],
+ "parameters": [
+ "s"
+ ]
+ },
+ "Onet": {
+ "domains": [
+ "szukaj.onet.pl"
+ ],
+ "parameters": [
+ "qt"
+ ]
+ },
+ "Online.no": {
+ "domains": [
+ "online.no"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Opplysningen 1881": {
+ "domains": [
+ "www.1881.no"
+ ],
+ "parameters": [
+ "Query"
+ ]
+ },
+ "Orange": {
+ "domains": [
+ "busca.orange.es",
+ "search.orange.co.uk"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Paperball": {
+ "domains": [
+ "www.paperball.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "PeoplePC": {
+ "domains": [
+ "search.peoplepc.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Picsearch": {
+ "domains": [
+ "www.picsearch.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Plazoo": {
+ "domains": [
+ "www.plazoo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Poisk.ru": {
+ "domains": [
+ "www.plazoo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "PriceRunner": {
+ "domains": [
+ "www.pricerunner.co.uk"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Qualigo": {
+ "domains": [
+ "www.qualigo.at",
+ "www.qualigo.ch",
+ "www.qualigo.de",
+ "www.qualigo.nl"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "RPMFind": {
+ "domains": [
+ "rpmfind.net",
+ "fr2.rpmfind.net"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Rakuten": {
+ "domains": [
+ "websearch.rakuten.co.jp"
+ ],
+ "parameters": [
+ "qt"
+ ]
+ },
+ "Rambler": {
+ "domains": [
+ "nova.rambler.ru"
+ ],
+ "parameters": [
+ "query",
+ "words"
+ ]
+ },
+ "Road Runner Search": {
+ "domains": [
+ "search.rr.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Sapo": {
+ "domains": [
+ "pesquisa.sapo.pt"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Search This": {
+ "domains": [
+ "www.searchthis.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Search.ch": {
+ "domains": [
+ "www.search.ch"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Search.com": {
+ "domains": [
+ "www.search.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "SearchCanvas": {
+ "domains": [
+ "www.searchcanvas.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Searchalot": {
+ "domains": [
+ "searchalot.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "SearchLock": {
+ "domains": [
+ "searchlock.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Searchy": {
+ "domains": [
+ "www.searchy.co.uk"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Seznam": {
+ "domains": [
+ "search.seznam.cz"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Sharelook": {
+ "domains": [
+ "www.sharelook.fr"
+ ],
+ "parameters": [
+ "keyword"
+ ]
+ },
+ "Skynet": {
+ "domains": [
+ "www.skynet.be"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "The Smart Search": {
+ "domains": [
+ "thesmartsearch.net",
+ "www.thesmartsearch.net"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Softonic": {
+ "domains": [
+ "search.softonic.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Sogou": {
+ "domains": [
+ "www.sogou.com",
+ "www.soso.com"
+ ],
+ "parameters": [
+ "query",
+ "w"
+ ]
+ },
+ "Startpagina": {
+ "domains": [
+ "startgoogle.startpagina.nl"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Startsiden": {
+ "domains": [
+ "www.startsiden.no"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Suchmaschine.com": {
+ "domains": [
+ "www.suchmaschine.com"
+ ],
+ "parameters": [
+ "suchstr"
+ ]
+ },
+ "Suchnase": {
+ "domains": [
+ "www.suchnase.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Superpages": {
+ "domains": [
+ "superpages.com"
+ ],
+ "parameters": [
+ "C"
+ ]
+ },
+ "T-Online": {
+ "domains": [
+ "suche.t-online.de",
+ "brisbane.t-online.de",
+ "navigationshilfe.t-online.de"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "TalkTalk": {
+ "domains": [
+ "www.talktalk.co.uk"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Technorati": {
+ "domains": [
+ "technorati.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Telstra": {
+ "domains": [
+ "search.media.telstra.com.au"
+ ],
+ "parameters": [
+ "find"
+ ]
+ },
+ "Teoma": {
+ "domains": [
+ "www.teoma.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Terra": {
+ "domains": [
+ "buscador.terra.es",
+ "buscador.terra.cl",
+ "buscador.terra.com.br"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Tiscali": {
+ "domains": [
+ "search.tiscali.it",
+ "search-dyn.tiscali.it",
+ "hledani.tiscali.cz"
+ ],
+ "parameters": [
+ "q",
+ "key"
+ ]
+ },
+ "Tixuma": {
+ "domains": [
+ "www.tixuma.de"
+ ],
+ "parameters": [
+ "sc"
+ ]
+ },
+ "Toolbarhome": {
+ "domains": [
+ "www.toolbarhome.com",
+ "vshare.toolbarhome.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Trouvez.com": {
+ "domains": [
+ "www.trouvez.com"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "TrovaRapido": {
+ "domains": [
+ "www.trovarapido.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Trusted-Search": {
+ "domains": [
+ "www.trusted--search.com"
+ ],
+ "parameters": [
+ "w"
+ ]
+ },
+ "Tut.by": {
+ "domains": [
+ "search.tut.by"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Twingly": {
+ "domains": [
+ "www.twingly.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "UKR.net": {
+ "domains": [
+ "search.ukr.net"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "URL.ORGanizier": {
+ "domains": [
+ "www.url.org"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Vinden": {
+ "domains": [
+ "www.vinden.nl"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Vindex": {
+ "domains": [
+ "www.vindex.nl",
+ "search.vindex.nl"
+ ],
+ "parameters": [
+ "search_for"
+ ]
+ },
+ "Virgilio": {
+ "domains": [
+ "ricerca.virgilio.it",
+ "ricercaimmagini.virgilio.it",
+ "ricercavideo.virgilio.it",
+ "ricercanews.virgilio.it",
+ "mobile.virgilio.it"
+ ],
+ "parameters": [
+ "qs"
+ ]
+ },
+ "Vi-view": {
+ "domains": [
+ "viview.inspsearch.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Voila": {
+ "domains": [
+ "search.ke.voila.fr",
+ "www.lemoteur.fr"
+ ],
+ "parameters": [
+ "rdata",
+ "kw"
+ ]
+ },
+ "Volny": {
+ "domains": [
+ "web.volny.cz"
+ ],
+ "parameters": [
+ "search"
+ ]
+ },
+ "WWW": {
+ "domains": [
+ "search.www.ee"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Walhello": {
+ "domains": [
+ "www.walhello.info",
+ "www.walhello.com",
+ "www.walhello.de",
+ "www.walhello.nl"
+ ],
+ "parameters": [
+ "key"
+ ]
+ },
+ "Web.de": {
+ "domains": [
+ "suche.web.de"
+ ],
+ "parameters": [
+ "su"
+ ]
+ },
+ "Web.nl": {
+ "domains": [
+ "www.web.nl"
+ ],
+ "parameters": [
+ "zoekwoord"
+ ]
+ },
+ "WebSearch": {
+ "domains": [
+ "www.websearch.com"
+ ],
+ "parameters": [
+ "qkw",
+ "q"
+ ]
+ },
+ "Weborama": {
+ "domains": [
+ "www.weborama.com"
+ ],
+ "parameters": [
+ "QUERY"
+ ]
+ },
+ "Winamp": {
+ "domains": [
+ "search.winamp.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Wirtualna Polska": {
+ "domains": [
+ "szukaj.wp.pl"
+ ],
+ "parameters": [
+ "szukaj"
+ ]
+ },
+ "Witch": {
+ "domains": [
+ "www.witch.de"
+ ],
+ "parameters": [
+ "search"
+ ]
+ },
+ "X-recherche": {
+ "domains": [
+ "www.x-recherche.com"
+ ],
+ "parameters": [
+ "MOTS"
+ ]
+ },
+ "Yahoo!": {
+ "domains": [
+ "search.yahoo.com",
+ "yahoo.com",
+ "ar.search.yahoo.com",
+ "ar.yahoo.com",
+ "au.search.yahoo.com",
+ "au.yahoo.com",
+ "br.search.yahoo.com",
+ "br.yahoo.com",
+ "cade.searchde.yahoo.com",
+ "cade.yahoo.com",
+ "chinese.searchinese.yahoo.com",
+ "chinese.yahoo.com",
+ "cn.search.yahoo.com",
+ "cn.yahoo.com",
+ "de.search.yahoo.com",
+ "de.yahoo.com",
+ "dk.search.yahoo.com",
+ "dk.yahoo.com",
+ "es.search.yahoo.com",
+ "es.yahoo.com",
+ "espanol.searchpanol.yahoo.com",
+ "espanol.searchpanol.yahoo.com",
+ "espanol.yahoo.com",
+ "espanol.yahoo.com",
+ "fr.search.yahoo.com",
+ "fr.yahoo.com",
+ "ie.search.yahoo.com",
+ "ie.yahoo.com",
+ "it.search.yahoo.com",
+ "it.yahoo.com",
+ "kr.search.yahoo.com",
+ "kr.yahoo.com",
+ "mx.search.yahoo.com",
+ "mx.yahoo.com",
+ "no.search.yahoo.com",
+ "no.yahoo.com",
+ "nz.search.yahoo.com",
+ "nz.yahoo.com",
+ "one.cn.yahoo.com",
+ "one.searchn.yahoo.com",
+ "qc.search.yahoo.com",
+ "qc.search.yahoo.com",
+ "qc.search.yahoo.com",
+ "qc.yahoo.com",
+ "qc.yahoo.com",
+ "se.search.yahoo.com",
+ "se.search.yahoo.com",
+ "se.yahoo.com",
+ "search.searcharch.yahoo.com",
+ "search.yahoo.com",
+ "uk.search.yahoo.com",
+ "uk.yahoo.com",
+ "www.yahoo.co.jp",
+ "search.yahoo.co.jp",
+ "m.chiebukuro.yahoo.co.jp",
+ "detail.chiebukuro.yahoo.co.jp",
+ "www.cercato.it",
+ "search.offerbox.com",
+ "ys.mirostart.com"
+ ],
+ "parameters": [
+ "p",
+ "q"
+ ]
+ },
+ "Yahoo! Images": {
+ "domains": [
+ "image.yahoo.cn",
+ "images.search.yahoo.com",
+ "image.search.yahoo.co.jp"
+ ],
+ "parameters": [
+ "p",
+ "q"
+ ]
+ },
+ "Yam": {
+ "domains": [
+ "search.yam.com"
+ ],
+ "parameters": [
+ "k"
+ ]
+ },
+ "Yandex": {
+ "domains": [
+ "yandex.ru",
+ "yandex.ua",
+ "yandex.com",
+ "yandex.by",
+ "www.yandex.ru",
+ "www.yandex.ua",
+ "www.yandex.com",
+ "www.yandex.by"
+ ],
+ "parameters": [
+ "text"
+ ]
+ },
+ "Yandex Images": {
+ "domains": [
+ "images.yandex.ru",
+ "images.yandex.ua",
+ "images.yandex.com"
+ ],
+ "parameters": [
+ "text"
+ ]
+ },
+ "Yasni": {
+ "domains": [
+ "www.yasni.de",
+ "www.yasni.com",
+ "www.yasni.co.uk",
+ "www.yasni.ch",
+ "www.yasni.at"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "Yatedo": {
+ "domains": [
+ "www.yatedo.com",
+ "www.yatedo.fr"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Yellowpages": {
+ "domains": [
+ "www.yellowpages.com",
+ "www.yellowpages.com.au",
+ "www.yellowpages.ca"
+ ],
+ "parameters": [
+ "q",
+ "search_terms"
+ ]
+ },
+ "Yippy": {
+ "domains": [
+ "search.yippy.com"
+ ],
+ "parameters": [
+ "q",
+ "query"
+ ]
+ },
+ "YouGoo": {
+ "domains": [
+ "www.yougoo.fr"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Zapmeta": {
+ "domains": [
+ "www.zapmeta.com",
+ "www.zapmeta.nl",
+ "www.zapmeta.de",
+ "uk.zapmeta.com"
+ ],
+ "parameters": [
+ "q",
+ "query"
+ ]
+ },
+ "Zhongsou": {
+ "domains": [
+ "p.zhongsou.com"
+ ],
+ "parameters": [
+ "w"
+ ]
+ },
+ "Zoek": {
+ "domains": [
+ "www3.zoek.nl"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Zoeken": {
+ "domains": [
+ "www.zoeken.nl"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Zoohoo": {
+ "domains": [
+ "zoohoo.cz"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "all.by": {
+ "domains": [
+ "all.by"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "arama": {
+ "domains": [
+ "arama.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "blekko": {
+ "domains": [
+ "blekko.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "canoe.ca": {
+ "domains": [
+ "web.canoe.ca"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "dmoz": {
+ "domains": [
+ "dmoz.org",
+ "editors.dmoz.org"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "earthlink": {
+ "domains": [
+ "search.earthlink.net"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "eo": {
+ "domains": [
+ "eo.st"
+ ],
+ "parameters": [
+ "x_query"
+ ]
+ },
+ "goo": {
+ "domains": [
+ "search.goo.ne.jp",
+ "ocnsearch.goo.ne.jp"
+ ],
+ "parameters": [
+ "MT"
+ ]
+ },
+ "maailm": {
+ "domains": [
+ "www.maailm.com"
+ ],
+ "parameters": [
+ "tekst"
+ ]
+ },
+ "qip": {
+ "domains": [
+ "search.qip.ru"
+ ],
+ "parameters": [
+ "query"
+ ]
+ },
+ "SoSoDesk": {
+ "domains": [
+ "www.soso.com",
+ "sosodesktop.com",
+ "search.sosodesktop.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "Snapdo": {
+ "domains": [
+ "search.snapdo.com"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "suche.info": {
+ "domains": [
+ "suche.info"
+ ],
+ "parameters": [
+ "q"
+ ]
+ },
+ "uol.com.br": {
+ "domains": [
+ "busca.uol.com.br"
+ ],
+ "parameters": [
+ "q"
+ ]
+ }
+ },
+ "social": {
+ "Badoo": {
+ "domains": [
+ "badoo.com"
+ ]
+ },
+ "Bebo": {
+ "domains": [
+ "bebo.com"
+ ]
+ },
+ "BlackPlanet": {
+ "domains": [
+ "blackplanet.com"
+ ]
+ },
+ "Bloglovin'": {
+ "domains": [
+ "bloglovin.com"
+ ]
+ },
+ "Buzznet": {
+ "domains": [
+ "wayn.com",
+ "buzznet.com"
+ ]
+ },
+ "Classmates": {
+ "domains": [
+ "classmates.com"
+ ]
+ },
+ "Cyworld": {
+ "domains": [
+ "global.cyworld.com"
+ ]
+ },
+ "DeviantArt":{
+ "domains": [
+ "deviantart.com"
+ ]
+ },
+ "Delicious":{
+ "domains": [
+ "delicious.com"
+ ]
+ },
+ "Discus": {
+ "domains": [
+ "redirect.disqus.com",
+ "disq.us",
+ "disqus.com"
+ ]
+ },
+ "Donanimhaber": {
+ "domains": [
+ "donanimhaber.com"
+ ]
+ },
+ "Douban": {
+ "domains": [
+ "douban.com"
+ ]
+ },
+ "Facebook": {
+ "domains": [
+ "facebook.com",
+ "fb.me",
+ "m.facebook.com",
+ "l.facebook.com",
+ "lm.facebook.com"
+ ]
+ },
+ "Flickr": {
+ "domains": [
+ "flickr.com"
+ ]
+ },
+ "Flixster": {
+ "domains": [
+ "flixster.com"
+ ]
+ },
+ "Flipboard": {
+ "domains": [
+ "flipboard.com"
+ ]
+ },
+ "Fotolog": {
+ "domains": [
+ "fotolog.com"
+ ]
+ },
+ "Foursquare": {
+ "domains": [
+ "foursquare.com"
+ ]
+ },
+ "Friends Reunited": {
+ "domains": [
+ "friendsreunited.com"
+ ]
+ },
+ "Friendster": {
+ "domains": [
+ "friendster.com"
+ ]
+ },
+ "Gaia Online": {
+ "domains": [
+ "gaiaonline.com"
+ ]
+ },
+ "Geni": {
+ "domains": [
+ "geni.com"
+ ]
+ },
+ "GitHub": {
+ "domains": [
+ "github.com"
+ ]
+ },
+ "Google+": {
+ "domains": [
+ "url.google.com",
+ "plus.google.com",
+ "plus.url.google.com"
+ ]
+ },
+ "Habbo": {
+ "domains": [
+ "habbo.com"
+ ]
+ },
+ "Hacker News": {
+ "domains": [
+ "news.ycombinator.com"
+ ]
+ },
+ "Hocam.com": {
+ "domains": [
+ "hocam.com"
+ ]
+ },
+ "Hyves": {
+ "domains": [
+ "hyves.nl"
+ ]
+ },
+ "Iconosquare": {
+ "domains": [
+ "iconosquare.com"
+ ]
+ },
+ "Identi.ca": {
+ "domains": [
+ "identi.ca"
+ ]
+ },
+ "Imgur": {
+ "domains": [
+ "imgur.com"
+ ]
+ },
+ "Inci Sozluk": {
+ "domains": [
+ "inci.sozlukspot.com",
+ "incisozluk.com",
+ "incisozluk.cc"
+ ]
+ },
+ "Instagram": {
+ "domains": [
+ "instagram.com"
+ ]
+ },
+ "Instela": {
+ "domains": [
+ "instela.com"
+ ]
+ },
+ "Last.fm": {
+ "domains": [
+ "lastfm.ru"
+ ]
+ },
+ "LinkedIn": {
+ "domains": [
+ "linkedin.com",
+ "lnkd.in"
+ ]
+ },
+ "LiveJournal": {
+ "domains": [
+ "livejournal.ru"
+ ]
+ },
+ "Mail.ru": {
+ "domains": [
+ "my.mail.ru"
+ ]
+ },
+ "Medium": {
+ "domains": [
+ "medium.com"
+ ]
+ },
+ "Meetup": {
+ "domains": [
+ "meetup.com"
+ ]
+ },
+ "Messenger": {
+ "domains": [
+ "messenger.com"
+ ]
+ },
+ "Mixi": {
+ "domains": [
+ "mixi.jp"
+ ]
+ },
+ "MoiKrug.ru": {
+ "domains": [
+ "moikrug.ru"
+ ]
+ },
+ "Multiply": {
+ "domains": [
+ "multiply.com"
+ ]
+ },
+ "MyHeritage": {
+ "domains": [
+ "myheritage.com"
+ ]
+ },
+ "MyLife": {
+ "domains": [
+ "mylife.ru"
+ ]
+ },
+ "Myspace": {
+ "domains": [
+ "myspace.com"
+ ]
+ },
+ "Nasza-klasa.pl": {
+ "domains": [
+ "nk.pl"
+ ]
+ },
+ "Netlog": {
+ "domains": [
+ "netlog.com"
+ ]
+ },
+ "Odnoklassniki": {
+ "domains": [
+ "odnoklassniki.ru",
+ "ok.ru"
+ ]
+ },
+ "Orkut": {
+ "domains": [
+ "orkut.com"
+ ]
+ },
+ "Paper.li": {
+ "domains": [
+ "paper.li"
+ ]
+ },
+ "Pinterest": {
+ "domains": [
+ "pinterest.com"
+ ]
+ },
+ "Plaxo": {
+ "domains": [
+ "plaxo.com"
+ ]
+ },
+ "Pocket": {
+ "domains": [
+ "getpocket.com"
+ ]
+ },
+ "Polyvore": {
+ "domains": [
+ "polyvore.com"
+ ]
+ },
+ "Quora": {
+ "domains": [
+ "quora.com"
+ ]
+ },
+ "Qzone": {
+ "domains": [
+ "qzone.qq.com"
+ ]
+ },
+ "Reddit": {
+ "domains": [
+ "reddit.com"
+ ]
+ },
+ "Renren": {
+ "domains": [
+ "renren.com"
+ ]
+ },
+ "Skyrock": {
+ "domains": [
+ "skyrock.com"
+ ]
+ },
+ "Snapchat": {
+ "domains": [
+ "snapchat.com"
+ ]
+ },
+ "Sonico.com": {
+ "domains": [
+ "sonico.com"
+ ]
+ },
+ "SourceForge": {
+ "domains": [
+ "sourceforge.net"
+ ]
+ },
+ "StackOverflow": {
+ "domains": [
+ "stackoverflow.com"
+ ]
+ },
+ "StudiVZ": {
+ "domains": [
+ "studivz.net"
+ ]
+ },
+ "StumbleUpon": {
+ "domains": [
+ "stumbleupon.com"
+ ]
+ },
+ "Tagged": {
+ "domains": [
+ "login.tagged.com"
+ ]
+ },
+ "Taringa!": {
+ "domains": [
+ "taringa.net"
+ ]
+ },
+ "TikTok": {
+ "domains": [
+ "tiktok.com",
+ "tiktokcdn.com"
+ ]
+ },
+ "Tuenti": {
+ "domains": [
+ "tuenti.com"
+ ]
+ },
+ "Tumblr": {
+ "domains": [
+ "tumblr.com",
+ "umblr.com",
+ "t.umblr.com"
+ ]
+ },
+ "Twitter": {
+ "domains": [
+ "twitter.com",
+ "t.co"
+ ]
+ },
+ "Twitch":{
+ "domains": [
+ "twitch.tv",
+ "twitch.com"
+ ]
+ },
+ "Viadeo": {
+ "domains": [
+ "viadeo.com"
+ ]
+ },
+ "Vimeo": {
+ "domains": [
+ "vimeo.com"
+ ]
+ },
+ "Vkontakte": {
+ "domains": [
+ "vk.com",
+ "vkontakte.ru"
+ ]
+ },
+ "Wanelo": {
+ "domains": [
+ "wanelo.com"
+ ]
+ },
+ "WAYN": {
+ "domains": [
+ "wayn.com"
+ ]
+ },
+ "WeeWorld": {
+ "domains": [
+ "weeworld.com"
+ ]
+ },
+ "Weibo": {
+ "domains": [
+ "weibo.com",
+ "t.cn"
+ ]
+ },
+ "Windows Live Spaces": {
+ "domains": [
+ "login.live.com"
+ ]
+ },
+ "XING": {
+ "domains": [
+ "xing.com"
+ ]
+ },
+ "Xanga": {
+ "domains": [
+ "xanga.com"
+ ]
+ },
+ "hi5": {
+ "domains": [
+ "hi5.com"
+ ]
+ },
+ "myYearbook": {
+ "domains": [
+ "myyearbook.com"
+ ]
+ },
+ "ITU Sozluk": {
+ "domains": [
+ "itusozluk.com"
+ ]
+ },
+ "Eksi Sozluk": {
+ "domains": [
+ "Sozluk.com",
+ "sourtimes.org"
+ ]
+ },
+ "Uludag Sozluk": {
+ "domains": [
+ "uludagsozluk.com",
+ "ulusozluk.com"
+ ]
+ },
+ "vKruguDruzei.ru": {
+ "domains": [
+ "vkrugudruzei.ru"
+ ]
+ },
+ "Whirlpool": {
+ "domains": [
+ "forums.whirlpool.net.au"
+ ]
+ },
+ "Youtube": {
+ "domains": [
+ "youtube.com",
+ "youtu.be"
+ ]
+ }
+ },
+ "unknown": {
+ "Google": {
+ "domains": [
+ "support.google.com",
+ "developers.google.com",
+ "maps.google.com",
+ "accounts.google.com",
+ "drive.google.com",
+ "sites.google.com",
+ "groups.google.com",
+ "groups.google.co.uk",
+ "news.google.co.uk"
+ ]
+ },
+ "Yahoo!": {
+ "domains": [
+ "finance.yahoo.com",
+ "news.yahoo.com",
+ "eurosport.yahoo.com",
+ "sports.yahoo.com",
+ "astrology.yahoo.com",
+ "travel.yahoo.com",
+ "answers.yahoo.com",
+ "screen.yahoo.com",
+ "weather.yahoo.com",
+ "messenger.yahoo.com",
+ "games.yahoo.com",
+ "shopping.yahoo.net",
+ "movies.yahoo.com",
+ "cars.yahoo.com",
+ "lifestyle.yahoo.com",
+ "omg.yahoo.com",
+ "match.yahoo.net"
+ ]
+ }
+ }
+}
+`
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/dev.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/dev.yml
new file mode 100644
index 000000000000..50417d8ab09f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/dev.yml
@@ -0,0 +1,15 @@
+name: goreferrer
+
+up:
+ - go:
+ version: "1.17"
+ modules: on
+ - custom:
+ name: Setup go dependencies
+ meet: echo 'go mod failed to install packages'; false
+ met?: go mod download
+
+commands:
+ test:
+ run: go get -race -t ./... && go test -race ./...
+ desc: 'run unit tests'
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/referrer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/referrer.go
new file mode 100644
index 000000000000..b9a2263e12d5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/referrer.go
@@ -0,0 +1,76 @@
+package goreferrer
+
+type ReferrerType int
+
+const (
+ Invalid ReferrerType = iota
+ Indirect
+ Direct
+ Email
+ Search
+ Social
+)
+
+func (r ReferrerType) String() string {
+ switch r {
+ default:
+ return "invalid"
+ case Indirect:
+ return "indirect"
+ case Direct:
+ return "direct"
+ case Email:
+ return "email"
+ case Search:
+ return "search"
+ case Social:
+ return "social"
+ }
+}
+
+type Referrer struct {
+ Type ReferrerType
+ Label string
+ URL string
+ Subdomain string
+ Domain string
+ Tld string
+ Path string
+ Query string
+ GoogleType GoogleSearchType
+}
+
+func (r *Referrer) RegisteredDomain() string {
+ if r.Domain != "" && r.Tld != "" {
+ return r.Domain + "." + r.Tld
+ }
+
+ return ""
+}
+
+func (r *Referrer) Host() string {
+ if r.Subdomain != "" {
+ return r.Subdomain + "." + r.RegisteredDomain()
+ }
+
+ return r.RegisteredDomain()
+}
+
+type GoogleSearchType int
+
+const (
+ NotGoogleSearch GoogleSearchType = iota
+ OrganicSearch
+ Adwords
+)
+
+func (g GoogleSearchType) String() string {
+ switch g {
+ default:
+ return "not google search"
+ case OrganicSearch:
+ return "organic google search"
+ case Adwords:
+ return "google adwords referrer"
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/rich_url.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/rich_url.go
new file mode 100644
index 000000000000..882d0767a58d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/rich_url.go
@@ -0,0 +1,53 @@
+package goreferrer
+
+import (
+ "net/url"
+ "strings"
+
+ "golang.org/x/net/publicsuffix"
+)
+
+type richUrl struct {
+ *url.URL
+ Subdomain string
+ Domain string
+ Tld string
+}
+
+func parseRichUrl(s string) (*richUrl, bool) {
+ u, err := url.Parse(s)
+ if err != nil {
+ return nil, false
+ }
+
+ // assume a default scheme of http://
+ if u.Scheme == "" {
+ s = "http://" + s
+ u, err = url.Parse(s)
+ if err != nil {
+ return nil, false
+ }
+ }
+
+ tld, _ := publicsuffix.PublicSuffix(u.Host)
+ if tld == "" || len(u.Host)-len(tld) < 2 {
+ return nil, false
+ }
+
+ hostWithoutTld := u.Host[:len(u.Host)-len(tld)-1]
+ lastDot := strings.LastIndex(hostWithoutTld, ".")
+ if lastDot == -1 {
+ return &richUrl{URL: u, Domain: hostWithoutTld, Tld: tld}, true
+ }
+
+ return &richUrl{
+ URL: u,
+ Subdomain: hostWithoutTld[:lastDot],
+ Domain: hostWithoutTld[lastDot+1:],
+ Tld: tld,
+ }, true
+}
+
+func (u *richUrl) RegisteredDomain() string {
+ return u.Domain + "." + u.Tld
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/rules.go b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/rules.go
new file mode 100644
index 000000000000..f6cc72d179b7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/Shopify/goreferrer/rules.go
@@ -0,0 +1,206 @@
+package goreferrer
+
+import (
+ "encoding/json"
+ "io"
+ "net/url"
+ "path"
+ "strings"
+)
+
+type DomainRule struct {
+ Type ReferrerType
+ Label string
+ Domain string
+ Parameters []string
+}
+
+type UaRule struct {
+ Url string
+ Domain string
+ Tld string
+}
+
+func (u UaRule) RegisteredDomain() string {
+ if u.Domain == "" || u.Tld == "" {
+ return ""
+ }
+
+ return u.Domain + "." + u.Tld
+}
+
+type RuleSet struct {
+ DomainRules map[string]DomainRule
+ UaRules map[string]UaRule
+}
+
+func NewRuleSet() RuleSet {
+ return RuleSet{
+ DomainRules: make(map[string]DomainRule),
+ UaRules: make(map[string]UaRule),
+ }
+}
+
+func (r RuleSet) Merge(other RuleSet) {
+ for k, v := range other.DomainRules {
+ r.DomainRules[k] = v
+ }
+ for k, v := range other.UaRules {
+ r.UaRules[k] = v
+ }
+}
+
+func (r RuleSet) Parse(URL string) Referrer {
+ return r.ParseWith(URL, nil, "")
+}
+
+func (r RuleSet) ParseWith(URL string, domains []string, agent string) Referrer {
+ ref := Referrer{
+ Type: Indirect,
+ URL: strings.Trim(URL, " \t\r\n"),
+ }
+
+ uaRule := r.getUaRule(agent)
+ if ref.URL == "" {
+ ref.URL = uaRule.Url
+ }
+ if ref.URL == "" {
+ ref.Type = Direct
+ return ref
+ }
+
+ u, ok := parseRichUrl(ref.URL)
+ if !ok {
+ ref.Type = Invalid
+ return ref
+ }
+
+ ref.Subdomain = u.Subdomain
+ ref.Domain = u.Domain
+ ref.Tld = u.Tld
+ ref.Path = cleanPath(u.Path)
+
+ if ref.Domain == "" {
+ ref.Domain = uaRule.Domain
+ }
+ if ref.Tld == "" {
+ ref.Tld = uaRule.Tld
+ }
+
+ for _, domain := range domains {
+ if u.Host == domain {
+ ref.Type = Direct
+ return ref
+ }
+ }
+
+ variations := []string{
+ path.Join(u.Host, u.Path),
+ path.Join(u.RegisteredDomain(), u.Path),
+ u.Host,
+ u.RegisteredDomain(),
+ }
+
+ for _, host := range variations {
+ domainRule, exists := r.DomainRules[host]
+ if !exists {
+ continue
+ }
+
+ query := getQuery(u.Query(), domainRule.Parameters)
+ if query == "" {
+ values, err := url.ParseQuery(u.Fragment)
+ if err == nil {
+ query = getQuery(values, domainRule.Parameters)
+ }
+ }
+
+ ref.Type = domainRule.Type
+ ref.Label = domainRule.Label
+ ref.Query = query
+ ref.GoogleType = googleSearchType(ref)
+ return ref
+ }
+
+ ref.Label = strings.Title(u.Domain)
+ return ref
+}
+
+func (r *RuleSet) getUaRule(agent string) UaRule {
+ for pattern, rule := range r.UaRules {
+ if strings.Contains(agent, pattern) {
+ return rule
+ }
+ }
+
+ return UaRule{}
+}
+
+func getQuery(values url.Values, params []string) string {
+ for _, param := range params {
+ query := values.Get(param)
+ if query != "" {
+ return query
+ }
+ }
+
+ return ""
+}
+
+func googleSearchType(ref Referrer) GoogleSearchType {
+ if ref.Type != Search || !strings.Contains(ref.Label, "Google") {
+ return NotGoogleSearch
+ }
+
+ if strings.HasPrefix(ref.Path, "/aclk") || strings.HasPrefix(ref.Path, "/pagead/aclk") {
+ return Adwords
+ }
+
+ return OrganicSearch
+}
+
+func cleanPath(path string) string {
+ if i := strings.Index(path, ";"); i != -1 {
+ return path[:i]
+ }
+ return path
+}
+
+type jsonRule struct {
+ Domains []string
+ Parameters []string
+}
+
+type jsonRules struct {
+ Email map[string]jsonRule
+ Search map[string]jsonRule
+ Social map[string]jsonRule
+}
+
+func LoadJsonDomainRules(reader io.Reader) (map[string]DomainRule, error) {
+ var decoded jsonRules
+ if err := json.NewDecoder(reader).Decode(&decoded); err != nil {
+ return nil, err
+ }
+
+ rules := NewRuleSet()
+ rules.Merge(extractRules(decoded.Email, Email))
+ rules.Merge(extractRules(decoded.Search, Search))
+ rules.Merge(extractRules(decoded.Social, Social))
+ return rules.DomainRules, nil
+}
+
+func extractRules(ruleMap map[string]jsonRule, Type ReferrerType) RuleSet {
+ rules := NewRuleSet()
+ for label, jsonRule := range ruleMap {
+ for _, domain := range jsonRule.Domains {
+ rules.DomainRules[domain] = DomainRule{
+ Type: Type,
+ Label: label,
+ Domain: domain,
+ Parameters: jsonRule.Parameters,
+ }
+ }
+ }
+ return rules
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/LICENSE
new file mode 100644
index 000000000000..33b7cdd2dbae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/README.md
new file mode 100644
index 000000000000..1ea7fdb759d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/README.md
@@ -0,0 +1,7 @@
+This package is a brotli compressor and decompressor implemented in Go.
+It was translated from the reference implementation (https://github.com/google/brotli)
+with the `c2go` tool at https://github.com/andybalholm/c2go.
+
+I am using it in production with https://github.com/andybalholm/redwood.
+
+API documentation is found at https://pkg.go.dev/github.com/andybalholm/brotli?tab=doc.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/backward_references.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/backward_references.go
new file mode 100644
index 000000000000..008c054d1c03
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/backward_references.go
@@ -0,0 +1,185 @@
+package brotli
+
+import (
+ "sync"
+)
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find backward reference copies. */
+
+func computeDistanceCode(distance uint, max_distance uint, dist_cache []int) uint {
+ if distance <= max_distance {
+ var distance_plus_3 uint = distance + 3
+ var offset0 uint = distance_plus_3 - uint(dist_cache[0])
+ var offset1 uint = distance_plus_3 - uint(dist_cache[1])
+ if distance == uint(dist_cache[0]) {
+ return 0
+ } else if distance == uint(dist_cache[1]) {
+ return 1
+ } else if offset0 < 7 {
+ return (0x9750468 >> (4 * offset0)) & 0xF
+ } else if offset1 < 7 {
+ return (0xFDB1ACE >> (4 * offset1)) & 0xF
+ } else if distance == uint(dist_cache[2]) {
+ return 2
+ } else if distance == uint(dist_cache[3]) {
+ return 3
+ }
+ }
+
+ return distance + numDistanceShortCodes - 1
+}
+
+var hasherSearchResultPool sync.Pool
+
+func createBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var insert_length uint = *last_insert_len
+ var pos_end uint = position + num_bytes
+ var store_end uint
+ if num_bytes >= hasher.StoreLookahead() {
+ store_end = position + num_bytes - hasher.StoreLookahead() + 1
+ } else {
+ store_end = position
+ }
+ var random_heuristics_window_size uint = literalSpreeLengthForSparseSearch(params)
+ var apply_random_heuristics uint = position + random_heuristics_window_size
+ var gap uint = 0
+ /* Set maximum distance, see section 9.1. of the spec. */
+
+ const kMinScore uint = scoreBase + 100
+
+ /* For speed up heuristics for random data. */
+
+ /* Minimum score to accept a backward reference. */
+ hasher.PrepareDistanceCache(dist_cache)
+ sr2, _ := hasherSearchResultPool.Get().(*hasherSearchResult)
+ if sr2 == nil {
+ sr2 = &hasherSearchResult{}
+ }
+ sr, _ := hasherSearchResultPool.Get().(*hasherSearchResult)
+ if sr == nil {
+ sr = &hasherSearchResult{}
+ }
+
+ for position+hasher.HashTypeLength() < pos_end {
+ var max_length uint = pos_end - position
+ var max_distance uint = brotli_min_size_t(position, max_backward_limit)
+ sr.len = 0
+ sr.len_code_delta = 0
+ sr.distance = 0
+ sr.score = kMinScore
+ hasher.FindLongestMatch(¶ms.dictionary, ringbuffer, ringbuffer_mask, dist_cache, position, max_length, max_distance, gap, params.dist.max_distance, sr)
+ if sr.score > kMinScore {
+ /* Found a match. Let's look for something even better ahead. */
+ var delayed_backward_references_in_row int = 0
+ max_length--
+ for ; ; max_length-- {
+ var cost_diff_lazy uint = 175
+ if params.quality < minQualityForExtensiveReferenceSearch {
+ sr2.len = brotli_min_size_t(sr.len-1, max_length)
+ } else {
+ sr2.len = 0
+ }
+ sr2.len_code_delta = 0
+ sr2.distance = 0
+ sr2.score = kMinScore
+ max_distance = brotli_min_size_t(position+1, max_backward_limit)
+ hasher.FindLongestMatch(¶ms.dictionary, ringbuffer, ringbuffer_mask, dist_cache, position+1, max_length, max_distance, gap, params.dist.max_distance, sr2)
+ if sr2.score >= sr.score+cost_diff_lazy {
+ /* Ok, let's just write one byte for now and start a match from the
+ next byte. */
+ position++
+
+ insert_length++
+ *sr = *sr2
+ delayed_backward_references_in_row++
+ if delayed_backward_references_in_row < 4 && position+hasher.HashTypeLength() < pos_end {
+ continue
+ }
+ }
+
+ break
+ }
+
+ apply_random_heuristics = position + 2*sr.len + random_heuristics_window_size
+ max_distance = brotli_min_size_t(position, max_backward_limit)
+ {
+ /* The first 16 codes are special short-codes,
+ and the minimum offset is 1. */
+ var distance_code uint = computeDistanceCode(sr.distance, max_distance+gap, dist_cache)
+ if (sr.distance <= (max_distance + gap)) && distance_code > 0 {
+ dist_cache[3] = dist_cache[2]
+ dist_cache[2] = dist_cache[1]
+ dist_cache[1] = dist_cache[0]
+ dist_cache[0] = int(sr.distance)
+ hasher.PrepareDistanceCache(dist_cache)
+ }
+
+ *commands = append(*commands, makeCommand(¶ms.dist, insert_length, sr.len, sr.len_code_delta, distance_code))
+ }
+
+ *num_literals += insert_length
+ insert_length = 0
+ /* Put the hash keys into the table, if there are enough bytes left.
+ Depending on the hasher implementation, it can push all positions
+ in the given range or only a subset of them.
+ Avoid hash poisoning with RLE data. */
+ {
+ var range_start uint = position + 2
+ var range_end uint = brotli_min_size_t(position+sr.len, store_end)
+ if sr.distance < sr.len>>2 {
+ range_start = brotli_min_size_t(range_end, brotli_max_size_t(range_start, position+sr.len-(sr.distance<<2)))
+ }
+
+ hasher.StoreRange(ringbuffer, ringbuffer_mask, range_start, range_end)
+ }
+
+ position += sr.len
+ } else {
+ insert_length++
+ position++
+
+ /* If we have not seen matches for a long time, we can skip some
+ match lookups. Unsuccessful match lookups are very very expensive
+ and this kind of a heuristic speeds up compression quite
+ a lot. */
+ if position > apply_random_heuristics {
+ /* Going through uncompressible data, jump. */
+ if position > apply_random_heuristics+4*random_heuristics_window_size {
+ var kMargin uint = brotli_max_size_t(hasher.StoreLookahead()-1, 4)
+ /* It is quite a long time since we saw a copy, so we assume
+ that this data is not compressible, and store hashes less
+ often. Hashes of non compressible data are less likely to
+ turn out to be useful in the future, too, so we store less of
+ them to not to flood out the hash table of good compressible
+ data. */
+
+ var pos_jump uint = brotli_min_size_t(position+16, pos_end-kMargin)
+ for ; position < pos_jump; position += 4 {
+ hasher.Store(ringbuffer, ringbuffer_mask, position)
+ insert_length += 4
+ }
+ } else {
+ var kMargin uint = brotli_max_size_t(hasher.StoreLookahead()-1, 2)
+ var pos_jump uint = brotli_min_size_t(position+8, pos_end-kMargin)
+ for ; position < pos_jump; position += 2 {
+ hasher.Store(ringbuffer, ringbuffer_mask, position)
+ insert_length += 2
+ }
+ }
+ }
+ }
+ }
+
+ insert_length += pos_end - position
+ *last_insert_len = insert_length
+
+ hasherSearchResultPool.Put(sr)
+ hasherSearchResultPool.Put(sr2)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/backward_references_hq.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/backward_references_hq.go
new file mode 100644
index 000000000000..21629c1cdb71
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/backward_references_hq.go
@@ -0,0 +1,796 @@
+package brotli
+
+import "math"
+
+type zopfliNode struct {
+ length uint32
+ distance uint32
+ dcode_insert_length uint32
+ u struct {
+ cost float32
+ next uint32
+ shortcut uint32
+ }
+}
+
+const maxEffectiveDistanceAlphabetSize = 544
+
+const kInfinity float32 = 1.7e38 /* ~= 2 ^ 127 */
+
+var kDistanceCacheIndex = []uint32{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}
+
+var kDistanceCacheOffset = []int{0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3}
+
+func initZopfliNodes(array []zopfliNode, length uint) {
+ var stub zopfliNode
+ var i uint
+ stub.length = 1
+ stub.distance = 0
+ stub.dcode_insert_length = 0
+ stub.u.cost = kInfinity
+ for i = 0; i < length; i++ {
+ array[i] = stub
+ }
+}
+
+func zopfliNodeCopyLength(self *zopfliNode) uint32 {
+ return self.length & 0x1FFFFFF
+}
+
+func zopfliNodeLengthCode(self *zopfliNode) uint32 {
+ var modifier uint32 = self.length >> 25
+ return zopfliNodeCopyLength(self) + 9 - modifier
+}
+
+func zopfliNodeCopyDistance(self *zopfliNode) uint32 {
+ return self.distance
+}
+
+func zopfliNodeDistanceCode(self *zopfliNode) uint32 {
+ var short_code uint32 = self.dcode_insert_length >> 27
+ if short_code == 0 {
+ return zopfliNodeCopyDistance(self) + numDistanceShortCodes - 1
+ } else {
+ return short_code - 1
+ }
+}
+
+func zopfliNodeCommandLength(self *zopfliNode) uint32 {
+ return zopfliNodeCopyLength(self) + (self.dcode_insert_length & 0x7FFFFFF)
+}
+
+/* Histogram based cost model for zopflification. */
+type zopfliCostModel struct {
+ cost_cmd_ [numCommandSymbols]float32
+ cost_dist_ []float32
+ distance_histogram_size uint32
+ literal_costs_ []float32
+ min_cost_cmd_ float32
+ num_bytes_ uint
+}
+
+func initZopfliCostModel(self *zopfliCostModel, dist *distanceParams, num_bytes uint) {
+ var distance_histogram_size uint32 = dist.alphabet_size
+ if distance_histogram_size > maxEffectiveDistanceAlphabetSize {
+ distance_histogram_size = maxEffectiveDistanceAlphabetSize
+ }
+
+ self.num_bytes_ = num_bytes
+ self.literal_costs_ = make([]float32, (num_bytes + 2))
+ self.cost_dist_ = make([]float32, (dist.alphabet_size))
+ self.distance_histogram_size = distance_histogram_size
+}
+
+func cleanupZopfliCostModel(self *zopfliCostModel) {
+ self.literal_costs_ = nil
+ self.cost_dist_ = nil
+}
+
+func setCost(histogram []uint32, histogram_size uint, literal_histogram bool, cost []float32) {
+ var sum uint = 0
+ var missing_symbol_sum uint
+ var log2sum float32
+ var missing_symbol_cost float32
+ var i uint
+ for i = 0; i < histogram_size; i++ {
+ sum += uint(histogram[i])
+ }
+
+ log2sum = float32(fastLog2(sum))
+ missing_symbol_sum = sum
+ if !literal_histogram {
+ for i = 0; i < histogram_size; i++ {
+ if histogram[i] == 0 {
+ missing_symbol_sum++
+ }
+ }
+ }
+
+ missing_symbol_cost = float32(fastLog2(missing_symbol_sum)) + 2
+ for i = 0; i < histogram_size; i++ {
+ if histogram[i] == 0 {
+ cost[i] = missing_symbol_cost
+ continue
+ }
+
+ /* Shannon bits for this symbol. */
+ cost[i] = log2sum - float32(fastLog2(uint(histogram[i])))
+
+ /* Cannot be coded with less than 1 bit */
+ if cost[i] < 1 {
+ cost[i] = 1
+ }
+ }
+}
+
+func zopfliCostModelSetFromCommands(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint, commands []command, last_insert_len uint) {
+ var histogram_literal [numLiteralSymbols]uint32
+ var histogram_cmd [numCommandSymbols]uint32
+ var histogram_dist [maxEffectiveDistanceAlphabetSize]uint32
+ var cost_literal [numLiteralSymbols]float32
+ var pos uint = position - last_insert_len
+ var min_cost_cmd float32 = kInfinity
+ var cost_cmd []float32 = self.cost_cmd_[:]
+ var literal_costs []float32
+
+ histogram_literal = [numLiteralSymbols]uint32{}
+ histogram_cmd = [numCommandSymbols]uint32{}
+ histogram_dist = [maxEffectiveDistanceAlphabetSize]uint32{}
+
+ for i := range commands {
+ var inslength uint = uint(commands[i].insert_len_)
+ var copylength uint = uint(commandCopyLen(&commands[i]))
+ var distcode uint = uint(commands[i].dist_prefix_) & 0x3FF
+ var cmdcode uint = uint(commands[i].cmd_prefix_)
+ var j uint
+
+ histogram_cmd[cmdcode]++
+ if cmdcode >= 128 {
+ histogram_dist[distcode]++
+ }
+
+ for j = 0; j < inslength; j++ {
+ histogram_literal[ringbuffer[(pos+j)&ringbuffer_mask]]++
+ }
+
+ pos += inslength + copylength
+ }
+
+ setCost(histogram_literal[:], numLiteralSymbols, true, cost_literal[:])
+ setCost(histogram_cmd[:], numCommandSymbols, false, cost_cmd)
+ setCost(histogram_dist[:], uint(self.distance_histogram_size), false, self.cost_dist_)
+
+ for i := 0; i < numCommandSymbols; i++ {
+ min_cost_cmd = brotli_min_float(min_cost_cmd, cost_cmd[i])
+ }
+
+ self.min_cost_cmd_ = min_cost_cmd
+ {
+ literal_costs = self.literal_costs_
+ var literal_carry float32 = 0.0
+ num_bytes := int(self.num_bytes_)
+ literal_costs[0] = 0.0
+ for i := 0; i < num_bytes; i++ {
+ literal_carry += cost_literal[ringbuffer[(position+uint(i))&ringbuffer_mask]]
+ literal_costs[i+1] = literal_costs[i] + literal_carry
+ literal_carry -= literal_costs[i+1] - literal_costs[i]
+ }
+ }
+}
+
+func zopfliCostModelSetFromLiteralCosts(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint) {
+ var literal_costs []float32 = self.literal_costs_
+ var literal_carry float32 = 0.0
+ var cost_dist []float32 = self.cost_dist_
+ var cost_cmd []float32 = self.cost_cmd_[:]
+ var num_bytes uint = self.num_bytes_
+ var i uint
+ estimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask, ringbuffer, literal_costs[1:])
+ literal_costs[0] = 0.0
+ for i = 0; i < num_bytes; i++ {
+ literal_carry += literal_costs[i+1]
+ literal_costs[i+1] = literal_costs[i] + literal_carry
+ literal_carry -= literal_costs[i+1] - literal_costs[i]
+ }
+
+ for i = 0; i < numCommandSymbols; i++ {
+ cost_cmd[i] = float32(fastLog2(uint(11 + uint32(i))))
+ }
+
+ for i = 0; uint32(i) < self.distance_histogram_size; i++ {
+ cost_dist[i] = float32(fastLog2(uint(20 + uint32(i))))
+ }
+
+ self.min_cost_cmd_ = float32(fastLog2(11))
+}
+
+func zopfliCostModelGetCommandCost(self *zopfliCostModel, cmdcode uint16) float32 {
+ return self.cost_cmd_[cmdcode]
+}
+
+func zopfliCostModelGetDistanceCost(self *zopfliCostModel, distcode uint) float32 {
+ return self.cost_dist_[distcode]
+}
+
+func zopfliCostModelGetLiteralCosts(self *zopfliCostModel, from uint, to uint) float32 {
+ return self.literal_costs_[to] - self.literal_costs_[from]
+}
+
+func zopfliCostModelGetMinCostCmd(self *zopfliCostModel) float32 {
+ return self.min_cost_cmd_
+}
+
+/* REQUIRES: len >= 2, start_pos <= pos */
+/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */
+/* Maintains the "ZopfliNode array invariant". */
+func updateZopfliNode(nodes []zopfliNode, pos uint, start_pos uint, len uint, len_code uint, dist uint, short_code uint, cost float32) {
+ var next *zopfliNode = &nodes[pos+len]
+ next.length = uint32(len | (len+9-len_code)<<25)
+ next.distance = uint32(dist)
+ next.dcode_insert_length = uint32(short_code<<27 | (pos - start_pos))
+ next.u.cost = cost
+}
+
+type posData struct {
+ pos uint
+ distance_cache [4]int
+ costdiff float32
+ cost float32
+}
+
+/* Maintains the smallest 8 cost difference together with their positions */
+type startPosQueue struct {
+ q_ [8]posData
+ idx_ uint
+}
+
+func initStartPosQueue(self *startPosQueue) {
+ self.idx_ = 0
+}
+
+func startPosQueueSize(self *startPosQueue) uint {
+ return brotli_min_size_t(self.idx_, 8)
+}
+
+func startPosQueuePush(self *startPosQueue, posdata *posData) {
+ var offset uint = ^(self.idx_) & 7
+ self.idx_++
+ var len uint = startPosQueueSize(self)
+ var i uint
+ var q []posData = self.q_[:]
+ q[offset] = *posdata
+
+ /* Restore the sorted order. In the list of |len| items at most |len - 1|
+ adjacent element comparisons / swaps are required. */
+ for i = 1; i < len; i++ {
+ if q[offset&7].costdiff > q[(offset+1)&7].costdiff {
+ var tmp posData = q[offset&7]
+ q[offset&7] = q[(offset+1)&7]
+ q[(offset+1)&7] = tmp
+ }
+
+ offset++
+ }
+}
+
+func startPosQueueAt(self *startPosQueue, k uint) *posData {
+ return &self.q_[(k-self.idx_)&7]
+}
+
+/* Returns the minimum possible copy length that can improve the cost of any */
+/* future position. */
+func computeMinimumCopyLength(start_cost float32, nodes []zopfliNode, num_bytes uint, pos uint) uint {
+ var min_cost float32 = start_cost
+ var len uint = 2
+ var next_len_bucket uint = 4
+ /* Compute the minimum possible cost of reaching any future position. */
+
+ var next_len_offset uint = 10
+ for pos+len <= num_bytes && nodes[pos+len].u.cost <= min_cost {
+ /* We already reached (pos + len) with no more cost than the minimum
+ possible cost of reaching anything from this pos, so there is no point in
+ looking for lengths <= len. */
+ len++
+
+ if len == next_len_offset {
+ /* We reached the next copy length code bucket, so we add one more
+ extra bit to the minimum cost. */
+ min_cost += 1.0
+
+ next_len_offset += next_len_bucket
+ next_len_bucket *= 2
+ }
+ }
+
+ return uint(len)
+}
+
+/* REQUIRES: nodes[pos].cost < kInfinity
+ REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
+func computeDistanceShortcut(block_start uint, pos uint, max_backward_limit uint, gap uint, nodes []zopfliNode) uint32 {
+ var clen uint = uint(zopfliNodeCopyLength(&nodes[pos]))
+ var ilen uint = uint(nodes[pos].dcode_insert_length & 0x7FFFFFF)
+ var dist uint = uint(zopfliNodeCopyDistance(&nodes[pos]))
+
+ /* Since |block_start + pos| is the end position of the command, the copy part
+ starts from |block_start + pos - clen|. Distances that are greater than
+ this or greater than |max_backward_limit| + |gap| are static dictionary
+ references, and do not update the last distances.
+ Also distance code 0 (last distance) does not update the last distances. */
+ if pos == 0 {
+ return 0
+ } else if dist+clen <= block_start+pos+gap && dist <= max_backward_limit+gap && zopfliNodeDistanceCode(&nodes[pos]) > 0 {
+ return uint32(pos)
+ } else {
+ return nodes[pos-clen-ilen].u.shortcut
+ }
+}
+
+/* Fills in dist_cache[0..3] with the last four distances (as defined by
+ Section 4. of the Spec) that would be used at (block_start + pos) if we
+ used the shortest path of commands from block_start, computed from
+ nodes[0..pos]. The last four distances at block_start are in
+ starting_dist_cache[0..3].
+ REQUIRES: nodes[pos].cost < kInfinity
+ REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
+func computeDistanceCache(pos uint, starting_dist_cache []int, nodes []zopfliNode, dist_cache []int) {
+ var idx int = 0
+ var p uint = uint(nodes[pos].u.shortcut)
+ for idx < 4 && p > 0 {
+ var ilen uint = uint(nodes[p].dcode_insert_length & 0x7FFFFFF)
+ var clen uint = uint(zopfliNodeCopyLength(&nodes[p]))
+ var dist uint = uint(zopfliNodeCopyDistance(&nodes[p]))
+ dist_cache[idx] = int(dist)
+ idx++
+
+ /* Because of prerequisite, p >= clen + ilen >= 2. */
+ p = uint(nodes[p-clen-ilen].u.shortcut)
+ }
+
+ for ; idx < 4; idx++ {
+ dist_cache[idx] = starting_dist_cache[0]
+ starting_dist_cache = starting_dist_cache[1:]
+ }
+}
+
+/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
+ is eligible. */
+func evaluateNode(block_start uint, pos uint, max_backward_limit uint, gap uint, starting_dist_cache []int, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) {
+ /* Save cost, because ComputeDistanceCache invalidates it. */
+ var node_cost float32 = nodes[pos].u.cost
+ nodes[pos].u.shortcut = computeDistanceShortcut(block_start, pos, max_backward_limit, gap, nodes)
+ if node_cost <= zopfliCostModelGetLiteralCosts(model, 0, pos) {
+ var posdata posData
+ posdata.pos = pos
+ posdata.cost = node_cost
+ posdata.costdiff = node_cost - zopfliCostModelGetLiteralCosts(model, 0, pos)
+ computeDistanceCache(pos, starting_dist_cache, nodes, posdata.distance_cache[:])
+ startPosQueuePush(queue, &posdata)
+ }
+}
+
+/* Returns longest copy length. */
+func updateNodes(num_bytes uint, block_start uint, pos uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, max_backward_limit uint, starting_dist_cache []int, num_matches uint, matches []backwardMatch, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) uint {
+ var cur_ix uint = block_start + pos
+ var cur_ix_masked uint = cur_ix & ringbuffer_mask
+ var max_distance uint = brotli_min_size_t(cur_ix, max_backward_limit)
+ var max_len uint = num_bytes - pos
+ var max_zopfli_len uint = maxZopfliLen(params)
+ var max_iters uint = maxZopfliCandidates(params)
+ var min_len uint
+ var result uint = 0
+ var k uint
+ var gap uint = 0
+
+ evaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache, model, queue, nodes)
+ {
+ var posdata *posData = startPosQueueAt(queue, 0)
+ var min_cost float32 = (posdata.cost + zopfliCostModelGetMinCostCmd(model) + zopfliCostModelGetLiteralCosts(model, posdata.pos, pos))
+ min_len = computeMinimumCopyLength(min_cost, nodes, num_bytes, pos)
+ }
+
+ /* Go over the command starting positions in order of increasing cost
+ difference. */
+ for k = 0; k < max_iters && k < startPosQueueSize(queue); k++ {
+ var posdata *posData = startPosQueueAt(queue, k)
+ var start uint = posdata.pos
+ var inscode uint16 = getInsertLengthCode(pos - start)
+ var start_costdiff float32 = posdata.costdiff
+ var base_cost float32 = start_costdiff + float32(getInsertExtra(inscode)) + zopfliCostModelGetLiteralCosts(model, 0, pos)
+ var best_len uint = min_len - 1
+ var j uint = 0
+ /* Look for last distance matches using the distance cache from this
+ starting position. */
+ for ; j < numDistanceShortCodes && best_len < max_len; j++ {
+ var idx uint = uint(kDistanceCacheIndex[j])
+ var backward uint = uint(posdata.distance_cache[idx] + kDistanceCacheOffset[j])
+ var prev_ix uint = cur_ix - backward
+ var len uint = 0
+ var continuation byte = ringbuffer[cur_ix_masked+best_len]
+ if cur_ix_masked+best_len > ringbuffer_mask {
+ break
+ }
+
+ if backward > max_distance+gap {
+ /* Word dictionary -> ignore. */
+ continue
+ }
+
+ if backward <= max_distance {
+ /* Regular backward reference. */
+ if prev_ix >= cur_ix {
+ continue
+ }
+
+ prev_ix &= ringbuffer_mask
+ if prev_ix+best_len > ringbuffer_mask || continuation != ringbuffer[prev_ix+best_len] {
+ continue
+ }
+
+ len = findMatchLengthWithLimit(ringbuffer[prev_ix:], ringbuffer[cur_ix_masked:], max_len)
+ } else {
+ continue
+ }
+ {
+ var dist_cost float32 = base_cost + zopfliCostModelGetDistanceCost(model, j)
+ var l uint
+ for l = best_len + 1; l <= len; l++ {
+ var copycode uint16 = getCopyLengthCode(l)
+ var cmdcode uint16 = combineLengthCodes(inscode, copycode, j == 0)
+ var tmp float32
+ if cmdcode < 128 {
+ tmp = base_cost
+ } else {
+ tmp = dist_cost
+ }
+ var cost float32 = tmp + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)
+ if cost < nodes[pos+l].u.cost {
+ updateZopfliNode(nodes, pos, start, l, l, backward, j+1, cost)
+ result = brotli_max_size_t(result, l)
+ }
+
+ best_len = l
+ }
+ }
+ }
+
+ /* At higher iterations look only for new last distance matches, since
+ looking only for new command start positions with the same distances
+ does not help much. */
+ if k >= 2 {
+ continue
+ }
+ {
+ /* Loop through all possible copy lengths at this position. */
+ var len uint = min_len
+ for j = 0; j < num_matches; j++ {
+ var match backwardMatch = matches[j]
+ var dist uint = uint(match.distance)
+ var is_dictionary_match bool = (dist > max_distance+gap)
+ var dist_code uint = dist + numDistanceShortCodes - 1
+ var dist_symbol uint16
+ var distextra uint32
+ var distnumextra uint32
+ var dist_cost float32
+ var max_match_len uint
+ /* We already tried all possible last distance matches, so we can use
+ normal distance code here. */
+ prefixEncodeCopyDistance(dist_code, uint(params.dist.num_direct_distance_codes), uint(params.dist.distance_postfix_bits), &dist_symbol, &distextra)
+
+ distnumextra = uint32(dist_symbol) >> 10
+ dist_cost = base_cost + float32(distnumextra) + zopfliCostModelGetDistanceCost(model, uint(dist_symbol)&0x3FF)
+
+ /* Try all copy lengths up until the maximum copy length corresponding
+ to this distance. If the distance refers to the static dictionary, or
+ the maximum length is long enough, try only one maximum length. */
+ max_match_len = backwardMatchLength(&match)
+
+ if len < max_match_len && (is_dictionary_match || max_match_len > max_zopfli_len) {
+ len = max_match_len
+ }
+
+ for ; len <= max_match_len; len++ {
+ var len_code uint
+ if is_dictionary_match {
+ len_code = backwardMatchLengthCode(&match)
+ } else {
+ len_code = len
+ }
+ var copycode uint16 = getCopyLengthCode(len_code)
+ var cmdcode uint16 = combineLengthCodes(inscode, copycode, false)
+ var cost float32 = dist_cost + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)
+ if cost < nodes[pos+len].u.cost {
+ updateZopfliNode(nodes, pos, start, uint(len), len_code, dist, 0, cost)
+ if len > result {
+ result = len
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result
+}
+
+func computeShortestPathFromNodes(num_bytes uint, nodes []zopfliNode) uint {
+ var index uint = num_bytes
+ var num_commands uint = 0
+ for nodes[index].dcode_insert_length&0x7FFFFFF == 0 && nodes[index].length == 1 {
+ index--
+ }
+ nodes[index].u.next = math.MaxUint32
+ for index != 0 {
+ var len uint = uint(zopfliNodeCommandLength(&nodes[index]))
+ index -= uint(len)
+ nodes[index].u.next = uint32(len)
+ num_commands++
+ }
+
+ return num_commands
+}
+
+/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
+func zopfliCreateCommands(num_bytes uint, block_start uint, nodes []zopfliNode, dist_cache []int, last_insert_len *uint, params *encoderParams, commands *[]command, num_literals *uint) {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var pos uint = 0
+ var offset uint32 = nodes[0].u.next
+ var i uint
+ var gap uint = 0
+ for i = 0; offset != math.MaxUint32; i++ {
+ var next *zopfliNode = &nodes[uint32(pos)+offset]
+ var copy_length uint = uint(zopfliNodeCopyLength(next))
+ var insert_length uint = uint(next.dcode_insert_length & 0x7FFFFFF)
+ pos += insert_length
+ offset = next.u.next
+ if i == 0 {
+ insert_length += *last_insert_len
+ *last_insert_len = 0
+ }
+ {
+ var distance uint = uint(zopfliNodeCopyDistance(next))
+ var len_code uint = uint(zopfliNodeLengthCode(next))
+ var max_distance uint = brotli_min_size_t(block_start+pos, max_backward_limit)
+ var is_dictionary bool = (distance > max_distance+gap)
+ var dist_code uint = uint(zopfliNodeDistanceCode(next))
+ *commands = append(*commands, makeCommand(¶ms.dist, insert_length, copy_length, int(len_code)-int(copy_length), dist_code))
+
+ if !is_dictionary && dist_code > 0 {
+ dist_cache[3] = dist_cache[2]
+ dist_cache[2] = dist_cache[1]
+ dist_cache[1] = dist_cache[0]
+ dist_cache[0] = int(distance)
+ }
+ }
+
+ *num_literals += insert_length
+ pos += copy_length
+ }
+
+ *last_insert_len += num_bytes - pos
+}
+
+func zopfliIterate(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, gap uint, dist_cache []int, model *zopfliCostModel, num_matches []uint32, matches []backwardMatch, nodes []zopfliNode) uint {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var max_zopfli_len uint = maxZopfliLen(params)
+ var queue startPosQueue
+ var cur_match_pos uint = 0
+ var i uint
+ nodes[0].length = 0
+ nodes[0].u.cost = 0
+ initStartPosQueue(&queue)
+ for i = 0; i+3 < num_bytes; i++ {
+ var skip uint = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, uint(num_matches[i]), matches[cur_match_pos:], model, &queue, nodes)
+ if skip < longCopyQuickStep {
+ skip = 0
+ }
+ cur_match_pos += uint(num_matches[i])
+ if num_matches[i] == 1 && backwardMatchLength(&matches[cur_match_pos-1]) > max_zopfli_len {
+ skip = brotli_max_size_t(backwardMatchLength(&matches[cur_match_pos-1]), skip)
+ }
+
+ if skip > 1 {
+ skip--
+ for skip != 0 {
+ i++
+ if i+3 >= num_bytes {
+ break
+ }
+ evaluateNode(position, i, max_backward_limit, gap, dist_cache, model, &queue, nodes)
+ cur_match_pos += uint(num_matches[i])
+ skip--
+ }
+ }
+ }
+
+ return computeShortestPathFromNodes(num_bytes, nodes)
+}
+
+/* Computes the shortest path of commands from position to at most
+ position + num_bytes.
+
+ On return, path->size() is the number of commands found and path[i] is the
+ length of the i-th command (copy length plus insert length).
+ Note that the sum of the lengths of all commands can be less than num_bytes.
+
+ On return, the nodes[0..num_bytes] array will have the following
+ "ZopfliNode array invariant":
+ For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then
+ (1) nodes[i].copy_length() >= 2
+ (2) nodes[i].command_length() <= i and
+ (3) nodes[i - nodes[i].command_length()].cost < kInfinity
+
+ REQUIRES: nodes != nil and len(nodes) >= num_bytes + 1 */
+func zopfliComputeShortestPath(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, dist_cache []int, hasher *h10, nodes []zopfliNode) uint {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var max_zopfli_len uint = maxZopfliLen(params)
+ var model zopfliCostModel
+ var queue startPosQueue
+ var matches [2 * (maxNumMatchesH10 + 64)]backwardMatch
+ var store_end uint
+ if num_bytes >= hasher.StoreLookahead() {
+ store_end = position + num_bytes - hasher.StoreLookahead() + 1
+ } else {
+ store_end = position
+ }
+ var i uint
+ var gap uint = 0
+ var lz_matches_offset uint = 0
+ nodes[0].length = 0
+ nodes[0].u.cost = 0
+ initZopfliCostModel(&model, ¶ms.dist, num_bytes)
+ zopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)
+ initStartPosQueue(&queue)
+ for i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {
+ var pos uint = position + i
+ var max_distance uint = brotli_min_size_t(pos, max_backward_limit)
+ var skip uint
+ var num_matches uint
+ num_matches = findAllMatchesH10(hasher, ¶ms.dictionary, ringbuffer, ringbuffer_mask, pos, num_bytes-i, max_distance, gap, params, matches[lz_matches_offset:])
+ if num_matches > 0 && backwardMatchLength(&matches[num_matches-1]) > max_zopfli_len {
+ matches[0] = matches[num_matches-1]
+ num_matches = 1
+ }
+
+ skip = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, num_matches, matches[:], &model, &queue, nodes)
+ if skip < longCopyQuickStep {
+ skip = 0
+ }
+ if num_matches == 1 && backwardMatchLength(&matches[0]) > max_zopfli_len {
+ skip = brotli_max_size_t(backwardMatchLength(&matches[0]), skip)
+ }
+
+ if skip > 1 {
+ /* Add the tail of the copy to the hasher. */
+ hasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+skip, store_end))
+
+ skip--
+ for skip != 0 {
+ i++
+ if i+hasher.HashTypeLength()-1 >= num_bytes {
+ break
+ }
+ evaluateNode(position, i, max_backward_limit, gap, dist_cache, &model, &queue, nodes)
+ skip--
+ }
+ }
+ }
+
+ cleanupZopfliCostModel(&model)
+ return computeShortestPathFromNodes(num_bytes, nodes)
+}
+
+func createZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher *h10, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
+ var nodes []zopfliNode
+ nodes = make([]zopfliNode, (num_bytes + 1))
+ initZopfliNodes(nodes, num_bytes+1)
+ zopfliComputeShortestPath(num_bytes, position, ringbuffer, ringbuffer_mask, params, dist_cache, hasher, nodes)
+ zopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)
+ nodes = nil
+}
+
+func createHqZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {
+ var max_backward_limit uint = maxBackwardLimit(params.lgwin)
+ var num_matches []uint32 = make([]uint32, num_bytes)
+ var matches_size uint = 4 * num_bytes
+ var store_end uint
+ if num_bytes >= hasher.StoreLookahead() {
+ store_end = position + num_bytes - hasher.StoreLookahead() + 1
+ } else {
+ store_end = position
+ }
+ var cur_match_pos uint = 0
+ var i uint
+ var orig_num_literals uint
+ var orig_last_insert_len uint
+ var orig_dist_cache [4]int
+ var orig_num_commands int
+ var model zopfliCostModel
+ var nodes []zopfliNode
+ var matches []backwardMatch = make([]backwardMatch, matches_size)
+ var gap uint = 0
+ var shadow_matches uint = 0
+ var new_array []backwardMatch
+ for i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {
+ var pos uint = position + i
+ var max_distance uint = brotli_min_size_t(pos, max_backward_limit)
+ var max_length uint = num_bytes - i
+ var num_found_matches uint
+ var cur_match_end uint
+ var j uint
+
+ /* Ensure that we have enough free slots. */
+ if matches_size < cur_match_pos+maxNumMatchesH10+shadow_matches {
+ var new_size uint = matches_size
+ if new_size == 0 {
+ new_size = cur_match_pos + maxNumMatchesH10 + shadow_matches
+ }
+
+ for new_size < cur_match_pos+maxNumMatchesH10+shadow_matches {
+ new_size *= 2
+ }
+
+ new_array = make([]backwardMatch, new_size)
+ if matches_size != 0 {
+ copy(new_array, matches[:matches_size])
+ }
+
+ matches = new_array
+ matches_size = new_size
+ }
+
+ num_found_matches = findAllMatchesH10(hasher.(*h10), ¶ms.dictionary, ringbuffer, ringbuffer_mask, pos, max_length, max_distance, gap, params, matches[cur_match_pos+shadow_matches:])
+ cur_match_end = cur_match_pos + num_found_matches
+ for j = cur_match_pos; j+1 < cur_match_end; j++ {
+ assert(backwardMatchLength(&matches[j]) <= backwardMatchLength(&matches[j+1]))
+ }
+
+ num_matches[i] = uint32(num_found_matches)
+ if num_found_matches > 0 {
+ var match_len uint = backwardMatchLength(&matches[cur_match_end-1])
+ if match_len > maxZopfliLenQuality11 {
+ var skip uint = match_len - 1
+ matches[cur_match_pos] = matches[cur_match_end-1]
+ cur_match_pos++
+ num_matches[i] = 1
+
+ /* Add the tail of the copy to the hasher. */
+ hasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+match_len, store_end))
+ var pos uint = i
+ for i := 0; i < int(skip); i++ {
+ num_matches[pos+1:][i] = 0
+ }
+ i += skip
+ } else {
+ cur_match_pos = cur_match_end
+ }
+ }
+ }
+
+ orig_num_literals = *num_literals
+ orig_last_insert_len = *last_insert_len
+ copy(orig_dist_cache[:], dist_cache[:4])
+ orig_num_commands = len(*commands)
+ nodes = make([]zopfliNode, (num_bytes + 1))
+ initZopfliCostModel(&model, ¶ms.dist, num_bytes)
+ for i = 0; i < 2; i++ {
+ initZopfliNodes(nodes, num_bytes+1)
+ if i == 0 {
+ zopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)
+ } else {
+ zopfliCostModelSetFromCommands(&model, position, ringbuffer, ringbuffer_mask, (*commands)[orig_num_commands:], orig_last_insert_len)
+ }
+
+ *commands = (*commands)[:orig_num_commands]
+ *num_literals = orig_num_literals
+ *last_insert_len = orig_last_insert_len
+ copy(dist_cache, orig_dist_cache[:4])
+ zopfliIterate(num_bytes, position, ringbuffer, ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches, nodes)
+ zopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)
+ }
+
+ cleanupZopfliCostModel(&model)
+ nodes = nil
+ matches = nil
+ num_matches = nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/bit_cost.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/bit_cost.go
new file mode 100644
index 000000000000..0005fc15e63b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/bit_cost.go
@@ -0,0 +1,436 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions to estimate the bit cost of Huffman trees. */
+func shannonEntropy(population []uint32, size uint, total *uint) float64 {
+ var sum uint = 0
+ var retval float64 = 0
+ var population_end []uint32 = population[size:]
+ var p uint
+ for -cap(population) < -cap(population_end) {
+ p = uint(population[0])
+ population = population[1:]
+ sum += p
+ retval -= float64(p) * fastLog2(p)
+ }
+
+ if sum != 0 {
+ retval += float64(sum) * fastLog2(sum)
+ }
+ *total = sum
+ return retval
+}
+
+func bitsEntropy(population []uint32, size uint) float64 {
+ var sum uint
+ var retval float64 = shannonEntropy(population, size, &sum)
+ if retval < float64(sum) {
+ /* At least one bit per literal is needed. */
+ retval = float64(sum)
+ }
+
+ return retval
+}
+
+const kOneSymbolHistogramCost float64 = 12
+const kTwoSymbolHistogramCost float64 = 20
+const kThreeSymbolHistogramCost float64 = 28
+const kFourSymbolHistogramCost float64 = 37
+
+func populationCostLiteral(histogram *histogramLiteral) float64 {
+ var data_size uint = histogramDataSizeLiteral()
+ var count int = 0
+ var s [5]uint
+ var bits float64 = 0.0
+ var i uint
+ if histogram.total_count_ == 0 {
+ return kOneSymbolHistogramCost
+ }
+
+ for i = 0; i < data_size; i++ {
+ if histogram.data_[i] > 0 {
+ s[count] = i
+ count++
+ if count > 4 {
+ break
+ }
+ }
+ }
+
+ if count == 1 {
+ return kOneSymbolHistogramCost
+ }
+
+ if count == 2 {
+ return kTwoSymbolHistogramCost + float64(histogram.total_count_)
+ }
+
+ if count == 3 {
+ var histo0 uint32 = histogram.data_[s[0]]
+ var histo1 uint32 = histogram.data_[s[1]]
+ var histo2 uint32 = histogram.data_[s[2]]
+ var histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))
+ return kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)
+ }
+
+ if count == 4 {
+ var histo [4]uint32
+ var h23 uint32
+ var histomax uint32
+ for i = 0; i < 4; i++ {
+ histo[i] = histogram.data_[s[i]]
+ }
+
+ /* Sort */
+ for i = 0; i < 4; i++ {
+ var j uint
+ for j = i + 1; j < 4; j++ {
+ if histo[j] > histo[i] {
+ var tmp uint32 = histo[j]
+ histo[j] = histo[i]
+ histo[i] = tmp
+ }
+ }
+ }
+
+ h23 = histo[2] + histo[3]
+ histomax = brotli_max_uint32_t(h23, histo[0])
+ return kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)
+ }
+ {
+ var max_depth uint = 1
+ var depth_histo = [codeLengthCodes]uint32{0}
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+
+ var log2total float64 = fastLog2(histogram.total_count_)
+ for i = 0; i < data_size; {
+ if histogram.data_[i] > 0 {
+ var log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+
+ var depth uint = uint(log2p + 0.5)
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ bits += float64(histogram.data_[i]) * log2p
+
+ if depth > 15 {
+ depth = 15
+ }
+
+ if depth > max_depth {
+ max_depth = depth
+ }
+
+ depth_histo[depth]++
+ i++
+ } else {
+ var reps uint32 = 1
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+
+ var k uint
+ for k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ if i == data_size {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break
+ }
+
+ if reps < 3 {
+ depth_histo[0] += reps
+ } else {
+ reps -= 2
+ for reps > 0 {
+ depth_histo[repeatZeroCodeLength]++
+
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3
+
+ reps >>= 3
+ }
+ }
+ }
+ }
+
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += float64(18 + 2*max_depth)
+
+ /* Add the entropy of the code length code histogram. */
+ bits += bitsEntropy(depth_histo[:], codeLengthCodes)
+ }
+
+ return bits
+}
+
+func populationCostCommand(histogram *histogramCommand) float64 {
+ var data_size uint = histogramDataSizeCommand()
+ var count int = 0
+ var s [5]uint
+ var bits float64 = 0.0
+ var i uint
+ if histogram.total_count_ == 0 {
+ return kOneSymbolHistogramCost
+ }
+
+ for i = 0; i < data_size; i++ {
+ if histogram.data_[i] > 0 {
+ s[count] = i
+ count++
+ if count > 4 {
+ break
+ }
+ }
+ }
+
+ if count == 1 {
+ return kOneSymbolHistogramCost
+ }
+
+ if count == 2 {
+ return kTwoSymbolHistogramCost + float64(histogram.total_count_)
+ }
+
+ if count == 3 {
+ var histo0 uint32 = histogram.data_[s[0]]
+ var histo1 uint32 = histogram.data_[s[1]]
+ var histo2 uint32 = histogram.data_[s[2]]
+ var histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))
+ return kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)
+ }
+
+ if count == 4 {
+ var histo [4]uint32
+ var h23 uint32
+ var histomax uint32
+ for i = 0; i < 4; i++ {
+ histo[i] = histogram.data_[s[i]]
+ }
+
+ /* Sort */
+ for i = 0; i < 4; i++ {
+ var j uint
+ for j = i + 1; j < 4; j++ {
+ if histo[j] > histo[i] {
+ var tmp uint32 = histo[j]
+ histo[j] = histo[i]
+ histo[i] = tmp
+ }
+ }
+ }
+
+ h23 = histo[2] + histo[3]
+ histomax = brotli_max_uint32_t(h23, histo[0])
+ return kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)
+ }
+ {
+ var max_depth uint = 1
+ var depth_histo = [codeLengthCodes]uint32{0}
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+
+ var log2total float64 = fastLog2(histogram.total_count_)
+ for i = 0; i < data_size; {
+ if histogram.data_[i] > 0 {
+ var log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+
+ var depth uint = uint(log2p + 0.5)
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ bits += float64(histogram.data_[i]) * log2p
+
+ if depth > 15 {
+ depth = 15
+ }
+
+ if depth > max_depth {
+ max_depth = depth
+ }
+
+ depth_histo[depth]++
+ i++
+ } else {
+ var reps uint32 = 1
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+
+ var k uint
+ for k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ if i == data_size {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break
+ }
+
+ if reps < 3 {
+ depth_histo[0] += reps
+ } else {
+ reps -= 2
+ for reps > 0 {
+ depth_histo[repeatZeroCodeLength]++
+
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3
+
+ reps >>= 3
+ }
+ }
+ }
+ }
+
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += float64(18 + 2*max_depth)
+
+ /* Add the entropy of the code length code histogram. */
+ bits += bitsEntropy(depth_histo[:], codeLengthCodes)
+ }
+
+ return bits
+}
+
+func populationCostDistance(histogram *histogramDistance) float64 {
+ var data_size uint = histogramDataSizeDistance()
+ var count int = 0
+ var s [5]uint
+ var bits float64 = 0.0
+ var i uint
+ if histogram.total_count_ == 0 {
+ return kOneSymbolHistogramCost
+ }
+
+ for i = 0; i < data_size; i++ {
+ if histogram.data_[i] > 0 {
+ s[count] = i
+ count++
+ if count > 4 {
+ break
+ }
+ }
+ }
+
+ if count == 1 {
+ return kOneSymbolHistogramCost
+ }
+
+ if count == 2 {
+ return kTwoSymbolHistogramCost + float64(histogram.total_count_)
+ }
+
+ if count == 3 {
+ var histo0 uint32 = histogram.data_[s[0]]
+ var histo1 uint32 = histogram.data_[s[1]]
+ var histo2 uint32 = histogram.data_[s[2]]
+ var histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))
+ return kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)
+ }
+
+ if count == 4 {
+ var histo [4]uint32
+ var h23 uint32
+ var histomax uint32
+ for i = 0; i < 4; i++ {
+ histo[i] = histogram.data_[s[i]]
+ }
+
+ /* Sort */
+ for i = 0; i < 4; i++ {
+ var j uint
+ for j = i + 1; j < 4; j++ {
+ if histo[j] > histo[i] {
+ var tmp uint32 = histo[j]
+ histo[j] = histo[i]
+ histo[i] = tmp
+ }
+ }
+ }
+
+ h23 = histo[2] + histo[3]
+ histomax = brotli_max_uint32_t(h23, histo[0])
+ return kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)
+ }
+ {
+ var max_depth uint = 1
+ var depth_histo = [codeLengthCodes]uint32{0}
+ /* In this loop we compute the entropy of the histogram and simultaneously
+ build a simplified histogram of the code length codes where we use the
+ zero repeat code 17, but we don't use the non-zero repeat code 16. */
+
+ var log2total float64 = fastLog2(histogram.total_count_)
+ for i = 0; i < data_size; {
+ if histogram.data_[i] > 0 {
+ var log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))
+ /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
+ = log2(total_count) - log2(count(symbol)) */
+
+ var depth uint = uint(log2p + 0.5)
+ /* Approximate the bit depth by round(-log2(P(symbol))) */
+ bits += float64(histogram.data_[i]) * log2p
+
+ if depth > 15 {
+ depth = 15
+ }
+
+ if depth > max_depth {
+ max_depth = depth
+ }
+
+ depth_histo[depth]++
+ i++
+ } else {
+ var reps uint32 = 1
+ /* Compute the run length of zeros and add the appropriate number of 0
+ and 17 code length codes to the code length code histogram. */
+
+ var k uint
+ for k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ if i == data_size {
+ /* Don't add any cost for the last zero run, since these are encoded
+ only implicitly. */
+ break
+ }
+
+ if reps < 3 {
+ depth_histo[0] += reps
+ } else {
+ reps -= 2
+ for reps > 0 {
+ depth_histo[repeatZeroCodeLength]++
+
+ /* Add the 3 extra bits for the 17 code length code. */
+ bits += 3
+
+ reps >>= 3
+ }
+ }
+ }
+ }
+
+ /* Add the estimated encoding cost of the code length code histogram. */
+ bits += float64(18 + 2*max_depth)
+
+ /* Add the entropy of the code length code histogram. */
+ bits += bitsEntropy(depth_histo[:], codeLengthCodes)
+ }
+
+ return bits
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/bit_reader.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/bit_reader.go
new file mode 100644
index 000000000000..fba8687c69f3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/bit_reader.go
@@ -0,0 +1,266 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Bit reading helpers */
+
+const shortFillBitWindowRead = (8 >> 1)
+
+var kBitMask = [33]uint32{
+ 0x00000000,
+ 0x00000001,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000F,
+ 0x0000001F,
+ 0x0000003F,
+ 0x0000007F,
+ 0x000000FF,
+ 0x000001FF,
+ 0x000003FF,
+ 0x000007FF,
+ 0x00000FFF,
+ 0x00001FFF,
+ 0x00003FFF,
+ 0x00007FFF,
+ 0x0000FFFF,
+ 0x0001FFFF,
+ 0x0003FFFF,
+ 0x0007FFFF,
+ 0x000FFFFF,
+ 0x001FFFFF,
+ 0x003FFFFF,
+ 0x007FFFFF,
+ 0x00FFFFFF,
+ 0x01FFFFFF,
+ 0x03FFFFFF,
+ 0x07FFFFFF,
+ 0x0FFFFFFF,
+ 0x1FFFFFFF,
+ 0x3FFFFFFF,
+ 0x7FFFFFFF,
+ 0xFFFFFFFF,
+}
+
+func bitMask(n uint32) uint32 {
+ return kBitMask[n]
+}
+
+type bitReader struct {
+ val_ uint64
+ bit_pos_ uint32
+ input []byte
+ input_len uint
+ byte_pos uint
+}
+
+type bitReaderState struct {
+ val_ uint64
+ bit_pos_ uint32
+ input []byte
+ input_len uint
+ byte_pos uint
+}
+
+/* Initializes the BrotliBitReader fields. */
+
+/* Ensures that accumulator is not empty.
+ May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
+ Returns false if data is required but there is no input available.
+ For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
+ reading. */
+func bitReaderSaveState(from *bitReader, to *bitReaderState) {
+ to.val_ = from.val_
+ to.bit_pos_ = from.bit_pos_
+ to.input = from.input
+ to.input_len = from.input_len
+ to.byte_pos = from.byte_pos
+}
+
+func bitReaderRestoreState(to *bitReader, from *bitReaderState) {
+ to.val_ = from.val_
+ to.bit_pos_ = from.bit_pos_
+ to.input = from.input
+ to.input_len = from.input_len
+ to.byte_pos = from.byte_pos
+}
+
+func getAvailableBits(br *bitReader) uint32 {
+ return 64 - br.bit_pos_
+}
+
+/* Returns amount of unread bytes the bit reader still has buffered from the
+ BrotliInput, including whole bytes in br->val_. */
+func getRemainingBytes(br *bitReader) uint {
+ return uint(uint32(br.input_len-br.byte_pos) + (getAvailableBits(br) >> 3))
+}
+
+/* Checks if there is at least |num| bytes left in the input ring-buffer
+ (excluding the bits remaining in br->val_). */
+func checkInputAmount(br *bitReader, num uint) bool {
+ return br.input_len-br.byte_pos >= num
+}
+
+/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
+ Precondition: accumulator contains at least 1 bit.
+ |n_bits| should be in the range [1..24] for regular build. For portable
+ non-64-bit little-endian build only 16 bits are safe to request. */
+func fillBitWindow(br *bitReader, n_bits uint32) {
+ if br.bit_pos_ >= 32 {
+ br.val_ >>= 32
+ br.bit_pos_ ^= 32 /* here same as -= 32 because of the if condition */
+ br.val_ |= (uint64(binary.LittleEndian.Uint32(br.input[br.byte_pos:]))) << 32
+ br.byte_pos += 4
+ }
+}
+
+/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
+ more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */
+func fillBitWindow16(br *bitReader) {
+ fillBitWindow(br, 17)
+}
+
+/* Tries to pull one byte of input to accumulator.
+ Returns false if there is no input available. */
+func pullByte(br *bitReader) bool {
+ if br.byte_pos == br.input_len {
+ return false
+ }
+
+ br.val_ >>= 8
+ br.val_ |= (uint64(br.input[br.byte_pos])) << 56
+ br.bit_pos_ -= 8
+ br.byte_pos++
+ return true
+}
+
+/* Returns currently available bits.
+ The number of valid bits could be calculated by BrotliGetAvailableBits. */
+func getBitsUnmasked(br *bitReader) uint64 {
+ return br.val_ >> br.bit_pos_
+}
+
+/* Like BrotliGetBits, but does not mask the result.
+ The result contains at least 16 valid bits. */
+func get16BitsUnmasked(br *bitReader) uint32 {
+ fillBitWindow(br, 16)
+ return uint32(getBitsUnmasked(br))
+}
+
+/* Returns the specified number of bits from |br| without advancing bit
+ position. */
+func getBits(br *bitReader, n_bits uint32) uint32 {
+ fillBitWindow(br, n_bits)
+ return uint32(getBitsUnmasked(br)) & bitMask(n_bits)
+}
+
+/* Tries to peek the specified amount of bits. Returns false, if there
+ is not enough input. */
+func safeGetBits(br *bitReader, n_bits uint32, val *uint32) bool {
+ for getAvailableBits(br) < n_bits {
+ if !pullByte(br) {
+ return false
+ }
+ }
+
+ *val = uint32(getBitsUnmasked(br)) & bitMask(n_bits)
+ return true
+}
+
+/* Advances the bit pos by |n_bits|. */
+func dropBits(br *bitReader, n_bits uint32) {
+ br.bit_pos_ += n_bits
+}
+
+func bitReaderUnload(br *bitReader) {
+ var unused_bytes uint32 = getAvailableBits(br) >> 3
+ var unused_bits uint32 = unused_bytes << 3
+ br.byte_pos -= uint(unused_bytes)
+ if unused_bits == 64 {
+ br.val_ = 0
+ } else {
+ br.val_ <<= unused_bits
+ }
+
+ br.bit_pos_ += unused_bits
+}
+
+/* Reads the specified number of bits from |br| and advances the bit pos.
+ Precondition: accumulator MUST contain at least |n_bits|. */
+func takeBits(br *bitReader, n_bits uint32, val *uint32) {
+ *val = uint32(getBitsUnmasked(br)) & bitMask(n_bits)
+ dropBits(br, n_bits)
+}
+
+/* Reads the specified number of bits from |br| and advances the bit pos.
+ Assumes that there is enough input to perform BrotliFillBitWindow. */
+func readBits(br *bitReader, n_bits uint32) uint32 {
+ var val uint32
+ fillBitWindow(br, n_bits)
+ takeBits(br, n_bits, &val)
+ return val
+}
+
+/* Tries to read the specified amount of bits. Returns false, if there
+ is not enough input. |n_bits| MUST be positive. */
+func safeReadBits(br *bitReader, n_bits uint32, val *uint32) bool {
+ for getAvailableBits(br) < n_bits {
+ if !pullByte(br) {
+ return false
+ }
+ }
+
+ takeBits(br, n_bits, val)
+ return true
+}
+
+/* Advances the bit reader position to the next byte boundary and verifies
+ that any skipped bits are set to zero. */
+func bitReaderJumpToByteBoundary(br *bitReader) bool {
+ var pad_bits_count uint32 = getAvailableBits(br) & 0x7
+ var pad_bits uint32 = 0
+ if pad_bits_count != 0 {
+ takeBits(br, pad_bits_count, &pad_bits)
+ }
+
+ return pad_bits == 0
+}
+
+/* Copies remaining input bytes stored in the bit reader to the output. Value
+ |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
+ warmed up again after this. */
+func copyBytes(dest []byte, br *bitReader, num uint) {
+ for getAvailableBits(br) >= 8 && num > 0 {
+ dest[0] = byte(getBitsUnmasked(br))
+ dropBits(br, 8)
+ dest = dest[1:]
+ num--
+ }
+
+ copy(dest, br.input[br.byte_pos:][:num])
+ br.byte_pos += num
+}
+
+func initBitReader(br *bitReader) {
+ br.val_ = 0
+ br.bit_pos_ = 64
+}
+
+func warmupBitReader(br *bitReader) bool {
+ /* Fixing alignment after unaligned BrotliFillWindow would result accumulator
+ overflow. If unalignment is caused by BrotliSafeReadBits, then there is
+ enough space in accumulator to fix alignment. */
+ if getAvailableBits(br) == 0 {
+ if !pullByte(br) {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter.go
new file mode 100644
index 000000000000..978a1314748d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter.go
@@ -0,0 +1,144 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Block split point selection utilities. */
+
+type blockSplit struct {
+ num_types uint
+ num_blocks uint
+ types []byte
+ lengths []uint32
+ types_alloc_size uint
+ lengths_alloc_size uint
+}
+
+const (
+ kMaxLiteralHistograms uint = 100
+ kMaxCommandHistograms uint = 50
+ kLiteralBlockSwitchCost float64 = 28.1
+ kCommandBlockSwitchCost float64 = 13.5
+ kDistanceBlockSwitchCost float64 = 14.6
+ kLiteralStrideLength uint = 70
+ kCommandStrideLength uint = 40
+ kSymbolsPerLiteralHistogram uint = 544
+ kSymbolsPerCommandHistogram uint = 530
+ kSymbolsPerDistanceHistogram uint = 544
+ kMinLengthForBlockSplitting uint = 128
+ kIterMulForRefining uint = 2
+ kMinItersForRefining uint = 100
+)
+
+func countLiterals(cmds []command) uint {
+ var total_length uint = 0
+ /* Count how many we have. */
+
+ for i := range cmds {
+ total_length += uint(cmds[i].insert_len_)
+ }
+
+ return total_length
+}
+
+func copyLiteralsToByteArray(cmds []command, data []byte, offset uint, mask uint, literals []byte) {
+ var pos uint = 0
+ var from_pos uint = offset & mask
+ for i := range cmds {
+ var insert_len uint = uint(cmds[i].insert_len_)
+ if from_pos+insert_len > mask {
+ var head_size uint = mask + 1 - from_pos
+ copy(literals[pos:], data[from_pos:][:head_size])
+ from_pos = 0
+ pos += head_size
+ insert_len -= head_size
+ }
+
+ if insert_len > 0 {
+ copy(literals[pos:], data[from_pos:][:insert_len])
+ pos += insert_len
+ }
+
+ from_pos = uint((uint32(from_pos+insert_len) + commandCopyLen(&cmds[i])) & uint32(mask))
+ }
+}
+
+func myRand(seed *uint32) uint32 {
+ /* Initial seed should be 7. In this case, loop length is (1 << 29). */
+ *seed *= 16807
+
+ return *seed
+}
+
+func bitCost(count uint) float64 {
+ if count == 0 {
+ return -2.0
+ } else {
+ return fastLog2(count)
+ }
+}
+
+const histogramsPerBatch = 64
+
+const clustersPerBatch = 16
+
+func initBlockSplit(self *blockSplit) {
+ self.num_types = 0
+ self.num_blocks = 0
+ self.types = self.types[:0]
+ self.lengths = self.lengths[:0]
+ self.types_alloc_size = 0
+ self.lengths_alloc_size = 0
+}
+
+func splitBlock(cmds []command, data []byte, pos uint, mask uint, params *encoderParams, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit) {
+ {
+ var literals_count uint = countLiterals(cmds)
+ var literals []byte = make([]byte, literals_count)
+
+ /* Create a continuous array of literals. */
+ copyLiteralsToByteArray(cmds, data, pos, mask, literals)
+
+ /* Create the block split on the array of literals.
+ Literal histograms have alphabet size 256. */
+ splitByteVectorLiteral(literals, literals_count, kSymbolsPerLiteralHistogram, kMaxLiteralHistograms, kLiteralStrideLength, kLiteralBlockSwitchCost, params, literal_split)
+
+ literals = nil
+ }
+ {
+ var insert_and_copy_codes []uint16 = make([]uint16, len(cmds))
+ /* Compute prefix codes for commands. */
+
+ for i := range cmds {
+ insert_and_copy_codes[i] = cmds[i].cmd_prefix_
+ }
+
+ /* Create the block split on the array of command prefixes. */
+ splitByteVectorCommand(insert_and_copy_codes, kSymbolsPerCommandHistogram, kMaxCommandHistograms, kCommandStrideLength, kCommandBlockSwitchCost, params, insert_and_copy_split)
+
+ /* TODO: reuse for distances? */
+
+ insert_and_copy_codes = nil
+ }
+ {
+ var distance_prefixes []uint16 = make([]uint16, len(cmds))
+ var j uint = 0
+ /* Create a continuous array of distance prefixes. */
+
+ for i := range cmds {
+ var cmd *command = &cmds[i]
+ if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ distance_prefixes[j] = cmd.dist_prefix_ & 0x3FF
+ j++
+ }
+ }
+
+ /* Create the block split on the array of distance prefixes. */
+ splitByteVectorDistance(distance_prefixes, j, kSymbolsPerDistanceHistogram, kMaxCommandHistograms, kCommandStrideLength, kDistanceBlockSwitchCost, params, dist_split)
+
+ distance_prefixes = nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_command.go
new file mode 100644
index 000000000000..9dec13e4d907
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_command.go
@@ -0,0 +1,434 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func initialEntropyCodesCommand(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramCommand) {
+ var seed uint32 = 7
+ var block_length uint = length / num_histograms
+ var i uint
+ clearHistogramsCommand(histograms, num_histograms)
+ for i = 0; i < num_histograms; i++ {
+ var pos uint = length * i / num_histograms
+ if i != 0 {
+ pos += uint(myRand(&seed) % uint32(block_length))
+ }
+
+ if pos+stride >= length {
+ pos = length - stride - 1
+ }
+
+ histogramAddVectorCommand(&histograms[i], data[pos:], stride)
+ }
+}
+
+func randomSampleCommand(seed *uint32, data []uint16, length uint, stride uint, sample *histogramCommand) {
+ var pos uint = 0
+ if stride >= length {
+ stride = length
+ } else {
+ pos = uint(myRand(seed) % uint32(length-stride+1))
+ }
+
+ histogramAddVectorCommand(sample, data[pos:], stride)
+}
+
+func refineEntropyCodesCommand(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramCommand) {
+ var iters uint = kIterMulForRefining*length/stride + kMinItersForRefining
+ var seed uint32 = 7
+ var iter uint
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms
+ for iter = 0; iter < iters; iter++ {
+ var sample histogramCommand
+ histogramClearCommand(&sample)
+ randomSampleCommand(&seed, data, length, stride, &sample)
+ histogramAddHistogramCommand(&histograms[iter%num_histograms], &sample)
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+func findBlocksCommand(data []uint16, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramCommand, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {
+ var data_size uint = histogramDataSizeCommand()
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var num_blocks uint = 1
+ var i uint
+ var j uint
+ assert(num_histograms <= 256)
+ if num_histograms <= 1 {
+ for i = 0; i < length; i++ {
+ block_id[i] = 0
+ }
+
+ return 1
+ }
+
+ for i := 0; i < int(data_size*num_histograms); i++ {
+ insert_cost[i] = 0
+ }
+ for i = 0; i < num_histograms; i++ {
+ insert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))
+ }
+
+ for i = data_size; i != 0; {
+ i--
+ for j = 0; j < num_histograms; j++ {
+ insert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))
+ }
+ }
+
+ for i := 0; i < int(num_histograms); i++ {
+ cost[i] = 0
+ }
+ for i := 0; i < int(length*bitmaplen); i++ {
+ switch_signal[i] = 0
+ }
+
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for i = 0; i < length; i++ {
+ var byte_ix uint = i
+ var ix uint = byte_ix * bitmaplen
+ var insert_cost_ix uint = uint(data[byte_ix]) * num_histograms
+ var min_cost float64 = 1e99
+ var block_switch_cost float64 = block_switch_bitcost
+ var k uint
+ for k = 0; k < num_histograms; k++ {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix+k]
+
+ if cost[k] < min_cost {
+ min_cost = cost[k]
+ block_id[byte_ix] = byte(k)
+ }
+ }
+
+ /* More blocks for the beginning. */
+ if byte_ix < 2000 {
+ block_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000
+ }
+
+ for k = 0; k < num_histograms; k++ {
+ cost[k] -= min_cost
+ if cost[k] >= block_switch_cost {
+ var mask byte = byte(1 << (k & 7))
+ cost[k] = block_switch_cost
+ assert(k>>3 < bitmaplen)
+ switch_signal[ix+(k>>3)] |= mask
+ /* Trace back from the last position and switch at the marked places. */
+ }
+ }
+ }
+ {
+ var byte_ix uint = length - 1
+ var ix uint = byte_ix * bitmaplen
+ var cur_id byte = block_id[byte_ix]
+ for byte_ix > 0 {
+ var mask byte = byte(1 << (cur_id & 7))
+ assert(uint(cur_id)>>3 < bitmaplen)
+ byte_ix--
+ ix -= bitmaplen
+ if switch_signal[ix+uint(cur_id>>3)]&mask != 0 {
+ if cur_id != block_id[byte_ix] {
+ cur_id = block_id[byte_ix]
+ num_blocks++
+ }
+ }
+
+ block_id[byte_ix] = cur_id
+ }
+ }
+
+ return num_blocks
+}
+
+var remapBlockIdsCommand_kInvalidId uint16 = 256
+
+func remapBlockIdsCommand(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {
+ var next_id uint16 = 0
+ var i uint
+ for i = 0; i < num_histograms; i++ {
+ new_id[i] = remapBlockIdsCommand_kInvalidId
+ }
+
+ for i = 0; i < length; i++ {
+ assert(uint(block_ids[i]) < num_histograms)
+ if new_id[block_ids[i]] == remapBlockIdsCommand_kInvalidId {
+ new_id[block_ids[i]] = next_id
+ next_id++
+ }
+ }
+
+ for i = 0; i < length; i++ {
+ block_ids[i] = byte(new_id[block_ids[i]])
+ assert(uint(block_ids[i]) < num_histograms)
+ }
+
+ assert(uint(next_id) <= num_histograms)
+ return uint(next_id)
+}
+
+func buildBlockHistogramsCommand(data []uint16, length uint, block_ids []byte, num_histograms uint, histograms []histogramCommand) {
+ var i uint
+ clearHistogramsCommand(histograms, num_histograms)
+ for i = 0; i < length; i++ {
+ histogramAddCommand(&histograms[block_ids[i]], uint(data[i]))
+ }
+}
+
+var clusterBlocksCommand_kInvalidIndex uint32 = math.MaxUint32
+
+func clusterBlocksCommand(data []uint16, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {
+ var histogram_symbols []uint32 = make([]uint32, num_blocks)
+ var block_lengths []uint32 = make([]uint32, num_blocks)
+ var expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch
+ var all_histograms_size uint = 0
+ var all_histograms_capacity uint = expected_num_clusters
+ var all_histograms []histogramCommand = make([]histogramCommand, all_histograms_capacity)
+ var cluster_size_size uint = 0
+ var cluster_size_capacity uint = expected_num_clusters
+ var cluster_size []uint32 = make([]uint32, cluster_size_capacity)
+ var num_clusters uint = 0
+ var histograms []histogramCommand = make([]histogramCommand, brotli_min_size_t(num_blocks, histogramsPerBatch))
+ var max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2
+ var pairs_capacity uint = max_num_pairs + 1
+ var pairs []histogramPair = make([]histogramPair, pairs_capacity)
+ var pos uint = 0
+ var clusters []uint32
+ var num_final_clusters uint
+ var new_index []uint32
+ var i uint
+ var sizes = [histogramsPerBatch]uint32{0}
+ var new_clusters = [histogramsPerBatch]uint32{0}
+ var symbols = [histogramsPerBatch]uint32{0}
+ var remap = [histogramsPerBatch]uint32{0}
+
+ for i := 0; i < int(num_blocks); i++ {
+ block_lengths[i] = 0
+ }
+ {
+ var block_idx uint = 0
+ for i = 0; i < length; i++ {
+ assert(block_idx < num_blocks)
+ block_lengths[block_idx]++
+ if i+1 == length || block_ids[i] != block_ids[i+1] {
+ block_idx++
+ }
+ }
+
+ assert(block_idx == num_blocks)
+ }
+
+ for i = 0; i < num_blocks; i += histogramsPerBatch {
+ var num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ var k uint
+ histogramClearCommand(&histograms[j])
+ for k = 0; uint32(k) < block_lengths[i+j]; k++ {
+ histogramAddCommand(&histograms[j], uint(data[pos]))
+ pos++
+ }
+
+ histograms[j].bit_cost_ = populationCostCommand(&histograms[j])
+ new_clusters[j] = uint32(j)
+ symbols[j] = uint32(j)
+ sizes[j] = 1
+ }
+
+ num_new_clusters = histogramCombineCommand(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)
+ if all_histograms_capacity < (all_histograms_size + num_new_clusters) {
+ var _new_size uint
+ if all_histograms_capacity == 0 {
+ _new_size = all_histograms_size + num_new_clusters
+ } else {
+ _new_size = all_histograms_capacity
+ }
+ var new_array []histogramCommand
+ for _new_size < (all_histograms_size + num_new_clusters) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramCommand, _new_size)
+ if all_histograms_capacity != 0 {
+ copy(new_array, all_histograms[:all_histograms_capacity])
+ }
+
+ all_histograms = new_array
+ all_histograms_capacity = _new_size
+ }
+
+ brotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)
+ for j = 0; j < num_new_clusters; j++ {
+ all_histograms[all_histograms_size] = histograms[new_clusters[j]]
+ all_histograms_size++
+ cluster_size[cluster_size_size] = sizes[new_clusters[j]]
+ cluster_size_size++
+ remap[new_clusters[j]] = uint32(j)
+ }
+
+ for j = 0; j < num_to_combine; j++ {
+ histogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]
+ }
+
+ num_clusters += num_new_clusters
+ assert(num_clusters == cluster_size_size)
+ assert(num_clusters == all_histograms_size)
+ }
+
+ histograms = nil
+
+ max_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < max_num_pairs+1 {
+ pairs = nil
+ pairs = make([]histogramPair, (max_num_pairs + 1))
+ }
+
+ clusters = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ clusters[i] = uint32(i)
+ }
+
+ num_final_clusters = histogramCombineCommand(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)
+ pairs = nil
+ cluster_size = nil
+
+ new_index = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ new_index[i] = clusterBlocksCommand_kInvalidIndex
+ }
+ pos = 0
+ {
+ var next_index uint32 = 0
+ for i = 0; i < num_blocks; i++ {
+ var histo histogramCommand
+ var j uint
+ var best_out uint32
+ var best_bits float64
+ histogramClearCommand(&histo)
+ for j = 0; uint32(j) < block_lengths[i]; j++ {
+ histogramAddCommand(&histo, uint(data[pos]))
+ pos++
+ }
+
+ if i == 0 {
+ best_out = histogram_symbols[0]
+ } else {
+ best_out = histogram_symbols[i-1]
+ }
+ best_bits = histogramBitCostDistanceCommand(&histo, &all_histograms[best_out])
+ for j = 0; j < num_final_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceCommand(&histo, &all_histograms[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ histogram_symbols[i] = best_out
+ if new_index[best_out] == clusterBlocksCommand_kInvalidIndex {
+ new_index[best_out] = next_index
+ next_index++
+ }
+ }
+ }
+
+ clusters = nil
+ all_histograms = nil
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)
+ {
+ var cur_length uint32 = 0
+ var block_idx uint = 0
+ var max_type byte = 0
+ for i = 0; i < num_blocks; i++ {
+ cur_length += block_lengths[i]
+ if i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {
+ var id byte = byte(new_index[histogram_symbols[i]])
+ split.types[block_idx] = id
+ split.lengths[block_idx] = cur_length
+ max_type = brotli_max_uint8_t(max_type, id)
+ cur_length = 0
+ block_idx++
+ }
+ }
+
+ split.num_blocks = block_idx
+ split.num_types = uint(max_type) + 1
+ }
+
+ new_index = nil
+ block_lengths = nil
+ histogram_symbols = nil
+}
+
+func splitByteVectorCommand(data []uint16, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {
+ length := uint(len(data))
+ var data_size uint = histogramDataSizeCommand()
+ var num_histograms uint = length/literals_per_histogram + 1
+ var histograms []histogramCommand
+ if num_histograms > max_histograms {
+ num_histograms = max_histograms
+ }
+
+ if length == 0 {
+ split.num_types = 1
+ return
+ } else if length < kMinLengthForBlockSplitting {
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)
+ split.num_types = 1
+ split.types[split.num_blocks] = 0
+ split.lengths[split.num_blocks] = uint32(length)
+ split.num_blocks++
+ return
+ }
+
+ histograms = make([]histogramCommand, num_histograms)
+
+ /* Find good entropy codes. */
+ initialEntropyCodesCommand(data, length, sampling_stride_length, num_histograms, histograms)
+
+ refineEntropyCodesCommand(data, length, sampling_stride_length, num_histograms, histograms)
+ {
+ var block_ids []byte = make([]byte, length)
+ var num_blocks uint = 0
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var insert_cost []float64 = make([]float64, (data_size * num_histograms))
+ var cost []float64 = make([]float64, num_histograms)
+ var switch_signal []byte = make([]byte, (length * bitmaplen))
+ var new_id []uint16 = make([]uint16, num_histograms)
+ var iters uint
+ if params.quality < hqZopflificationQuality {
+ iters = 3
+ } else {
+ iters = 10
+ }
+ /* Find a good path through literals with the good entropy codes. */
+
+ var i uint
+ for i = 0; i < iters; i++ {
+ num_blocks = findBlocksCommand(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)
+ num_histograms = remapBlockIdsCommand(block_ids, length, new_id, num_histograms)
+ buildBlockHistogramsCommand(data, length, block_ids, num_histograms, histograms)
+ }
+
+ insert_cost = nil
+ cost = nil
+ switch_signal = nil
+ new_id = nil
+ histograms = nil
+ clusterBlocksCommand(data, length, num_blocks, block_ids, split)
+ block_ids = nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_distance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_distance.go
new file mode 100644
index 000000000000..953530d518e5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_distance.go
@@ -0,0 +1,433 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func initialEntropyCodesDistance(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramDistance) {
+ var seed uint32 = 7
+ var block_length uint = length / num_histograms
+ var i uint
+ clearHistogramsDistance(histograms, num_histograms)
+ for i = 0; i < num_histograms; i++ {
+ var pos uint = length * i / num_histograms
+ if i != 0 {
+ pos += uint(myRand(&seed) % uint32(block_length))
+ }
+
+ if pos+stride >= length {
+ pos = length - stride - 1
+ }
+
+ histogramAddVectorDistance(&histograms[i], data[pos:], stride)
+ }
+}
+
+func randomSampleDistance(seed *uint32, data []uint16, length uint, stride uint, sample *histogramDistance) {
+ var pos uint = 0
+ if stride >= length {
+ stride = length
+ } else {
+ pos = uint(myRand(seed) % uint32(length-stride+1))
+ }
+
+ histogramAddVectorDistance(sample, data[pos:], stride)
+}
+
+func refineEntropyCodesDistance(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramDistance) {
+ var iters uint = kIterMulForRefining*length/stride + kMinItersForRefining
+ var seed uint32 = 7
+ var iter uint
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms
+ for iter = 0; iter < iters; iter++ {
+ var sample histogramDistance
+ histogramClearDistance(&sample)
+ randomSampleDistance(&seed, data, length, stride, &sample)
+ histogramAddHistogramDistance(&histograms[iter%num_histograms], &sample)
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+func findBlocksDistance(data []uint16, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramDistance, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {
+ var data_size uint = histogramDataSizeDistance()
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var num_blocks uint = 1
+ var i uint
+ var j uint
+ assert(num_histograms <= 256)
+ if num_histograms <= 1 {
+ for i = 0; i < length; i++ {
+ block_id[i] = 0
+ }
+
+ return 1
+ }
+
+ for i := 0; i < int(data_size*num_histograms); i++ {
+ insert_cost[i] = 0
+ }
+ for i = 0; i < num_histograms; i++ {
+ insert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))
+ }
+
+ for i = data_size; i != 0; {
+ i--
+ for j = 0; j < num_histograms; j++ {
+ insert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))
+ }
+ }
+
+ for i := 0; i < int(num_histograms); i++ {
+ cost[i] = 0
+ }
+ for i := 0; i < int(length*bitmaplen); i++ {
+ switch_signal[i] = 0
+ }
+
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for i = 0; i < length; i++ {
+ var byte_ix uint = i
+ var ix uint = byte_ix * bitmaplen
+ var insert_cost_ix uint = uint(data[byte_ix]) * num_histograms
+ var min_cost float64 = 1e99
+ var block_switch_cost float64 = block_switch_bitcost
+ var k uint
+ for k = 0; k < num_histograms; k++ {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix+k]
+
+ if cost[k] < min_cost {
+ min_cost = cost[k]
+ block_id[byte_ix] = byte(k)
+ }
+ }
+
+ /* More blocks for the beginning. */
+ if byte_ix < 2000 {
+ block_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000
+ }
+
+ for k = 0; k < num_histograms; k++ {
+ cost[k] -= min_cost
+ if cost[k] >= block_switch_cost {
+ var mask byte = byte(1 << (k & 7))
+ cost[k] = block_switch_cost
+ assert(k>>3 < bitmaplen)
+ switch_signal[ix+(k>>3)] |= mask
+ /* Trace back from the last position and switch at the marked places. */
+ }
+ }
+ }
+ {
+ var byte_ix uint = length - 1
+ var ix uint = byte_ix * bitmaplen
+ var cur_id byte = block_id[byte_ix]
+ for byte_ix > 0 {
+ var mask byte = byte(1 << (cur_id & 7))
+ assert(uint(cur_id)>>3 < bitmaplen)
+ byte_ix--
+ ix -= bitmaplen
+ if switch_signal[ix+uint(cur_id>>3)]&mask != 0 {
+ if cur_id != block_id[byte_ix] {
+ cur_id = block_id[byte_ix]
+ num_blocks++
+ }
+ }
+
+ block_id[byte_ix] = cur_id
+ }
+ }
+
+ return num_blocks
+}
+
+var remapBlockIdsDistance_kInvalidId uint16 = 256
+
+func remapBlockIdsDistance(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {
+ var next_id uint16 = 0
+ var i uint
+ for i = 0; i < num_histograms; i++ {
+ new_id[i] = remapBlockIdsDistance_kInvalidId
+ }
+
+ for i = 0; i < length; i++ {
+ assert(uint(block_ids[i]) < num_histograms)
+ if new_id[block_ids[i]] == remapBlockIdsDistance_kInvalidId {
+ new_id[block_ids[i]] = next_id
+ next_id++
+ }
+ }
+
+ for i = 0; i < length; i++ {
+ block_ids[i] = byte(new_id[block_ids[i]])
+ assert(uint(block_ids[i]) < num_histograms)
+ }
+
+ assert(uint(next_id) <= num_histograms)
+ return uint(next_id)
+}
+
+func buildBlockHistogramsDistance(data []uint16, length uint, block_ids []byte, num_histograms uint, histograms []histogramDistance) {
+ var i uint
+ clearHistogramsDistance(histograms, num_histograms)
+ for i = 0; i < length; i++ {
+ histogramAddDistance(&histograms[block_ids[i]], uint(data[i]))
+ }
+}
+
+var clusterBlocksDistance_kInvalidIndex uint32 = math.MaxUint32
+
+func clusterBlocksDistance(data []uint16, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {
+ var histogram_symbols []uint32 = make([]uint32, num_blocks)
+ var block_lengths []uint32 = make([]uint32, num_blocks)
+ var expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch
+ var all_histograms_size uint = 0
+ var all_histograms_capacity uint = expected_num_clusters
+ var all_histograms []histogramDistance = make([]histogramDistance, all_histograms_capacity)
+ var cluster_size_size uint = 0
+ var cluster_size_capacity uint = expected_num_clusters
+ var cluster_size []uint32 = make([]uint32, cluster_size_capacity)
+ var num_clusters uint = 0
+ var histograms []histogramDistance = make([]histogramDistance, brotli_min_size_t(num_blocks, histogramsPerBatch))
+ var max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2
+ var pairs_capacity uint = max_num_pairs + 1
+ var pairs []histogramPair = make([]histogramPair, pairs_capacity)
+ var pos uint = 0
+ var clusters []uint32
+ var num_final_clusters uint
+ var new_index []uint32
+ var i uint
+ var sizes = [histogramsPerBatch]uint32{0}
+ var new_clusters = [histogramsPerBatch]uint32{0}
+ var symbols = [histogramsPerBatch]uint32{0}
+ var remap = [histogramsPerBatch]uint32{0}
+
+ for i := 0; i < int(num_blocks); i++ {
+ block_lengths[i] = 0
+ }
+ {
+ var block_idx uint = 0
+ for i = 0; i < length; i++ {
+ assert(block_idx < num_blocks)
+ block_lengths[block_idx]++
+ if i+1 == length || block_ids[i] != block_ids[i+1] {
+ block_idx++
+ }
+ }
+
+ assert(block_idx == num_blocks)
+ }
+
+ for i = 0; i < num_blocks; i += histogramsPerBatch {
+ var num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ var k uint
+ histogramClearDistance(&histograms[j])
+ for k = 0; uint32(k) < block_lengths[i+j]; k++ {
+ histogramAddDistance(&histograms[j], uint(data[pos]))
+ pos++
+ }
+
+ histograms[j].bit_cost_ = populationCostDistance(&histograms[j])
+ new_clusters[j] = uint32(j)
+ symbols[j] = uint32(j)
+ sizes[j] = 1
+ }
+
+ num_new_clusters = histogramCombineDistance(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)
+ if all_histograms_capacity < (all_histograms_size + num_new_clusters) {
+ var _new_size uint
+ if all_histograms_capacity == 0 {
+ _new_size = all_histograms_size + num_new_clusters
+ } else {
+ _new_size = all_histograms_capacity
+ }
+ var new_array []histogramDistance
+ for _new_size < (all_histograms_size + num_new_clusters) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramDistance, _new_size)
+ if all_histograms_capacity != 0 {
+ copy(new_array, all_histograms[:all_histograms_capacity])
+ }
+
+ all_histograms = new_array
+ all_histograms_capacity = _new_size
+ }
+
+ brotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)
+ for j = 0; j < num_new_clusters; j++ {
+ all_histograms[all_histograms_size] = histograms[new_clusters[j]]
+ all_histograms_size++
+ cluster_size[cluster_size_size] = sizes[new_clusters[j]]
+ cluster_size_size++
+ remap[new_clusters[j]] = uint32(j)
+ }
+
+ for j = 0; j < num_to_combine; j++ {
+ histogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]
+ }
+
+ num_clusters += num_new_clusters
+ assert(num_clusters == cluster_size_size)
+ assert(num_clusters == all_histograms_size)
+ }
+
+ histograms = nil
+
+ max_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < max_num_pairs+1 {
+ pairs = nil
+ pairs = make([]histogramPair, (max_num_pairs + 1))
+ }
+
+ clusters = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ clusters[i] = uint32(i)
+ }
+
+ num_final_clusters = histogramCombineDistance(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)
+ pairs = nil
+ cluster_size = nil
+
+ new_index = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ new_index[i] = clusterBlocksDistance_kInvalidIndex
+ }
+ pos = 0
+ {
+ var next_index uint32 = 0
+ for i = 0; i < num_blocks; i++ {
+ var histo histogramDistance
+ var j uint
+ var best_out uint32
+ var best_bits float64
+ histogramClearDistance(&histo)
+ for j = 0; uint32(j) < block_lengths[i]; j++ {
+ histogramAddDistance(&histo, uint(data[pos]))
+ pos++
+ }
+
+ if i == 0 {
+ best_out = histogram_symbols[0]
+ } else {
+ best_out = histogram_symbols[i-1]
+ }
+ best_bits = histogramBitCostDistanceDistance(&histo, &all_histograms[best_out])
+ for j = 0; j < num_final_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceDistance(&histo, &all_histograms[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ histogram_symbols[i] = best_out
+ if new_index[best_out] == clusterBlocksDistance_kInvalidIndex {
+ new_index[best_out] = next_index
+ next_index++
+ }
+ }
+ }
+
+ clusters = nil
+ all_histograms = nil
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)
+ {
+ var cur_length uint32 = 0
+ var block_idx uint = 0
+ var max_type byte = 0
+ for i = 0; i < num_blocks; i++ {
+ cur_length += block_lengths[i]
+ if i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {
+ var id byte = byte(new_index[histogram_symbols[i]])
+ split.types[block_idx] = id
+ split.lengths[block_idx] = cur_length
+ max_type = brotli_max_uint8_t(max_type, id)
+ cur_length = 0
+ block_idx++
+ }
+ }
+
+ split.num_blocks = block_idx
+ split.num_types = uint(max_type) + 1
+ }
+
+ new_index = nil
+ block_lengths = nil
+ histogram_symbols = nil
+}
+
+func splitByteVectorDistance(data []uint16, length uint, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {
+ var data_size uint = histogramDataSizeDistance()
+ var num_histograms uint = length/literals_per_histogram + 1
+ var histograms []histogramDistance
+ if num_histograms > max_histograms {
+ num_histograms = max_histograms
+ }
+
+ if length == 0 {
+ split.num_types = 1
+ return
+ } else if length < kMinLengthForBlockSplitting {
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)
+ split.num_types = 1
+ split.types[split.num_blocks] = 0
+ split.lengths[split.num_blocks] = uint32(length)
+ split.num_blocks++
+ return
+ }
+
+ histograms = make([]histogramDistance, num_histograms)
+
+ /* Find good entropy codes. */
+ initialEntropyCodesDistance(data, length, sampling_stride_length, num_histograms, histograms)
+
+ refineEntropyCodesDistance(data, length, sampling_stride_length, num_histograms, histograms)
+ {
+ var block_ids []byte = make([]byte, length)
+ var num_blocks uint = 0
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var insert_cost []float64 = make([]float64, (data_size * num_histograms))
+ var cost []float64 = make([]float64, num_histograms)
+ var switch_signal []byte = make([]byte, (length * bitmaplen))
+ var new_id []uint16 = make([]uint16, num_histograms)
+ var iters uint
+ if params.quality < hqZopflificationQuality {
+ iters = 3
+ } else {
+ iters = 10
+ }
+ /* Find a good path through literals with the good entropy codes. */
+
+ var i uint
+ for i = 0; i < iters; i++ {
+ num_blocks = findBlocksDistance(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)
+ num_histograms = remapBlockIdsDistance(block_ids, length, new_id, num_histograms)
+ buildBlockHistogramsDistance(data, length, block_ids, num_histograms, histograms)
+ }
+
+ insert_cost = nil
+ cost = nil
+ switch_signal = nil
+ new_id = nil
+ histograms = nil
+ clusterBlocksDistance(data, length, num_blocks, block_ids, split)
+ block_ids = nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_literal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_literal.go
new file mode 100644
index 000000000000..1c895cf38895
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/block_splitter_literal.go
@@ -0,0 +1,433 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func initialEntropyCodesLiteral(data []byte, length uint, stride uint, num_histograms uint, histograms []histogramLiteral) {
+ var seed uint32 = 7
+ var block_length uint = length / num_histograms
+ var i uint
+ clearHistogramsLiteral(histograms, num_histograms)
+ for i = 0; i < num_histograms; i++ {
+ var pos uint = length * i / num_histograms
+ if i != 0 {
+ pos += uint(myRand(&seed) % uint32(block_length))
+ }
+
+ if pos+stride >= length {
+ pos = length - stride - 1
+ }
+
+ histogramAddVectorLiteral(&histograms[i], data[pos:], stride)
+ }
+}
+
+func randomSampleLiteral(seed *uint32, data []byte, length uint, stride uint, sample *histogramLiteral) {
+ var pos uint = 0
+ if stride >= length {
+ stride = length
+ } else {
+ pos = uint(myRand(seed) % uint32(length-stride+1))
+ }
+
+ histogramAddVectorLiteral(sample, data[pos:], stride)
+}
+
+func refineEntropyCodesLiteral(data []byte, length uint, stride uint, num_histograms uint, histograms []histogramLiteral) {
+ var iters uint = kIterMulForRefining*length/stride + kMinItersForRefining
+ var seed uint32 = 7
+ var iter uint
+ iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms
+ for iter = 0; iter < iters; iter++ {
+ var sample histogramLiteral
+ histogramClearLiteral(&sample)
+ randomSampleLiteral(&seed, data, length, stride, &sample)
+ histogramAddHistogramLiteral(&histograms[iter%num_histograms], &sample)
+ }
+}
+
+/* Assigns a block id from the range [0, num_histograms) to each data element
+ in data[0..length) and fills in block_id[0..length) with the assigned values.
+ Returns the number of blocks, i.e. one plus the number of block switches. */
+func findBlocksLiteral(data []byte, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramLiteral, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {
+ var data_size uint = histogramDataSizeLiteral()
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var num_blocks uint = 1
+ var i uint
+ var j uint
+ assert(num_histograms <= 256)
+ if num_histograms <= 1 {
+ for i = 0; i < length; i++ {
+ block_id[i] = 0
+ }
+
+ return 1
+ }
+
+ for i := 0; i < int(data_size*num_histograms); i++ {
+ insert_cost[i] = 0
+ }
+ for i = 0; i < num_histograms; i++ {
+ insert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))
+ }
+
+ for i = data_size; i != 0; {
+ i--
+ for j = 0; j < num_histograms; j++ {
+ insert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))
+ }
+ }
+
+ for i := 0; i < int(num_histograms); i++ {
+ cost[i] = 0
+ }
+ for i := 0; i < int(length*bitmaplen); i++ {
+ switch_signal[i] = 0
+ }
+
+ /* After each iteration of this loop, cost[k] will contain the difference
+ between the minimum cost of arriving at the current byte position using
+ entropy code k, and the minimum cost of arriving at the current byte
+ position. This difference is capped at the block switch cost, and if it
+ reaches block switch cost, it means that when we trace back from the last
+ position, we need to switch here. */
+ for i = 0; i < length; i++ {
+ var byte_ix uint = i
+ var ix uint = byte_ix * bitmaplen
+ var insert_cost_ix uint = uint(data[byte_ix]) * num_histograms
+ var min_cost float64 = 1e99
+ var block_switch_cost float64 = block_switch_bitcost
+ var k uint
+ for k = 0; k < num_histograms; k++ {
+ /* We are coding the symbol in data[byte_ix] with entropy code k. */
+ cost[k] += insert_cost[insert_cost_ix+k]
+
+ if cost[k] < min_cost {
+ min_cost = cost[k]
+ block_id[byte_ix] = byte(k)
+ }
+ }
+
+ /* More blocks for the beginning. */
+ if byte_ix < 2000 {
+ block_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000
+ }
+
+ for k = 0; k < num_histograms; k++ {
+ cost[k] -= min_cost
+ if cost[k] >= block_switch_cost {
+ var mask byte = byte(1 << (k & 7))
+ cost[k] = block_switch_cost
+ assert(k>>3 < bitmaplen)
+ switch_signal[ix+(k>>3)] |= mask
+ /* Trace back from the last position and switch at the marked places. */
+ }
+ }
+ }
+ {
+ var byte_ix uint = length - 1
+ var ix uint = byte_ix * bitmaplen
+ var cur_id byte = block_id[byte_ix]
+ for byte_ix > 0 {
+ var mask byte = byte(1 << (cur_id & 7))
+ assert(uint(cur_id)>>3 < bitmaplen)
+ byte_ix--
+ ix -= bitmaplen
+ if switch_signal[ix+uint(cur_id>>3)]&mask != 0 {
+ if cur_id != block_id[byte_ix] {
+ cur_id = block_id[byte_ix]
+ num_blocks++
+ }
+ }
+
+ block_id[byte_ix] = cur_id
+ }
+ }
+
+ return num_blocks
+}
+
+var remapBlockIdsLiteral_kInvalidId uint16 = 256
+
+func remapBlockIdsLiteral(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {
+ var next_id uint16 = 0
+ var i uint
+ for i = 0; i < num_histograms; i++ {
+ new_id[i] = remapBlockIdsLiteral_kInvalidId
+ }
+
+ for i = 0; i < length; i++ {
+ assert(uint(block_ids[i]) < num_histograms)
+ if new_id[block_ids[i]] == remapBlockIdsLiteral_kInvalidId {
+ new_id[block_ids[i]] = next_id
+ next_id++
+ }
+ }
+
+ for i = 0; i < length; i++ {
+ block_ids[i] = byte(new_id[block_ids[i]])
+ assert(uint(block_ids[i]) < num_histograms)
+ }
+
+ assert(uint(next_id) <= num_histograms)
+ return uint(next_id)
+}
+
+func buildBlockHistogramsLiteral(data []byte, length uint, block_ids []byte, num_histograms uint, histograms []histogramLiteral) {
+ var i uint
+ clearHistogramsLiteral(histograms, num_histograms)
+ for i = 0; i < length; i++ {
+ histogramAddLiteral(&histograms[block_ids[i]], uint(data[i]))
+ }
+}
+
+var clusterBlocksLiteral_kInvalidIndex uint32 = math.MaxUint32
+
+func clusterBlocksLiteral(data []byte, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {
+ var histogram_symbols []uint32 = make([]uint32, num_blocks)
+ var block_lengths []uint32 = make([]uint32, num_blocks)
+ var expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch
+ var all_histograms_size uint = 0
+ var all_histograms_capacity uint = expected_num_clusters
+ var all_histograms []histogramLiteral = make([]histogramLiteral, all_histograms_capacity)
+ var cluster_size_size uint = 0
+ var cluster_size_capacity uint = expected_num_clusters
+ var cluster_size []uint32 = make([]uint32, cluster_size_capacity)
+ var num_clusters uint = 0
+ var histograms []histogramLiteral = make([]histogramLiteral, brotli_min_size_t(num_blocks, histogramsPerBatch))
+ var max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2
+ var pairs_capacity uint = max_num_pairs + 1
+ var pairs []histogramPair = make([]histogramPair, pairs_capacity)
+ var pos uint = 0
+ var clusters []uint32
+ var num_final_clusters uint
+ var new_index []uint32
+ var i uint
+ var sizes = [histogramsPerBatch]uint32{0}
+ var new_clusters = [histogramsPerBatch]uint32{0}
+ var symbols = [histogramsPerBatch]uint32{0}
+ var remap = [histogramsPerBatch]uint32{0}
+
+ for i := 0; i < int(num_blocks); i++ {
+ block_lengths[i] = 0
+ }
+ {
+ var block_idx uint = 0
+ for i = 0; i < length; i++ {
+ assert(block_idx < num_blocks)
+ block_lengths[block_idx]++
+ if i+1 == length || block_ids[i] != block_ids[i+1] {
+ block_idx++
+ }
+ }
+
+ assert(block_idx == num_blocks)
+ }
+
+ for i = 0; i < num_blocks; i += histogramsPerBatch {
+ var num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ var k uint
+ histogramClearLiteral(&histograms[j])
+ for k = 0; uint32(k) < block_lengths[i+j]; k++ {
+ histogramAddLiteral(&histograms[j], uint(data[pos]))
+ pos++
+ }
+
+ histograms[j].bit_cost_ = populationCostLiteral(&histograms[j])
+ new_clusters[j] = uint32(j)
+ symbols[j] = uint32(j)
+ sizes[j] = 1
+ }
+
+ num_new_clusters = histogramCombineLiteral(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)
+ if all_histograms_capacity < (all_histograms_size + num_new_clusters) {
+ var _new_size uint
+ if all_histograms_capacity == 0 {
+ _new_size = all_histograms_size + num_new_clusters
+ } else {
+ _new_size = all_histograms_capacity
+ }
+ var new_array []histogramLiteral
+ for _new_size < (all_histograms_size + num_new_clusters) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramLiteral, _new_size)
+ if all_histograms_capacity != 0 {
+ copy(new_array, all_histograms[:all_histograms_capacity])
+ }
+
+ all_histograms = new_array
+ all_histograms_capacity = _new_size
+ }
+
+ brotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)
+ for j = 0; j < num_new_clusters; j++ {
+ all_histograms[all_histograms_size] = histograms[new_clusters[j]]
+ all_histograms_size++
+ cluster_size[cluster_size_size] = sizes[new_clusters[j]]
+ cluster_size_size++
+ remap[new_clusters[j]] = uint32(j)
+ }
+
+ for j = 0; j < num_to_combine; j++ {
+ histogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]
+ }
+
+ num_clusters += num_new_clusters
+ assert(num_clusters == cluster_size_size)
+ assert(num_clusters == all_histograms_size)
+ }
+
+ histograms = nil
+
+ max_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < max_num_pairs+1 {
+ pairs = nil
+ pairs = make([]histogramPair, (max_num_pairs + 1))
+ }
+
+ clusters = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ clusters[i] = uint32(i)
+ }
+
+ num_final_clusters = histogramCombineLiteral(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)
+ pairs = nil
+ cluster_size = nil
+
+ new_index = make([]uint32, num_clusters)
+ for i = 0; i < num_clusters; i++ {
+ new_index[i] = clusterBlocksLiteral_kInvalidIndex
+ }
+ pos = 0
+ {
+ var next_index uint32 = 0
+ for i = 0; i < num_blocks; i++ {
+ var histo histogramLiteral
+ var j uint
+ var best_out uint32
+ var best_bits float64
+ histogramClearLiteral(&histo)
+ for j = 0; uint32(j) < block_lengths[i]; j++ {
+ histogramAddLiteral(&histo, uint(data[pos]))
+ pos++
+ }
+
+ if i == 0 {
+ best_out = histogram_symbols[0]
+ } else {
+ best_out = histogram_symbols[i-1]
+ }
+ best_bits = histogramBitCostDistanceLiteral(&histo, &all_histograms[best_out])
+ for j = 0; j < num_final_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceLiteral(&histo, &all_histograms[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ histogram_symbols[i] = best_out
+ if new_index[best_out] == clusterBlocksLiteral_kInvalidIndex {
+ new_index[best_out] = next_index
+ next_index++
+ }
+ }
+ }
+
+ clusters = nil
+ all_histograms = nil
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)
+ {
+ var cur_length uint32 = 0
+ var block_idx uint = 0
+ var max_type byte = 0
+ for i = 0; i < num_blocks; i++ {
+ cur_length += block_lengths[i]
+ if i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {
+ var id byte = byte(new_index[histogram_symbols[i]])
+ split.types[block_idx] = id
+ split.lengths[block_idx] = cur_length
+ max_type = brotli_max_uint8_t(max_type, id)
+ cur_length = 0
+ block_idx++
+ }
+ }
+
+ split.num_blocks = block_idx
+ split.num_types = uint(max_type) + 1
+ }
+
+ new_index = nil
+ block_lengths = nil
+ histogram_symbols = nil
+}
+
+func splitByteVectorLiteral(data []byte, length uint, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {
+ var data_size uint = histogramDataSizeLiteral()
+ var num_histograms uint = length/literals_per_histogram + 1
+ var histograms []histogramLiteral
+ if num_histograms > max_histograms {
+ num_histograms = max_histograms
+ }
+
+ if length == 0 {
+ split.num_types = 1
+ return
+ } else if length < kMinLengthForBlockSplitting {
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)
+ split.num_types = 1
+ split.types[split.num_blocks] = 0
+ split.lengths[split.num_blocks] = uint32(length)
+ split.num_blocks++
+ return
+ }
+
+ histograms = make([]histogramLiteral, num_histograms)
+
+ /* Find good entropy codes. */
+ initialEntropyCodesLiteral(data, length, sampling_stride_length, num_histograms, histograms)
+
+ refineEntropyCodesLiteral(data, length, sampling_stride_length, num_histograms, histograms)
+ {
+ var block_ids []byte = make([]byte, length)
+ var num_blocks uint = 0
+ var bitmaplen uint = (num_histograms + 7) >> 3
+ var insert_cost []float64 = make([]float64, (data_size * num_histograms))
+ var cost []float64 = make([]float64, num_histograms)
+ var switch_signal []byte = make([]byte, (length * bitmaplen))
+ var new_id []uint16 = make([]uint16, num_histograms)
+ var iters uint
+ if params.quality < hqZopflificationQuality {
+ iters = 3
+ } else {
+ iters = 10
+ }
+ /* Find a good path through literals with the good entropy codes. */
+
+ var i uint
+ for i = 0; i < iters; i++ {
+ num_blocks = findBlocksLiteral(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)
+ num_histograms = remapBlockIdsLiteral(block_ids, length, new_id, num_histograms)
+ buildBlockHistogramsLiteral(data, length, block_ids, num_histograms, histograms)
+ }
+
+ insert_cost = nil
+ cost = nil
+ switch_signal = nil
+ new_id = nil
+ histograms = nil
+ clusterBlocksLiteral(data, length, num_blocks, block_ids, split)
+ block_ids = nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
new file mode 100644
index 000000000000..7acfb1806161
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
@@ -0,0 +1,1300 @@
+package brotli
+
+import (
+ "math"
+ "sync"
+)
+
+const maxHuffmanTreeSize = (2*numCommandSymbols + 1)
+
+/* The maximum size of Huffman dictionary for distances assuming that
+ NPOSTFIX = 0 and NDIRECT = 0. */
+const maxSimpleDistanceAlphabetSize = 140
+
+/* Represents the range of values belonging to a prefix code:
+ [offset, offset + 2^nbits) */
+type prefixCodeRange struct {
+ offset uint32
+ nbits uint32
+}
+
+var kBlockLengthPrefixCode = [numBlockLenSymbols]prefixCodeRange{
+ prefixCodeRange{1, 2},
+ prefixCodeRange{5, 2},
+ prefixCodeRange{9, 2},
+ prefixCodeRange{13, 2},
+ prefixCodeRange{17, 3},
+ prefixCodeRange{25, 3},
+ prefixCodeRange{33, 3},
+ prefixCodeRange{41, 3},
+ prefixCodeRange{49, 4},
+ prefixCodeRange{65, 4},
+ prefixCodeRange{81, 4},
+ prefixCodeRange{97, 4},
+ prefixCodeRange{113, 5},
+ prefixCodeRange{145, 5},
+ prefixCodeRange{177, 5},
+ prefixCodeRange{209, 5},
+ prefixCodeRange{241, 6},
+ prefixCodeRange{305, 6},
+ prefixCodeRange{369, 7},
+ prefixCodeRange{497, 8},
+ prefixCodeRange{753, 9},
+ prefixCodeRange{1265, 10},
+ prefixCodeRange{2289, 11},
+ prefixCodeRange{4337, 12},
+ prefixCodeRange{8433, 13},
+ prefixCodeRange{16625, 24},
+}
+
+func blockLengthPrefixCode(len uint32) uint32 {
+ var code uint32
+ if len >= 177 {
+ if len >= 753 {
+ code = 20
+ } else {
+ code = 14
+ }
+ } else if len >= 41 {
+ code = 7
+ } else {
+ code = 0
+ }
+ for code < (numBlockLenSymbols-1) && len >= kBlockLengthPrefixCode[code+1].offset {
+ code++
+ }
+ return code
+}
+
+func getBlockLengthPrefixCode(len uint32, code *uint, n_extra *uint32, extra *uint32) {
+ *code = uint(blockLengthPrefixCode(uint32(len)))
+ *n_extra = kBlockLengthPrefixCode[*code].nbits
+ *extra = len - kBlockLengthPrefixCode[*code].offset
+}
+
+type blockTypeCodeCalculator struct {
+ last_type uint
+ second_last_type uint
+}
+
+func initBlockTypeCodeCalculator(self *blockTypeCodeCalculator) {
+ self.last_type = 1
+ self.second_last_type = 0
+}
+
+func nextBlockTypeCode(calculator *blockTypeCodeCalculator, type_ byte) uint {
+ var type_code uint
+ if uint(type_) == calculator.last_type+1 {
+ type_code = 1
+ } else if uint(type_) == calculator.second_last_type {
+ type_code = 0
+ } else {
+ type_code = uint(type_) + 2
+ }
+ calculator.second_last_type = calculator.last_type
+ calculator.last_type = uint(type_)
+ return type_code
+}
+
+/* |nibblesbits| represents the 2 bits to encode MNIBBLES (0-3)
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+func encodeMlen(length uint, bits *uint64, numbits *uint, nibblesbits *uint64) {
+ var lg uint
+ if length == 1 {
+ lg = 1
+ } else {
+ lg = uint(log2FloorNonZero(uint(uint32(length-1)))) + 1
+ }
+ var tmp uint
+ if lg < 16 {
+ tmp = 16
+ } else {
+ tmp = (lg + 3)
+ }
+ var mnibbles uint = tmp / 4
+ assert(length > 0)
+ assert(length <= 1<<24)
+ assert(lg <= 24)
+ *nibblesbits = uint64(mnibbles) - 4
+ *numbits = mnibbles * 4
+ *bits = uint64(length) - 1
+}
+
+func storeCommandExtra(cmd *command, storage_ix *uint, storage []byte) {
+ var copylen_code uint32 = commandCopyLenCode(cmd)
+ var inscode uint16 = getInsertLengthCode(uint(cmd.insert_len_))
+ var copycode uint16 = getCopyLengthCode(uint(copylen_code))
+ var insnumextra uint32 = getInsertExtra(inscode)
+ var insextraval uint64 = uint64(cmd.insert_len_) - uint64(getInsertBase(inscode))
+ var copyextraval uint64 = uint64(copylen_code) - uint64(getCopyBase(copycode))
+ var bits uint64 = copyextraval< 0
+ REQUIRES: length <= (1 << 24) */
+func storeCompressedMetaBlockHeader(is_final_block bool, length uint, storage_ix *uint, storage []byte) {
+ var lenbits uint64
+ var nlenbits uint
+ var nibblesbits uint64
+ var is_final uint64
+ if is_final_block {
+ is_final = 1
+ } else {
+ is_final = 0
+ }
+
+ /* Write ISLAST bit. */
+ writeBits(1, is_final, storage_ix, storage)
+
+ /* Write ISEMPTY bit. */
+ if is_final_block {
+ writeBits(1, 0, storage_ix, storage)
+ }
+
+ encodeMlen(length, &lenbits, &nlenbits, &nibblesbits)
+ writeBits(2, nibblesbits, storage_ix, storage)
+ writeBits(nlenbits, lenbits, storage_ix, storage)
+
+ if !is_final_block {
+ /* Write ISUNCOMPRESSED bit. */
+ writeBits(1, 0, storage_ix, storage)
+ }
+}
+
+/* Stores the uncompressed meta-block header.
+ REQUIRES: length > 0
+ REQUIRES: length <= (1 << 24) */
+func storeUncompressedMetaBlockHeader(length uint, storage_ix *uint, storage []byte) {
+ var lenbits uint64
+ var nlenbits uint
+ var nibblesbits uint64
+
+ /* Write ISLAST bit.
+ Uncompressed block cannot be the last one, so set to 0. */
+ writeBits(1, 0, storage_ix, storage)
+
+ encodeMlen(length, &lenbits, &nlenbits, &nibblesbits)
+ writeBits(2, nibblesbits, storage_ix, storage)
+ writeBits(nlenbits, lenbits, storage_ix, storage)
+
+ /* Write ISUNCOMPRESSED bit. */
+ writeBits(1, 1, storage_ix, storage)
+}
+
+var storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder = [codeLengthCodes]byte{1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+
+var storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeSymbols = [6]byte{0, 7, 3, 2, 1, 15}
+var storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeBitLengths = [6]byte{2, 4, 3, 2, 2, 4}
+
+func storeHuffmanTreeOfHuffmanTreeToBitMask(num_codes int, code_length_bitdepth []byte, storage_ix *uint, storage []byte) {
+ var skip_some uint = 0
+ var codes_to_store uint = codeLengthCodes
+ /* The bit lengths of the Huffman code over the code length alphabet
+ are compressed with the following static Huffman code:
+ Symbol Code
+ ------ ----
+ 0 00
+ 1 1110
+ 2 110
+ 3 01
+ 4 10
+ 5 1111 */
+
+ /* Throw away trailing zeros: */
+ if num_codes > 1 {
+ for ; codes_to_store > 0; codes_to_store-- {
+ if code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[codes_to_store-1]] != 0 {
+ break
+ }
+ }
+ }
+
+ if code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[0]] == 0 && code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[1]] == 0 {
+ skip_some = 2 /* skips two. */
+ if code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[2]] == 0 {
+ skip_some = 3 /* skips three. */
+ }
+ }
+
+ writeBits(2, uint64(skip_some), storage_ix, storage)
+ {
+ var i uint
+ for i = skip_some; i < codes_to_store; i++ {
+ var l uint = uint(code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[i]])
+ writeBits(uint(storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeBitLengths[l]), uint64(storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeSymbols[l]), storage_ix, storage)
+ }
+ }
+}
+
+func storeHuffmanTreeToBitMask(huffman_tree_size uint, huffman_tree []byte, huffman_tree_extra_bits []byte, code_length_bitdepth []byte, code_length_bitdepth_symbols []uint16, storage_ix *uint, storage []byte) {
+ var i uint
+ for i = 0; i < huffman_tree_size; i++ {
+ var ix uint = uint(huffman_tree[i])
+ writeBits(uint(code_length_bitdepth[ix]), uint64(code_length_bitdepth_symbols[ix]), storage_ix, storage)
+
+ /* Extra bits */
+ switch ix {
+ case repeatPreviousCodeLength:
+ writeBits(2, uint64(huffman_tree_extra_bits[i]), storage_ix, storage)
+
+ case repeatZeroCodeLength:
+ writeBits(3, uint64(huffman_tree_extra_bits[i]), storage_ix, storage)
+ }
+ }
+}
+
+func storeSimpleHuffmanTree(depths []byte, symbols []uint, num_symbols uint, max_bits uint, storage_ix *uint, storage []byte) {
+ /* value of 1 indicates a simple Huffman code */
+ writeBits(2, 1, storage_ix, storage)
+
+ writeBits(2, uint64(num_symbols)-1, storage_ix, storage) /* NSYM - 1 */
+ {
+ /* Sort */
+ var i uint
+ for i = 0; i < num_symbols; i++ {
+ var j uint
+ for j = i + 1; j < num_symbols; j++ {
+ if depths[symbols[j]] < depths[symbols[i]] {
+ var tmp uint = symbols[j]
+ symbols[j] = symbols[i]
+ symbols[i] = tmp
+ }
+ }
+ }
+ }
+
+ if num_symbols == 2 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ } else if num_symbols == 3 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ } else {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[3]), storage_ix, storage)
+
+ /* tree-select */
+ var tmp int
+ if depths[symbols[0]] == 1 {
+ tmp = 1
+ } else {
+ tmp = 0
+ }
+ writeBits(1, uint64(tmp), storage_ix, storage)
+ }
+}
+
+/* num = alphabet size
+ depths = symbol depths */
+func storeHuffmanTree(depths []byte, num uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var huffman_tree [numCommandSymbols]byte
+ var huffman_tree_extra_bits [numCommandSymbols]byte
+ var huffman_tree_size uint = 0
+ var code_length_bitdepth = [codeLengthCodes]byte{0}
+ var code_length_bitdepth_symbols [codeLengthCodes]uint16
+ var huffman_tree_histogram = [codeLengthCodes]uint32{0}
+ var i uint
+ var num_codes int = 0
+ /* Write the Huffman tree into the brotli-representation.
+ The command alphabet is the largest, so this allocation will fit all
+ alphabets. */
+
+ var code uint = 0
+
+ assert(num <= numCommandSymbols)
+
+ writeHuffmanTree(depths, num, &huffman_tree_size, huffman_tree[:], huffman_tree_extra_bits[:])
+
+ /* Calculate the statistics of the Huffman tree in brotli-representation. */
+ for i = 0; i < huffman_tree_size; i++ {
+ huffman_tree_histogram[huffman_tree[i]]++
+ }
+
+ for i = 0; i < codeLengthCodes; i++ {
+ if huffman_tree_histogram[i] != 0 {
+ if num_codes == 0 {
+ code = i
+ num_codes = 1
+ } else if num_codes == 1 {
+ num_codes = 2
+ break
+ }
+ }
+ }
+
+ /* Calculate another Huffman tree to use for compressing both the
+ earlier Huffman tree with. */
+ createHuffmanTree(huffman_tree_histogram[:], codeLengthCodes, 5, tree, code_length_bitdepth[:])
+
+ convertBitDepthsToSymbols(code_length_bitdepth[:], codeLengthCodes, code_length_bitdepth_symbols[:])
+
+ /* Now, we have all the data, let's start storing it */
+ storeHuffmanTreeOfHuffmanTreeToBitMask(num_codes, code_length_bitdepth[:], storage_ix, storage)
+
+ if num_codes == 1 {
+ code_length_bitdepth[code] = 0
+ }
+
+ /* Store the real Huffman tree now. */
+ storeHuffmanTreeToBitMask(huffman_tree_size, huffman_tree[:], huffman_tree_extra_bits[:], code_length_bitdepth[:], code_length_bitdepth_symbols[:], storage_ix, storage)
+}
+
+/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and
+ bits[0:length] and stores the encoded tree to the bit stream. */
+func buildAndStoreHuffmanTree(histogram []uint32, histogram_length uint, alphabet_size uint, tree []huffmanTree, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var count uint = 0
+ var s4 = [4]uint{0}
+ var i uint
+ var max_bits uint = 0
+ for i = 0; i < histogram_length; i++ {
+ if histogram[i] != 0 {
+ if count < 4 {
+ s4[count] = i
+ } else if count > 4 {
+ break
+ }
+
+ count++
+ }
+ }
+ {
+ var max_bits_counter uint = alphabet_size - 1
+ for max_bits_counter != 0 {
+ max_bits_counter >>= 1
+ max_bits++
+ }
+ }
+
+ if count <= 1 {
+ writeBits(4, 1, storage_ix, storage)
+ writeBits(max_bits, uint64(s4[0]), storage_ix, storage)
+ depth[s4[0]] = 0
+ bits[s4[0]] = 0
+ return
+ }
+
+ for i := 0; i < int(histogram_length); i++ {
+ depth[i] = 0
+ }
+ createHuffmanTree(histogram, histogram_length, 15, tree, depth)
+ convertBitDepthsToSymbols(depth, histogram_length, bits)
+
+ if count <= 4 {
+ storeSimpleHuffmanTree(depth, s4[:], count, max_bits, storage_ix, storage)
+ } else {
+ storeHuffmanTree(depth, histogram_length, tree, storage_ix, storage)
+ }
+}
+
+func sortHuffmanTree1(v0 huffmanTree, v1 huffmanTree) bool {
+ return v0.total_count_ < v1.total_count_
+}
+
+var huffmanTreePool sync.Pool
+
+func buildAndStoreHuffmanTreeFast(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var count uint = 0
+ var symbols = [4]uint{0}
+ var length uint = 0
+ var total uint = histogram_total
+ for total != 0 {
+ if histogram[length] != 0 {
+ if count < 4 {
+ symbols[count] = length
+ }
+
+ count++
+ total -= uint(histogram[length])
+ }
+
+ length++
+ }
+
+ if count <= 1 {
+ writeBits(4, 1, storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ depth[symbols[0]] = 0
+ bits[symbols[0]] = 0
+ return
+ }
+
+ for i := 0; i < int(length); i++ {
+ depth[i] = 0
+ }
+ {
+ var max_tree_size uint = 2*length + 1
+ tree, _ := huffmanTreePool.Get().(*[]huffmanTree)
+ if tree == nil || cap(*tree) < int(max_tree_size) {
+ tmp := make([]huffmanTree, max_tree_size)
+ tree = &tmp
+ } else {
+ *tree = (*tree)[:max_tree_size]
+ }
+ var count_limit uint32
+ for count_limit = 1; ; count_limit *= 2 {
+ var node int = 0
+ var l uint
+ for l = length; l != 0; {
+ l--
+ if histogram[l] != 0 {
+ if histogram[l] >= count_limit {
+ initHuffmanTree(&(*tree)[node:][0], histogram[l], -1, int16(l))
+ } else {
+ initHuffmanTree(&(*tree)[node:][0], count_limit, -1, int16(l))
+ }
+
+ node++
+ }
+ }
+ {
+ var n int = node
+ /* Points to the next leaf node. */ /* Points to the next non-leaf node. */
+ var sentinel huffmanTree
+ var i int = 0
+ var j int = n + 1
+ var k int
+
+ sortHuffmanTreeItems(*tree, uint(n), huffmanTreeComparator(sortHuffmanTree1))
+
+ /* The nodes are:
+ [0, n): the sorted leaf nodes that we start with.
+ [n]: we add a sentinel here.
+ [n + 1, 2n): new parent nodes are added here, starting from
+ (n+1). These are naturally in ascending order.
+ [2n]: we add a sentinel at the end as well.
+ There will be (2n+1) elements at the end. */
+ initHuffmanTree(&sentinel, math.MaxUint32, -1, -1)
+
+ (*tree)[node] = sentinel
+ node++
+ (*tree)[node] = sentinel
+ node++
+
+ for k = n - 1; k > 0; k-- {
+ var left int
+ var right int
+ if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
+ left = i
+ i++
+ } else {
+ left = j
+ j++
+ }
+
+ if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
+ right = i
+ i++
+ } else {
+ right = j
+ j++
+ }
+
+ /* The sentinel node becomes the parent node. */
+ (*tree)[node-1].total_count_ = (*tree)[left].total_count_ + (*tree)[right].total_count_
+
+ (*tree)[node-1].index_left_ = int16(left)
+ (*tree)[node-1].index_right_or_value_ = int16(right)
+
+ /* Add back the last sentinel node. */
+ (*tree)[node] = sentinel
+ node++
+ }
+
+ if setDepth(2*n-1, *tree, depth, 14) {
+ /* We need to pack the Huffman tree in 14 bits. If this was not
+ successful, add fake entities to the lowest values and retry. */
+ break
+ }
+ }
+ }
+
+ huffmanTreePool.Put(tree)
+ }
+
+ convertBitDepthsToSymbols(depth, length, bits)
+ if count <= 4 {
+ var i uint
+
+ /* value of 1 indicates a simple Huffman code */
+ writeBits(2, 1, storage_ix, storage)
+
+ writeBits(2, uint64(count)-1, storage_ix, storage) /* NSYM - 1 */
+
+ /* Sort */
+ for i = 0; i < count; i++ {
+ var j uint
+ for j = i + 1; j < count; j++ {
+ if depth[symbols[j]] < depth[symbols[i]] {
+ var tmp uint = symbols[j]
+ symbols[j] = symbols[i]
+ symbols[i] = tmp
+ }
+ }
+ }
+
+ if count == 2 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ } else if count == 3 {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ } else {
+ writeBits(max_bits, uint64(symbols[0]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[1]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[2]), storage_ix, storage)
+ writeBits(max_bits, uint64(symbols[3]), storage_ix, storage)
+
+ /* tree-select */
+ var tmp int
+ if depth[symbols[0]] == 1 {
+ tmp = 1
+ } else {
+ tmp = 0
+ }
+ writeBits(1, uint64(tmp), storage_ix, storage)
+ }
+ } else {
+ var previous_value byte = 8
+ var i uint
+
+ /* Complex Huffman Tree */
+ storeStaticCodeLengthCode(storage_ix, storage)
+
+ /* Actual RLE coding. */
+ for i = 0; i < length; {
+ var value byte = depth[i]
+ var reps uint = 1
+ var k uint
+ for k = i + 1; k < length && depth[k] == value; k++ {
+ reps++
+ }
+
+ i += reps
+ if value == 0 {
+ writeBits(uint(kZeroRepsDepth[reps]), kZeroRepsBits[reps], storage_ix, storage)
+ } else {
+ if previous_value != value {
+ writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]), storage_ix, storage)
+ reps--
+ }
+
+ if reps < 3 {
+ for reps != 0 {
+ reps--
+ writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]), storage_ix, storage)
+ }
+ } else {
+ reps -= 3
+ writeBits(uint(kNonZeroRepsDepth[reps]), kNonZeroRepsBits[reps], storage_ix, storage)
+ }
+
+ previous_value = value
+ }
+ }
+ }
+}
+
+func indexOf(v []byte, v_size uint, value byte) uint {
+ var i uint = 0
+ for ; i < v_size; i++ {
+ if v[i] == value {
+ return i
+ }
+ }
+
+ return i
+}
+
+func moveToFront(v []byte, index uint) {
+ var value byte = v[index]
+ var i uint
+ for i = index; i != 0; i-- {
+ v[i] = v[i-1]
+ }
+
+ v[0] = value
+}
+
+func moveToFrontTransform(v_in []uint32, v_size uint, v_out []uint32) {
+ var i uint
+ var mtf [256]byte
+ var max_value uint32
+ if v_size == 0 {
+ return
+ }
+
+ max_value = v_in[0]
+ for i = 1; i < v_size; i++ {
+ if v_in[i] > max_value {
+ max_value = v_in[i]
+ }
+ }
+
+ assert(max_value < 256)
+ for i = 0; uint32(i) <= max_value; i++ {
+ mtf[i] = byte(i)
+ }
+ {
+ var mtf_size uint = uint(max_value + 1)
+ for i = 0; i < v_size; i++ {
+ var index uint = indexOf(mtf[:], mtf_size, byte(v_in[i]))
+ assert(index < mtf_size)
+ v_out[i] = uint32(index)
+ moveToFront(mtf[:], index)
+ }
+ }
+}
+
+/* Finds runs of zeros in v[0..in_size) and replaces them with a prefix code of
+ the run length plus extra bits (lower 9 bits is the prefix code and the rest
+ are the extra bits). Non-zero values in v[] are shifted by
+ *max_length_prefix. Will not create prefix codes bigger than the initial
+ value of *max_run_length_prefix. The prefix code of run length L is simply
+ Log2Floor(L) and the number of extra bits is the same as the prefix code. */
+func runLengthCodeZeros(in_size uint, v []uint32, out_size *uint, max_run_length_prefix *uint32) {
+ var max_reps uint32 = 0
+ var i uint
+ var max_prefix uint32
+ for i = 0; i < in_size; {
+ var reps uint32 = 0
+ for ; i < in_size && v[i] != 0; i++ {
+ }
+ for ; i < in_size && v[i] == 0; i++ {
+ reps++
+ }
+
+ max_reps = brotli_max_uint32_t(reps, max_reps)
+ }
+
+ if max_reps > 0 {
+ max_prefix = log2FloorNonZero(uint(max_reps))
+ } else {
+ max_prefix = 0
+ }
+ max_prefix = brotli_min_uint32_t(max_prefix, *max_run_length_prefix)
+ *max_run_length_prefix = max_prefix
+ *out_size = 0
+ for i = 0; i < in_size; {
+ assert(*out_size <= i)
+ if v[i] != 0 {
+ v[*out_size] = v[i] + *max_run_length_prefix
+ i++
+ (*out_size)++
+ } else {
+ var reps uint32 = 1
+ var k uint
+ for k = i + 1; k < in_size && v[k] == 0; k++ {
+ reps++
+ }
+
+ i += uint(reps)
+ for reps != 0 {
+ if reps < 2< 0)
+ writeSingleBit(use_rle, storage_ix, storage)
+ if use_rle {
+ writeBits(4, uint64(max_run_length_prefix)-1, storage_ix, storage)
+ }
+ }
+
+ buildAndStoreHuffmanTree(histogram[:], uint(uint32(num_clusters)+max_run_length_prefix), uint(uint32(num_clusters)+max_run_length_prefix), tree, depths[:], bits[:], storage_ix, storage)
+ for i = 0; i < num_rle_symbols; i++ {
+ var rle_symbol uint32 = rle_symbols[i] & encodeContextMap_kSymbolMask
+ var extra_bits_val uint32 = rle_symbols[i] >> symbolBits
+ writeBits(uint(depths[rle_symbol]), uint64(bits[rle_symbol]), storage_ix, storage)
+ if rle_symbol > 0 && rle_symbol <= max_run_length_prefix {
+ writeBits(uint(rle_symbol), uint64(extra_bits_val), storage_ix, storage)
+ }
+ }
+
+ writeBits(1, 1, storage_ix, storage) /* use move-to-front */
+ rle_symbols = nil
+}
+
+/* Stores the block switch command with index block_ix to the bit stream. */
+func storeBlockSwitch(code *blockSplitCode, block_len uint32, block_type byte, is_first_block bool, storage_ix *uint, storage []byte) {
+ var typecode uint = nextBlockTypeCode(&code.type_code_calculator, block_type)
+ var lencode uint
+ var len_nextra uint32
+ var len_extra uint32
+ if !is_first_block {
+ writeBits(uint(code.type_depths[typecode]), uint64(code.type_bits[typecode]), storage_ix, storage)
+ }
+
+ getBlockLengthPrefixCode(block_len, &lencode, &len_nextra, &len_extra)
+
+ writeBits(uint(code.length_depths[lencode]), uint64(code.length_bits[lencode]), storage_ix, storage)
+ writeBits(uint(len_nextra), uint64(len_extra), storage_ix, storage)
+}
+
+/* Builds a BlockSplitCode data structure from the block split given by the
+ vector of block types and block lengths and stores it to the bit stream. */
+func buildAndStoreBlockSplitCode(types []byte, lengths []uint32, num_blocks uint, num_types uint, tree []huffmanTree, code *blockSplitCode, storage_ix *uint, storage []byte) {
+ var type_histo [maxBlockTypeSymbols]uint32
+ var length_histo [numBlockLenSymbols]uint32
+ var i uint
+ var type_code_calculator blockTypeCodeCalculator
+ for i := 0; i < int(num_types+2); i++ {
+ type_histo[i] = 0
+ }
+ length_histo = [numBlockLenSymbols]uint32{}
+ initBlockTypeCodeCalculator(&type_code_calculator)
+ for i = 0; i < num_blocks; i++ {
+ var type_code uint = nextBlockTypeCode(&type_code_calculator, types[i])
+ if i != 0 {
+ type_histo[type_code]++
+ }
+ length_histo[blockLengthPrefixCode(lengths[i])]++
+ }
+
+ storeVarLenUint8(num_types-1, storage_ix, storage)
+ if num_types > 1 { /* TODO: else? could StoreBlockSwitch occur? */
+ buildAndStoreHuffmanTree(type_histo[0:], num_types+2, num_types+2, tree, code.type_depths[0:], code.type_bits[0:], storage_ix, storage)
+ buildAndStoreHuffmanTree(length_histo[0:], numBlockLenSymbols, numBlockLenSymbols, tree, code.length_depths[0:], code.length_bits[0:], storage_ix, storage)
+ storeBlockSwitch(code, lengths[0], types[0], true, storage_ix, storage)
+ }
+}
+
+/* Stores a context map where the histogram type is always the block type. */
+func storeTrivialContextMap(num_types uint, context_bits uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ storeVarLenUint8(num_types-1, storage_ix, storage)
+ if num_types > 1 {
+ var repeat_code uint = context_bits - 1
+ var repeat_bits uint = (1 << repeat_code) - 1
+ var alphabet_size uint = num_types + repeat_code
+ var histogram [maxContextMapSymbols]uint32
+ var depths [maxContextMapSymbols]byte
+ var bits [maxContextMapSymbols]uint16
+ var i uint
+ for i := 0; i < int(alphabet_size); i++ {
+ histogram[i] = 0
+ }
+
+ /* Write RLEMAX. */
+ writeBits(1, 1, storage_ix, storage)
+
+ writeBits(4, uint64(repeat_code)-1, storage_ix, storage)
+ histogram[repeat_code] = uint32(num_types)
+ histogram[0] = 1
+ for i = context_bits; i < alphabet_size; i++ {
+ histogram[i] = 1
+ }
+
+ buildAndStoreHuffmanTree(histogram[:], alphabet_size, alphabet_size, tree, depths[:], bits[:], storage_ix, storage)
+ for i = 0; i < num_types; i++ {
+ var tmp uint
+ if i == 0 {
+ tmp = 0
+ } else {
+ tmp = i + context_bits - 1
+ }
+ var code uint = tmp
+ writeBits(uint(depths[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(depths[repeat_code]), uint64(bits[repeat_code]), storage_ix, storage)
+ writeBits(repeat_code, uint64(repeat_bits), storage_ix, storage)
+ }
+
+ /* Write IMTF (inverse-move-to-front) bit. */
+ writeBits(1, 1, storage_ix, storage)
+ }
+}
+
+/* Manages the encoding of one block category (literal, command or distance). */
+type blockEncoder struct {
+ histogram_length_ uint
+ num_block_types_ uint
+ block_types_ []byte
+ block_lengths_ []uint32
+ num_blocks_ uint
+ block_split_code_ blockSplitCode
+ block_ix_ uint
+ block_len_ uint
+ entropy_ix_ uint
+ depths_ []byte
+ bits_ []uint16
+}
+
+var blockEncoderPool sync.Pool
+
+func getBlockEncoder(histogram_length uint, num_block_types uint, block_types []byte, block_lengths []uint32, num_blocks uint) *blockEncoder {
+ self, _ := blockEncoderPool.Get().(*blockEncoder)
+
+ if self != nil {
+ self.block_ix_ = 0
+ self.entropy_ix_ = 0
+ self.depths_ = self.depths_[:0]
+ self.bits_ = self.bits_[:0]
+ } else {
+ self = &blockEncoder{}
+ }
+
+ self.histogram_length_ = histogram_length
+ self.num_block_types_ = num_block_types
+ self.block_types_ = block_types
+ self.block_lengths_ = block_lengths
+ self.num_blocks_ = num_blocks
+ initBlockTypeCodeCalculator(&self.block_split_code_.type_code_calculator)
+ if num_blocks == 0 {
+ self.block_len_ = 0
+ } else {
+ self.block_len_ = uint(block_lengths[0])
+ }
+
+ return self
+}
+
+func cleanupBlockEncoder(self *blockEncoder) {
+ blockEncoderPool.Put(self)
+}
+
+/* Creates entropy codes of block lengths and block types and stores them
+ to the bit stream. */
+func buildAndStoreBlockSwitchEntropyCodes(self *blockEncoder, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ buildAndStoreBlockSplitCode(self.block_types_, self.block_lengths_, self.num_blocks_, self.num_block_types_, tree, &self.block_split_code_, storage_ix, storage)
+}
+
+/* Stores the next symbol with the entropy code of the current block type.
+ Updates the block type and block length at block boundaries. */
+func storeSymbol(self *blockEncoder, symbol uint, storage_ix *uint, storage []byte) {
+ if self.block_len_ == 0 {
+ self.block_ix_++
+ var block_ix uint = self.block_ix_
+ var block_len uint32 = self.block_lengths_[block_ix]
+ var block_type byte = self.block_types_[block_ix]
+ self.block_len_ = uint(block_len)
+ self.entropy_ix_ = uint(block_type) * self.histogram_length_
+ storeBlockSwitch(&self.block_split_code_, block_len, block_type, false, storage_ix, storage)
+ }
+
+ self.block_len_--
+ {
+ var ix uint = self.entropy_ix_ + symbol
+ writeBits(uint(self.depths_[ix]), uint64(self.bits_[ix]), storage_ix, storage)
+ }
+}
+
+/* Stores the next symbol with the entropy code of the current block type and
+ context value.
+ Updates the block type and block length at block boundaries. */
+func storeSymbolWithContext(self *blockEncoder, symbol uint, context uint, context_map []uint32, storage_ix *uint, storage []byte, context_bits uint) {
+ if self.block_len_ == 0 {
+ self.block_ix_++
+ var block_ix uint = self.block_ix_
+ var block_len uint32 = self.block_lengths_[block_ix]
+ var block_type byte = self.block_types_[block_ix]
+ self.block_len_ = uint(block_len)
+ self.entropy_ix_ = uint(block_type) << context_bits
+ storeBlockSwitch(&self.block_split_code_, block_len, block_type, false, storage_ix, storage)
+ }
+
+ self.block_len_--
+ {
+ var histo_ix uint = uint(context_map[self.entropy_ix_+context])
+ var ix uint = histo_ix*self.histogram_length_ + symbol
+ writeBits(uint(self.depths_[ix]), uint64(self.bits_[ix]), storage_ix, storage)
+ }
+}
+
+func buildAndStoreEntropyCodesLiteral(self *blockEncoder, histograms []histogramLiteral, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var table_size uint = histograms_size * self.histogram_length_
+ if cap(self.depths_) < int(table_size) {
+ self.depths_ = make([]byte, table_size)
+ } else {
+ self.depths_ = self.depths_[:table_size]
+ }
+ if cap(self.bits_) < int(table_size) {
+ self.bits_ = make([]uint16, table_size)
+ } else {
+ self.bits_ = self.bits_[:table_size]
+ }
+ {
+ var i uint
+ for i = 0; i < histograms_size; i++ {
+ var ix uint = i * self.histogram_length_
+ buildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)
+ }
+ }
+}
+
+func buildAndStoreEntropyCodesCommand(self *blockEncoder, histograms []histogramCommand, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var table_size uint = histograms_size * self.histogram_length_
+ if cap(self.depths_) < int(table_size) {
+ self.depths_ = make([]byte, table_size)
+ } else {
+ self.depths_ = self.depths_[:table_size]
+ }
+ if cap(self.bits_) < int(table_size) {
+ self.bits_ = make([]uint16, table_size)
+ } else {
+ self.bits_ = self.bits_[:table_size]
+ }
+ {
+ var i uint
+ for i = 0; i < histograms_size; i++ {
+ var ix uint = i * self.histogram_length_
+ buildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)
+ }
+ }
+}
+
+func buildAndStoreEntropyCodesDistance(self *blockEncoder, histograms []histogramDistance, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {
+ var table_size uint = histograms_size * self.histogram_length_
+ if cap(self.depths_) < int(table_size) {
+ self.depths_ = make([]byte, table_size)
+ } else {
+ self.depths_ = self.depths_[:table_size]
+ }
+ if cap(self.bits_) < int(table_size) {
+ self.bits_ = make([]uint16, table_size)
+ } else {
+ self.bits_ = self.bits_[:table_size]
+ }
+ {
+ var i uint
+ for i = 0; i < histograms_size; i++ {
+ var ix uint = i * self.histogram_length_
+ buildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)
+ }
+ }
+}
+
+func jumpToByteBoundary(storage_ix *uint, storage []byte) {
+ *storage_ix = (*storage_ix + 7) &^ 7
+ storage[*storage_ix>>3] = 0
+}
+
+func storeMetaBlock(input []byte, start_pos uint, length uint, mask uint, prev_byte byte, prev_byte2 byte, is_last bool, params *encoderParams, literal_context_mode int, commands []command, mb *metaBlockSplit, storage_ix *uint, storage []byte) {
+ var pos uint = start_pos
+ var i uint
+ var num_distance_symbols uint32 = params.dist.alphabet_size
+ var num_effective_distance_symbols uint32 = num_distance_symbols
+ var tree []huffmanTree
+ var literal_context_lut contextLUT = getContextLUT(literal_context_mode)
+ var dist *distanceParams = ¶ms.dist
+ if params.large_window && num_effective_distance_symbols > numHistogramDistanceSymbols {
+ num_effective_distance_symbols = numHistogramDistanceSymbols
+ }
+
+ storeCompressedMetaBlockHeader(is_last, length, storage_ix, storage)
+
+ tree = make([]huffmanTree, maxHuffmanTreeSize)
+ literal_enc := getBlockEncoder(numLiteralSymbols, mb.literal_split.num_types, mb.literal_split.types, mb.literal_split.lengths, mb.literal_split.num_blocks)
+ command_enc := getBlockEncoder(numCommandSymbols, mb.command_split.num_types, mb.command_split.types, mb.command_split.lengths, mb.command_split.num_blocks)
+ distance_enc := getBlockEncoder(uint(num_effective_distance_symbols), mb.distance_split.num_types, mb.distance_split.types, mb.distance_split.lengths, mb.distance_split.num_blocks)
+
+ buildAndStoreBlockSwitchEntropyCodes(literal_enc, tree, storage_ix, storage)
+ buildAndStoreBlockSwitchEntropyCodes(command_enc, tree, storage_ix, storage)
+ buildAndStoreBlockSwitchEntropyCodes(distance_enc, tree, storage_ix, storage)
+
+ writeBits(2, uint64(dist.distance_postfix_bits), storage_ix, storage)
+ writeBits(4, uint64(dist.num_direct_distance_codes)>>dist.distance_postfix_bits, storage_ix, storage)
+ for i = 0; i < mb.literal_split.num_types; i++ {
+ writeBits(2, uint64(literal_context_mode), storage_ix, storage)
+ }
+
+ if mb.literal_context_map_size == 0 {
+ storeTrivialContextMap(mb.literal_histograms_size, literalContextBits, tree, storage_ix, storage)
+ } else {
+ encodeContextMap(mb.literal_context_map, mb.literal_context_map_size, mb.literal_histograms_size, tree, storage_ix, storage)
+ }
+
+ if mb.distance_context_map_size == 0 {
+ storeTrivialContextMap(mb.distance_histograms_size, distanceContextBits, tree, storage_ix, storage)
+ } else {
+ encodeContextMap(mb.distance_context_map, mb.distance_context_map_size, mb.distance_histograms_size, tree, storage_ix, storage)
+ }
+
+ buildAndStoreEntropyCodesLiteral(literal_enc, mb.literal_histograms, mb.literal_histograms_size, numLiteralSymbols, tree, storage_ix, storage)
+ buildAndStoreEntropyCodesCommand(command_enc, mb.command_histograms, mb.command_histograms_size, numCommandSymbols, tree, storage_ix, storage)
+ buildAndStoreEntropyCodesDistance(distance_enc, mb.distance_histograms, mb.distance_histograms_size, uint(num_distance_symbols), tree, storage_ix, storage)
+ tree = nil
+
+ for _, cmd := range commands {
+ var cmd_code uint = uint(cmd.cmd_prefix_)
+ storeSymbol(command_enc, cmd_code, storage_ix, storage)
+ storeCommandExtra(&cmd, storage_ix, storage)
+ if mb.literal_context_map_size == 0 {
+ var j uint
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ storeSymbol(literal_enc, uint(input[pos&mask]), storage_ix, storage)
+ pos++
+ }
+ } else {
+ var j uint
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ var context uint = uint(getContext(prev_byte, prev_byte2, literal_context_lut))
+ var literal byte = input[pos&mask]
+ storeSymbolWithContext(literal_enc, uint(literal), context, mb.literal_context_map, storage_ix, storage, literalContextBits)
+ prev_byte2 = prev_byte
+ prev_byte = literal
+ pos++
+ }
+ }
+
+ pos += uint(commandCopyLen(&cmd))
+ if commandCopyLen(&cmd) != 0 {
+ prev_byte2 = input[(pos-2)&mask]
+ prev_byte = input[(pos-1)&mask]
+ if cmd.cmd_prefix_ >= 128 {
+ var dist_code uint = uint(cmd.dist_prefix_) & 0x3FF
+ var distnumextra uint32 = uint32(cmd.dist_prefix_) >> 10
+ var distextra uint64 = uint64(cmd.dist_extra_)
+ if mb.distance_context_map_size == 0 {
+ storeSymbol(distance_enc, dist_code, storage_ix, storage)
+ } else {
+ var context uint = uint(commandDistanceContext(&cmd))
+ storeSymbolWithContext(distance_enc, dist_code, context, mb.distance_context_map, storage_ix, storage, distanceContextBits)
+ }
+
+ writeBits(uint(distnumextra), distextra, storage_ix, storage)
+ }
+ }
+ }
+
+ cleanupBlockEncoder(distance_enc)
+ cleanupBlockEncoder(command_enc)
+ cleanupBlockEncoder(literal_enc)
+ if is_last {
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
+
+func buildHistograms(input []byte, start_pos uint, mask uint, commands []command, lit_histo *histogramLiteral, cmd_histo *histogramCommand, dist_histo *histogramDistance) {
+ var pos uint = start_pos
+ for _, cmd := range commands {
+ var j uint
+ histogramAddCommand(cmd_histo, uint(cmd.cmd_prefix_))
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ histogramAddLiteral(lit_histo, uint(input[pos&mask]))
+ pos++
+ }
+
+ pos += uint(commandCopyLen(&cmd))
+ if commandCopyLen(&cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ histogramAddDistance(dist_histo, uint(cmd.dist_prefix_)&0x3FF)
+ }
+ }
+}
+
+func storeDataWithHuffmanCodes(input []byte, start_pos uint, mask uint, commands []command, lit_depth []byte, lit_bits []uint16, cmd_depth []byte, cmd_bits []uint16, dist_depth []byte, dist_bits []uint16, storage_ix *uint, storage []byte) {
+ var pos uint = start_pos
+ for _, cmd := range commands {
+ var cmd_code uint = uint(cmd.cmd_prefix_)
+ var j uint
+ writeBits(uint(cmd_depth[cmd_code]), uint64(cmd_bits[cmd_code]), storage_ix, storage)
+ storeCommandExtra(&cmd, storage_ix, storage)
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ var literal byte = input[pos&mask]
+ writeBits(uint(lit_depth[literal]), uint64(lit_bits[literal]), storage_ix, storage)
+ pos++
+ }
+
+ pos += uint(commandCopyLen(&cmd))
+ if commandCopyLen(&cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ var dist_code uint = uint(cmd.dist_prefix_) & 0x3FF
+ var distnumextra uint32 = uint32(cmd.dist_prefix_) >> 10
+ var distextra uint32 = cmd.dist_extra_
+ writeBits(uint(dist_depth[dist_code]), uint64(dist_bits[dist_code]), storage_ix, storage)
+ writeBits(uint(distnumextra), uint64(distextra), storage_ix, storage)
+ }
+ }
+}
+
+func storeMetaBlockTrivial(input []byte, start_pos uint, length uint, mask uint, is_last bool, params *encoderParams, commands []command, storage_ix *uint, storage []byte) {
+ var lit_histo histogramLiteral
+ var cmd_histo histogramCommand
+ var dist_histo histogramDistance
+ var lit_depth [numLiteralSymbols]byte
+ var lit_bits [numLiteralSymbols]uint16
+ var cmd_depth [numCommandSymbols]byte
+ var cmd_bits [numCommandSymbols]uint16
+ var dist_depth [maxSimpleDistanceAlphabetSize]byte
+ var dist_bits [maxSimpleDistanceAlphabetSize]uint16
+ var tree []huffmanTree
+ var num_distance_symbols uint32 = params.dist.alphabet_size
+
+ storeCompressedMetaBlockHeader(is_last, length, storage_ix, storage)
+
+ histogramClearLiteral(&lit_histo)
+ histogramClearCommand(&cmd_histo)
+ histogramClearDistance(&dist_histo)
+
+ buildHistograms(input, start_pos, mask, commands, &lit_histo, &cmd_histo, &dist_histo)
+
+ writeBits(13, 0, storage_ix, storage)
+
+ tree = make([]huffmanTree, maxHuffmanTreeSize)
+ buildAndStoreHuffmanTree(lit_histo.data_[:], numLiteralSymbols, numLiteralSymbols, tree, lit_depth[:], lit_bits[:], storage_ix, storage)
+ buildAndStoreHuffmanTree(cmd_histo.data_[:], numCommandSymbols, numCommandSymbols, tree, cmd_depth[:], cmd_bits[:], storage_ix, storage)
+ buildAndStoreHuffmanTree(dist_histo.data_[:], maxSimpleDistanceAlphabetSize, uint(num_distance_symbols), tree, dist_depth[:], dist_bits[:], storage_ix, storage)
+ tree = nil
+ storeDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], cmd_depth[:], cmd_bits[:], dist_depth[:], dist_bits[:], storage_ix, storage)
+ if is_last {
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
+
+func storeMetaBlockFast(input []byte, start_pos uint, length uint, mask uint, is_last bool, params *encoderParams, commands []command, storage_ix *uint, storage []byte) {
+ var num_distance_symbols uint32 = params.dist.alphabet_size
+ var distance_alphabet_bits uint32 = log2FloorNonZero(uint(num_distance_symbols-1)) + 1
+
+ storeCompressedMetaBlockHeader(is_last, length, storage_ix, storage)
+
+ writeBits(13, 0, storage_ix, storage)
+
+ if len(commands) <= 128 {
+ var histogram = [numLiteralSymbols]uint32{0}
+ var pos uint = start_pos
+ var num_literals uint = 0
+ var lit_depth [numLiteralSymbols]byte
+ var lit_bits [numLiteralSymbols]uint16
+ for _, cmd := range commands {
+ var j uint
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ histogram[input[pos&mask]]++
+ pos++
+ }
+
+ num_literals += uint(cmd.insert_len_)
+ pos += uint(commandCopyLen(&cmd))
+ }
+
+ buildAndStoreHuffmanTreeFast(histogram[:], num_literals, /* max_bits = */
+ 8, lit_depth[:], lit_bits[:], storage_ix, storage)
+
+ storeStaticCommandHuffmanTree(storage_ix, storage)
+ storeStaticDistanceHuffmanTree(storage_ix, storage)
+ storeDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], kStaticCommandCodeDepth[:], kStaticCommandCodeBits[:], kStaticDistanceCodeDepth[:], kStaticDistanceCodeBits[:], storage_ix, storage)
+ } else {
+ var lit_histo histogramLiteral
+ var cmd_histo histogramCommand
+ var dist_histo histogramDistance
+ var lit_depth [numLiteralSymbols]byte
+ var lit_bits [numLiteralSymbols]uint16
+ var cmd_depth [numCommandSymbols]byte
+ var cmd_bits [numCommandSymbols]uint16
+ var dist_depth [maxSimpleDistanceAlphabetSize]byte
+ var dist_bits [maxSimpleDistanceAlphabetSize]uint16
+ histogramClearLiteral(&lit_histo)
+ histogramClearCommand(&cmd_histo)
+ histogramClearDistance(&dist_histo)
+ buildHistograms(input, start_pos, mask, commands, &lit_histo, &cmd_histo, &dist_histo)
+ buildAndStoreHuffmanTreeFast(lit_histo.data_[:], lit_histo.total_count_, /* max_bits = */
+ 8, lit_depth[:], lit_bits[:], storage_ix, storage)
+
+ buildAndStoreHuffmanTreeFast(cmd_histo.data_[:], cmd_histo.total_count_, /* max_bits = */
+ 10, cmd_depth[:], cmd_bits[:], storage_ix, storage)
+
+ buildAndStoreHuffmanTreeFast(dist_histo.data_[:], dist_histo.total_count_, /* max_bits = */
+ uint(distance_alphabet_bits), dist_depth[:], dist_bits[:], storage_ix, storage)
+
+ storeDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], cmd_depth[:], cmd_bits[:], dist_depth[:], dist_bits[:], storage_ix, storage)
+ }
+
+ if is_last {
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
+
+/* This is for storing uncompressed blocks (simple raw storage of
+ bytes-as-bytes). */
+func storeUncompressedMetaBlock(is_final_block bool, input []byte, position uint, mask uint, len uint, storage_ix *uint, storage []byte) {
+ var masked_pos uint = position & mask
+ storeUncompressedMetaBlockHeader(uint(len), storage_ix, storage)
+ jumpToByteBoundary(storage_ix, storage)
+
+ if masked_pos+len > mask+1 {
+ var len1 uint = mask + 1 - masked_pos
+ copy(storage[*storage_ix>>3:], input[masked_pos:][:len1])
+ *storage_ix += len1 << 3
+ len -= len1
+ masked_pos = 0
+ }
+
+ copy(storage[*storage_ix>>3:], input[masked_pos:][:len])
+ *storage_ix += uint(len << 3)
+
+ /* We need to clear the next 4 bytes to continue to be
+ compatible with BrotliWriteBits. */
+ writeBitsPrepareStorage(*storage_ix, storage)
+
+ /* Since the uncompressed block itself may not be the final block, add an
+ empty one after this. */
+ if is_final_block {
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ jumpToByteBoundary(storage_ix, storage)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster.go
new file mode 100644
index 000000000000..df8a32822456
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster.go
@@ -0,0 +1,30 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for clustering similar histograms together. */
+
+type histogramPair struct {
+ idx1 uint32
+ idx2 uint32
+ cost_combo float64
+ cost_diff float64
+}
+
+func histogramPairIsLess(p1 *histogramPair, p2 *histogramPair) bool {
+ if p1.cost_diff != p2.cost_diff {
+ return p1.cost_diff > p2.cost_diff
+ }
+
+ return (p1.idx2 - p1.idx1) > (p2.idx2 - p2.idx1)
+}
+
+/* Returns entropy reduction of the context map when we combine two clusters. */
+func clusterCostDiff(size_a uint, size_b uint) float64 {
+ var size_c uint = size_a + size_b
+ return float64(size_a)*fastLog2(size_a) + float64(size_b)*fastLog2(size_b) - float64(size_c)*fastLog2(size_c)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_command.go
new file mode 100644
index 000000000000..45b569bb2a59
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_command.go
@@ -0,0 +1,164 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+func compareAndPushToQueueCommand(out []histogramCommand, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {
+ var is_good_pair bool = false
+ var p histogramPair
+ p.idx2 = 0
+ p.idx1 = p.idx2
+ p.cost_combo = 0
+ p.cost_diff = p.cost_combo
+ if idx1 == idx2 {
+ return
+ }
+
+ if idx2 < idx1 {
+ var t uint32 = idx2
+ idx2 = idx1
+ idx1 = t
+ }
+
+ p.idx1 = idx1
+ p.idx2 = idx2
+ p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))
+ p.cost_diff -= out[idx1].bit_cost_
+ p.cost_diff -= out[idx2].bit_cost_
+
+ if out[idx1].total_count_ == 0 {
+ p.cost_combo = out[idx2].bit_cost_
+ is_good_pair = true
+ } else if out[idx2].total_count_ == 0 {
+ p.cost_combo = out[idx1].bit_cost_
+ is_good_pair = true
+ } else {
+ var threshold float64
+ if *num_pairs == 0 {
+ threshold = 1e99
+ } else {
+ threshold = brotli_max_double(0.0, pairs[0].cost_diff)
+ }
+ var combo histogramCommand = out[idx1]
+ var cost_combo float64
+ histogramAddHistogramCommand(&combo, &out[idx2])
+ cost_combo = populationCostCommand(&combo)
+ if cost_combo < threshold-p.cost_diff {
+ p.cost_combo = cost_combo
+ is_good_pair = true
+ }
+ }
+
+ if is_good_pair {
+ p.cost_diff += p.cost_combo
+ if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {
+ /* Replace the top of the queue if needed. */
+ if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = pairs[0]
+ (*num_pairs)++
+ }
+
+ pairs[0] = p
+ } else if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = p
+ (*num_pairs)++
+ }
+ }
+}
+
+func histogramCombineCommand(out []histogramCommand, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {
+ var cost_diff_threshold float64 = 0.0
+ var min_cluster_size uint = 1
+ var num_pairs uint = 0
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ var idx1 uint
+ for idx1 = 0; idx1 < num_clusters; idx1++ {
+ var idx2 uint
+ for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {
+ compareAndPushToQueueCommand(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+ }
+
+ for num_clusters > min_cluster_size {
+ var best_idx1 uint32
+ var best_idx2 uint32
+ var i uint
+ if pairs[0].cost_diff >= cost_diff_threshold {
+ cost_diff_threshold = 1e99
+ min_cluster_size = max_clusters
+ continue
+ }
+
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1
+
+ best_idx2 = pairs[0].idx2
+ histogramAddHistogramCommand(&out[best_idx1], &out[best_idx2])
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo
+ cluster_size[best_idx1] += cluster_size[best_idx2]
+ for i = 0; i < symbols_size; i++ {
+ if symbols[i] == best_idx2 {
+ symbols[i] = best_idx1
+ }
+ }
+
+ for i = 0; i < num_clusters; i++ {
+ if clusters[i] == best_idx2 {
+ copy(clusters[i:], clusters[i+1:][:num_clusters-i-1])
+ break
+ }
+ }
+
+ num_clusters--
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ var copy_to_idx uint = 0
+ for i = 0; i < num_pairs; i++ {
+ var p *histogramPair = &pairs[i]
+ if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {
+ /* Remove invalid pair from the queue. */
+ continue
+ }
+
+ if histogramPairIsLess(&pairs[0], p) {
+ /* Replace the top of the queue if needed. */
+ var front histogramPair = pairs[0]
+ pairs[0] = *p
+ pairs[copy_to_idx] = front
+ } else {
+ pairs[copy_to_idx] = *p
+ }
+
+ copy_to_idx++
+ }
+
+ num_pairs = copy_to_idx
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for i = 0; i < num_clusters; i++ {
+ compareAndPushToQueueCommand(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+
+ return num_clusters
+}
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+func histogramBitCostDistanceCommand(histogram *histogramCommand, candidate *histogramCommand) float64 {
+ if histogram.total_count_ == 0 {
+ return 0.0
+ } else {
+ var tmp histogramCommand = *histogram
+ histogramAddHistogramCommand(&tmp, candidate)
+ return populationCostCommand(&tmp) - candidate.bit_cost_
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_distance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_distance.go
new file mode 100644
index 000000000000..1aaa86e6ed83
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_distance.go
@@ -0,0 +1,326 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+func compareAndPushToQueueDistance(out []histogramDistance, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {
+ var is_good_pair bool = false
+ var p histogramPair
+ p.idx2 = 0
+ p.idx1 = p.idx2
+ p.cost_combo = 0
+ p.cost_diff = p.cost_combo
+ if idx1 == idx2 {
+ return
+ }
+
+ if idx2 < idx1 {
+ var t uint32 = idx2
+ idx2 = idx1
+ idx1 = t
+ }
+
+ p.idx1 = idx1
+ p.idx2 = idx2
+ p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))
+ p.cost_diff -= out[idx1].bit_cost_
+ p.cost_diff -= out[idx2].bit_cost_
+
+ if out[idx1].total_count_ == 0 {
+ p.cost_combo = out[idx2].bit_cost_
+ is_good_pair = true
+ } else if out[idx2].total_count_ == 0 {
+ p.cost_combo = out[idx1].bit_cost_
+ is_good_pair = true
+ } else {
+ var threshold float64
+ if *num_pairs == 0 {
+ threshold = 1e99
+ } else {
+ threshold = brotli_max_double(0.0, pairs[0].cost_diff)
+ }
+ var combo histogramDistance = out[idx1]
+ var cost_combo float64
+ histogramAddHistogramDistance(&combo, &out[idx2])
+ cost_combo = populationCostDistance(&combo)
+ if cost_combo < threshold-p.cost_diff {
+ p.cost_combo = cost_combo
+ is_good_pair = true
+ }
+ }
+
+ if is_good_pair {
+ p.cost_diff += p.cost_combo
+ if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {
+ /* Replace the top of the queue if needed. */
+ if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = pairs[0]
+ (*num_pairs)++
+ }
+
+ pairs[0] = p
+ } else if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = p
+ (*num_pairs)++
+ }
+ }
+}
+
+func histogramCombineDistance(out []histogramDistance, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {
+ var cost_diff_threshold float64 = 0.0
+ var min_cluster_size uint = 1
+ var num_pairs uint = 0
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ var idx1 uint
+ for idx1 = 0; idx1 < num_clusters; idx1++ {
+ var idx2 uint
+ for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {
+ compareAndPushToQueueDistance(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+ }
+
+ for num_clusters > min_cluster_size {
+ var best_idx1 uint32
+ var best_idx2 uint32
+ var i uint
+ if pairs[0].cost_diff >= cost_diff_threshold {
+ cost_diff_threshold = 1e99
+ min_cluster_size = max_clusters
+ continue
+ }
+
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1
+
+ best_idx2 = pairs[0].idx2
+ histogramAddHistogramDistance(&out[best_idx1], &out[best_idx2])
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo
+ cluster_size[best_idx1] += cluster_size[best_idx2]
+ for i = 0; i < symbols_size; i++ {
+ if symbols[i] == best_idx2 {
+ symbols[i] = best_idx1
+ }
+ }
+
+ for i = 0; i < num_clusters; i++ {
+ if clusters[i] == best_idx2 {
+ copy(clusters[i:], clusters[i+1:][:num_clusters-i-1])
+ break
+ }
+ }
+
+ num_clusters--
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ var copy_to_idx uint = 0
+ for i = 0; i < num_pairs; i++ {
+ var p *histogramPair = &pairs[i]
+ if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {
+ /* Remove invalid pair from the queue. */
+ continue
+ }
+
+ if histogramPairIsLess(&pairs[0], p) {
+ /* Replace the top of the queue if needed. */
+ var front histogramPair = pairs[0]
+ pairs[0] = *p
+ pairs[copy_to_idx] = front
+ } else {
+ pairs[copy_to_idx] = *p
+ }
+
+ copy_to_idx++
+ }
+
+ num_pairs = copy_to_idx
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for i = 0; i < num_clusters; i++ {
+ compareAndPushToQueueDistance(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+
+ return num_clusters
+}
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+func histogramBitCostDistanceDistance(histogram *histogramDistance, candidate *histogramDistance) float64 {
+ if histogram.total_count_ == 0 {
+ return 0.0
+ } else {
+ var tmp histogramDistance = *histogram
+ histogramAddHistogramDistance(&tmp, candidate)
+ return populationCostDistance(&tmp) - candidate.bit_cost_
+ }
+}
+
+/* Find the best 'out' histogram for each of the 'in' histograms.
+ When called, clusters[0..num_clusters) contains the unique values from
+ symbols[0..in_size), but this property is not preserved in this function.
+ Note: we assume that out[]->bit_cost_ is already up-to-date. */
+func histogramRemapDistance(in []histogramDistance, in_size uint, clusters []uint32, num_clusters uint, out []histogramDistance, symbols []uint32) {
+ var i uint
+ for i = 0; i < in_size; i++ {
+ var best_out uint32
+ if i == 0 {
+ best_out = symbols[0]
+ } else {
+ best_out = symbols[i-1]
+ }
+ var best_bits float64 = histogramBitCostDistanceDistance(&in[i], &out[best_out])
+ var j uint
+ for j = 0; j < num_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceDistance(&in[i], &out[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ symbols[i] = best_out
+ }
+
+ /* Recompute each out based on raw and symbols. */
+ for i = 0; i < num_clusters; i++ {
+ histogramClearDistance(&out[clusters[i]])
+ }
+
+ for i = 0; i < in_size; i++ {
+ histogramAddHistogramDistance(&out[symbols[i]], &in[i])
+ }
+}
+
+/* Reorders elements of the out[0..length) array and changes values in
+ symbols[0..length) array in the following way:
+ * when called, symbols[] contains indexes into out[], and has N unique
+ values (possibly N < length)
+ * on return, symbols'[i] = f(symbols[i]) and
+ out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
+ where f is a bijection between the range of symbols[] and [0..N), and
+ the first occurrences of values in symbols'[i] come in consecutive
+ increasing order.
+ Returns N, the number of unique values in symbols[]. */
+
+var histogramReindexDistance_kInvalidIndex uint32 = math.MaxUint32
+
+func histogramReindexDistance(out []histogramDistance, symbols []uint32, length uint) uint {
+ var new_index []uint32 = make([]uint32, length)
+ var next_index uint32
+ var tmp []histogramDistance
+ var i uint
+ for i = 0; i < length; i++ {
+ new_index[i] = histogramReindexDistance_kInvalidIndex
+ }
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == histogramReindexDistance_kInvalidIndex {
+ new_index[symbols[i]] = next_index
+ next_index++
+ }
+ }
+
+ /* TODO: by using idea of "cycle-sort" we can avoid allocation of
+ tmp and reduce the number of copying by the factor of 2. */
+ tmp = make([]histogramDistance, next_index)
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == next_index {
+ tmp[next_index] = out[symbols[i]]
+ next_index++
+ }
+
+ symbols[i] = new_index[symbols[i]]
+ }
+
+ new_index = nil
+ for i = 0; uint32(i) < next_index; i++ {
+ out[i] = tmp[i]
+ }
+
+ tmp = nil
+ return uint(next_index)
+}
+
+func clusterHistogramsDistance(in []histogramDistance, in_size uint, max_histograms uint, out []histogramDistance, out_size *uint, histogram_symbols []uint32) {
+ var cluster_size []uint32 = make([]uint32, in_size)
+ var clusters []uint32 = make([]uint32, in_size)
+ var num_clusters uint = 0
+ var max_input_histograms uint = 64
+ var pairs_capacity uint = max_input_histograms * max_input_histograms / 2
+ var pairs []histogramPair = make([]histogramPair, (pairs_capacity + 1))
+ var i uint
+
+ /* For the first pass of clustering, we allow all pairs. */
+ for i = 0; i < in_size; i++ {
+ cluster_size[i] = 1
+ }
+
+ for i = 0; i < in_size; i++ {
+ out[i] = in[i]
+ out[i].bit_cost_ = populationCostDistance(&in[i])
+ histogram_symbols[i] = uint32(i)
+ }
+
+ for i = 0; i < in_size; i += max_input_histograms {
+ var num_to_combine uint = brotli_min_size_t(in_size-i, max_input_histograms)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ clusters[num_clusters+j] = uint32(i + j)
+ }
+
+ num_new_clusters = histogramCombineDistance(out, cluster_size, histogram_symbols[i:], clusters[num_clusters:], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity)
+ num_clusters += num_new_clusters
+ }
+ {
+ /* For the second pass, we limit the total number of histogram pairs.
+ After this limit is reached, we only keep searching for the best pair. */
+ var max_num_pairs uint = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < (max_num_pairs + 1) {
+ var _new_size uint
+ if pairs_capacity == 0 {
+ _new_size = max_num_pairs + 1
+ } else {
+ _new_size = pairs_capacity
+ }
+ var new_array []histogramPair
+ for _new_size < (max_num_pairs + 1) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramPair, _new_size)
+ if pairs_capacity != 0 {
+ copy(new_array, pairs[:pairs_capacity])
+ }
+
+ pairs = new_array
+ pairs_capacity = _new_size
+ }
+
+ /* Collapse similar histograms. */
+ num_clusters = histogramCombineDistance(out, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs)
+ }
+
+ pairs = nil
+ cluster_size = nil
+
+ /* Find the optimal map from original histograms to the final ones. */
+ histogramRemapDistance(in, in_size, clusters, num_clusters, out, histogram_symbols)
+
+ clusters = nil
+
+ /* Convert the context map to a canonical form. */
+ *out_size = histogramReindexDistance(out, histogram_symbols, in_size)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_literal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_literal.go
new file mode 100644
index 000000000000..6ba66f31b2cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/cluster_literal.go
@@ -0,0 +1,326 @@
+package brotli
+
+import "math"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
+ it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
+func compareAndPushToQueueLiteral(out []histogramLiteral, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {
+ var is_good_pair bool = false
+ var p histogramPair
+ p.idx2 = 0
+ p.idx1 = p.idx2
+ p.cost_combo = 0
+ p.cost_diff = p.cost_combo
+ if idx1 == idx2 {
+ return
+ }
+
+ if idx2 < idx1 {
+ var t uint32 = idx2
+ idx2 = idx1
+ idx1 = t
+ }
+
+ p.idx1 = idx1
+ p.idx2 = idx2
+ p.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))
+ p.cost_diff -= out[idx1].bit_cost_
+ p.cost_diff -= out[idx2].bit_cost_
+
+ if out[idx1].total_count_ == 0 {
+ p.cost_combo = out[idx2].bit_cost_
+ is_good_pair = true
+ } else if out[idx2].total_count_ == 0 {
+ p.cost_combo = out[idx1].bit_cost_
+ is_good_pair = true
+ } else {
+ var threshold float64
+ if *num_pairs == 0 {
+ threshold = 1e99
+ } else {
+ threshold = brotli_max_double(0.0, pairs[0].cost_diff)
+ }
+ var combo histogramLiteral = out[idx1]
+ var cost_combo float64
+ histogramAddHistogramLiteral(&combo, &out[idx2])
+ cost_combo = populationCostLiteral(&combo)
+ if cost_combo < threshold-p.cost_diff {
+ p.cost_combo = cost_combo
+ is_good_pair = true
+ }
+ }
+
+ if is_good_pair {
+ p.cost_diff += p.cost_combo
+ if *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {
+ /* Replace the top of the queue if needed. */
+ if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = pairs[0]
+ (*num_pairs)++
+ }
+
+ pairs[0] = p
+ } else if *num_pairs < max_num_pairs {
+ pairs[*num_pairs] = p
+ (*num_pairs)++
+ }
+ }
+}
+
+func histogramCombineLiteral(out []histogramLiteral, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {
+ var cost_diff_threshold float64 = 0.0
+ var min_cluster_size uint = 1
+ var num_pairs uint = 0
+ {
+ /* We maintain a vector of histogram pairs, with the property that the pair
+ with the maximum bit cost reduction is the first. */
+ var idx1 uint
+ for idx1 = 0; idx1 < num_clusters; idx1++ {
+ var idx2 uint
+ for idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {
+ compareAndPushToQueueLiteral(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+ }
+
+ for num_clusters > min_cluster_size {
+ var best_idx1 uint32
+ var best_idx2 uint32
+ var i uint
+ if pairs[0].cost_diff >= cost_diff_threshold {
+ cost_diff_threshold = 1e99
+ min_cluster_size = max_clusters
+ continue
+ }
+
+ /* Take the best pair from the top of heap. */
+ best_idx1 = pairs[0].idx1
+
+ best_idx2 = pairs[0].idx2
+ histogramAddHistogramLiteral(&out[best_idx1], &out[best_idx2])
+ out[best_idx1].bit_cost_ = pairs[0].cost_combo
+ cluster_size[best_idx1] += cluster_size[best_idx2]
+ for i = 0; i < symbols_size; i++ {
+ if symbols[i] == best_idx2 {
+ symbols[i] = best_idx1
+ }
+ }
+
+ for i = 0; i < num_clusters; i++ {
+ if clusters[i] == best_idx2 {
+ copy(clusters[i:], clusters[i+1:][:num_clusters-i-1])
+ break
+ }
+ }
+
+ num_clusters--
+ {
+ /* Remove pairs intersecting the just combined best pair. */
+ var copy_to_idx uint = 0
+ for i = 0; i < num_pairs; i++ {
+ var p *histogramPair = &pairs[i]
+ if p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {
+ /* Remove invalid pair from the queue. */
+ continue
+ }
+
+ if histogramPairIsLess(&pairs[0], p) {
+ /* Replace the top of the queue if needed. */
+ var front histogramPair = pairs[0]
+ pairs[0] = *p
+ pairs[copy_to_idx] = front
+ } else {
+ pairs[copy_to_idx] = *p
+ }
+
+ copy_to_idx++
+ }
+
+ num_pairs = copy_to_idx
+ }
+
+ /* Push new pairs formed with the combined histogram to the heap. */
+ for i = 0; i < num_clusters; i++ {
+ compareAndPushToQueueLiteral(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)
+ }
+ }
+
+ return num_clusters
+}
+
+/* What is the bit cost of moving histogram from cur_symbol to candidate. */
+func histogramBitCostDistanceLiteral(histogram *histogramLiteral, candidate *histogramLiteral) float64 {
+ if histogram.total_count_ == 0 {
+ return 0.0
+ } else {
+ var tmp histogramLiteral = *histogram
+ histogramAddHistogramLiteral(&tmp, candidate)
+ return populationCostLiteral(&tmp) - candidate.bit_cost_
+ }
+}
+
+/* Find the best 'out' histogram for each of the 'in' histograms.
+ When called, clusters[0..num_clusters) contains the unique values from
+ symbols[0..in_size), but this property is not preserved in this function.
+ Note: we assume that out[]->bit_cost_ is already up-to-date. */
+func histogramRemapLiteral(in []histogramLiteral, in_size uint, clusters []uint32, num_clusters uint, out []histogramLiteral, symbols []uint32) {
+ var i uint
+ for i = 0; i < in_size; i++ {
+ var best_out uint32
+ if i == 0 {
+ best_out = symbols[0]
+ } else {
+ best_out = symbols[i-1]
+ }
+ var best_bits float64 = histogramBitCostDistanceLiteral(&in[i], &out[best_out])
+ var j uint
+ for j = 0; j < num_clusters; j++ {
+ var cur_bits float64 = histogramBitCostDistanceLiteral(&in[i], &out[clusters[j]])
+ if cur_bits < best_bits {
+ best_bits = cur_bits
+ best_out = clusters[j]
+ }
+ }
+
+ symbols[i] = best_out
+ }
+
+ /* Recompute each out based on raw and symbols. */
+ for i = 0; i < num_clusters; i++ {
+ histogramClearLiteral(&out[clusters[i]])
+ }
+
+ for i = 0; i < in_size; i++ {
+ histogramAddHistogramLiteral(&out[symbols[i]], &in[i])
+ }
+}
+
+/* Reorders elements of the out[0..length) array and changes values in
+ symbols[0..length) array in the following way:
+ * when called, symbols[] contains indexes into out[], and has N unique
+ values (possibly N < length)
+ * on return, symbols'[i] = f(symbols[i]) and
+ out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
+ where f is a bijection between the range of symbols[] and [0..N), and
+ the first occurrences of values in symbols'[i] come in consecutive
+ increasing order.
+ Returns N, the number of unique values in symbols[]. */
+
+var histogramReindexLiteral_kInvalidIndex uint32 = math.MaxUint32
+
+func histogramReindexLiteral(out []histogramLiteral, symbols []uint32, length uint) uint {
+ var new_index []uint32 = make([]uint32, length)
+ var next_index uint32
+ var tmp []histogramLiteral
+ var i uint
+ for i = 0; i < length; i++ {
+ new_index[i] = histogramReindexLiteral_kInvalidIndex
+ }
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == histogramReindexLiteral_kInvalidIndex {
+ new_index[symbols[i]] = next_index
+ next_index++
+ }
+ }
+
+ /* TODO: by using idea of "cycle-sort" we can avoid allocation of
+ tmp and reduce the number of copying by the factor of 2. */
+ tmp = make([]histogramLiteral, next_index)
+
+ next_index = 0
+ for i = 0; i < length; i++ {
+ if new_index[symbols[i]] == next_index {
+ tmp[next_index] = out[symbols[i]]
+ next_index++
+ }
+
+ symbols[i] = new_index[symbols[i]]
+ }
+
+ new_index = nil
+ for i = 0; uint32(i) < next_index; i++ {
+ out[i] = tmp[i]
+ }
+
+ tmp = nil
+ return uint(next_index)
+}
+
+func clusterHistogramsLiteral(in []histogramLiteral, in_size uint, max_histograms uint, out []histogramLiteral, out_size *uint, histogram_symbols []uint32) {
+ var cluster_size []uint32 = make([]uint32, in_size)
+ var clusters []uint32 = make([]uint32, in_size)
+ var num_clusters uint = 0
+ var max_input_histograms uint = 64
+ var pairs_capacity uint = max_input_histograms * max_input_histograms / 2
+ var pairs []histogramPair = make([]histogramPair, (pairs_capacity + 1))
+ var i uint
+
+ /* For the first pass of clustering, we allow all pairs. */
+ for i = 0; i < in_size; i++ {
+ cluster_size[i] = 1
+ }
+
+ for i = 0; i < in_size; i++ {
+ out[i] = in[i]
+ out[i].bit_cost_ = populationCostLiteral(&in[i])
+ histogram_symbols[i] = uint32(i)
+ }
+
+ for i = 0; i < in_size; i += max_input_histograms {
+ var num_to_combine uint = brotli_min_size_t(in_size-i, max_input_histograms)
+ var num_new_clusters uint
+ var j uint
+ for j = 0; j < num_to_combine; j++ {
+ clusters[num_clusters+j] = uint32(i + j)
+ }
+
+ num_new_clusters = histogramCombineLiteral(out, cluster_size, histogram_symbols[i:], clusters[num_clusters:], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity)
+ num_clusters += num_new_clusters
+ }
+ {
+ /* For the second pass, we limit the total number of histogram pairs.
+ After this limit is reached, we only keep searching for the best pair. */
+ var max_num_pairs uint = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)
+ if pairs_capacity < (max_num_pairs + 1) {
+ var _new_size uint
+ if pairs_capacity == 0 {
+ _new_size = max_num_pairs + 1
+ } else {
+ _new_size = pairs_capacity
+ }
+ var new_array []histogramPair
+ for _new_size < (max_num_pairs + 1) {
+ _new_size *= 2
+ }
+ new_array = make([]histogramPair, _new_size)
+ if pairs_capacity != 0 {
+ copy(new_array, pairs[:pairs_capacity])
+ }
+
+ pairs = new_array
+ pairs_capacity = _new_size
+ }
+
+ /* Collapse similar histograms. */
+ num_clusters = histogramCombineLiteral(out, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs)
+ }
+
+ pairs = nil
+ cluster_size = nil
+
+ /* Find the optimal map from original histograms to the final ones. */
+ histogramRemapLiteral(in, in_size, clusters, num_clusters, out, histogram_symbols)
+
+ clusters = nil
+
+ /* Convert the context map to a canonical form. */
+ *out_size = histogramReindexLiteral(out, histogram_symbols, in_size)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/command.go
new file mode 100644
index 000000000000..b1662a55552f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/command.go
@@ -0,0 +1,254 @@
+package brotli
+
+var kInsBase = []uint32{
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 8,
+ 10,
+ 14,
+ 18,
+ 26,
+ 34,
+ 50,
+ 66,
+ 98,
+ 130,
+ 194,
+ 322,
+ 578,
+ 1090,
+ 2114,
+ 6210,
+ 22594,
+}
+
+var kInsExtra = []uint32{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 12,
+ 14,
+ 24,
+}
+
+var kCopyBase = []uint32{
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 12,
+ 14,
+ 18,
+ 22,
+ 30,
+ 38,
+ 54,
+ 70,
+ 102,
+ 134,
+ 198,
+ 326,
+ 582,
+ 1094,
+ 2118,
+}
+
+var kCopyExtra = []uint32{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 24,
+}
+
+func getInsertLengthCode(insertlen uint) uint16 {
+ if insertlen < 6 {
+ return uint16(insertlen)
+ } else if insertlen < 130 {
+ var nbits uint32 = log2FloorNonZero(insertlen-2) - 1
+ return uint16((nbits << 1) + uint32((insertlen-2)>>nbits) + 2)
+ } else if insertlen < 2114 {
+ return uint16(log2FloorNonZero(insertlen-66) + 10)
+ } else if insertlen < 6210 {
+ return 21
+ } else if insertlen < 22594 {
+ return 22
+ } else {
+ return 23
+ }
+}
+
+func getCopyLengthCode(copylen uint) uint16 {
+ if copylen < 10 {
+ return uint16(copylen - 2)
+ } else if copylen < 134 {
+ var nbits uint32 = log2FloorNonZero(copylen-6) - 1
+ return uint16((nbits << 1) + uint32((copylen-6)>>nbits) + 4)
+ } else if copylen < 2118 {
+ return uint16(log2FloorNonZero(copylen-70) + 12)
+ } else {
+ return 23
+ }
+}
+
+func combineLengthCodes(inscode uint16, copycode uint16, use_last_distance bool) uint16 {
+ var bits64 uint16 = uint16(copycode&0x7 | (inscode&0x7)<<3)
+ if use_last_distance && inscode < 8 && copycode < 16 {
+ if copycode < 8 {
+ return bits64
+ } else {
+ return bits64 | 64
+ }
+ } else {
+ /* Specification: 5 Encoding of ... (last table) */
+ /* offset = 2 * index, where index is in range [0..8] */
+ var offset uint32 = 2 * ((uint32(copycode) >> 3) + 3*(uint32(inscode)>>3))
+
+ /* All values in specification are K * 64,
+ where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
+ i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
+ K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
+ All values in D require only 2 bits to encode.
+ Magic constant is shifted 6 bits left, to avoid final multiplication. */
+ offset = (offset << 5) + 0x40 + ((0x520D40 >> offset) & 0xC0)
+
+ return uint16(offset | uint32(bits64))
+ }
+}
+
+func getLengthCode(insertlen uint, copylen uint, use_last_distance bool, code *uint16) {
+ var inscode uint16 = getInsertLengthCode(insertlen)
+ var copycode uint16 = getCopyLengthCode(copylen)
+ *code = combineLengthCodes(inscode, copycode, use_last_distance)
+}
+
+func getInsertBase(inscode uint16) uint32 {
+ return kInsBase[inscode]
+}
+
+func getInsertExtra(inscode uint16) uint32 {
+ return kInsExtra[inscode]
+}
+
+func getCopyBase(copycode uint16) uint32 {
+ return kCopyBase[copycode]
+}
+
+func getCopyExtra(copycode uint16) uint32 {
+ return kCopyExtra[copycode]
+}
+
+type command struct {
+ insert_len_ uint32
+ copy_len_ uint32
+ dist_extra_ uint32
+ cmd_prefix_ uint16
+ dist_prefix_ uint16
+}
+
+/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
+func makeCommand(dist *distanceParams, insertlen uint, copylen uint, copylen_code_delta int, distance_code uint) (cmd command) {
+ /* Don't rely on signed int representation, use honest casts. */
+ var delta uint32 = uint32(byte(int8(copylen_code_delta)))
+ cmd.insert_len_ = uint32(insertlen)
+ cmd.copy_len_ = uint32(uint32(copylen) | delta<<25)
+
+ /* The distance prefix and extra bits are stored in this Command as if
+ npostfix and ndirect were 0, they are only recomputed later after the
+ clustering if needed. */
+ prefixEncodeCopyDistance(distance_code, uint(dist.num_direct_distance_codes), uint(dist.distance_postfix_bits), &cmd.dist_prefix_, &cmd.dist_extra_)
+ getLengthCode(insertlen, uint(int(copylen)+copylen_code_delta), (cmd.dist_prefix_&0x3FF == 0), &cmd.cmd_prefix_)
+
+ return cmd
+}
+
+func makeInsertCommand(insertlen uint) (cmd command) {
+ cmd.insert_len_ = uint32(insertlen)
+ cmd.copy_len_ = 4 << 25
+ cmd.dist_extra_ = 0
+ cmd.dist_prefix_ = numDistanceShortCodes
+ getLengthCode(insertlen, 4, false, &cmd.cmd_prefix_)
+ return cmd
+}
+
+func commandRestoreDistanceCode(self *command, dist *distanceParams) uint32 {
+ if uint32(self.dist_prefix_&0x3FF) < numDistanceShortCodes+dist.num_direct_distance_codes {
+ return uint32(self.dist_prefix_) & 0x3FF
+ } else {
+ var dcode uint32 = uint32(self.dist_prefix_) & 0x3FF
+ var nbits uint32 = uint32(self.dist_prefix_) >> 10
+ var extra uint32 = self.dist_extra_
+ var postfix_mask uint32 = (1 << dist.distance_postfix_bits) - 1
+ var hcode uint32 = (dcode - dist.num_direct_distance_codes - numDistanceShortCodes) >> dist.distance_postfix_bits
+ var lcode uint32 = (dcode - dist.num_direct_distance_codes - numDistanceShortCodes) & postfix_mask
+ var offset uint32 = ((2 + (hcode & 1)) << nbits) - 4
+ return ((offset + extra) << dist.distance_postfix_bits) + lcode + dist.num_direct_distance_codes + numDistanceShortCodes
+ }
+}
+
+func commandDistanceContext(self *command) uint32 {
+ var r uint32 = uint32(self.cmd_prefix_) >> 6
+ var c uint32 = uint32(self.cmd_prefix_) & 7
+ if (r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2) {
+ return c
+ }
+
+ return 3
+}
+
+func commandCopyLen(self *command) uint32 {
+ return self.copy_len_ & 0x1FFFFFF
+}
+
+func commandCopyLenCode(self *command) uint32 {
+ var modifier uint32 = self.copy_len_ >> 25
+ var delta int32 = int32(int8(byte(modifier | (modifier&0x40)<<1)))
+ return uint32(int32(self.copy_len_&0x1FFFFFF) + delta)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/compress_fragment.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/compress_fragment.go
new file mode 100644
index 000000000000..c9bd05770565
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/compress_fragment.go
@@ -0,0 +1,834 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses one-pass processing: when we find a backward
+ match, we immediately emit the corresponding command and literal codes to
+ the bit stream.
+
+ Adapted from the CompressFragment() function in
+ https://github.com/google/snappy/blob/master/snappy.cc */
+
+const maxDistance_compress_fragment = 262128
+
+func hash5(p []byte, shift uint) uint32 {
+ var h uint64 = (binary.LittleEndian.Uint64(p) << 24) * uint64(kHashMul32)
+ return uint32(h >> shift)
+}
+
+func hashBytesAtOffset5(v uint64, offset int, shift uint) uint32 {
+ assert(offset >= 0)
+ assert(offset <= 3)
+ {
+ var h uint64 = ((v >> uint(8*offset)) << 24) * uint64(kHashMul32)
+ return uint32(h >> shift)
+ }
+}
+
+func isMatch5(p1 []byte, p2 []byte) bool {
+ return binary.LittleEndian.Uint32(p1) == binary.LittleEndian.Uint32(p2) &&
+ p1[4] == p2[4]
+}
+
+/* Builds a literal prefix code into "depths" and "bits" based on the statistics
+ of the "input" string and stores it into the bit stream.
+ Note that the prefix code here is built from the pre-LZ77 input, therefore
+ we can only approximate the statistics of the actual literal stream.
+ Moreover, for long inputs we build a histogram from a sample of the input
+ and thus have to assign a non-zero depth for each literal.
+ Returns estimated compression ratio millibytes/char for encoding given input
+ with generated code. */
+func buildAndStoreLiteralPrefixCode(input []byte, input_size uint, depths []byte, bits []uint16, storage_ix *uint, storage []byte) uint {
+ var histogram = [256]uint32{0}
+ var histogram_total uint
+ var i uint
+ if input_size < 1<<15 {
+ for i = 0; i < input_size; i++ {
+ histogram[input[i]]++
+ }
+
+ histogram_total = input_size
+ for i = 0; i < 256; i++ {
+ /* We weigh the first 11 samples with weight 3 to account for the
+ balancing effect of the LZ77 phase on the histogram. */
+ var adjust uint32 = 2 * brotli_min_uint32_t(histogram[i], 11)
+ histogram[i] += adjust
+ histogram_total += uint(adjust)
+ }
+ } else {
+ const kSampleRate uint = 29
+ for i = 0; i < input_size; i += kSampleRate {
+ histogram[input[i]]++
+ }
+
+ histogram_total = (input_size + kSampleRate - 1) / kSampleRate
+ for i = 0; i < 256; i++ {
+ /* We add 1 to each population count to avoid 0 bit depths (since this is
+ only a sample and we don't know if the symbol appears or not), and we
+ weigh the first 11 samples with weight 3 to account for the balancing
+ effect of the LZ77 phase on the histogram (more frequent symbols are
+ more likely to be in backward references instead as literals). */
+ var adjust uint32 = 1 + 2*brotli_min_uint32_t(histogram[i], 11)
+ histogram[i] += adjust
+ histogram_total += uint(adjust)
+ }
+ }
+
+ buildAndStoreHuffmanTreeFast(histogram[:], histogram_total, /* max_bits = */
+ 8, depths, bits, storage_ix, storage)
+ {
+ var literal_ratio uint = 0
+ for i = 0; i < 256; i++ {
+ if histogram[i] != 0 {
+ literal_ratio += uint(histogram[i] * uint32(depths[i]))
+ }
+ }
+
+ /* Estimated encoding ratio, millibytes per symbol. */
+ return (literal_ratio * 125) / histogram_total
+ }
+}
+
+/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
+ "bits" based on "histogram" and stores it into the bit stream. */
+func buildAndStoreCommandPrefixCode1(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var tree [129]huffmanTree
+ var cmd_depth = [numCommandSymbols]byte{0}
+ /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
+
+ var cmd_bits [64]uint16
+
+ createHuffmanTree(histogram, 64, 15, tree[:], depth)
+ createHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])
+
+ /* We have to jump through a few hoops here in order to compute
+ the command bits because the symbols are in a different order than in
+ the full alphabet. This looks complicated, but having the symbols
+ in this order in the command bits saves a few branches in the Emit*
+ functions. */
+ copy(cmd_depth[:], depth[:24])
+
+ copy(cmd_depth[24:][:], depth[40:][:8])
+ copy(cmd_depth[32:][:], depth[24:][:8])
+ copy(cmd_depth[40:][:], depth[48:][:8])
+ copy(cmd_depth[48:][:], depth[32:][:8])
+ copy(cmd_depth[56:][:], depth[56:][:8])
+ convertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])
+ copy(bits, cmd_bits[:24])
+ copy(bits[24:], cmd_bits[32:][:8])
+ copy(bits[32:], cmd_bits[48:][:8])
+ copy(bits[40:], cmd_bits[24:][:8])
+ copy(bits[48:], cmd_bits[40:][:8])
+ copy(bits[56:], cmd_bits[56:][:8])
+ convertBitDepthsToSymbols(depth[64:], 64, bits[64:])
+ {
+ /* Create the bit length array for the full command alphabet. */
+ var i uint
+ for i := 0; i < int(64); i++ {
+ cmd_depth[i] = 0
+ } /* only 64 first values were used */
+ copy(cmd_depth[:], depth[:8])
+ copy(cmd_depth[64:][:], depth[8:][:8])
+ copy(cmd_depth[128:][:], depth[16:][:8])
+ copy(cmd_depth[192:][:], depth[24:][:8])
+ copy(cmd_depth[384:][:], depth[32:][:8])
+ for i = 0; i < 8; i++ {
+ cmd_depth[128+8*i] = depth[40+i]
+ cmd_depth[256+8*i] = depth[48+i]
+ cmd_depth[448+8*i] = depth[56+i]
+ }
+
+ storeHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)
+ }
+
+ storeHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)
+}
+
+/* REQUIRES: insertlen < 6210 */
+func emitInsertLen1(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {
+ if insertlen < 6 {
+ var code uint = insertlen + 40
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ histo[code]++
+ } else if insertlen < 130 {
+ var tail uint = insertlen - 2
+ var nbits uint32 = log2FloorNonZero(tail) - 1
+ var prefix uint = tail >> nbits
+ var inscode uint = uint((nbits << 1) + uint32(prefix) + 42)
+ writeBits(uint(depth[inscode]), uint64(bits[inscode]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<> nbits
+ var code uint = uint((nbits << 1) + uint32(prefix) + 20)
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<> nbits
+ var code uint = uint((nbits << 1) + uint32(prefix) + 4)
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(prefix)<> 5) + 30
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(5, uint64(tail)&31, storage_ix, storage)
+ writeBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)
+ histo[code]++
+ histo[64]++
+ } else if copylen < 2120 {
+ var tail uint = copylen - 72
+ var nbits uint32 = log2FloorNonZero(tail)
+ var code uint = uint(nbits + 28)
+ writeBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(tail)-(uint64(uint(1))<> nbits) & 1
+ var offset uint = (2 + prefix) << nbits
+ var distcode uint = uint(2*(nbits-1) + uint32(prefix) + 80)
+ writeBits(uint(depth[distcode]), uint64(bits[distcode]), storage_ix, storage)
+ writeBits(uint(nbits), uint64(d)-uint64(offset), storage_ix, storage)
+ histo[distcode]++
+}
+
+func emitLiterals(input []byte, len uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var j uint
+ for j = 0; j < len; j++ {
+ var lit byte = input[j]
+ writeBits(uint(depth[lit]), uint64(bits[lit]), storage_ix, storage)
+ }
+}
+
+/* REQUIRES: len <= 1 << 24. */
+func storeMetaBlockHeader1(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {
+ var nibbles uint = 6
+
+ /* ISLAST */
+ writeBits(1, 0, storage_ix, storage)
+
+ if len <= 1<<16 {
+ nibbles = 4
+ } else if len <= 1<<20 {
+ nibbles = 5
+ }
+
+ writeBits(2, uint64(nibbles)-4, storage_ix, storage)
+ writeBits(nibbles*4, uint64(len)-1, storage_ix, storage)
+
+ /* ISUNCOMPRESSED */
+ writeSingleBit(is_uncompressed, storage_ix, storage)
+}
+
+func updateBits(n_bits uint, bits uint32, pos uint, array []byte) {
+ for n_bits > 0 {
+ var byte_pos uint = pos >> 3
+ var n_unchanged_bits uint = pos & 7
+ var n_changed_bits uint = brotli_min_size_t(n_bits, 8-n_unchanged_bits)
+ var total_bits uint = n_unchanged_bits + n_changed_bits
+ var mask uint32 = (^((1 << total_bits) - 1)) | ((1 << n_unchanged_bits) - 1)
+ var unchanged_bits uint32 = uint32(array[byte_pos]) & mask
+ var changed_bits uint32 = bits & ((1 << n_changed_bits) - 1)
+ array[byte_pos] = byte(changed_bits<>= n_changed_bits
+ pos += n_changed_bits
+ }
+}
+
+func rewindBitPosition1(new_storage_ix uint, storage_ix *uint, storage []byte) {
+ var bitpos uint = new_storage_ix & 7
+ var mask uint = (1 << bitpos) - 1
+ storage[new_storage_ix>>3] &= byte(mask)
+ *storage_ix = new_storage_ix
+}
+
+var shouldMergeBlock_kSampleRate uint = 43
+
+func shouldMergeBlock(data []byte, len uint, depths []byte) bool {
+ var histo = [256]uint{0}
+ var i uint
+ for i = 0; i < len; i += shouldMergeBlock_kSampleRate {
+ histo[data[i]]++
+ }
+ {
+ var total uint = (len + shouldMergeBlock_kSampleRate - 1) / shouldMergeBlock_kSampleRate
+ var r float64 = (fastLog2(total)+0.5)*float64(total) + 200
+ for i = 0; i < 256; i++ {
+ r -= float64(histo[i]) * (float64(depths[i]) + fastLog2(histo[i]))
+ }
+
+ return r >= 0.0
+ }
+}
+
+func shouldUseUncompressedMode(metablock_start []byte, next_emit []byte, insertlen uint, literal_ratio uint) bool {
+ var compressed uint = uint(-cap(next_emit) + cap(metablock_start))
+ if compressed*50 > insertlen {
+ return false
+ } else {
+ return literal_ratio > 980
+ }
+}
+
+func emitUncompressedMetaBlock1(begin []byte, end []byte, storage_ix_start uint, storage_ix *uint, storage []byte) {
+ var len uint = uint(-cap(end) + cap(begin))
+ rewindBitPosition1(storage_ix_start, storage_ix, storage)
+ storeMetaBlockHeader1(uint(len), true, storage_ix, storage)
+ *storage_ix = (*storage_ix + 7) &^ 7
+ copy(storage[*storage_ix>>3:], begin[:len])
+ *storage_ix += uint(len << 3)
+ storage[*storage_ix>>3] = 0
+}
+
+var kCmdHistoSeed = [128]uint32{
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+}
+
+var compressFragmentFastImpl_kFirstBlockSize uint = 3 << 15
+var compressFragmentFastImpl_kMergeBlockSize uint = 1 << 16
+
+func compressFragmentFastImpl(in []byte, input_size uint, is_last bool, table []int, table_bits uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {
+ var cmd_histo [128]uint32
+ var ip_end int
+ var next_emit int = 0
+ var base_ip int = 0
+ var input int = 0
+ const kInputMarginBytes uint = windowGap
+ const kMinMatchLen uint = 5
+ var metablock_start int = input
+ var block_size uint = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)
+ var total_block_size uint = block_size
+ var mlen_storage_ix uint = *storage_ix + 3
+ var lit_depth [256]byte
+ var lit_bits [256]uint16
+ var literal_ratio uint
+ var ip int
+ var last_distance int
+ var shift uint = 64 - table_bits
+
+ /* "next_emit" is a pointer to the first byte that is not covered by a
+ previous copy. Bytes between "next_emit" and the start of the next copy or
+ the end of the input will be emitted as literal bytes. */
+
+ /* Save the start of the first block for position and distance computations.
+ */
+
+ /* Save the bit position of the MLEN field of the meta-block header, so that
+ we can update it later if we decide to extend this meta-block. */
+ storeMetaBlockHeader1(block_size, false, storage_ix, storage)
+
+ /* No block splits, no contexts. */
+ writeBits(13, 0, storage_ix, storage)
+
+ literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)
+ {
+ /* Store the pre-compressed command and distance prefix codes. */
+ var i uint
+ for i = 0; i+7 < *cmd_code_numbits; i += 8 {
+ writeBits(8, uint64(cmd_code[i>>3]), storage_ix, storage)
+ }
+ }
+
+ writeBits(*cmd_code_numbits&7, uint64(cmd_code[*cmd_code_numbits>>3]), storage_ix, storage)
+
+ /* Initialize the command and distance histograms. We will gather
+ statistics of command and distance codes during the processing
+ of this block and use it to update the command and distance
+ prefix codes for the next block. */
+emit_commands:
+ copy(cmd_histo[:], kCmdHistoSeed[:])
+
+ /* "ip" is the input pointer. */
+ ip = input
+
+ last_distance = -1
+ ip_end = int(uint(input) + block_size)
+
+ if block_size >= kInputMarginBytes {
+ var len_limit uint = brotli_min_size_t(block_size-kMinMatchLen, input_size-kInputMarginBytes)
+ var ip_limit int = int(uint(input) + len_limit)
+ /* For the last block, we need to keep a 16 bytes margin so that we can be
+ sure that all distances are at most window size - 16.
+ For all other blocks, we only need to keep a margin of 5 bytes so that
+ we don't go over the block size with a copy. */
+
+ var next_hash uint32
+ ip++
+ for next_hash = hash5(in[ip:], shift); ; {
+ var skip uint32 = 32
+ var next_ip int = ip
+ /* Step 1: Scan forward in the input looking for a 5-byte-long match.
+ If we get close to exhausting the input then goto emit_remainder.
+
+ Heuristic match skipping: If 32 bytes are scanned with no matches
+ found, start looking only at every other byte. If 32 more bytes are
+ scanned, look at every third byte, etc.. When a match is found,
+ immediately go back to looking at every byte. This is a small loss
+ (~5% performance, ~0.1% density) for compressible data due to more
+ bookkeeping, but for non-compressible data (such as JPEG) it's a huge
+ win since the compressor quickly "realizes" the data is incompressible
+ and doesn't bother looking for matches everywhere.
+
+ The "skip" variable keeps track of how many bytes there are since the
+ last match; dividing it by 32 (i.e. right-shifting by five) gives the
+ number of bytes to move ahead for each iteration. */
+
+ var candidate int
+ assert(next_emit < ip)
+
+ trawl:
+ for {
+ var hash uint32 = next_hash
+ var bytes_between_hash_lookups uint32 = skip >> 5
+ skip++
+ assert(hash == hash5(in[next_ip:], shift))
+ ip = next_ip
+ next_ip = int(uint32(ip) + bytes_between_hash_lookups)
+ if next_ip > ip_limit {
+ goto emit_remainder
+ }
+
+ next_hash = hash5(in[next_ip:], shift)
+ candidate = ip - last_distance
+ if isMatch5(in[ip:], in[candidate:]) {
+ if candidate < ip {
+ table[hash] = int(ip - base_ip)
+ break
+ }
+ }
+
+ candidate = base_ip + table[hash]
+ assert(candidate >= base_ip)
+ assert(candidate < ip)
+
+ table[hash] = int(ip - base_ip)
+ if isMatch5(in[ip:], in[candidate:]) {
+ break
+ }
+ }
+
+ /* Check copy distance. If candidate is not feasible, continue search.
+ Checking is done outside of hot loop to reduce overhead. */
+ if ip-candidate > maxDistance_compress_fragment {
+ goto trawl
+ }
+
+ /* Step 2: Emit the found match together with the literal bytes from
+ "next_emit" to the bit stream, and then see if we can find a next match
+ immediately afterwards. Repeat until we find no match for the input
+ without emitting some literal bytes. */
+ {
+ var base int = ip
+ /* > 0 */
+ var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)
+ var distance int = int(base - candidate)
+ /* We have a 5-byte match at ip, and we need to emit bytes in
+ [next_emit, ip). */
+
+ var insert uint = uint(base - next_emit)
+ ip += int(matched)
+ if insert < 6210 {
+ emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ } else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {
+ emitUncompressedMetaBlock1(in[metablock_start:], in[base:], mlen_storage_ix-3, storage_ix, storage)
+ input_size -= uint(base - input)
+ input = base
+ next_emit = input
+ goto next_block
+ } else {
+ emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ }
+
+ emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
+ if distance == last_distance {
+ writeBits(uint(cmd_depth[64]), uint64(cmd_bits[64]), storage_ix, storage)
+ cmd_histo[64]++
+ } else {
+ emitDistance1(uint(distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ last_distance = distance
+ }
+
+ emitCopyLenLastDistance1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some positions
+ within the last copy. */
+ {
+ var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])
+ var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)
+ var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset5(input_bytes, 1, shift)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset5(input_bytes, 2, shift)
+ table[prev_hash] = int(ip - base_ip - 1)
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ for isMatch5(in[ip:], in[candidate:]) {
+ var base int = ip
+ /* We have a 5-byte match at ip, and no need to emit any literal bytes
+ prior to ip. */
+
+ var matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)
+ if ip-candidate > maxDistance_compress_fragment {
+ break
+ }
+ ip += int(matched)
+ last_distance = int(base - candidate) /* > 0 */
+ emitCopyLen1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ emitDistance1(uint(last_distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some positions
+ within the last copy. */
+ {
+ var input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])
+ var prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)
+ var cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset5(input_bytes, 1, shift)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset5(input_bytes, 2, shift)
+ table[prev_hash] = int(ip - base_ip - 1)
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ ip++
+ next_hash = hash5(in[ip:], shift)
+ }
+ }
+
+emit_remainder:
+ assert(next_emit <= ip_end)
+ input += int(block_size)
+ input_size -= block_size
+ block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kMergeBlockSize)
+
+ /* Decide if we want to continue this meta-block instead of emitting the
+ last insert-only command. */
+ if input_size > 0 && total_block_size+block_size <= 1<<20 && shouldMergeBlock(in[input:], block_size, lit_depth[:]) {
+ assert(total_block_size > 1<<16)
+
+ /* Update the size of the current meta-block and continue emitting commands.
+ We can do this because the current size and the new size both have 5
+ nibbles. */
+ total_block_size += block_size
+
+ updateBits(20, uint32(total_block_size-1), mlen_storage_ix, storage)
+ goto emit_commands
+ }
+
+ /* Emit the remaining bytes as literals. */
+ if next_emit < ip_end {
+ var insert uint = uint(ip_end - next_emit)
+ if insert < 6210 {
+ emitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
+ } else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {
+ emitUncompressedMetaBlock1(in[metablock_start:], in[ip_end:], mlen_storage_ix-3, storage_ix, storage)
+ } else {
+ emitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)
+ emitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)
+ }
+ }
+
+ next_emit = ip_end
+
+ /* If we have more data, write a new meta-block header and prefix codes and
+ then continue emitting commands. */
+next_block:
+ if input_size > 0 {
+ metablock_start = input
+ block_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)
+ total_block_size = block_size
+
+ /* Save the bit position of the MLEN field of the meta-block header, so that
+ we can update it later if we decide to extend this meta-block. */
+ mlen_storage_ix = *storage_ix + 3
+
+ storeMetaBlockHeader1(block_size, false, storage_ix, storage)
+
+ /* No block splits, no contexts. */
+ writeBits(13, 0, storage_ix, storage)
+
+ literal_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)
+ buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, storage_ix, storage)
+ goto emit_commands
+ }
+
+ if !is_last {
+ /* If this is not the last block, update the command and distance prefix
+ codes for the next block and store the compressed forms. */
+ cmd_code[0] = 0
+
+ *cmd_code_numbits = 0
+ buildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, cmd_code_numbits, cmd_code)
+ }
+}
+
+/* Compresses "input" string to the "*storage" buffer as one or more complete
+ meta-blocks, and updates the "*storage_ix" bit position.
+
+ If "is_last" is 1, emits an additional empty last meta-block.
+
+ "cmd_depth" and "cmd_bits" contain the command and distance prefix codes
+ (see comment in encode.h) used for the encoding of this input fragment.
+ If "is_last" is 0, they are updated to reflect the statistics
+ of this input fragment, to be used for the encoding of the next fragment.
+
+ "*cmd_code_numbits" is the number of bits of the compressed representation
+ of the command and distance prefix codes, and "cmd_code" is an array of
+ at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed
+ command and distance prefix codes. If "is_last" is 0, these are also
+ updated to represent the updated "cmd_depth" and "cmd_bits".
+
+ REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
+ REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
+ REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
+ REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
+ OUTPUT: maximal copy distance <= |input_size|
+ OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
+func compressFragmentFast(input []byte, input_size uint, is_last bool, table []int, table_size uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {
+ var initial_storage_ix uint = *storage_ix
+ var table_bits uint = uint(log2FloorNonZero(table_size))
+
+ if input_size == 0 {
+ assert(is_last)
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ *storage_ix = (*storage_ix + 7) &^ 7
+ return
+ }
+
+ compressFragmentFastImpl(input, input_size, is_last, table, table_bits, cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage)
+
+ /* If output is larger than single uncompressed block, rewrite it. */
+ if *storage_ix-initial_storage_ix > 31+(input_size<<3) {
+ emitUncompressedMetaBlock1(input, input[input_size:], initial_storage_ix, storage_ix, storage)
+ }
+
+ if is_last {
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ *storage_ix = (*storage_ix + 7) &^ 7
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go
new file mode 100644
index 000000000000..172dc7f46071
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go
@@ -0,0 +1,748 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function for fast encoding of an input fragment, independently from the input
+ history. This function uses two-pass processing: in the first pass we save
+ the found backward matches and literal bytes into a buffer, and in the
+ second pass we emit them into the bit stream using prefix codes built based
+ on the actual command and literal byte histograms. */
+
+const kCompressFragmentTwoPassBlockSize uint = 1 << 17
+
+func hash1(p []byte, shift uint, length uint) uint32 {
+ var h uint64 = (binary.LittleEndian.Uint64(p) << ((8 - length) * 8)) * uint64(kHashMul32)
+ return uint32(h >> shift)
+}
+
+func hashBytesAtOffset(v uint64, offset uint, shift uint, length uint) uint32 {
+ assert(offset <= 8-length)
+ {
+ var h uint64 = ((v >> (8 * offset)) << ((8 - length) * 8)) * uint64(kHashMul32)
+ return uint32(h >> shift)
+ }
+}
+
+func isMatch1(p1 []byte, p2 []byte, length uint) bool {
+ if binary.LittleEndian.Uint32(p1) != binary.LittleEndian.Uint32(p2) {
+ return false
+ }
+ if length == 4 {
+ return true
+ }
+ return p1[4] == p2[4] && p1[5] == p2[5]
+}
+
+/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
+ "bits" based on "histogram" and stores it into the bit stream. */
+func buildAndStoreCommandPrefixCode(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
+ var tree [129]huffmanTree
+ var cmd_depth = [numCommandSymbols]byte{0}
+ /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
+
+ var cmd_bits [64]uint16
+ createHuffmanTree(histogram, 64, 15, tree[:], depth)
+ createHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])
+
+ /* We have to jump through a few hoops here in order to compute
+ the command bits because the symbols are in a different order than in
+ the full alphabet. This looks complicated, but having the symbols
+ in this order in the command bits saves a few branches in the Emit*
+ functions. */
+ copy(cmd_depth[:], depth[24:][:24])
+
+ copy(cmd_depth[24:][:], depth[:8])
+ copy(cmd_depth[32:][:], depth[48:][:8])
+ copy(cmd_depth[40:][:], depth[8:][:8])
+ copy(cmd_depth[48:][:], depth[56:][:8])
+ copy(cmd_depth[56:][:], depth[16:][:8])
+ convertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])
+ copy(bits, cmd_bits[24:][:8])
+ copy(bits[8:], cmd_bits[40:][:8])
+ copy(bits[16:], cmd_bits[56:][:8])
+ copy(bits[24:], cmd_bits[:24])
+ copy(bits[48:], cmd_bits[32:][:8])
+ copy(bits[56:], cmd_bits[48:][:8])
+ convertBitDepthsToSymbols(depth[64:], 64, bits[64:])
+ {
+ /* Create the bit length array for the full command alphabet. */
+ var i uint
+ for i := 0; i < int(64); i++ {
+ cmd_depth[i] = 0
+ } /* only 64 first values were used */
+ copy(cmd_depth[:], depth[24:][:8])
+ copy(cmd_depth[64:][:], depth[32:][:8])
+ copy(cmd_depth[128:][:], depth[40:][:8])
+ copy(cmd_depth[192:][:], depth[48:][:8])
+ copy(cmd_depth[384:][:], depth[56:][:8])
+ for i = 0; i < 8; i++ {
+ cmd_depth[128+8*i] = depth[i]
+ cmd_depth[256+8*i] = depth[8+i]
+ cmd_depth[448+8*i] = depth[16+i]
+ }
+
+ storeHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)
+ }
+
+ storeHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)
+}
+
+func emitInsertLen(insertlen uint32, commands *[]uint32) {
+ if insertlen < 6 {
+ (*commands)[0] = insertlen
+ } else if insertlen < 130 {
+ var tail uint32 = insertlen - 2
+ var nbits uint32 = log2FloorNonZero(uint(tail)) - 1
+ var prefix uint32 = tail >> nbits
+ var inscode uint32 = (nbits << 1) + prefix + 2
+ var extra uint32 = tail - (prefix << nbits)
+ (*commands)[0] = inscode | extra<<8
+ } else if insertlen < 2114 {
+ var tail uint32 = insertlen - 66
+ var nbits uint32 = log2FloorNonZero(uint(tail))
+ var code uint32 = nbits + 10
+ var extra uint32 = tail - (1 << nbits)
+ (*commands)[0] = code | extra<<8
+ } else if insertlen < 6210 {
+ var extra uint32 = insertlen - 2114
+ (*commands)[0] = 21 | extra<<8
+ } else if insertlen < 22594 {
+ var extra uint32 = insertlen - 6210
+ (*commands)[0] = 22 | extra<<8
+ } else {
+ var extra uint32 = insertlen - 22594
+ (*commands)[0] = 23 | extra<<8
+ }
+
+ *commands = (*commands)[1:]
+}
+
+func emitCopyLen(copylen uint, commands *[]uint32) {
+ if copylen < 10 {
+ (*commands)[0] = uint32(copylen + 38)
+ } else if copylen < 134 {
+ var tail uint = copylen - 6
+ var nbits uint = uint(log2FloorNonZero(tail) - 1)
+ var prefix uint = tail >> nbits
+ var code uint = (nbits << 1) + prefix + 44
+ var extra uint = tail - (prefix << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ } else if copylen < 2118 {
+ var tail uint = copylen - 70
+ var nbits uint = uint(log2FloorNonZero(tail))
+ var code uint = nbits + 52
+ var extra uint = tail - (uint(1) << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ } else {
+ var extra uint = copylen - 2118
+ (*commands)[0] = uint32(63 | extra<<8)
+ }
+
+ *commands = (*commands)[1:]
+}
+
+func emitCopyLenLastDistance(copylen uint, commands *[]uint32) {
+ if copylen < 12 {
+ (*commands)[0] = uint32(copylen + 20)
+ *commands = (*commands)[1:]
+ } else if copylen < 72 {
+ var tail uint = copylen - 8
+ var nbits uint = uint(log2FloorNonZero(tail) - 1)
+ var prefix uint = tail >> nbits
+ var code uint = (nbits << 1) + prefix + 28
+ var extra uint = tail - (prefix << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ *commands = (*commands)[1:]
+ } else if copylen < 136 {
+ var tail uint = copylen - 8
+ var code uint = (tail >> 5) + 54
+ var extra uint = tail & 31
+ (*commands)[0] = uint32(code | extra<<8)
+ *commands = (*commands)[1:]
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ } else if copylen < 2120 {
+ var tail uint = copylen - 72
+ var nbits uint = uint(log2FloorNonZero(tail))
+ var code uint = nbits + 52
+ var extra uint = tail - (uint(1) << nbits)
+ (*commands)[0] = uint32(code | extra<<8)
+ *commands = (*commands)[1:]
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ } else {
+ var extra uint = copylen - 2120
+ (*commands)[0] = uint32(63 | extra<<8)
+ *commands = (*commands)[1:]
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ }
+}
+
+func emitDistance(distance uint32, commands *[]uint32) {
+ var d uint32 = distance + 3
+ var nbits uint32 = log2FloorNonZero(uint(d)) - 1
+ var prefix uint32 = (d >> nbits) & 1
+ var offset uint32 = (2 + prefix) << nbits
+ var distcode uint32 = 2*(nbits-1) + prefix + 80
+ var extra uint32 = d - offset
+ (*commands)[0] = distcode | extra<<8
+ *commands = (*commands)[1:]
+}
+
+/* REQUIRES: len <= 1 << 24. */
+func storeMetaBlockHeader(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {
+ var nibbles uint = 6
+
+ /* ISLAST */
+ writeBits(1, 0, storage_ix, storage)
+
+ if len <= 1<<16 {
+ nibbles = 4
+ } else if len <= 1<<20 {
+ nibbles = 5
+ }
+
+ writeBits(2, uint64(nibbles)-4, storage_ix, storage)
+ writeBits(nibbles*4, uint64(len)-1, storage_ix, storage)
+
+ /* ISUNCOMPRESSED */
+ writeSingleBit(is_uncompressed, storage_ix, storage)
+}
+
+func createCommands(input []byte, block_size uint, input_size uint, base_ip_ptr []byte, table []int, table_bits uint, min_match uint, literals *[]byte, commands *[]uint32) {
+ var ip int = 0
+ var shift uint = 64 - table_bits
+ var ip_end int = int(block_size)
+ var base_ip int = -cap(base_ip_ptr) + cap(input)
+ var next_emit int = 0
+ var last_distance int = -1
+ /* "ip" is the input pointer. */
+
+ const kInputMarginBytes uint = windowGap
+
+ /* "next_emit" is a pointer to the first byte that is not covered by a
+ previous copy. Bytes between "next_emit" and the start of the next copy or
+ the end of the input will be emitted as literal bytes. */
+ if block_size >= kInputMarginBytes {
+ var len_limit uint = brotli_min_size_t(block_size-min_match, input_size-kInputMarginBytes)
+ var ip_limit int = int(len_limit)
+ /* For the last block, we need to keep a 16 bytes margin so that we can be
+ sure that all distances are at most window size - 16.
+ For all other blocks, we only need to keep a margin of 5 bytes so that
+ we don't go over the block size with a copy. */
+
+ var next_hash uint32
+ ip++
+ for next_hash = hash1(input[ip:], shift, min_match); ; {
+ var skip uint32 = 32
+ var next_ip int = ip
+ /* Step 1: Scan forward in the input looking for a 6-byte-long match.
+ If we get close to exhausting the input then goto emit_remainder.
+
+ Heuristic match skipping: If 32 bytes are scanned with no matches
+ found, start looking only at every other byte. If 32 more bytes are
+ scanned, look at every third byte, etc.. When a match is found,
+ immediately go back to looking at every byte. This is a small loss
+ (~5% performance, ~0.1% density) for compressible data due to more
+ bookkeeping, but for non-compressible data (such as JPEG) it's a huge
+ win since the compressor quickly "realizes" the data is incompressible
+ and doesn't bother looking for matches everywhere.
+
+ The "skip" variable keeps track of how many bytes there are since the
+ last match; dividing it by 32 (ie. right-shifting by five) gives the
+ number of bytes to move ahead for each iteration. */
+
+ var candidate int
+
+ assert(next_emit < ip)
+
+ trawl:
+ for {
+ var hash uint32 = next_hash
+ var bytes_between_hash_lookups uint32 = skip >> 5
+ skip++
+ ip = next_ip
+ assert(hash == hash1(input[ip:], shift, min_match))
+ next_ip = int(uint32(ip) + bytes_between_hash_lookups)
+ if next_ip > ip_limit {
+ goto emit_remainder
+ }
+
+ next_hash = hash1(input[next_ip:], shift, min_match)
+ candidate = ip - last_distance
+ if isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {
+ if candidate < ip {
+ table[hash] = int(ip - base_ip)
+ break
+ }
+ }
+
+ candidate = base_ip + table[hash]
+ assert(candidate >= base_ip)
+ assert(candidate < ip)
+
+ table[hash] = int(ip - base_ip)
+ if isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {
+ break
+ }
+ }
+
+ /* Check copy distance. If candidate is not feasible, continue search.
+ Checking is done outside of hot loop to reduce overhead. */
+ if ip-candidate > maxDistance_compress_fragment {
+ goto trawl
+ }
+
+ /* Step 2: Emit the found match together with the literal bytes from
+ "next_emit", and then see if we can find a next match immediately
+ afterwards. Repeat until we find no match for the input
+ without emitting some literal bytes. */
+ {
+ var base int = ip
+ /* > 0 */
+ var matched uint = min_match + findMatchLengthWithLimit(base_ip_ptr[uint(candidate-base_ip)+min_match:], input[uint(ip)+min_match:], uint(ip_end-ip)-min_match)
+ var distance int = int(base - candidate)
+ /* We have a 6-byte match at ip, and we need to emit bytes in
+ [next_emit, ip). */
+
+ var insert int = int(base - next_emit)
+ ip += int(matched)
+ emitInsertLen(uint32(insert), commands)
+ copy(*literals, input[next_emit:][:uint(insert)])
+ *literals = (*literals)[insert:]
+ if distance == last_distance {
+ (*commands)[0] = 64
+ *commands = (*commands)[1:]
+ } else {
+ emitDistance(uint32(distance), commands)
+ last_distance = distance
+ }
+
+ emitCopyLenLastDistance(matched, commands)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+ {
+ var input_bytes uint64
+ var cur_hash uint32
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some
+ positions within the last copy. */
+
+ var prev_hash uint32
+ if min_match == 4 {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-3:])
+ cur_hash = hashBytesAtOffset(input_bytes, 3, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ } else {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-5:])
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 5)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 4)
+ prev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ input_bytes = binary.LittleEndian.Uint64(input[ip-2:])
+ cur_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ }
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ for ip-candidate <= maxDistance_compress_fragment && isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {
+ var base int = ip
+ /* We have a 6-byte match at ip, and no need to emit any
+ literal bytes prior to ip. */
+
+ var matched uint = min_match + findMatchLengthWithLimit(base_ip_ptr[uint(candidate-base_ip)+min_match:], input[uint(ip)+min_match:], uint(ip_end-ip)-min_match)
+ ip += int(matched)
+ last_distance = int(base - candidate) /* > 0 */
+ emitCopyLen(matched, commands)
+ emitDistance(uint32(last_distance), commands)
+
+ next_emit = ip
+ if ip >= ip_limit {
+ goto emit_remainder
+ }
+ {
+ var input_bytes uint64
+ var cur_hash uint32
+ /* We could immediately start working at ip now, but to improve
+ compression we first update "table" with the hashes of some
+ positions within the last copy. */
+
+ var prev_hash uint32
+ if min_match == 4 {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-3:])
+ cur_hash = hashBytesAtOffset(input_bytes, 3, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ } else {
+ input_bytes = binary.LittleEndian.Uint64(input[ip-5:])
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 5)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 4)
+ prev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 3)
+ input_bytes = binary.LittleEndian.Uint64(input[ip-2:])
+ cur_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)
+ prev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 2)
+ prev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)
+ table[prev_hash] = int(ip - base_ip - 1)
+ }
+
+ candidate = base_ip + table[cur_hash]
+ table[cur_hash] = int(ip - base_ip)
+ }
+ }
+
+ ip++
+ next_hash = hash1(input[ip:], shift, min_match)
+ }
+ }
+
+emit_remainder:
+ assert(next_emit <= ip_end)
+
+ /* Emit the remaining bytes as literals. */
+ if next_emit < ip_end {
+ var insert uint32 = uint32(ip_end - next_emit)
+ emitInsertLen(insert, commands)
+ copy(*literals, input[next_emit:][:insert])
+ *literals = (*literals)[insert:]
+ }
+}
+
+var storeCommands_kNumExtraBits = [128]uint32{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 12,
+ 14,
+ 24,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 24,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 6,
+ 7,
+ 7,
+ 8,
+ 8,
+ 9,
+ 9,
+ 10,
+ 10,
+ 11,
+ 11,
+ 12,
+ 12,
+ 13,
+ 13,
+ 14,
+ 14,
+ 15,
+ 15,
+ 16,
+ 16,
+ 17,
+ 17,
+ 18,
+ 18,
+ 19,
+ 19,
+ 20,
+ 20,
+ 21,
+ 21,
+ 22,
+ 22,
+ 23,
+ 23,
+ 24,
+ 24,
+}
+var storeCommands_kInsertOffset = [24]uint32{
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 8,
+ 10,
+ 14,
+ 18,
+ 26,
+ 34,
+ 50,
+ 66,
+ 98,
+ 130,
+ 194,
+ 322,
+ 578,
+ 1090,
+ 2114,
+ 6210,
+ 22594,
+}
+
+func storeCommands(literals []byte, num_literals uint, commands []uint32, num_commands uint, storage_ix *uint, storage []byte) {
+ var lit_depths [256]byte
+ var lit_bits [256]uint16
+ var lit_histo = [256]uint32{0}
+ var cmd_depths = [128]byte{0}
+ var cmd_bits = [128]uint16{0}
+ var cmd_histo = [128]uint32{0}
+ var i uint
+ for i = 0; i < num_literals; i++ {
+ lit_histo[literals[i]]++
+ }
+
+ buildAndStoreHuffmanTreeFast(lit_histo[:], num_literals, /* max_bits = */
+ 8, lit_depths[:], lit_bits[:], storage_ix, storage)
+
+ for i = 0; i < num_commands; i++ {
+ var code uint32 = commands[i] & 0xFF
+ assert(code < 128)
+ cmd_histo[code]++
+ }
+
+ cmd_histo[1] += 1
+ cmd_histo[2] += 1
+ cmd_histo[64] += 1
+ cmd_histo[84] += 1
+ buildAndStoreCommandPrefixCode(cmd_histo[:], cmd_depths[:], cmd_bits[:], storage_ix, storage)
+
+ for i = 0; i < num_commands; i++ {
+ var cmd uint32 = commands[i]
+ var code uint32 = cmd & 0xFF
+ var extra uint32 = cmd >> 8
+ assert(code < 128)
+ writeBits(uint(cmd_depths[code]), uint64(cmd_bits[code]), storage_ix, storage)
+ writeBits(uint(storeCommands_kNumExtraBits[code]), uint64(extra), storage_ix, storage)
+ if code < 24 {
+ var insert uint32 = storeCommands_kInsertOffset[code] + extra
+ var j uint32
+ for j = 0; j < insert; j++ {
+ var lit byte = literals[0]
+ writeBits(uint(lit_depths[lit]), uint64(lit_bits[lit]), storage_ix, storage)
+ literals = literals[1:]
+ }
+ }
+ }
+}
+
+/* Acceptable loss for uncompressible speedup is 2% */
+const minRatio = 0.98
+
+const sampleRate = 43
+
+func shouldCompress(input []byte, input_size uint, num_literals uint) bool {
+ var corpus_size float64 = float64(input_size)
+ if float64(num_literals) < minRatio*corpus_size {
+ return true
+ } else {
+ var literal_histo = [256]uint32{0}
+ var max_total_bit_cost float64 = corpus_size * 8 * minRatio / sampleRate
+ var i uint
+ for i = 0; i < input_size; i += sampleRate {
+ literal_histo[input[i]]++
+ }
+
+ return bitsEntropy(literal_histo[:], 256) < max_total_bit_cost
+ }
+}
+
+func rewindBitPosition(new_storage_ix uint, storage_ix *uint, storage []byte) {
+ var bitpos uint = new_storage_ix & 7
+ var mask uint = (1 << bitpos) - 1
+ storage[new_storage_ix>>3] &= byte(mask)
+ *storage_ix = new_storage_ix
+}
+
+func emitUncompressedMetaBlock(input []byte, input_size uint, storage_ix *uint, storage []byte) {
+ storeMetaBlockHeader(input_size, true, storage_ix, storage)
+ *storage_ix = (*storage_ix + 7) &^ 7
+ copy(storage[*storage_ix>>3:], input[:input_size])
+ *storage_ix += input_size << 3
+ storage[*storage_ix>>3] = 0
+}
+
+func compressFragmentTwoPassImpl(input []byte, input_size uint, is_last bool, command_buf []uint32, literal_buf []byte, table []int, table_bits uint, min_match uint, storage_ix *uint, storage []byte) {
+ /* Save the start of the first block for position and distance computations.
+ */
+ var base_ip []byte = input
+
+ for input_size > 0 {
+ var block_size uint = brotli_min_size_t(input_size, kCompressFragmentTwoPassBlockSize)
+ var commands []uint32 = command_buf
+ var literals []byte = literal_buf
+ var num_literals uint
+ createCommands(input, block_size, input_size, base_ip, table, table_bits, min_match, &literals, &commands)
+ num_literals = uint(-cap(literals) + cap(literal_buf))
+ if shouldCompress(input, block_size, num_literals) {
+ var num_commands uint = uint(-cap(commands) + cap(command_buf))
+ storeMetaBlockHeader(block_size, false, storage_ix, storage)
+
+ /* No block splits, no contexts. */
+ writeBits(13, 0, storage_ix, storage)
+
+ storeCommands(literal_buf, num_literals, command_buf, num_commands, storage_ix, storage)
+ } else {
+ /* Since we did not find many backward references and the entropy of
+ the data is close to 8 bits, we can simply emit an uncompressed block.
+ This makes compression speed of uncompressible data about 3x faster. */
+ emitUncompressedMetaBlock(input, block_size, storage_ix, storage)
+ }
+
+ input = input[block_size:]
+ input_size -= block_size
+ }
+}
+
+/* Compresses "input" string to the "*storage" buffer as one or more complete
+ meta-blocks, and updates the "*storage_ix" bit position.
+
+ If "is_last" is 1, emits an additional empty last meta-block.
+
+ REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
+ REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
+ REQUIRES: "command_buf" and "literal_buf" point to at least
+ kCompressFragmentTwoPassBlockSize long arrays.
+ REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
+ REQUIRES: "table_size" is a power of two
+ OUTPUT: maximal copy distance <= |input_size|
+ OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
+func compressFragmentTwoPass(input []byte, input_size uint, is_last bool, command_buf []uint32, literal_buf []byte, table []int, table_size uint, storage_ix *uint, storage []byte) {
+ var initial_storage_ix uint = *storage_ix
+ var table_bits uint = uint(log2FloorNonZero(table_size))
+ var min_match uint
+ if table_bits <= 15 {
+ min_match = 4
+ } else {
+ min_match = 6
+ }
+ compressFragmentTwoPassImpl(input, input_size, is_last, command_buf, literal_buf, table, table_bits, min_match, storage_ix, storage)
+
+ /* If output is larger than single uncompressed block, rewrite it. */
+ if *storage_ix-initial_storage_ix > 31+(input_size<<3) {
+ rewindBitPosition(initial_storage_ix, storage_ix, storage)
+ emitUncompressedMetaBlock(input, input_size, storage_ix, storage)
+ }
+
+ if is_last {
+ writeBits(1, 1, storage_ix, storage) /* islast */
+ writeBits(1, 1, storage_ix, storage) /* isempty */
+ *storage_ix = (*storage_ix + 7) &^ 7
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/constants.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/constants.go
new file mode 100644
index 000000000000..a880dff789d0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/constants.go
@@ -0,0 +1,77 @@
+package brotli
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Specification: 7.3. Encoding of the context map */
+const contextMapMaxRle = 16
+
+/* Specification: 2. Compressed representation overview */
+const maxNumberOfBlockTypes = 256
+
+/* Specification: 3.3. Alphabet sizes: insert-and-copy length */
+const numLiteralSymbols = 256
+
+const numCommandSymbols = 704
+
+const numBlockLenSymbols = 26
+
+const maxContextMapSymbols = (maxNumberOfBlockTypes + contextMapMaxRle)
+
+const maxBlockTypeSymbols = (maxNumberOfBlockTypes + 2)
+
+/* Specification: 3.5. Complex prefix codes */
+const repeatPreviousCodeLength = 16
+
+const repeatZeroCodeLength = 17
+
+const codeLengthCodes = (repeatZeroCodeLength + 1)
+
+/* "code length of 8 is repeated" */
+const initialRepeatedCodeLength = 8
+
+/* "Large Window Brotli" */
+const largeMaxDistanceBits = 62
+
+const largeMinWbits = 10
+
+const largeMaxWbits = 30
+
+/* Specification: 4. Encoding of distances */
+const numDistanceShortCodes = 16
+
+const maxNpostfix = 3
+
+const maxNdirect = 120
+
+const maxDistanceBits = 24
+
+func distanceAlphabetSize(NPOSTFIX uint, NDIRECT uint, MAXNBITS uint) uint {
+ return numDistanceShortCodes + NDIRECT + uint(MAXNBITS<<(NPOSTFIX+1))
+}
+
+/* numDistanceSymbols == 1128 */
+const numDistanceSymbols = 1128
+
+const maxDistance = 0x3FFFFFC
+
+const maxAllowedDistance = 0x7FFFFFFC
+
+/* 7.1. Context modes and context ID lookup for literals */
+/* "context IDs for literals are in the range of 0..63" */
+const literalContextBits = 6
+
+/* 7.2. Context ID for distances */
+const distanceContextBits = 2
+
+/* 9.1. Format of the Stream Header */
+/* Number of slack bytes for window size. Don't confuse
+ with BROTLI_NUM_DISTANCE_SHORT_CODES. */
+const windowGap = 16
+
+func maxBackwardLimit(W uint) uint {
+ return (uint(1) << W) - windowGap
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/context.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/context.go
new file mode 100644
index 000000000000..884ff8a2d696
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/context.go
@@ -0,0 +1,2176 @@
+package brotli
+
+/* Lookup table to map the previous two bytes to a context id.
+
+There are four different context modeling modes defined here:
+ contextLSB6: context id is the least significant 6 bits of the last byte,
+ contextMSB6: context id is the most significant 6 bits of the last byte,
+ contextUTF8: second-order context model tuned for UTF8-encoded text,
+ contextSigned: second-order context model tuned for signed integers.
+
+If |p1| and |p2| are the previous two bytes, and |mode| is current context
+mode, we calculate the context as:
+
+ context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].
+
+For contextUTF8 mode, if the previous two bytes are ASCII characters
+(i.e. < 128), this will be equivalent to
+
+ context = 4 * context1(p1) + context2(p2),
+
+where context1 is based on the previous byte in the following way:
+
+ 0 : non-ASCII control
+ 1 : \t, \n, \r
+ 2 : space
+ 3 : other punctuation
+ 4 : " '
+ 5 : %
+ 6 : ( < [ {
+ 7 : ) > ] }
+ 8 : , ; :
+ 9 : .
+ 10 : =
+ 11 : number
+ 12 : upper-case vowel
+ 13 : upper-case consonant
+ 14 : lower-case vowel
+ 15 : lower-case consonant
+
+and context2 is based on the second last byte:
+
+ 0 : control, space
+ 1 : punctuation
+ 2 : upper-case letter, number
+ 3 : lower-case letter
+
+If the last byte is ASCII, and the second last byte is not (in a valid UTF8
+stream it will be a continuation byte, value between 128 and 191), the
+context is the same as if the second last byte was an ASCII control or space.
+
+If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
+be a continuation byte and the context id is 2 or 3 depending on the LSB of
+the last byte and to a lesser extent on the second last byte if it is ASCII.
+
+If the last byte is a UTF8 continuation byte, the second last byte can be:
+ - continuation byte: the next byte is probably ASCII or lead byte (assuming
+ 4-byte UTF8 characters are rare) and the context id is 0 or 1.
+ - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
+ - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
+
+The possible value combinations of the previous two bytes, the range of
+context ids and the type of the next byte is summarized in the table below:
+
+|--------\-----------------------------------------------------------------|
+| \ Last byte |
+| Second \---------------------------------------------------------------|
+| last byte \ ASCII | cont. byte | lead byte |
+| \ (0-127) | (128-191) | (192-) |
+|=============|===================|=====================|==================|
+| ASCII | next: ASCII/lead | not valid | next: cont. |
+| (0-127) | context: 4 - 63 | | context: 2 - 3 |
+|-------------|-------------------|---------------------|------------------|
+| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
+| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
+|-------------|-------------------|---------------------|------------------|
+| lead byte | not valid | next: ASCII/lead | not valid |
+| (192-207) | | context: 0 - 1 | |
+|-------------|-------------------|---------------------|------------------|
+| lead byte | not valid | next: cont. | not valid |
+| (208-) | | context: 2 - 3 | |
+|-------------|-------------------|---------------------|------------------|
+*/
+
+const (
+ contextLSB6 = 0
+ contextMSB6 = 1
+ contextUTF8 = 2
+ contextSigned = 3
+)
+
+/* Common context lookup table for all context modes. */
+var kContextLookup = [2048]byte{
+ /* CONTEXT_LSB6, last byte. */
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+
+ /* CONTEXT_LSB6, second last byte, */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ /* CONTEXT_MSB6, last byte. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 3,
+ 3,
+ 3,
+ 3,
+ 4,
+ 4,
+ 4,
+ 4,
+ 5,
+ 5,
+ 5,
+ 5,
+ 6,
+ 6,
+ 6,
+ 6,
+ 7,
+ 7,
+ 7,
+ 7,
+ 8,
+ 8,
+ 8,
+ 8,
+ 9,
+ 9,
+ 9,
+ 9,
+ 10,
+ 10,
+ 10,
+ 10,
+ 11,
+ 11,
+ 11,
+ 11,
+ 12,
+ 12,
+ 12,
+ 12,
+ 13,
+ 13,
+ 13,
+ 13,
+ 14,
+ 14,
+ 14,
+ 14,
+ 15,
+ 15,
+ 15,
+ 15,
+ 16,
+ 16,
+ 16,
+ 16,
+ 17,
+ 17,
+ 17,
+ 17,
+ 18,
+ 18,
+ 18,
+ 18,
+ 19,
+ 19,
+ 19,
+ 19,
+ 20,
+ 20,
+ 20,
+ 20,
+ 21,
+ 21,
+ 21,
+ 21,
+ 22,
+ 22,
+ 22,
+ 22,
+ 23,
+ 23,
+ 23,
+ 23,
+ 24,
+ 24,
+ 24,
+ 24,
+ 25,
+ 25,
+ 25,
+ 25,
+ 26,
+ 26,
+ 26,
+ 26,
+ 27,
+ 27,
+ 27,
+ 27,
+ 28,
+ 28,
+ 28,
+ 28,
+ 29,
+ 29,
+ 29,
+ 29,
+ 30,
+ 30,
+ 30,
+ 30,
+ 31,
+ 31,
+ 31,
+ 31,
+ 32,
+ 32,
+ 32,
+ 32,
+ 33,
+ 33,
+ 33,
+ 33,
+ 34,
+ 34,
+ 34,
+ 34,
+ 35,
+ 35,
+ 35,
+ 35,
+ 36,
+ 36,
+ 36,
+ 36,
+ 37,
+ 37,
+ 37,
+ 37,
+ 38,
+ 38,
+ 38,
+ 38,
+ 39,
+ 39,
+ 39,
+ 39,
+ 40,
+ 40,
+ 40,
+ 40,
+ 41,
+ 41,
+ 41,
+ 41,
+ 42,
+ 42,
+ 42,
+ 42,
+ 43,
+ 43,
+ 43,
+ 43,
+ 44,
+ 44,
+ 44,
+ 44,
+ 45,
+ 45,
+ 45,
+ 45,
+ 46,
+ 46,
+ 46,
+ 46,
+ 47,
+ 47,
+ 47,
+ 47,
+ 48,
+ 48,
+ 48,
+ 48,
+ 49,
+ 49,
+ 49,
+ 49,
+ 50,
+ 50,
+ 50,
+ 50,
+ 51,
+ 51,
+ 51,
+ 51,
+ 52,
+ 52,
+ 52,
+ 52,
+ 53,
+ 53,
+ 53,
+ 53,
+ 54,
+ 54,
+ 54,
+ 54,
+ 55,
+ 55,
+ 55,
+ 55,
+ 56,
+ 56,
+ 56,
+ 56,
+ 57,
+ 57,
+ 57,
+ 57,
+ 58,
+ 58,
+ 58,
+ 58,
+ 59,
+ 59,
+ 59,
+ 59,
+ 60,
+ 60,
+ 60,
+ 60,
+ 61,
+ 61,
+ 61,
+ 61,
+ 62,
+ 62,
+ 62,
+ 62,
+ 63,
+ 63,
+ 63,
+ 63,
+
+ /* CONTEXT_MSB6, second last byte, */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ /* CONTEXT_UTF8, last byte. */
+ /* ASCII range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4,
+ 4,
+ 0,
+ 0,
+ 4,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8,
+ 12,
+ 16,
+ 12,
+ 12,
+ 20,
+ 12,
+ 16,
+ 24,
+ 28,
+ 12,
+ 12,
+ 32,
+ 12,
+ 36,
+ 12,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 44,
+ 32,
+ 32,
+ 24,
+ 40,
+ 28,
+ 12,
+ 12,
+ 48,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 52,
+ 52,
+ 48,
+ 52,
+ 52,
+ 52,
+ 52,
+ 52,
+ 24,
+ 12,
+ 28,
+ 12,
+ 12,
+ 12,
+ 56,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 60,
+ 60,
+ 56,
+ 60,
+ 60,
+ 60,
+ 60,
+ 60,
+ 24,
+ 12,
+ 28,
+ 12,
+ 0,
+
+ /* UTF8 continuation byte range. */
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+
+ /* UTF8 lead byte range. */
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+ 2,
+ 3,
+
+ /* CONTEXT_UTF8 second last byte. */
+ /* ASCII range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+
+ /* UTF8 continuation byte range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ /* UTF8 lead byte range. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+
+ /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
+ 0,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 16,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 32,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 40,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 48,
+ 56,
+
+ /* CONTEXT_SIGNED, second last byte. */
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 5,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 7,
+}
+
+type contextLUT []byte
+
+func getContextLUT(mode int) contextLUT {
+ return kContextLookup[mode<<9:]
+}
+
+func getContext(p1 byte, p2 byte, lut contextLUT) byte {
+ return lut[p1] | lut[256+int(p2)]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/decode.go
new file mode 100644
index 000000000000..9d9513b7cfbc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/decode.go
@@ -0,0 +1,2581 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+const (
+ decoderResultError = 0
+ decoderResultSuccess = 1
+ decoderResultNeedsMoreInput = 2
+ decoderResultNeedsMoreOutput = 3
+)
+
+/**
+ * Error code for detailed logging / production debugging.
+ *
+ * See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE.
+ */
+const (
+ decoderNoError = 0
+ decoderSuccess = 1
+ decoderNeedsMoreInput = 2
+ decoderNeedsMoreOutput = 3
+ decoderErrorFormatExuberantNibble = -1
+ decoderErrorFormatReserved = -2
+ decoderErrorFormatExuberantMetaNibble = -3
+ decoderErrorFormatSimpleHuffmanAlphabet = -4
+ decoderErrorFormatSimpleHuffmanSame = -5
+ decoderErrorFormatClSpace = -6
+ decoderErrorFormatHuffmanSpace = -7
+ decoderErrorFormatContextMapRepeat = -8
+ decoderErrorFormatBlockLength1 = -9
+ decoderErrorFormatBlockLength2 = -10
+ decoderErrorFormatTransform = -11
+ decoderErrorFormatDictionary = -12
+ decoderErrorFormatWindowBits = -13
+ decoderErrorFormatPadding1 = -14
+ decoderErrorFormatPadding2 = -15
+ decoderErrorFormatDistance = -16
+ decoderErrorDictionaryNotSet = -19
+ decoderErrorInvalidArguments = -20
+ decoderErrorAllocContextModes = -21
+ decoderErrorAllocTreeGroups = -22
+ decoderErrorAllocContextMap = -25
+ decoderErrorAllocRingBuffer1 = -26
+ decoderErrorAllocRingBuffer2 = -27
+ decoderErrorAllocBlockTypeTrees = -30
+ decoderErrorUnreachable = -31
+)
+
+const huffmanTableBits = 8
+
+const huffmanTableMask = 0xFF
+
+/* We need the slack region for the following reasons:
+ - doing up to two 16-byte copies for fast backward copying
+ - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
+const kRingBufferWriteAheadSlack uint32 = 42
+
+var kCodeLengthCodeOrder = [codeLengthCodes]byte{1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+
+/* Static prefix code for the complex code length code lengths. */
+var kCodeLengthPrefixLength = [16]byte{2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4}
+
+var kCodeLengthPrefixValue = [16]byte{0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5}
+
+/* Saves error code and converts it to BrotliDecoderResult. */
+func saveErrorCode(s *Reader, e int) int {
+ s.error_code = int(e)
+ switch e {
+ case decoderSuccess:
+ return decoderResultSuccess
+
+ case decoderNeedsMoreInput:
+ return decoderResultNeedsMoreInput
+
+ case decoderNeedsMoreOutput:
+ return decoderResultNeedsMoreOutput
+
+ default:
+ return decoderResultError
+ }
+}
+
+/* Decodes WBITS by reading 1 - 7 bits, or 0x11 for "Large Window Brotli".
+ Precondition: bit-reader accumulator has at least 8 bits. */
+func decodeWindowBits(s *Reader, br *bitReader) int {
+ var n uint32
+ var large_window bool = s.large_window
+ s.large_window = false
+ takeBits(br, 1, &n)
+ if n == 0 {
+ s.window_bits = 16
+ return decoderSuccess
+ }
+
+ takeBits(br, 3, &n)
+ if n != 0 {
+ s.window_bits = 17 + n
+ return decoderSuccess
+ }
+
+ takeBits(br, 3, &n)
+ if n == 1 {
+ if large_window {
+ takeBits(br, 1, &n)
+ if n == 1 {
+ return decoderErrorFormatWindowBits
+ }
+
+ s.large_window = true
+ return decoderSuccess
+ } else {
+ return decoderErrorFormatWindowBits
+ }
+ }
+
+ if n != 0 {
+ s.window_bits = 8 + n
+ return decoderSuccess
+ }
+
+ s.window_bits = 17
+ return decoderSuccess
+}
+
+/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */
+func decodeVarLenUint8(s *Reader, br *bitReader, value *uint32) int {
+ var bits uint32
+ switch s.substate_decode_uint8 {
+ case stateDecodeUint8None:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits == 0 {
+ *value = 0
+ return decoderSuccess
+ }
+ fallthrough
+
+ /* Fall through. */
+ case stateDecodeUint8Short:
+ if !safeReadBits(br, 3, &bits) {
+ s.substate_decode_uint8 = stateDecodeUint8Short
+ return decoderNeedsMoreInput
+ }
+
+ if bits == 0 {
+ *value = 1
+ s.substate_decode_uint8 = stateDecodeUint8None
+ return decoderSuccess
+ }
+
+ /* Use output value as a temporary storage. It MUST be persisted. */
+ *value = bits
+ fallthrough
+
+ /* Fall through. */
+ case stateDecodeUint8Long:
+ if !safeReadBits(br, *value, &bits) {
+ s.substate_decode_uint8 = stateDecodeUint8Long
+ return decoderNeedsMoreInput
+ }
+
+ *value = (1 << *value) + bits
+ s.substate_decode_uint8 = stateDecodeUint8None
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+}
+
+/* Decodes a metablock length and flags by reading 2 - 31 bits. */
+func decodeMetaBlockLength(s *Reader, br *bitReader) int {
+ var bits uint32
+ var i int
+ for {
+ switch s.substate_metablock_header {
+ case stateMetablockHeaderNone:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ s.is_last_metablock = 1
+ } else {
+ s.is_last_metablock = 0
+ }
+ s.meta_block_remaining_len = 0
+ s.is_uncompressed = 0
+ s.is_metadata = 0
+ if s.is_last_metablock == 0 {
+ s.substate_metablock_header = stateMetablockHeaderNibbles
+ break
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderEmpty
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderEmpty:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderNibbles
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderNibbles:
+ if !safeReadBits(br, 2, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ s.size_nibbles = uint(byte(bits + 4))
+ s.loop_counter = 0
+ if bits == 3 {
+ s.is_metadata = 1
+ s.substate_metablock_header = stateMetablockHeaderReserved
+ break
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderSize
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderSize:
+ i = s.loop_counter
+
+ for ; i < int(s.size_nibbles); i++ {
+ if !safeReadBits(br, 4, &bits) {
+ s.loop_counter = i
+ return decoderNeedsMoreInput
+ }
+
+ if uint(i+1) == s.size_nibbles && s.size_nibbles > 4 && bits == 0 {
+ return decoderErrorFormatExuberantNibble
+ }
+
+ s.meta_block_remaining_len |= int(bits << uint(i*4))
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderUncompressed
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderUncompressed:
+ if s.is_last_metablock == 0 {
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ s.is_uncompressed = 1
+ } else {
+ s.is_uncompressed = 0
+ }
+ }
+
+ s.meta_block_remaining_len++
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+
+ case stateMetablockHeaderReserved:
+ if !safeReadBits(br, 1, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ return decoderErrorFormatReserved
+ }
+
+ s.substate_metablock_header = stateMetablockHeaderBytes
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderBytes:
+ if !safeReadBits(br, 2, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits == 0 {
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+ }
+
+ s.size_nibbles = uint(byte(bits))
+ s.substate_metablock_header = stateMetablockHeaderMetadata
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeaderMetadata:
+ i = s.loop_counter
+
+ for ; i < int(s.size_nibbles); i++ {
+ if !safeReadBits(br, 8, &bits) {
+ s.loop_counter = i
+ return decoderNeedsMoreInput
+ }
+
+ if uint(i+1) == s.size_nibbles && s.size_nibbles > 1 && bits == 0 {
+ return decoderErrorFormatExuberantMetaNibble
+ }
+
+ s.meta_block_remaining_len |= int(bits << uint(i*8))
+ }
+
+ s.meta_block_remaining_len++
+ s.substate_metablock_header = stateMetablockHeaderNone
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+ }
+}
+
+/* Decodes the Huffman code.
+ This method doesn't read data from the bit reader, BUT drops the amount of
+ bits that correspond to the decoded symbol.
+ bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */
+func decodeSymbol(bits uint32, table []huffmanCode, br *bitReader) uint32 {
+ table = table[bits&huffmanTableMask:]
+ if table[0].bits > huffmanTableBits {
+ var nbits uint32 = uint32(table[0].bits) - huffmanTableBits
+ dropBits(br, huffmanTableBits)
+ table = table[uint32(table[0].value)+((bits>>huffmanTableBits)&bitMask(nbits)):]
+ }
+
+ dropBits(br, uint32(table[0].bits))
+ return uint32(table[0].value)
+}
+
+/* Reads and decodes the next Huffman code from bit-stream.
+ This method peeks 16 bits of input and drops 0 - 15 of them. */
+func readSymbol(table []huffmanCode, br *bitReader) uint32 {
+ return decodeSymbol(get16BitsUnmasked(br), table, br)
+}
+
+/* Same as DecodeSymbol, but it is known that there is less than 15 bits of
+ input are currently available. */
+func safeDecodeSymbol(table []huffmanCode, br *bitReader, result *uint32) bool {
+ var val uint32
+ var available_bits uint32 = getAvailableBits(br)
+ if available_bits == 0 {
+ if table[0].bits == 0 {
+ *result = uint32(table[0].value)
+ return true
+ }
+
+ return false /* No valid bits at all. */
+ }
+
+ val = uint32(getBitsUnmasked(br))
+ table = table[val&huffmanTableMask:]
+ if table[0].bits <= huffmanTableBits {
+ if uint32(table[0].bits) <= available_bits {
+ dropBits(br, uint32(table[0].bits))
+ *result = uint32(table[0].value)
+ return true
+ } else {
+ return false /* Not enough bits for the first level. */
+ }
+ }
+
+ if available_bits <= huffmanTableBits {
+ return false /* Not enough bits to move to the second level. */
+ }
+
+ /* Speculatively drop HUFFMAN_TABLE_BITS. */
+ val = (val & bitMask(uint32(table[0].bits))) >> huffmanTableBits
+
+ available_bits -= huffmanTableBits
+ table = table[uint32(table[0].value)+val:]
+ if available_bits < uint32(table[0].bits) {
+ return false /* Not enough bits for the second level. */
+ }
+
+ dropBits(br, huffmanTableBits+uint32(table[0].bits))
+ *result = uint32(table[0].value)
+ return true
+}
+
+func safeReadSymbol(table []huffmanCode, br *bitReader, result *uint32) bool {
+ var val uint32
+ if safeGetBits(br, 15, &val) {
+ *result = decodeSymbol(val, table, br)
+ return true
+ }
+
+ return safeDecodeSymbol(table, br, result)
+}
+
+/* Makes a look-up in first level Huffman table. Peeks 8 bits. */
+func preloadSymbol(safe int, table []huffmanCode, br *bitReader, bits *uint32, value *uint32) {
+ if safe != 0 {
+ return
+ }
+
+ table = table[getBits(br, huffmanTableBits):]
+ *bits = uint32(table[0].bits)
+ *value = uint32(table[0].value)
+}
+
+/* Decodes the next Huffman code using data prepared by PreloadSymbol.
+ Reads 0 - 15 bits. Also peeks 8 following bits. */
+func readPreloadedSymbol(table []huffmanCode, br *bitReader, bits *uint32, value *uint32) uint32 {
+ var result uint32 = *value
+ var ext []huffmanCode
+ if *bits > huffmanTableBits {
+ var val uint32 = get16BitsUnmasked(br)
+ ext = table[val&huffmanTableMask:][*value:]
+ var mask uint32 = bitMask((*bits - huffmanTableBits))
+ dropBits(br, huffmanTableBits)
+ ext = ext[(val>>huffmanTableBits)&mask:]
+ dropBits(br, uint32(ext[0].bits))
+ result = uint32(ext[0].value)
+ } else {
+ dropBits(br, *bits)
+ }
+
+ preloadSymbol(0, table, br, bits, value)
+ return result
+}
+
+func log2Floor(x uint32) uint32 {
+ var result uint32 = 0
+ for x != 0 {
+ x >>= 1
+ result++
+ }
+
+ return result
+}
+
+/* Reads (s->symbol + 1) symbols.
+ Totally 1..4 symbols are read, 1..11 bits each.
+ The list of symbols MUST NOT contain duplicates. */
+func readSimpleHuffmanSymbols(alphabet_size uint32, max_symbol uint32, s *Reader) int {
+ var br *bitReader = &s.br
+ var max_bits uint32 = log2Floor(alphabet_size - 1)
+ var i uint32 = s.sub_loop_counter
+ /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
+
+ var num_symbols uint32 = s.symbol
+ for i <= num_symbols {
+ var v uint32
+ if !safeReadBits(br, max_bits, &v) {
+ s.sub_loop_counter = i
+ s.substate_huffman = stateHuffmanSimpleRead
+ return decoderNeedsMoreInput
+ }
+
+ if v >= max_symbol {
+ return decoderErrorFormatSimpleHuffmanAlphabet
+ }
+
+ s.symbols_lists_array[i] = uint16(v)
+ i++
+ }
+
+ for i = 0; i < num_symbols; i++ {
+ var k uint32 = i + 1
+ for ; k <= num_symbols; k++ {
+ if s.symbols_lists_array[i] == s.symbols_lists_array[k] {
+ return decoderErrorFormatSimpleHuffmanSame
+ }
+ }
+ }
+
+ return decoderSuccess
+}
+
+/* Process single decoded symbol code length:
+ A) reset the repeat variable
+ B) remember code length (if it is not 0)
+ C) extend corresponding index-chain
+ D) reduce the Huffman space
+ E) update the histogram */
+func processSingleCodeLength(code_len uint32, symbol *uint32, repeat *uint32, space *uint32, prev_code_len *uint32, symbol_lists symbolList, code_length_histo []uint16, next_symbol []int) {
+ *repeat = 0
+ if code_len != 0 { /* code_len == 1..15 */
+ symbolListPut(symbol_lists, next_symbol[code_len], uint16(*symbol))
+ next_symbol[code_len] = int(*symbol)
+ *prev_code_len = code_len
+ *space -= 32768 >> code_len
+ code_length_histo[code_len]++
+ }
+
+ (*symbol)++
+}
+
+/* Process repeated symbol code length.
+ A) Check if it is the extension of previous repeat sequence; if the decoded
+ value is not BROTLI_REPEAT_PREVIOUS_CODE_LENGTH, then it is a new
+ symbol-skip
+ B) Update repeat variable
+ C) Check if operation is feasible (fits alphabet)
+ D) For each symbol do the same operations as in ProcessSingleCodeLength
+
+ PRECONDITION: code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH or
+ code_len == BROTLI_REPEAT_ZERO_CODE_LENGTH */
+func processRepeatedCodeLength(code_len uint32, repeat_delta uint32, alphabet_size uint32, symbol *uint32, repeat *uint32, space *uint32, prev_code_len *uint32, repeat_code_len *uint32, symbol_lists symbolList, code_length_histo []uint16, next_symbol []int) {
+ var old_repeat uint32 /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */
+ var extra_bits uint32 = 3
+ var new_len uint32 = 0
+ if code_len == repeatPreviousCodeLength {
+ new_len = *prev_code_len
+ extra_bits = 2
+ }
+
+ if *repeat_code_len != new_len {
+ *repeat = 0
+ *repeat_code_len = new_len
+ }
+
+ old_repeat = *repeat
+ if *repeat > 0 {
+ *repeat -= 2
+ *repeat <<= extra_bits
+ }
+
+ *repeat += repeat_delta + 3
+ repeat_delta = *repeat - old_repeat
+ if *symbol+repeat_delta > alphabet_size {
+ *symbol = alphabet_size
+ *space = 0xFFFFF
+ return
+ }
+
+ if *repeat_code_len != 0 {
+ var last uint = uint(*symbol + repeat_delta)
+ var next int = next_symbol[*repeat_code_len]
+ for {
+ symbolListPut(symbol_lists, next, uint16(*symbol))
+ next = int(*symbol)
+ (*symbol)++
+ if (*symbol) == uint32(last) {
+ break
+ }
+ }
+
+ next_symbol[*repeat_code_len] = next
+ *space -= repeat_delta << (15 - *repeat_code_len)
+ code_length_histo[*repeat_code_len] = uint16(uint32(code_length_histo[*repeat_code_len]) + repeat_delta)
+ } else {
+ *symbol += repeat_delta
+ }
+}
+
+/* Reads and decodes symbol codelengths. */
+func readSymbolCodeLengths(alphabet_size uint32, s *Reader) int {
+ var br *bitReader = &s.br
+ var symbol uint32 = s.symbol
+ var repeat uint32 = s.repeat
+ var space uint32 = s.space
+ var prev_code_len uint32 = s.prev_code_len
+ var repeat_code_len uint32 = s.repeat_code_len
+ var symbol_lists symbolList = s.symbol_lists
+ var code_length_histo []uint16 = s.code_length_histo[:]
+ var next_symbol []int = s.next_symbol[:]
+ if !warmupBitReader(br) {
+ return decoderNeedsMoreInput
+ }
+ var p []huffmanCode
+ for symbol < alphabet_size && space > 0 {
+ p = s.table[:]
+ var code_len uint32
+ if !checkInputAmount(br, shortFillBitWindowRead) {
+ s.symbol = symbol
+ s.repeat = repeat
+ s.prev_code_len = prev_code_len
+ s.repeat_code_len = repeat_code_len
+ s.space = space
+ return decoderNeedsMoreInput
+ }
+
+ fillBitWindow16(br)
+ p = p[getBitsUnmasked(br)&uint64(bitMask(huffmanMaxCodeLengthCodeLength)):]
+ dropBits(br, uint32(p[0].bits)) /* Use 1..5 bits. */
+ code_len = uint32(p[0].value) /* code_len == 0..17 */
+ if code_len < repeatPreviousCodeLength {
+ processSingleCodeLength(code_len, &symbol, &repeat, &space, &prev_code_len, symbol_lists, code_length_histo, next_symbol) /* code_len == 16..17, extra_bits == 2..3 */
+ } else {
+ var extra_bits uint32
+ if code_len == repeatPreviousCodeLength {
+ extra_bits = 2
+ } else {
+ extra_bits = 3
+ }
+ var repeat_delta uint32 = uint32(getBitsUnmasked(br)) & bitMask(extra_bits)
+ dropBits(br, extra_bits)
+ processRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &symbol, &repeat, &space, &prev_code_len, &repeat_code_len, symbol_lists, code_length_histo, next_symbol)
+ }
+ }
+
+ s.space = space
+ return decoderSuccess
+}
+
+func safeReadSymbolCodeLengths(alphabet_size uint32, s *Reader) int {
+ var br *bitReader = &s.br
+ var get_byte bool = false
+ var p []huffmanCode
+ for s.symbol < alphabet_size && s.space > 0 {
+ p = s.table[:]
+ var code_len uint32
+ var available_bits uint32
+ var bits uint32 = 0
+ if get_byte && !pullByte(br) {
+ return decoderNeedsMoreInput
+ }
+ get_byte = false
+ available_bits = getAvailableBits(br)
+ if available_bits != 0 {
+ bits = uint32(getBitsUnmasked(br))
+ }
+
+ p = p[bits&bitMask(huffmanMaxCodeLengthCodeLength):]
+ if uint32(p[0].bits) > available_bits {
+ get_byte = true
+ continue
+ }
+
+ code_len = uint32(p[0].value) /* code_len == 0..17 */
+ if code_len < repeatPreviousCodeLength {
+ dropBits(br, uint32(p[0].bits))
+ processSingleCodeLength(code_len, &s.symbol, &s.repeat, &s.space, &s.prev_code_len, s.symbol_lists, s.code_length_histo[:], s.next_symbol[:]) /* code_len == 16..17, extra_bits == 2..3 */
+ } else {
+ var extra_bits uint32 = code_len - 14
+ var repeat_delta uint32 = (bits >> p[0].bits) & bitMask(extra_bits)
+ if available_bits < uint32(p[0].bits)+extra_bits {
+ get_byte = true
+ continue
+ }
+
+ dropBits(br, uint32(p[0].bits)+extra_bits)
+ processRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &s.symbol, &s.repeat, &s.space, &s.prev_code_len, &s.repeat_code_len, s.symbol_lists, s.code_length_histo[:], s.next_symbol[:])
+ }
+ }
+
+ return decoderSuccess
+}
+
+/* Reads and decodes 15..18 codes using static prefix code.
+ Each code is 2..4 bits long. In total 30..72 bits are used. */
+func readCodeLengthCodeLengths(s *Reader) int {
+ var br *bitReader = &s.br
+ var num_codes uint32 = s.repeat
+ var space uint32 = s.space
+ var i uint32 = s.sub_loop_counter
+ for ; i < codeLengthCodes; i++ {
+ var code_len_idx byte = kCodeLengthCodeOrder[i]
+ var ix uint32
+ var v uint32
+ if !safeGetBits(br, 4, &ix) {
+ var available_bits uint32 = getAvailableBits(br)
+ if available_bits != 0 {
+ ix = uint32(getBitsUnmasked(br) & 0xF)
+ } else {
+ ix = 0
+ }
+
+ if uint32(kCodeLengthPrefixLength[ix]) > available_bits {
+ s.sub_loop_counter = i
+ s.repeat = num_codes
+ s.space = space
+ s.substate_huffman = stateHuffmanComplex
+ return decoderNeedsMoreInput
+ }
+ }
+
+ v = uint32(kCodeLengthPrefixValue[ix])
+ dropBits(br, uint32(kCodeLengthPrefixLength[ix]))
+ s.code_length_code_lengths[code_len_idx] = byte(v)
+ if v != 0 {
+ space = space - (32 >> v)
+ num_codes++
+ s.code_length_histo[v]++
+ if space-1 >= 32 {
+ /* space is 0 or wrapped around. */
+ break
+ }
+ }
+ }
+
+ if num_codes != 1 && space != 0 {
+ return decoderErrorFormatClSpace
+ }
+
+ return decoderSuccess
+}
+
+/* Decodes the Huffman tables.
+ There are 2 scenarios:
+ A) Huffman code contains only few symbols (1..4). Those symbols are read
+ directly; their code lengths are defined by the number of symbols.
+ For this scenario 4 - 49 bits will be read.
+
+ B) 2-phase decoding:
+ B.1) Small Huffman table is decoded; it is specified with code lengths
+ encoded with predefined entropy code. 32 - 74 bits are used.
+ B.2) Decoded table is used to decode code lengths of symbols in resulting
+ Huffman table. In worst case 3520 bits are read. */
+func readHuffmanCode(alphabet_size uint32, max_symbol uint32, table []huffmanCode, opt_table_size *uint32, s *Reader) int {
+ var br *bitReader = &s.br
+
+ /* Unnecessary masking, but might be good for safety. */
+ alphabet_size &= 0x7FF
+
+ /* State machine. */
+ for {
+ switch s.substate_huffman {
+ case stateHuffmanNone:
+ if !safeReadBits(br, 2, &s.sub_loop_counter) {
+ return decoderNeedsMoreInput
+ }
+
+ /* The value is used as follows:
+ 1 for simple code;
+ 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
+ if s.sub_loop_counter != 1 {
+ s.space = 32
+ s.repeat = 0 /* num_codes */
+ var i int
+ for i = 0; i <= huffmanMaxCodeLengthCodeLength; i++ {
+ s.code_length_histo[i] = 0
+ }
+
+ for i = 0; i < codeLengthCodes; i++ {
+ s.code_length_code_lengths[i] = 0
+ }
+
+ s.substate_huffman = stateHuffmanComplex
+ continue
+ }
+ fallthrough
+
+ /* Read symbols, codes & code lengths directly. */
+ case stateHuffmanSimpleSize:
+ if !safeReadBits(br, 2, &s.symbol) { /* num_symbols */
+ s.substate_huffman = stateHuffmanSimpleSize
+ return decoderNeedsMoreInput
+ }
+
+ s.sub_loop_counter = 0
+ fallthrough
+
+ case stateHuffmanSimpleRead:
+ {
+ var result int = readSimpleHuffmanSymbols(alphabet_size, max_symbol, s)
+ if result != decoderSuccess {
+ return result
+ }
+ }
+ fallthrough
+
+ case stateHuffmanSimpleBuild:
+ var table_size uint32
+ if s.symbol == 3 {
+ var bits uint32
+ if !safeReadBits(br, 1, &bits) {
+ s.substate_huffman = stateHuffmanSimpleBuild
+ return decoderNeedsMoreInput
+ }
+
+ s.symbol += bits
+ }
+
+ table_size = buildSimpleHuffmanTable(table, huffmanTableBits, s.symbols_lists_array[:], s.symbol)
+ if opt_table_size != nil {
+ *opt_table_size = table_size
+ }
+
+ s.substate_huffman = stateHuffmanNone
+ return decoderSuccess
+
+ /* Decode Huffman-coded code lengths. */
+ case stateHuffmanComplex:
+ {
+ var i uint32
+ var result int = readCodeLengthCodeLengths(s)
+ if result != decoderSuccess {
+ return result
+ }
+
+ buildCodeLengthsHuffmanTable(s.table[:], s.code_length_code_lengths[:], s.code_length_histo[:])
+ for i = 0; i < 16; i++ {
+ s.code_length_histo[i] = 0
+ }
+
+ for i = 0; i <= huffmanMaxCodeLength; i++ {
+ s.next_symbol[i] = int(i) - (huffmanMaxCodeLength + 1)
+ symbolListPut(s.symbol_lists, s.next_symbol[i], 0xFFFF)
+ }
+
+ s.symbol = 0
+ s.prev_code_len = initialRepeatedCodeLength
+ s.repeat = 0
+ s.repeat_code_len = 0
+ s.space = 32768
+ s.substate_huffman = stateHuffmanLengthSymbols
+ }
+ fallthrough
+
+ case stateHuffmanLengthSymbols:
+ var table_size uint32
+ var result int = readSymbolCodeLengths(max_symbol, s)
+ if result == decoderNeedsMoreInput {
+ result = safeReadSymbolCodeLengths(max_symbol, s)
+ }
+
+ if result != decoderSuccess {
+ return result
+ }
+
+ if s.space != 0 {
+ return decoderErrorFormatHuffmanSpace
+ }
+
+ table_size = buildHuffmanTable(table, huffmanTableBits, s.symbol_lists, s.code_length_histo[:])
+ if opt_table_size != nil {
+ *opt_table_size = table_size
+ }
+
+ s.substate_huffman = stateHuffmanNone
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+ }
+}
+
+/* Decodes a block length by reading 3..39 bits. */
+func readBlockLength(table []huffmanCode, br *bitReader) uint32 {
+ var code uint32
+ var nbits uint32
+ code = readSymbol(table, br)
+ nbits = kBlockLengthPrefixCode[code].nbits /* nbits == 2..24 */
+ return kBlockLengthPrefixCode[code].offset + readBits(br, nbits)
+}
+
+/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
+ reading can't be continued with ReadBlockLength. */
+func safeReadBlockLength(s *Reader, result *uint32, table []huffmanCode, br *bitReader) bool {
+ var index uint32
+ if s.substate_read_block_length == stateReadBlockLengthNone {
+ if !safeReadSymbol(table, br, &index) {
+ return false
+ }
+ } else {
+ index = s.block_length_index
+ }
+ {
+ var bits uint32 /* nbits == 2..24 */
+ var nbits uint32 = kBlockLengthPrefixCode[index].nbits
+ if !safeReadBits(br, nbits, &bits) {
+ s.block_length_index = index
+ s.substate_read_block_length = stateReadBlockLengthSuffix
+ return false
+ }
+
+ *result = kBlockLengthPrefixCode[index].offset + bits
+ s.substate_read_block_length = stateReadBlockLengthNone
+ return true
+ }
+}
+
+/* Transform:
+ 1) initialize list L with values 0, 1,... 255
+ 2) For each input element X:
+ 2.1) let Y = L[X]
+ 2.2) remove X-th element from L
+ 2.3) prepend Y to L
+ 2.4) append Y to output
+
+ In most cases max(Y) <= 7, so most of L remains intact.
+ To reduce the cost of initialization, we reuse L, remember the upper bound
+ of Y values, and reinitialize only first elements in L.
+
+ Most of input values are 0 and 1. To reduce number of branches, we replace
+ inner for loop with do-while. */
+func inverseMoveToFrontTransform(v []byte, v_len uint32, state *Reader) {
+ var mtf [256]byte
+ var i int
+ for i = 1; i < 256; i++ {
+ mtf[i] = byte(i)
+ }
+ var mtf_1 byte
+
+ /* Transform the input. */
+ for i = 0; uint32(i) < v_len; i++ {
+ var index int = int(v[i])
+ var value byte = mtf[index]
+ v[i] = value
+ mtf_1 = value
+ for index >= 1 {
+ index--
+ mtf[index+1] = mtf[index]
+ }
+
+ mtf[0] = mtf_1
+ }
+}
+
+/* Decodes a series of Huffman table using ReadHuffmanCode function. */
+func huffmanTreeGroupDecode(group *huffmanTreeGroup, s *Reader) int {
+ if s.substate_tree_group != stateTreeGroupLoop {
+ s.next = group.codes
+ s.htree_index = 0
+ s.substate_tree_group = stateTreeGroupLoop
+ }
+
+ for s.htree_index < int(group.num_htrees) {
+ var table_size uint32
+ var result int = readHuffmanCode(uint32(group.alphabet_size), uint32(group.max_symbol), s.next, &table_size, s)
+ if result != decoderSuccess {
+ return result
+ }
+ group.htrees[s.htree_index] = s.next
+ s.next = s.next[table_size:]
+ s.htree_index++
+ }
+
+ s.substate_tree_group = stateTreeGroupNone
+ return decoderSuccess
+}
+
+/* Decodes a context map.
+ Decoding is done in 4 phases:
+ 1) Read auxiliary information (6..16 bits) and allocate memory.
+ In case of trivial context map, decoding is finished at this phase.
+ 2) Decode Huffman table using ReadHuffmanCode function.
+ This table will be used for reading context map items.
+ 3) Read context map items; "0" values could be run-length encoded.
+ 4) Optionally, apply InverseMoveToFront transform to the resulting map. */
+func decodeContextMap(context_map_size uint32, num_htrees *uint32, context_map_arg *[]byte, s *Reader) int {
+ var br *bitReader = &s.br
+ var result int = decoderSuccess
+
+ switch int(s.substate_context_map) {
+ case stateContextMapNone:
+ result = decodeVarLenUint8(s, br, num_htrees)
+ if result != decoderSuccess {
+ return result
+ }
+
+ (*num_htrees)++
+ s.context_index = 0
+ *context_map_arg = make([]byte, uint(context_map_size))
+ if *context_map_arg == nil {
+ return decoderErrorAllocContextMap
+ }
+
+ if *num_htrees <= 1 {
+ for i := 0; i < int(context_map_size); i++ {
+ (*context_map_arg)[i] = 0
+ }
+ return decoderSuccess
+ }
+
+ s.substate_context_map = stateContextMapReadPrefix
+ fallthrough
+ /* Fall through. */
+ case stateContextMapReadPrefix:
+ {
+ var bits uint32
+
+ /* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe
+ to peek 4 bits ahead. */
+ if !safeGetBits(br, 5, &bits) {
+ return decoderNeedsMoreInput
+ }
+
+ if bits&1 != 0 { /* Use RLE for zeros. */
+ s.max_run_length_prefix = (bits >> 1) + 1
+ dropBits(br, 5)
+ } else {
+ s.max_run_length_prefix = 0
+ dropBits(br, 1)
+ }
+
+ s.substate_context_map = stateContextMapHuffman
+ }
+ fallthrough
+
+ /* Fall through. */
+ case stateContextMapHuffman:
+ {
+ var alphabet_size uint32 = *num_htrees + s.max_run_length_prefix
+ result = readHuffmanCode(alphabet_size, alphabet_size, s.context_map_table[:], nil, s)
+ if result != decoderSuccess {
+ return result
+ }
+ s.code = 0xFFFF
+ s.substate_context_map = stateContextMapDecode
+ }
+ fallthrough
+
+ /* Fall through. */
+ case stateContextMapDecode:
+ {
+ var context_index uint32 = s.context_index
+ var max_run_length_prefix uint32 = s.max_run_length_prefix
+ var context_map []byte = *context_map_arg
+ var code uint32 = s.code
+ var skip_preamble bool = (code != 0xFFFF)
+ for context_index < context_map_size || skip_preamble {
+ if !skip_preamble {
+ if !safeReadSymbol(s.context_map_table[:], br, &code) {
+ s.code = 0xFFFF
+ s.context_index = context_index
+ return decoderNeedsMoreInput
+ }
+
+ if code == 0 {
+ context_map[context_index] = 0
+ context_index++
+ continue
+ }
+
+ if code > max_run_length_prefix {
+ context_map[context_index] = byte(code - max_run_length_prefix)
+ context_index++
+ continue
+ }
+ } else {
+ skip_preamble = false
+ }
+
+ /* RLE sub-stage. */
+ {
+ var reps uint32
+ if !safeReadBits(br, code, &reps) {
+ s.code = code
+ s.context_index = context_index
+ return decoderNeedsMoreInput
+ }
+
+ reps += 1 << code
+ if context_index+reps > context_map_size {
+ return decoderErrorFormatContextMapRepeat
+ }
+
+ for {
+ context_map[context_index] = 0
+ context_index++
+ reps--
+ if reps == 0 {
+ break
+ }
+ }
+ }
+ }
+ }
+ fallthrough
+
+ case stateContextMapTransform:
+ var bits uint32
+ if !safeReadBits(br, 1, &bits) {
+ s.substate_context_map = stateContextMapTransform
+ return decoderNeedsMoreInput
+ }
+
+ if bits != 0 {
+ inverseMoveToFrontTransform(*context_map_arg, context_map_size, s)
+ }
+
+ s.substate_context_map = stateContextMapNone
+ return decoderSuccess
+
+ default:
+ return decoderErrorUnreachable
+ }
+}
+
+/* Decodes a command or literal and updates block type ring-buffer.
+ Reads 3..54 bits. */
+func decodeBlockTypeAndLength(safe int, s *Reader, tree_type int) bool {
+ var max_block_type uint32 = s.num_block_types[tree_type]
+ type_tree := s.block_type_trees[tree_type*huffmanMaxSize258:]
+ len_tree := s.block_len_trees[tree_type*huffmanMaxSize26:]
+ var br *bitReader = &s.br
+ var ringbuffer []uint32 = s.block_type_rb[tree_type*2:]
+ var block_type uint32
+ if max_block_type <= 1 {
+ return false
+ }
+
+ /* Read 0..15 + 3..39 bits. */
+ if safe == 0 {
+ block_type = readSymbol(type_tree, br)
+ s.block_length[tree_type] = readBlockLength(len_tree, br)
+ } else {
+ var memento bitReaderState
+ bitReaderSaveState(br, &memento)
+ if !safeReadSymbol(type_tree, br, &block_type) {
+ return false
+ }
+ if !safeReadBlockLength(s, &s.block_length[tree_type], len_tree, br) {
+ s.substate_read_block_length = stateReadBlockLengthNone
+ bitReaderRestoreState(br, &memento)
+ return false
+ }
+ }
+
+ if block_type == 1 {
+ block_type = ringbuffer[1] + 1
+ } else if block_type == 0 {
+ block_type = ringbuffer[0]
+ } else {
+ block_type -= 2
+ }
+
+ if block_type >= max_block_type {
+ block_type -= max_block_type
+ }
+
+ ringbuffer[0] = ringbuffer[1]
+ ringbuffer[1] = block_type
+ return true
+}
+
+func detectTrivialLiteralBlockTypes(s *Reader) {
+ var i uint
+ for i = 0; i < 8; i++ {
+ s.trivial_literal_contexts[i] = 0
+ }
+ for i = 0; uint32(i) < s.num_block_types[0]; i++ {
+ var offset uint = i << literalContextBits
+ var error uint = 0
+ var sample uint = uint(s.context_map[offset])
+ var j uint
+ for j = 0; j < 1<>5] |= 1 << (i & 31)
+ }
+ }
+}
+
+func prepareLiteralDecoding(s *Reader) {
+ var context_mode byte
+ var trivial uint
+ var block_type uint32 = s.block_type_rb[1]
+ var context_offset uint32 = block_type << literalContextBits
+ s.context_map_slice = s.context_map[context_offset:]
+ trivial = uint(s.trivial_literal_contexts[block_type>>5])
+ s.trivial_literal_context = int((trivial >> (block_type & 31)) & 1)
+ s.literal_htree = []huffmanCode(s.literal_hgroup.htrees[s.context_map_slice[0]])
+ context_mode = s.context_modes[block_type] & 3
+ s.context_lookup = getContextLUT(int(context_mode))
+}
+
+/* Decodes the block type and updates the state for literal context.
+ Reads 3..54 bits. */
+func decodeLiteralBlockSwitchInternal(safe int, s *Reader) bool {
+ if !decodeBlockTypeAndLength(safe, s, 0) {
+ return false
+ }
+
+ prepareLiteralDecoding(s)
+ return true
+}
+
+func decodeLiteralBlockSwitch(s *Reader) {
+ decodeLiteralBlockSwitchInternal(0, s)
+}
+
+func safeDecodeLiteralBlockSwitch(s *Reader) bool {
+ return decodeLiteralBlockSwitchInternal(1, s)
+}
+
+/* Block switch for insert/copy length.
+ Reads 3..54 bits. */
+func decodeCommandBlockSwitchInternal(safe int, s *Reader) bool {
+ if !decodeBlockTypeAndLength(safe, s, 1) {
+ return false
+ }
+
+ s.htree_command = []huffmanCode(s.insert_copy_hgroup.htrees[s.block_type_rb[3]])
+ return true
+}
+
+func decodeCommandBlockSwitch(s *Reader) {
+ decodeCommandBlockSwitchInternal(0, s)
+}
+
+func safeDecodeCommandBlockSwitch(s *Reader) bool {
+ return decodeCommandBlockSwitchInternal(1, s)
+}
+
+/* Block switch for distance codes.
+ Reads 3..54 bits. */
+func decodeDistanceBlockSwitchInternal(safe int, s *Reader) bool {
+ if !decodeBlockTypeAndLength(safe, s, 2) {
+ return false
+ }
+
+ s.dist_context_map_slice = s.dist_context_map[s.block_type_rb[5]< s.ringbuffer_size {
+ pos = uint(s.ringbuffer_size)
+ } else {
+ pos = uint(s.pos)
+ }
+ var partial_pos_rb uint = (s.rb_roundtrips * uint(s.ringbuffer_size)) + pos
+ return partial_pos_rb - s.partial_pos_out
+}
+
+/* Dumps output.
+ Returns BROTLI_DECODER_NEEDS_MORE_OUTPUT only if there is more output to push
+ and either ring-buffer is as big as window size, or |force| is true. */
+func writeRingBuffer(s *Reader, available_out *uint, next_out *[]byte, total_out *uint, force bool) int {
+ start := s.ringbuffer[s.partial_pos_out&uint(s.ringbuffer_mask):]
+ var to_write uint = unwrittenBytes(s, true)
+ var num_written uint = *available_out
+ if num_written > to_write {
+ num_written = to_write
+ }
+
+ if s.meta_block_remaining_len < 0 {
+ return decoderErrorFormatBlockLength1
+ }
+
+ if next_out != nil && *next_out == nil {
+ *next_out = start
+ } else {
+ if next_out != nil {
+ copy(*next_out, start[:num_written])
+ *next_out = (*next_out)[num_written:]
+ }
+ }
+
+ *available_out -= num_written
+ s.partial_pos_out += num_written
+ if total_out != nil {
+ *total_out = s.partial_pos_out
+ }
+
+ if num_written < to_write {
+ if s.ringbuffer_size == 1<= s.ringbuffer_size {
+ s.pos -= s.ringbuffer_size
+ s.rb_roundtrips++
+ if uint(s.pos) != 0 {
+ s.should_wrap_ringbuffer = 1
+ } else {
+ s.should_wrap_ringbuffer = 0
+ }
+ }
+
+ return decoderSuccess
+}
+
+func wrapRingBuffer(s *Reader) {
+ if s.should_wrap_ringbuffer != 0 {
+ copy(s.ringbuffer, s.ringbuffer_end[:uint(s.pos)])
+ s.should_wrap_ringbuffer = 0
+ }
+}
+
+/* Allocates ring-buffer.
+
+ s->ringbuffer_size MUST be updated by BrotliCalculateRingBufferSize before
+ this function is called.
+
+ Last two bytes of ring-buffer are initialized to 0, so context calculation
+ could be done uniformly for the first two and all other positions. */
+func ensureRingBuffer(s *Reader) bool {
+ var old_ringbuffer []byte
+ if s.ringbuffer_size == s.new_ringbuffer_size {
+ return true
+ }
+ spaceNeeded := int(s.new_ringbuffer_size) + int(kRingBufferWriteAheadSlack)
+ if len(s.ringbuffer) < spaceNeeded {
+ old_ringbuffer = s.ringbuffer
+ s.ringbuffer = make([]byte, spaceNeeded)
+ }
+
+ s.ringbuffer[s.new_ringbuffer_size-2] = 0
+ s.ringbuffer[s.new_ringbuffer_size-1] = 0
+
+ if old_ringbuffer != nil {
+ copy(s.ringbuffer, old_ringbuffer[:uint(s.pos)])
+ }
+
+ s.ringbuffer_size = s.new_ringbuffer_size
+ s.ringbuffer_mask = s.new_ringbuffer_size - 1
+ s.ringbuffer_end = s.ringbuffer[s.ringbuffer_size:]
+
+ return true
+}
+
+func copyUncompressedBlockToOutput(available_out *uint, next_out *[]byte, total_out *uint, s *Reader) int {
+ /* TODO: avoid allocation for single uncompressed block. */
+ if !ensureRingBuffer(s) {
+ return decoderErrorAllocRingBuffer1
+ }
+
+ /* State machine */
+ for {
+ switch s.substate_uncompressed {
+ case stateUncompressedNone:
+ {
+ var nbytes int = int(getRemainingBytes(&s.br))
+ if nbytes > s.meta_block_remaining_len {
+ nbytes = s.meta_block_remaining_len
+ }
+
+ if s.pos+nbytes > s.ringbuffer_size {
+ nbytes = s.ringbuffer_size - s.pos
+ }
+
+ /* Copy remaining bytes from s->br.buf_ to ring-buffer. */
+ copyBytes(s.ringbuffer[s.pos:], &s.br, uint(nbytes))
+
+ s.pos += nbytes
+ s.meta_block_remaining_len -= nbytes
+ if s.pos < 1<>1 >= min_size {
+ new_ringbuffer_size >>= 1
+ }
+ }
+
+ s.new_ringbuffer_size = new_ringbuffer_size
+}
+
+/* Reads 1..256 2-bit context modes. */
+func readContextModes(s *Reader) int {
+ var br *bitReader = &s.br
+ var i int = s.loop_counter
+
+ for i < int(s.num_block_types[0]) {
+ var bits uint32
+ if !safeReadBits(br, 2, &bits) {
+ s.loop_counter = i
+ return decoderNeedsMoreInput
+ }
+
+ s.context_modes[i] = byte(bits)
+ i++
+ }
+
+ return decoderSuccess
+}
+
+func takeDistanceFromRingBuffer(s *Reader) {
+ if s.distance_code == 0 {
+ s.dist_rb_idx--
+ s.distance_code = s.dist_rb[s.dist_rb_idx&3]
+
+ /* Compensate double distance-ring-buffer roll for dictionary items. */
+ s.distance_context = 1
+ } else {
+ var distance_code int = s.distance_code << 1
+ const kDistanceShortCodeIndexOffset uint32 = 0xAAAFFF1B
+ const kDistanceShortCodeValueOffset uint32 = 0xFA5FA500
+ var v int = (s.dist_rb_idx + int(kDistanceShortCodeIndexOffset>>uint(distance_code))) & 0x3
+ /* kDistanceShortCodeIndexOffset has 2-bit values from LSB:
+ 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
+
+ /* kDistanceShortCodeValueOffset has 2-bit values from LSB:
+ -0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
+ s.distance_code = s.dist_rb[v]
+
+ v = int(kDistanceShortCodeValueOffset>>uint(distance_code)) & 0x3
+ if distance_code&0x3 != 0 {
+ s.distance_code += v
+ } else {
+ s.distance_code -= v
+ if s.distance_code <= 0 {
+ /* A huge distance will cause a () soon.
+ This is a little faster than failing here. */
+ s.distance_code = 0x7FFFFFFF
+ }
+ }
+ }
+}
+
+func safeReadBitsMaybeZero(br *bitReader, n_bits uint32, val *uint32) bool {
+ if n_bits != 0 {
+ return safeReadBits(br, n_bits, val)
+ } else {
+ *val = 0
+ return true
+ }
+}
+
+/* Precondition: s->distance_code < 0. */
+func readDistanceInternal(safe int, s *Reader, br *bitReader) bool {
+ var distval int
+ var memento bitReaderState
+ var distance_tree []huffmanCode = []huffmanCode(s.distance_hgroup.htrees[s.dist_htree_index])
+ if safe == 0 {
+ s.distance_code = int(readSymbol(distance_tree, br))
+ } else {
+ var code uint32
+ bitReaderSaveState(br, &memento)
+ if !safeReadSymbol(distance_tree, br, &code) {
+ return false
+ }
+
+ s.distance_code = int(code)
+ }
+
+ /* Convert the distance code to the actual distance by possibly
+ looking up past distances from the s->ringbuffer. */
+ s.distance_context = 0
+
+ if s.distance_code&^0xF == 0 {
+ takeDistanceFromRingBuffer(s)
+ s.block_length[2]--
+ return true
+ }
+
+ distval = s.distance_code - int(s.num_direct_distance_codes)
+ if distval >= 0 {
+ var nbits uint32
+ var postfix int
+ var offset int
+ if safe == 0 && (s.distance_postfix_bits == 0) {
+ nbits = (uint32(distval) >> 1) + 1
+ offset = ((2 + (distval & 1)) << nbits) - 4
+ s.distance_code = int(s.num_direct_distance_codes) + offset + int(readBits(br, nbits))
+ } else {
+ /* This branch also works well when s->distance_postfix_bits == 0. */
+ var bits uint32
+ postfix = distval & s.distance_postfix_mask
+ distval >>= s.distance_postfix_bits
+ nbits = (uint32(distval) >> 1) + 1
+ if safe != 0 {
+ if !safeReadBitsMaybeZero(br, nbits, &bits) {
+ s.distance_code = -1 /* Restore precondition. */
+ bitReaderRestoreState(br, &memento)
+ return false
+ }
+ } else {
+ bits = readBits(br, nbits)
+ }
+
+ offset = ((2 + (distval & 1)) << nbits) - 4
+ s.distance_code = int(s.num_direct_distance_codes) + ((offset + int(bits)) << s.distance_postfix_bits) + postfix
+ }
+ }
+
+ s.distance_code = s.distance_code - numDistanceShortCodes + 1
+ s.block_length[2]--
+ return true
+}
+
+func readDistance(s *Reader, br *bitReader) {
+ readDistanceInternal(0, s, br)
+}
+
+func safeReadDistance(s *Reader, br *bitReader) bool {
+ return readDistanceInternal(1, s, br)
+}
+
+func readCommandInternal(safe int, s *Reader, br *bitReader, insert_length *int) bool {
+ var cmd_code uint32
+ var insert_len_extra uint32 = 0
+ var copy_length uint32
+ var v cmdLutElement
+ var memento bitReaderState
+ if safe == 0 {
+ cmd_code = readSymbol(s.htree_command, br)
+ } else {
+ bitReaderSaveState(br, &memento)
+ if !safeReadSymbol(s.htree_command, br, &cmd_code) {
+ return false
+ }
+ }
+
+ v = kCmdLut[cmd_code]
+ s.distance_code = int(v.distance_code)
+ s.distance_context = int(v.context)
+ s.dist_htree_index = s.dist_context_map_slice[s.distance_context]
+ *insert_length = int(v.insert_len_offset)
+ if safe == 0 {
+ if v.insert_len_extra_bits != 0 {
+ insert_len_extra = readBits(br, uint32(v.insert_len_extra_bits))
+ }
+
+ copy_length = readBits(br, uint32(v.copy_len_extra_bits))
+ } else {
+ if !safeReadBitsMaybeZero(br, uint32(v.insert_len_extra_bits), &insert_len_extra) || !safeReadBitsMaybeZero(br, uint32(v.copy_len_extra_bits), ©_length) {
+ bitReaderRestoreState(br, &memento)
+ return false
+ }
+ }
+
+ s.copy_length = int(copy_length) + int(v.copy_len_offset)
+ s.block_length[1]--
+ *insert_length += int(insert_len_extra)
+ return true
+}
+
+func readCommand(s *Reader, br *bitReader, insert_length *int) {
+ readCommandInternal(0, s, br, insert_length)
+}
+
+func safeReadCommand(s *Reader, br *bitReader, insert_length *int) bool {
+ return readCommandInternal(1, s, br, insert_length)
+}
+
+func checkInputAmountMaybeSafe(safe int, br *bitReader, num uint) bool {
+ if safe != 0 {
+ return true
+ }
+
+ return checkInputAmount(br, num)
+}
+
+func processCommandsInternal(safe int, s *Reader) int {
+ var pos int = s.pos
+ var i int = s.loop_counter
+ var result int = decoderSuccess
+ var br *bitReader = &s.br
+ var hc []huffmanCode
+
+ if !checkInputAmountMaybeSafe(safe, br, 28) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if safe == 0 {
+ warmupBitReader(br)
+ }
+
+ /* Jump into state machine. */
+ if s.state == stateCommandBegin {
+ goto CommandBegin
+ } else if s.state == stateCommandInner {
+ goto CommandInner
+ } else if s.state == stateCommandPostDecodeLiterals {
+ goto CommandPostDecodeLiterals
+ } else if s.state == stateCommandPostWrapCopy {
+ goto CommandPostWrapCopy
+ } else {
+ return decoderErrorUnreachable
+ }
+
+CommandBegin:
+ if safe != 0 {
+ s.state = stateCommandBegin
+ }
+
+ if !checkInputAmountMaybeSafe(safe, br, 28) { /* 156 bits + 7 bytes */
+ s.state = stateCommandBegin
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if s.block_length[1] == 0 {
+ if safe != 0 {
+ if !safeDecodeCommandBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeCommandBlockSwitch(s)
+ }
+
+ goto CommandBegin
+ }
+
+ /* Read the insert/copy length in the command. */
+ if safe != 0 {
+ if !safeReadCommand(s, br, &i) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ readCommand(s, br, &i)
+ }
+
+ if i == 0 {
+ goto CommandPostDecodeLiterals
+ }
+
+ s.meta_block_remaining_len -= i
+
+CommandInner:
+ if safe != 0 {
+ s.state = stateCommandInner
+ }
+
+ /* Read the literals in the command. */
+ if s.trivial_literal_context != 0 {
+ var bits uint32
+ var value uint32
+ preloadSymbol(safe, s.literal_htree, br, &bits, &value)
+ for {
+ if !checkInputAmountMaybeSafe(safe, br, 28) { /* 162 bits + 7 bytes */
+ s.state = stateCommandInner
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if s.block_length[0] == 0 {
+ if safe != 0 {
+ if !safeDecodeLiteralBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeLiteralBlockSwitch(s)
+ }
+
+ preloadSymbol(safe, s.literal_htree, br, &bits, &value)
+ if s.trivial_literal_context == 0 {
+ goto CommandInner
+ }
+ }
+
+ if safe == 0 {
+ s.ringbuffer[pos] = byte(readPreloadedSymbol(s.literal_htree, br, &bits, &value))
+ } else {
+ var literal uint32
+ if !safeReadSymbol(s.literal_htree, br, &literal) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ s.ringbuffer[pos] = byte(literal)
+ }
+
+ s.block_length[0]--
+ pos++
+ if pos == s.ringbuffer_size {
+ s.state = stateCommandInnerWrite
+ i--
+ goto saveStateAndReturn
+ }
+ i--
+ if i == 0 {
+ break
+ }
+ }
+ } else {
+ var p1 byte = s.ringbuffer[(pos-1)&s.ringbuffer_mask]
+ var p2 byte = s.ringbuffer[(pos-2)&s.ringbuffer_mask]
+ for {
+ var context byte
+ if !checkInputAmountMaybeSafe(safe, br, 28) { /* 162 bits + 7 bytes */
+ s.state = stateCommandInner
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ if s.block_length[0] == 0 {
+ if safe != 0 {
+ if !safeDecodeLiteralBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeLiteralBlockSwitch(s)
+ }
+
+ if s.trivial_literal_context != 0 {
+ goto CommandInner
+ }
+ }
+
+ context = getContext(p1, p2, s.context_lookup)
+ hc = []huffmanCode(s.literal_hgroup.htrees[s.context_map_slice[context]])
+ p2 = p1
+ if safe == 0 {
+ p1 = byte(readSymbol(hc, br))
+ } else {
+ var literal uint32
+ if !safeReadSymbol(hc, br, &literal) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+
+ p1 = byte(literal)
+ }
+
+ s.ringbuffer[pos] = p1
+ s.block_length[0]--
+ pos++
+ if pos == s.ringbuffer_size {
+ s.state = stateCommandInnerWrite
+ i--
+ goto saveStateAndReturn
+ }
+ i--
+ if i == 0 {
+ break
+ }
+ }
+ }
+
+ if s.meta_block_remaining_len <= 0 {
+ s.state = stateMetablockDone
+ goto saveStateAndReturn
+ }
+
+CommandPostDecodeLiterals:
+ if safe != 0 {
+ s.state = stateCommandPostDecodeLiterals
+ }
+
+ if s.distance_code >= 0 {
+ /* Implicit distance case. */
+ if s.distance_code != 0 {
+ s.distance_context = 0
+ } else {
+ s.distance_context = 1
+ }
+
+ s.dist_rb_idx--
+ s.distance_code = s.dist_rb[s.dist_rb_idx&3]
+ } else {
+ /* Read distance code in the command, unless it was implicitly zero. */
+ if s.block_length[2] == 0 {
+ if safe != 0 {
+ if !safeDecodeDistanceBlockSwitch(s) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ decodeDistanceBlockSwitch(s)
+ }
+ }
+
+ if safe != 0 {
+ if !safeReadDistance(s, br) {
+ result = decoderNeedsMoreInput
+ goto saveStateAndReturn
+ }
+ } else {
+ readDistance(s, br)
+ }
+ }
+
+ if s.max_distance != s.max_backward_distance {
+ if pos < s.max_backward_distance {
+ s.max_distance = pos
+ } else {
+ s.max_distance = s.max_backward_distance
+ }
+ }
+
+ i = s.copy_length
+
+ /* Apply copy of LZ77 back-reference, or static dictionary reference if
+ the distance is larger than the max LZ77 distance */
+ if s.distance_code > s.max_distance {
+ /* The maximum allowed distance is BROTLI_MAX_ALLOWED_DISTANCE = 0x7FFFFFFC.
+ With this choice, no signed overflow can occur after decoding
+ a special distance code (e.g., after adding 3 to the last distance). */
+ if s.distance_code > maxAllowedDistance {
+ return decoderErrorFormatDistance
+ }
+
+ if i >= minDictionaryWordLength && i <= maxDictionaryWordLength {
+ var address int = s.distance_code - s.max_distance - 1
+ var words *dictionary = s.dictionary
+ var trans *transforms = s.transforms
+ var offset int = int(s.dictionary.offsets_by_length[i])
+ var shift uint32 = uint32(s.dictionary.size_bits_by_length[i])
+ var mask int = int(bitMask(shift))
+ var word_idx int = address & mask
+ var transform_idx int = address >> shift
+
+ /* Compensate double distance-ring-buffer roll. */
+ s.dist_rb_idx += s.distance_context
+
+ offset += word_idx * i
+ if words.data == nil {
+ return decoderErrorDictionaryNotSet
+ }
+
+ if transform_idx < int(trans.num_transforms) {
+ word := words.data[offset:]
+ var len int = i
+ if transform_idx == int(trans.cutOffTransforms[0]) {
+ copy(s.ringbuffer[pos:], word[:uint(len)])
+ } else {
+ len = transformDictionaryWord(s.ringbuffer[pos:], word, int(len), trans, transform_idx)
+ }
+
+ pos += int(len)
+ s.meta_block_remaining_len -= int(len)
+ if pos >= s.ringbuffer_size {
+ s.state = stateCommandPostWrite1
+ goto saveStateAndReturn
+ }
+ } else {
+ return decoderErrorFormatTransform
+ }
+ } else {
+ return decoderErrorFormatDictionary
+ }
+ } else {
+ var src_start int = (pos - s.distance_code) & s.ringbuffer_mask
+ copy_dst := s.ringbuffer[pos:]
+ copy_src := s.ringbuffer[src_start:]
+ var dst_end int = pos + i
+ var src_end int = src_start + i
+
+ /* Update the recent distances cache. */
+ s.dist_rb[s.dist_rb_idx&3] = s.distance_code
+
+ s.dist_rb_idx++
+ s.meta_block_remaining_len -= i
+
+ /* There are 32+ bytes of slack in the ring-buffer allocation.
+ Also, we have 16 short codes, that make these 16 bytes irrelevant
+ in the ring-buffer. Let's copy over them as a first guess. */
+ copy(copy_dst, copy_src[:16])
+
+ if src_end > pos && dst_end > src_start {
+ /* Regions intersect. */
+ goto CommandPostWrapCopy
+ }
+
+ if dst_end >= s.ringbuffer_size || src_end >= s.ringbuffer_size {
+ /* At least one region wraps. */
+ goto CommandPostWrapCopy
+ }
+
+ pos += i
+ if i > 16 {
+ if i > 32 {
+ copy(copy_dst[16:], copy_src[16:][:uint(i-16)])
+ } else {
+ /* This branch covers about 45% cases.
+ Fixed size short copy allows more compiler optimizations. */
+ copy(copy_dst[16:], copy_src[16:][:16])
+ }
+ }
+ }
+
+ if s.meta_block_remaining_len <= 0 {
+ /* Next metablock, if any. */
+ s.state = stateMetablockDone
+
+ goto saveStateAndReturn
+ } else {
+ goto CommandBegin
+ }
+CommandPostWrapCopy:
+ {
+ var wrap_guard int = s.ringbuffer_size - pos
+ for {
+ i--
+ if i < 0 {
+ break
+ }
+ s.ringbuffer[pos] = s.ringbuffer[(pos-s.distance_code)&s.ringbuffer_mask]
+ pos++
+ wrap_guard--
+ if wrap_guard == 0 {
+ s.state = stateCommandPostWrite2
+ goto saveStateAndReturn
+ }
+ }
+ }
+
+ if s.meta_block_remaining_len <= 0 {
+ /* Next metablock, if any. */
+ s.state = stateMetablockDone
+
+ goto saveStateAndReturn
+ } else {
+ goto CommandBegin
+ }
+
+saveStateAndReturn:
+ s.pos = pos
+ s.loop_counter = i
+ return result
+}
+
+func processCommands(s *Reader) int {
+ return processCommandsInternal(0, s)
+}
+
+func safeProcessCommands(s *Reader) int {
+ return processCommandsInternal(1, s)
+}
+
+/* Returns the maximum number of distance symbols which can only represent
+ distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */
+
+var maxDistanceSymbol_bound = [maxNpostfix + 1]uint32{0, 4, 12, 28}
+var maxDistanceSymbol_diff = [maxNpostfix + 1]uint32{73, 126, 228, 424}
+
+func maxDistanceSymbol(ndirect uint32, npostfix uint32) uint32 {
+ var postfix uint32 = 1 << npostfix
+ if ndirect < maxDistanceSymbol_bound[npostfix] {
+ return ndirect + maxDistanceSymbol_diff[npostfix] + postfix
+ } else if ndirect > maxDistanceSymbol_bound[npostfix]+postfix {
+ return ndirect + maxDistanceSymbol_diff[npostfix]
+ } else {
+ return maxDistanceSymbol_bound[npostfix] + maxDistanceSymbol_diff[npostfix] + postfix
+ }
+}
+
+/* Invariant: input stream is never overconsumed:
+ - invalid input implies that the whole stream is invalid -> any amount of
+ input could be read and discarded
+ - when result is "needs more input", then at least one more byte is REQUIRED
+ to complete decoding; all input data MUST be consumed by decoder, so
+ client could swap the input buffer
+ - when result is "needs more output" decoder MUST ensure that it doesn't
+ hold more than 7 bits in bit reader; this saves client from swapping input
+ buffer ahead of time
+ - when result is "success" decoder MUST return all unused data back to input
+ buffer; this is possible because the invariant is held on enter */
+func decoderDecompressStream(s *Reader, available_in *uint, next_in *[]byte, available_out *uint, next_out *[]byte) int {
+ var result int = decoderSuccess
+ var br *bitReader = &s.br
+
+ /* Do not try to process further in a case of unrecoverable error. */
+ if int(s.error_code) < 0 {
+ return decoderResultError
+ }
+
+ if *available_out != 0 && (next_out == nil || *next_out == nil) {
+ return saveErrorCode(s, decoderErrorInvalidArguments)
+ }
+
+ if *available_out == 0 {
+ next_out = nil
+ }
+ if s.buffer_length == 0 { /* Just connect bit reader to input stream. */
+ br.input_len = *available_in
+ br.input = *next_in
+ br.byte_pos = 0
+ } else {
+ /* At least one byte of input is required. More than one byte of input may
+ be required to complete the transaction -> reading more data must be
+ done in a loop -> do it in a main loop. */
+ result = decoderNeedsMoreInput
+
+ br.input = s.buffer.u8[:]
+ br.byte_pos = 0
+ }
+
+ /* State machine */
+ for {
+ if result != decoderSuccess {
+ /* Error, needs more input/output. */
+ if result == decoderNeedsMoreInput {
+ if s.ringbuffer != nil { /* Pro-actively push output. */
+ var intermediate_result int = writeRingBuffer(s, available_out, next_out, nil, true)
+
+ /* WriteRingBuffer checks s->meta_block_remaining_len validity. */
+ if int(intermediate_result) < 0 {
+ result = intermediate_result
+ break
+ }
+ }
+
+ if s.buffer_length != 0 { /* Used with internal buffer. */
+ if br.byte_pos == br.input_len {
+ /* Successfully finished read transaction.
+ Accumulator contains less than 8 bits, because internal buffer
+ is expanded byte-by-byte until it is enough to complete read. */
+ s.buffer_length = 0
+
+ /* Switch to input stream and restart. */
+ result = decoderSuccess
+
+ br.input_len = *available_in
+ br.input = *next_in
+ br.byte_pos = 0
+ continue
+ } else if *available_in != 0 {
+ /* Not enough data in buffer, but can take one more byte from
+ input stream. */
+ result = decoderSuccess
+
+ s.buffer.u8[s.buffer_length] = (*next_in)[0]
+ s.buffer_length++
+ br.input_len = uint(s.buffer_length)
+ *next_in = (*next_in)[1:]
+ (*available_in)--
+
+ /* Retry with more data in buffer. */
+ continue
+ }
+
+ /* Can't finish reading and no more input. */
+ break
+ /* Input stream doesn't contain enough input. */
+ } else {
+ /* Copy tail to internal buffer and return. */
+ *next_in = br.input[br.byte_pos:]
+
+ *available_in = br.input_len - br.byte_pos
+ for *available_in != 0 {
+ s.buffer.u8[s.buffer_length] = (*next_in)[0]
+ s.buffer_length++
+ *next_in = (*next_in)[1:]
+ (*available_in)--
+ }
+
+ break
+ }
+ }
+
+ /* Unreachable. */
+
+ /* Fail or needs more output. */
+ if s.buffer_length != 0 {
+ /* Just consumed the buffered input and produced some output. Otherwise
+ it would result in "needs more input". Reset internal buffer. */
+ s.buffer_length = 0
+ } else {
+ /* Using input stream in last iteration. When decoder switches to input
+ stream it has less than 8 bits in accumulator, so it is safe to
+ return unused accumulator bits there. */
+ bitReaderUnload(br)
+
+ *available_in = br.input_len - br.byte_pos
+ *next_in = br.input[br.byte_pos:]
+ }
+
+ break
+ }
+
+ switch s.state {
+ /* Prepare to the first read. */
+ case stateUninited:
+ if !warmupBitReader(br) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ /* Decode window size. */
+ result = decodeWindowBits(s, br) /* Reads 1..8 bits. */
+ if result != decoderSuccess {
+ break
+ }
+
+ if s.large_window {
+ s.state = stateLargeWindowBits
+ break
+ }
+
+ s.state = stateInitialize
+
+ case stateLargeWindowBits:
+ if !safeReadBits(br, 6, &s.window_bits) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ if s.window_bits < largeMinWbits || s.window_bits > largeMaxWbits {
+ result = decoderErrorFormatWindowBits
+ break
+ }
+
+ s.state = stateInitialize
+ fallthrough
+
+ /* Maximum distance, see section 9.1. of the spec. */
+ /* Fall through. */
+ case stateInitialize:
+ s.max_backward_distance = (1 << s.window_bits) - windowGap
+
+ /* Allocate memory for both block_type_trees and block_len_trees. */
+ s.block_type_trees = make([]huffmanCode, (3 * (huffmanMaxSize258 + huffmanMaxSize26)))
+
+ if s.block_type_trees == nil {
+ result = decoderErrorAllocBlockTypeTrees
+ break
+ }
+
+ s.block_len_trees = s.block_type_trees[3*huffmanMaxSize258:]
+
+ s.state = stateMetablockBegin
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockBegin:
+ decoderStateMetablockBegin(s)
+
+ s.state = stateMetablockHeader
+ fallthrough
+
+ /* Fall through. */
+ case stateMetablockHeader:
+ result = decodeMetaBlockLength(s, br)
+ /* Reads 2 - 31 bits. */
+ if result != decoderSuccess {
+ break
+ }
+
+ if s.is_metadata != 0 || s.is_uncompressed != 0 {
+ if !bitReaderJumpToByteBoundary(br) {
+ result = decoderErrorFormatPadding1
+ break
+ }
+ }
+
+ if s.is_metadata != 0 {
+ s.state = stateMetadata
+ break
+ }
+
+ if s.meta_block_remaining_len == 0 {
+ s.state = stateMetablockDone
+ break
+ }
+
+ calculateRingBufferSize(s)
+ if s.is_uncompressed != 0 {
+ s.state = stateUncompressed
+ break
+ }
+
+ s.loop_counter = 0
+ s.state = stateHuffmanCode0
+
+ case stateUncompressed:
+ result = copyUncompressedBlockToOutput(available_out, next_out, nil, s)
+ if result == decoderSuccess {
+ s.state = stateMetablockDone
+ }
+
+ case stateMetadata:
+ for ; s.meta_block_remaining_len > 0; s.meta_block_remaining_len-- {
+ var bits uint32
+
+ /* Read one byte and ignore it. */
+ if !safeReadBits(br, 8, &bits) {
+ result = decoderNeedsMoreInput
+ break
+ }
+ }
+
+ if result == decoderSuccess {
+ s.state = stateMetablockDone
+ }
+
+ case stateHuffmanCode0:
+ if s.loop_counter >= 3 {
+ s.state = stateMetablockHeader2
+ break
+ }
+
+ /* Reads 1..11 bits. */
+ result = decodeVarLenUint8(s, br, &s.num_block_types[s.loop_counter])
+
+ if result != decoderSuccess {
+ break
+ }
+
+ s.num_block_types[s.loop_counter]++
+ if s.num_block_types[s.loop_counter] < 2 {
+ s.loop_counter++
+ break
+ }
+
+ s.state = stateHuffmanCode1
+ fallthrough
+
+ case stateHuffmanCode1:
+ {
+ var alphabet_size uint32 = s.num_block_types[s.loop_counter] + 2
+ var tree_offset int = s.loop_counter * huffmanMaxSize258
+ result = readHuffmanCode(alphabet_size, alphabet_size, s.block_type_trees[tree_offset:], nil, s)
+ if result != decoderSuccess {
+ break
+ }
+ s.state = stateHuffmanCode2
+ }
+ fallthrough
+
+ case stateHuffmanCode2:
+ {
+ var alphabet_size uint32 = numBlockLenSymbols
+ var tree_offset int = s.loop_counter * huffmanMaxSize26
+ result = readHuffmanCode(alphabet_size, alphabet_size, s.block_len_trees[tree_offset:], nil, s)
+ if result != decoderSuccess {
+ break
+ }
+ s.state = stateHuffmanCode3
+ }
+ fallthrough
+
+ case stateHuffmanCode3:
+ var tree_offset int = s.loop_counter * huffmanMaxSize26
+ if !safeReadBlockLength(s, &s.block_length[s.loop_counter], s.block_len_trees[tree_offset:], br) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ s.loop_counter++
+ s.state = stateHuffmanCode0
+
+ case stateMetablockHeader2:
+ {
+ var bits uint32
+ if !safeReadBits(br, 6, &bits) {
+ result = decoderNeedsMoreInput
+ break
+ }
+
+ s.distance_postfix_bits = bits & bitMask(2)
+ bits >>= 2
+ s.num_direct_distance_codes = numDistanceShortCodes + (bits << s.distance_postfix_bits)
+ s.distance_postfix_mask = int(bitMask(s.distance_postfix_bits))
+ s.context_modes = make([]byte, uint(s.num_block_types[0]))
+ if s.context_modes == nil {
+ result = decoderErrorAllocContextModes
+ break
+ }
+
+ s.loop_counter = 0
+ s.state = stateContextModes
+ }
+ fallthrough
+
+ case stateContextModes:
+ result = readContextModes(s)
+
+ if result != decoderSuccess {
+ break
+ }
+
+ s.state = stateContextMap1
+ fallthrough
+
+ case stateContextMap1:
+ result = decodeContextMap(s.num_block_types[0]<= 3 {
+ prepareLiteralDecoding(s)
+ s.dist_context_map_slice = s.dist_context_map
+ s.htree_command = []huffmanCode(s.insert_copy_hgroup.htrees[0])
+ if !ensureRingBuffer(s) {
+ result = decoderErrorAllocRingBuffer2
+ break
+ }
+
+ s.state = stateCommandBegin
+ }
+
+ case stateCommandBegin, stateCommandInner, stateCommandPostDecodeLiterals, stateCommandPostWrapCopy:
+ result = processCommands(s)
+
+ if result == decoderNeedsMoreInput {
+ result = safeProcessCommands(s)
+ }
+
+ case stateCommandInnerWrite, stateCommandPostWrite1, stateCommandPostWrite2:
+ result = writeRingBuffer(s, available_out, next_out, nil, false)
+
+ if result != decoderSuccess {
+ break
+ }
+
+ wrapRingBuffer(s)
+ if s.ringbuffer_size == 1<= uint64(block_size) {
+ return 0
+ }
+ return block_size - uint(delta)
+}
+
+/* Wraps 64-bit input position to 32-bit ring-buffer position preserving
+ "not-a-first-lap" feature. */
+func wrapPosition(position uint64) uint32 {
+ var result uint32 = uint32(position)
+ var gb uint64 = position >> 30
+ if gb > 2 {
+ /* Wrap every 2GiB; The first 3GB are continuous. */
+ result = result&((1<<30)-1) | (uint32((gb-1)&1)+1)<<30
+ }
+
+ return result
+}
+
+func (s *Writer) getStorage(size int) []byte {
+ if len(s.storage) < size {
+ s.storage = make([]byte, size)
+ }
+
+ return s.storage
+}
+
+func hashTableSize(max_table_size uint, input_size uint) uint {
+ var htsize uint = 256
+ for htsize < max_table_size && htsize < input_size {
+ htsize <<= 1
+ }
+
+ return htsize
+}
+
+func getHashTable(s *Writer, quality int, input_size uint, table_size *uint) []int {
+ var max_table_size uint = maxHashTableSize(quality)
+ var htsize uint = hashTableSize(max_table_size, input_size)
+ /* Use smaller hash table when input.size() is smaller, since we
+ fill the table, incurring O(hash table size) overhead for
+ compression, and if the input is short, we won't need that
+ many hash table entries anyway. */
+
+ var table []int
+ assert(max_table_size >= 256)
+ if quality == fastOnePassCompressionQuality {
+ /* Only odd shifts are supported by fast-one-pass. */
+ if htsize&0xAAAAA == 0 {
+ htsize <<= 1
+ }
+ }
+
+ if htsize <= uint(len(s.small_table_)) {
+ table = s.small_table_[:]
+ } else {
+ if htsize > s.large_table_size_ {
+ s.large_table_size_ = htsize
+ s.large_table_ = nil
+ s.large_table_ = make([]int, htsize)
+ }
+
+ table = s.large_table_
+ }
+
+ *table_size = htsize
+ for i := 0; i < int(htsize); i++ {
+ table[i] = 0
+ }
+ return table
+}
+
+func encodeWindowBits(lgwin int, large_window bool, last_bytes *uint16, last_bytes_bits *byte) {
+ if large_window {
+ *last_bytes = uint16((lgwin&0x3F)<<8 | 0x11)
+ *last_bytes_bits = 14
+ } else {
+ if lgwin == 16 {
+ *last_bytes = 0
+ *last_bytes_bits = 1
+ } else if lgwin == 17 {
+ *last_bytes = 1
+ *last_bytes_bits = 7
+ } else if lgwin > 17 {
+ *last_bytes = uint16((lgwin-17)<<1 | 0x01)
+ *last_bytes_bits = 4
+ } else {
+ *last_bytes = uint16((lgwin-8)<<4 | 0x01)
+ *last_bytes_bits = 7
+ }
+ }
+}
+
+/* Decide about the context map based on the ability of the prediction
+ ability of the previous byte UTF8-prefix on the next byte. The
+ prediction ability is calculated as Shannon entropy. Here we need
+ Shannon entropy instead of 'BitsEntropy' since the prefix will be
+ encoded with the remaining 6 bits of the following byte, and
+ BitsEntropy will assume that symbol to be stored alone using Huffman
+ coding. */
+
+var kStaticContextMapContinuation = [64]uint32{
+ 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+}
+var kStaticContextMapSimpleUTF8 = [64]uint32{
+ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+}
+
+func chooseContextMap(quality int, bigram_histo []uint32, num_literal_contexts *uint, literal_context_map *[]uint32) {
+ var monogram_histo = [3]uint32{0}
+ var two_prefix_histo = [6]uint32{0}
+ var total uint
+ var i uint
+ var dummy uint
+ var entropy [4]float64
+ for i = 0; i < 9; i++ {
+ monogram_histo[i%3] += bigram_histo[i]
+ two_prefix_histo[i%6] += bigram_histo[i]
+ }
+
+ entropy[1] = shannonEntropy(monogram_histo[:], 3, &dummy)
+ entropy[2] = (shannonEntropy(two_prefix_histo[:], 3, &dummy) + shannonEntropy(two_prefix_histo[3:], 3, &dummy))
+ entropy[3] = 0
+ for i = 0; i < 3; i++ {
+ entropy[3] += shannonEntropy(bigram_histo[3*i:], 3, &dummy)
+ }
+
+ total = uint(monogram_histo[0] + monogram_histo[1] + monogram_histo[2])
+ assert(total != 0)
+ entropy[0] = 1.0 / float64(total)
+ entropy[1] *= entropy[0]
+ entropy[2] *= entropy[0]
+ entropy[3] *= entropy[0]
+
+ if quality < minQualityForHqContextModeling {
+ /* 3 context models is a bit slower, don't use it at lower qualities. */
+ entropy[3] = entropy[1] * 10
+ }
+
+ /* If expected savings by symbol are less than 0.2 bits, skip the
+ context modeling -- in exchange for faster decoding speed. */
+ if entropy[1]-entropy[2] < 0.2 && entropy[1]-entropy[3] < 0.2 {
+ *num_literal_contexts = 1
+ } else if entropy[2]-entropy[3] < 0.02 {
+ *num_literal_contexts = 2
+ *literal_context_map = kStaticContextMapSimpleUTF8[:]
+ } else {
+ *num_literal_contexts = 3
+ *literal_context_map = kStaticContextMapContinuation[:]
+ }
+}
+
+/* Decide if we want to use a more complex static context map containing 13
+ context values, based on the entropy reduction of histograms over the
+ first 5 bits of literals. */
+
+var kStaticContextMapComplexUTF8 = [64]uint32{
+ 11, 11, 12, 12, /* 0 special */
+ 0, 0, 0, 0, /* 4 lf */
+ 1, 1, 9, 9, /* 8 space */
+ 2, 2, 2, 2, /* !, first after space/lf and after something else. */
+ 1, 1, 1, 1, /* " */
+ 8, 3, 3, 3, /* % */
+ 1, 1, 1, 1, /* ({[ */
+ 2, 2, 2, 2, /* }]) */
+ 8, 4, 4, 4, /* :; */
+ 8, 7, 4, 4, /* . */
+ 8, 0, 0, 0, /* > */
+ 3, 3, 3, 3, /* [0..9] */
+ 5, 5, 10, 5, /* [A-Z] */
+ 5, 5, 10, 5,
+ 6, 6, 6, 6, /* [a-z] */
+ 6, 6, 6, 6,
+}
+
+func shouldUseComplexStaticContextMap(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) bool {
+ /* Try the more complex static context map only for long data. */
+ if size_hint < 1<<20 {
+ return false
+ } else {
+ var end_pos uint = start_pos + length
+ var combined_histo = [32]uint32{0}
+ var context_histo = [13][32]uint32{[32]uint32{0}}
+ var total uint32 = 0
+ var entropy [3]float64
+ var dummy uint
+ var i uint
+ var utf8_lut contextLUT = getContextLUT(contextUTF8)
+ /* To make entropy calculations faster and to fit on the stack, we collect
+ histograms over the 5 most significant bits of literals. One histogram
+ without context and 13 additional histograms for each context value. */
+ for ; start_pos+64 <= end_pos; start_pos += 4096 {
+ var stride_end_pos uint = start_pos + 64
+ var prev2 byte = input[start_pos&mask]
+ var prev1 byte = input[(start_pos+1)&mask]
+ var pos uint
+
+ /* To make the analysis of the data faster we only examine 64 byte long
+ strides at every 4kB intervals. */
+ for pos = start_pos + 2; pos < stride_end_pos; pos++ {
+ var literal byte = input[pos&mask]
+ var context byte = byte(kStaticContextMapComplexUTF8[getContext(prev1, prev2, utf8_lut)])
+ total++
+ combined_histo[literal>>3]++
+ context_histo[context][literal>>3]++
+ prev2 = prev1
+ prev1 = literal
+ }
+ }
+
+ entropy[1] = shannonEntropy(combined_histo[:], 32, &dummy)
+ entropy[2] = 0
+ for i = 0; i < 13; i++ {
+ entropy[2] += shannonEntropy(context_histo[i][0:], 32, &dummy)
+ }
+
+ entropy[0] = 1.0 / float64(total)
+ entropy[1] *= entropy[0]
+ entropy[2] *= entropy[0]
+
+ /* The triggering heuristics below were tuned by compressing the individual
+ files of the silesia corpus. If we skip this kind of context modeling
+ for not very well compressible input (i.e. entropy using context modeling
+ is 60% of maximal entropy) or if expected savings by symbol are less
+ than 0.2 bits, then in every case when it triggers, the final compression
+ ratio is improved. Note however that this heuristics might be too strict
+ for some cases and could be tuned further. */
+ if entropy[2] > 3.0 || entropy[1]-entropy[2] < 0.2 {
+ return false
+ } else {
+ *num_literal_contexts = 13
+ *literal_context_map = kStaticContextMapComplexUTF8[:]
+ return true
+ }
+ }
+}
+
+func decideOverLiteralContextModeling(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) {
+ if quality < minQualityForContextModeling || length < 64 {
+ return
+ } else if shouldUseComplexStaticContextMap(input, start_pos, length, mask, quality, size_hint, num_literal_contexts, literal_context_map) {
+ } else /* Context map was already set, nothing else to do. */
+ {
+ var end_pos uint = start_pos + length
+ /* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of
+ UTF8 data faster we only examine 64 byte long strides at every 4kB
+ intervals. */
+
+ var bigram_prefix_histo = [9]uint32{0}
+ for ; start_pos+64 <= end_pos; start_pos += 4096 {
+ var lut = [4]int{0, 0, 1, 2}
+ var stride_end_pos uint = start_pos + 64
+ var prev int = lut[input[start_pos&mask]>>6] * 3
+ var pos uint
+ for pos = start_pos + 1; pos < stride_end_pos; pos++ {
+ var literal byte = input[pos&mask]
+ bigram_prefix_histo[prev+lut[literal>>6]]++
+ prev = lut[literal>>6] * 3
+ }
+ }
+
+ chooseContextMap(quality, bigram_prefix_histo[0:], num_literal_contexts, literal_context_map)
+ }
+}
+
+func shouldCompress_encode(data []byte, mask uint, last_flush_pos uint64, bytes uint, num_literals uint, num_commands uint) bool {
+ /* TODO: find more precise minimal block overhead. */
+ if bytes <= 2 {
+ return false
+ }
+ if num_commands < (bytes>>8)+2 {
+ if float64(num_literals) > 0.99*float64(bytes) {
+ var literal_histo = [256]uint32{0}
+ const kSampleRate uint32 = 13
+ const kMinEntropy float64 = 7.92
+ var bit_cost_threshold float64 = float64(bytes) * kMinEntropy / float64(kSampleRate)
+ var t uint = uint((uint32(bytes) + kSampleRate - 1) / kSampleRate)
+ var pos uint32 = uint32(last_flush_pos)
+ var i uint
+ for i = 0; i < t; i++ {
+ literal_histo[data[pos&uint32(mask)]]++
+ pos += kSampleRate
+ }
+
+ if bitsEntropy(literal_histo[:], 256) > bit_cost_threshold {
+ return false
+ }
+ }
+ }
+
+ return true
+}
+
+/* Chooses the literal context mode for a metablock */
+func chooseContextMode(params *encoderParams, data []byte, pos uint, mask uint, length uint) int {
+ /* We only do the computation for the option of something else than
+ CONTEXT_UTF8 for the highest qualities */
+ if params.quality >= minQualityForHqBlockSplitting && !isMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio) {
+ return contextSigned
+ }
+
+ return contextUTF8
+}
+
+func writeMetaBlockInternal(data []byte, mask uint, last_flush_pos uint64, bytes uint, is_last bool, literal_context_mode int, params *encoderParams, prev_byte byte, prev_byte2 byte, num_literals uint, commands []command, saved_dist_cache []int, dist_cache []int, storage_ix *uint, storage []byte) {
+ var wrapped_last_flush_pos uint32 = wrapPosition(last_flush_pos)
+ var last_bytes uint16
+ var last_bytes_bits byte
+ var literal_context_lut contextLUT = getContextLUT(literal_context_mode)
+ var block_params encoderParams = *params
+
+ if bytes == 0 {
+ /* Write the ISLAST and ISEMPTY bits. */
+ writeBits(2, 3, storage_ix, storage)
+
+ *storage_ix = (*storage_ix + 7) &^ 7
+ return
+ }
+
+ if !shouldCompress_encode(data, mask, last_flush_pos, bytes, num_literals, uint(len(commands))) {
+ /* Restore the distance cache, as its last update by
+ CreateBackwardReferences is now unused. */
+ copy(dist_cache, saved_dist_cache[:4])
+
+ storeUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage)
+ return
+ }
+
+ assert(*storage_ix <= 14)
+ last_bytes = uint16(storage[1])<<8 | uint16(storage[0])
+ last_bytes_bits = byte(*storage_ix)
+ if params.quality <= maxQualityForStaticEntropyCodes {
+ storeMetaBlockFast(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage)
+ } else if params.quality < minQualityForBlockSplit {
+ storeMetaBlockTrivial(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage)
+ } else {
+ mb := getMetaBlockSplit()
+ if params.quality < minQualityForHqBlockSplitting {
+ var num_literal_contexts uint = 1
+ var literal_context_map []uint32 = nil
+ if !params.disable_literal_context_modeling {
+ decideOverLiteralContextModeling(data, uint(wrapped_last_flush_pos), bytes, mask, params.quality, params.size_hint, &num_literal_contexts, &literal_context_map)
+ }
+
+ buildMetaBlockGreedy(data, uint(wrapped_last_flush_pos), mask, prev_byte, prev_byte2, literal_context_lut, num_literal_contexts, literal_context_map, commands, mb)
+ } else {
+ buildMetaBlock(data, uint(wrapped_last_flush_pos), mask, &block_params, prev_byte, prev_byte2, commands, literal_context_mode, mb)
+ }
+
+ if params.quality >= minQualityForOptimizeHistograms {
+ /* The number of distance symbols effectively used for distance
+ histograms. It might be less than distance alphabet size
+ for "Large Window Brotli" (32-bit). */
+ var num_effective_dist_codes uint32 = block_params.dist.alphabet_size
+ if num_effective_dist_codes > numHistogramDistanceSymbols {
+ num_effective_dist_codes = numHistogramDistanceSymbols
+ }
+
+ optimizeHistograms(num_effective_dist_codes, mb)
+ }
+
+ storeMetaBlock(data, uint(wrapped_last_flush_pos), bytes, mask, prev_byte, prev_byte2, is_last, &block_params, literal_context_mode, commands, mb, storage_ix, storage)
+ freeMetaBlockSplit(mb)
+ }
+
+ if bytes+4 < *storage_ix>>3 {
+ /* Restore the distance cache and last byte. */
+ copy(dist_cache, saved_dist_cache[:4])
+
+ storage[0] = byte(last_bytes)
+ storage[1] = byte(last_bytes >> 8)
+ *storage_ix = uint(last_bytes_bits)
+ storeUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage)
+ }
+}
+
+func chooseDistanceParams(params *encoderParams) {
+ var distance_postfix_bits uint32 = 0
+ var num_direct_distance_codes uint32 = 0
+
+ if params.quality >= minQualityForNonzeroDistanceParams {
+ var ndirect_msb uint32
+ if params.mode == modeFont {
+ distance_postfix_bits = 1
+ num_direct_distance_codes = 12
+ } else {
+ distance_postfix_bits = params.dist.distance_postfix_bits
+ num_direct_distance_codes = params.dist.num_direct_distance_codes
+ }
+
+ ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F
+ if distance_postfix_bits > maxNpostfix || num_direct_distance_codes > maxNdirect || ndirect_msb<>25)), (last_command.dist_prefix_&0x3FF == 0), &last_command.cmd_prefix_)
+ }
+}
+
+/*
+ Processes the accumulated input data and writes
+ the new output meta-block to s.dest, if one has been
+ created (otherwise the processed input data is buffered internally).
+ If |is_last| or |force_flush| is true, an output meta-block is
+ always created. However, until |is_last| is true encoder may retain up
+ to 7 bits of the last byte of output. To force encoder to dump the remaining
+ bits use WriteMetadata() to append an empty meta-data block.
+ Returns false if the size of the input data is larger than
+ input_block_size().
+*/
+func encodeData(s *Writer, is_last bool, force_flush bool) bool {
+ var delta uint64 = unprocessedInputSize(s)
+ var bytes uint32 = uint32(delta)
+ var wrapped_last_processed_pos uint32 = wrapPosition(s.last_processed_pos_)
+ var data []byte
+ var mask uint32
+ var literal_context_mode int
+
+ data = s.ringbuffer_.buffer_
+ mask = s.ringbuffer_.mask_
+
+ /* Adding more blocks after "last" block is forbidden. */
+ if s.is_last_block_emitted_ {
+ return false
+ }
+ if is_last {
+ s.is_last_block_emitted_ = true
+ }
+
+ if delta > uint64(inputBlockSize(s)) {
+ return false
+ }
+
+ if s.params.quality == fastTwoPassCompressionQuality {
+ if s.command_buf_ == nil || cap(s.command_buf_) < int(kCompressFragmentTwoPassBlockSize) {
+ s.command_buf_ = make([]uint32, kCompressFragmentTwoPassBlockSize)
+ s.literal_buf_ = make([]byte, kCompressFragmentTwoPassBlockSize)
+ } else {
+ s.command_buf_ = s.command_buf_[:kCompressFragmentTwoPassBlockSize]
+ s.literal_buf_ = s.literal_buf_[:kCompressFragmentTwoPassBlockSize]
+ }
+ }
+
+ if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {
+ var storage []byte
+ var storage_ix uint = uint(s.last_bytes_bits_)
+ var table_size uint
+ var table []int
+
+ if delta == 0 && !is_last {
+ /* We have no new input data and we don't have to finish the stream, so
+ nothing to do. */
+ return true
+ }
+
+ storage = s.getStorage(int(2*bytes + 503))
+ storage[0] = byte(s.last_bytes_)
+ storage[1] = byte(s.last_bytes_ >> 8)
+ table = getHashTable(s, s.params.quality, uint(bytes), &table_size)
+ if s.params.quality == fastOnePassCompressionQuality {
+ compressFragmentFast(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage)
+ } else {
+ compressFragmentTwoPass(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, s.command_buf_, s.literal_buf_, table, table_size, &storage_ix, storage)
+ }
+
+ s.last_bytes_ = uint16(storage[storage_ix>>3])
+ s.last_bytes_bits_ = byte(storage_ix & 7)
+ updateLastProcessedPos(s)
+ s.writeOutput(storage[:storage_ix>>3])
+ return true
+ }
+ {
+ /* Theoretical max number of commands is 1 per 2 bytes. */
+ newsize := len(s.commands) + int(bytes)/2 + 1
+ if newsize > cap(s.commands) {
+ /* Reserve a bit more memory to allow merging with a next block
+ without reallocation: that would impact speed. */
+ newsize += int(bytes/4) + 16
+
+ new_commands := make([]command, len(s.commands), newsize)
+ if s.commands != nil {
+ copy(new_commands, s.commands)
+ }
+
+ s.commands = new_commands
+ }
+ }
+
+ initOrStitchToPreviousBlock(&s.hasher_, data, uint(mask), &s.params, uint(wrapped_last_processed_pos), uint(bytes), is_last)
+
+ literal_context_mode = chooseContextMode(&s.params, data, uint(wrapPosition(s.last_flush_pos_)), uint(mask), uint(s.input_pos_-s.last_flush_pos_))
+
+ if len(s.commands) != 0 && s.last_insert_len_ == 0 {
+ extendLastCommand(s, &bytes, &wrapped_last_processed_pos)
+ }
+
+ if s.params.quality == zopflificationQuality {
+ assert(s.params.hasher.type_ == 10)
+ createZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_.(*h10), s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)
+ } else if s.params.quality == hqZopflificationQuality {
+ assert(s.params.hasher.type_ == 10)
+ createHqZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)
+ } else {
+ createBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)
+ }
+ {
+ var max_length uint = maxMetablockSize(&s.params)
+ var max_literals uint = max_length / 8
+ max_commands := int(max_length / 8)
+ var processed_bytes uint = uint(s.input_pos_ - s.last_flush_pos_)
+ var next_input_fits_metablock bool = (processed_bytes+inputBlockSize(s) <= max_length)
+ var should_flush bool = (s.params.quality < minQualityForBlockSplit && s.num_literals_+uint(len(s.commands)) >= maxNumDelayedSymbols)
+ /* If maximal possible additional block doesn't fit metablock, flush now. */
+ /* TODO: Postpone decision until next block arrives? */
+
+ /* If block splitting is not used, then flush as soon as there is some
+ amount of commands / literals produced. */
+ if !is_last && !force_flush && !should_flush && next_input_fits_metablock && s.num_literals_ < max_literals && len(s.commands) < max_commands {
+ /* Merge with next input block. Everything will happen later. */
+ if updateLastProcessedPos(s) {
+ hasherReset(s.hasher_)
+ }
+
+ return true
+ }
+ }
+
+ /* Create the last insert-only command. */
+ if s.last_insert_len_ > 0 {
+ s.commands = append(s.commands, makeInsertCommand(s.last_insert_len_))
+ s.num_literals_ += s.last_insert_len_
+ s.last_insert_len_ = 0
+ }
+
+ if !is_last && s.input_pos_ == s.last_flush_pos_ {
+ /* We have no new input data and we don't have to finish the stream, so
+ nothing to do. */
+ return true
+ }
+
+ assert(s.input_pos_ >= s.last_flush_pos_)
+ assert(s.input_pos_ > s.last_flush_pos_ || is_last)
+ assert(s.input_pos_-s.last_flush_pos_ <= 1<<24)
+ {
+ var metablock_size uint32 = uint32(s.input_pos_ - s.last_flush_pos_)
+ var storage []byte = s.getStorage(int(2*metablock_size + 503))
+ var storage_ix uint = uint(s.last_bytes_bits_)
+ storage[0] = byte(s.last_bytes_)
+ storage[1] = byte(s.last_bytes_ >> 8)
+ writeMetaBlockInternal(data, uint(mask), s.last_flush_pos_, uint(metablock_size), is_last, literal_context_mode, &s.params, s.prev_byte_, s.prev_byte2_, s.num_literals_, s.commands, s.saved_dist_cache_[:], s.dist_cache_[:], &storage_ix, storage)
+ s.last_bytes_ = uint16(storage[storage_ix>>3])
+ s.last_bytes_bits_ = byte(storage_ix & 7)
+ s.last_flush_pos_ = s.input_pos_
+ if updateLastProcessedPos(s) {
+ hasherReset(s.hasher_)
+ }
+
+ if s.last_flush_pos_ > 0 {
+ s.prev_byte_ = data[(uint32(s.last_flush_pos_)-1)&mask]
+ }
+
+ if s.last_flush_pos_ > 1 {
+ s.prev_byte2_ = data[uint32(s.last_flush_pos_-2)&mask]
+ }
+
+ s.commands = s.commands[:0]
+ s.num_literals_ = 0
+
+ /* Save the state of the distance cache in case we need to restore it for
+ emitting an uncompressed block. */
+ copy(s.saved_dist_cache_[:], s.dist_cache_[:])
+
+ s.writeOutput(storage[:storage_ix>>3])
+ return true
+ }
+}
+
+/* Dumps remaining output bits and metadata header to |header|.
+ Returns number of produced bytes.
+ REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long.
+ REQUIRED: |block_size| <= (1 << 24). */
+func writeMetadataHeader(s *Writer, block_size uint, header []byte) uint {
+ storage_ix := uint(s.last_bytes_bits_)
+ header[0] = byte(s.last_bytes_)
+ header[1] = byte(s.last_bytes_ >> 8)
+ s.last_bytes_ = 0
+ s.last_bytes_bits_ = 0
+
+ writeBits(1, 0, &storage_ix, header)
+ writeBits(2, 3, &storage_ix, header)
+ writeBits(1, 0, &storage_ix, header)
+ if block_size == 0 {
+ writeBits(2, 0, &storage_ix, header)
+ } else {
+ var nbits uint32
+ if block_size == 1 {
+ nbits = 0
+ } else {
+ nbits = log2FloorNonZero(uint(uint32(block_size)-1)) + 1
+ }
+ var nbytes uint32 = (nbits + 7) / 8
+ writeBits(2, uint64(nbytes), &storage_ix, header)
+ writeBits(uint(8*nbytes), uint64(block_size)-1, &storage_ix, header)
+ }
+
+ return (storage_ix + 7) >> 3
+}
+
+func injectBytePaddingBlock(s *Writer) {
+ var seal uint32 = uint32(s.last_bytes_)
+ var seal_bits uint = uint(s.last_bytes_bits_)
+ s.last_bytes_ = 0
+ s.last_bytes_bits_ = 0
+
+ /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */
+ seal |= 0x6 << seal_bits
+
+ seal_bits += 6
+
+ destination := s.tiny_buf_.u8[:]
+
+ destination[0] = byte(seal)
+ if seal_bits > 8 {
+ destination[1] = byte(seal >> 8)
+ }
+ if seal_bits > 16 {
+ destination[2] = byte(seal >> 16)
+ }
+ s.writeOutput(destination[:(seal_bits+7)>>3])
+}
+
+func checkFlushComplete(s *Writer) {
+ if s.stream_state_ == streamFlushRequested && s.err == nil {
+ s.stream_state_ = streamProcessing
+ }
+}
+
+func encoderCompressStreamFast(s *Writer, op int, available_in *uint, next_in *[]byte) bool {
+ var block_size_limit uint = uint(1) << s.params.lgwin
+ var buf_size uint = brotli_min_size_t(kCompressFragmentTwoPassBlockSize, brotli_min_size_t(*available_in, block_size_limit))
+ var command_buf []uint32 = nil
+ var literal_buf []byte = nil
+ if s.params.quality != fastOnePassCompressionQuality && s.params.quality != fastTwoPassCompressionQuality {
+ return false
+ }
+
+ if s.params.quality == fastTwoPassCompressionQuality {
+ if s.command_buf_ == nil || cap(s.command_buf_) < int(buf_size) {
+ s.command_buf_ = make([]uint32, buf_size)
+ s.literal_buf_ = make([]byte, buf_size)
+ } else {
+ s.command_buf_ = s.command_buf_[:buf_size]
+ s.literal_buf_ = s.literal_buf_[:buf_size]
+ }
+
+ command_buf = s.command_buf_
+ literal_buf = s.literal_buf_
+ }
+
+ for {
+ if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {
+ injectBytePaddingBlock(s)
+ continue
+ }
+
+ /* Compress block only when stream is not
+ finished, there is no pending flush request, and there is either
+ additional input or pending operation. */
+ if s.stream_state_ == streamProcessing && (*available_in != 0 || op != int(operationProcess)) {
+ var block_size uint = brotli_min_size_t(block_size_limit, *available_in)
+ var is_last bool = (*available_in == block_size) && (op == int(operationFinish))
+ var force_flush bool = (*available_in == block_size) && (op == int(operationFlush))
+ var max_out_size uint = 2*block_size + 503
+ var storage []byte = nil
+ var storage_ix uint = uint(s.last_bytes_bits_)
+ var table_size uint
+ var table []int
+
+ if force_flush && block_size == 0 {
+ s.stream_state_ = streamFlushRequested
+ continue
+ }
+
+ storage = s.getStorage(int(max_out_size))
+
+ storage[0] = byte(s.last_bytes_)
+ storage[1] = byte(s.last_bytes_ >> 8)
+ table = getHashTable(s, s.params.quality, block_size, &table_size)
+
+ if s.params.quality == fastOnePassCompressionQuality {
+ compressFragmentFast(*next_in, block_size, is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage)
+ } else {
+ compressFragmentTwoPass(*next_in, block_size, is_last, command_buf, literal_buf, table, table_size, &storage_ix, storage)
+ }
+
+ *next_in = (*next_in)[block_size:]
+ *available_in -= block_size
+ var out_bytes uint = storage_ix >> 3
+ s.writeOutput(storage[:out_bytes])
+
+ s.last_bytes_ = uint16(storage[storage_ix>>3])
+ s.last_bytes_bits_ = byte(storage_ix & 7)
+
+ if force_flush {
+ s.stream_state_ = streamFlushRequested
+ }
+ if is_last {
+ s.stream_state_ = streamFinished
+ }
+ continue
+ }
+
+ break
+ }
+
+ checkFlushComplete(s)
+ return true
+}
+
+func processMetadata(s *Writer, available_in *uint, next_in *[]byte) bool {
+ if *available_in > 1<<24 {
+ return false
+ }
+
+ /* Switch to metadata block workflow, if required. */
+ if s.stream_state_ == streamProcessing {
+ s.remaining_metadata_bytes_ = uint32(*available_in)
+ s.stream_state_ = streamMetadataHead
+ }
+
+ if s.stream_state_ != streamMetadataHead && s.stream_state_ != streamMetadataBody {
+ return false
+ }
+
+ for {
+ if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {
+ injectBytePaddingBlock(s)
+ continue
+ }
+
+ if s.input_pos_ != s.last_flush_pos_ {
+ var result bool = encodeData(s, false, true)
+ if !result {
+ return false
+ }
+ continue
+ }
+
+ if s.stream_state_ == streamMetadataHead {
+ n := writeMetadataHeader(s, uint(s.remaining_metadata_bytes_), s.tiny_buf_.u8[:])
+ s.writeOutput(s.tiny_buf_.u8[:n])
+ s.stream_state_ = streamMetadataBody
+ continue
+ } else {
+ /* Exit workflow only when there is no more input and no more output.
+ Otherwise client may continue producing empty metadata blocks. */
+ if s.remaining_metadata_bytes_ == 0 {
+ s.remaining_metadata_bytes_ = math.MaxUint32
+ s.stream_state_ = streamProcessing
+ break
+ }
+
+ /* This guarantees progress in "TakeOutput" workflow. */
+ var c uint32 = brotli_min_uint32_t(s.remaining_metadata_bytes_, 16)
+ copy(s.tiny_buf_.u8[:], (*next_in)[:c])
+ *next_in = (*next_in)[c:]
+ *available_in -= uint(c)
+ s.remaining_metadata_bytes_ -= c
+ s.writeOutput(s.tiny_buf_.u8[:c])
+
+ continue
+ }
+ }
+
+ return true
+}
+
+func updateSizeHint(s *Writer, available_in uint) {
+ if s.params.size_hint == 0 {
+ var delta uint64 = unprocessedInputSize(s)
+ var tail uint64 = uint64(available_in)
+ var limit uint32 = 1 << 30
+ var total uint32
+ if (delta >= uint64(limit)) || (tail >= uint64(limit)) || ((delta + tail) >= uint64(limit)) {
+ total = limit
+ } else {
+ total = uint32(delta + tail)
+ }
+
+ s.params.size_hint = uint(total)
+ }
+}
+
+func encoderCompressStream(s *Writer, op int, available_in *uint, next_in *[]byte) bool {
+ if !ensureInitialized(s) {
+ return false
+ }
+
+ /* Unfinished metadata block; check requirements. */
+ if s.remaining_metadata_bytes_ != math.MaxUint32 {
+ if uint32(*available_in) != s.remaining_metadata_bytes_ {
+ return false
+ }
+ if op != int(operationEmitMetadata) {
+ return false
+ }
+ }
+
+ if op == int(operationEmitMetadata) {
+ updateSizeHint(s, 0) /* First data metablock might be emitted here. */
+ return processMetadata(s, available_in, next_in)
+ }
+
+ if s.stream_state_ == streamMetadataHead || s.stream_state_ == streamMetadataBody {
+ return false
+ }
+
+ if s.stream_state_ != streamProcessing && *available_in != 0 {
+ return false
+ }
+
+ if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {
+ return encoderCompressStreamFast(s, op, available_in, next_in)
+ }
+
+ for {
+ var remaining_block_size uint = remainingInputBlockSize(s)
+
+ if remaining_block_size != 0 && *available_in != 0 {
+ var copy_input_size uint = brotli_min_size_t(remaining_block_size, *available_in)
+ copyInputToRingBuffer(s, copy_input_size, *next_in)
+ *next_in = (*next_in)[copy_input_size:]
+ *available_in -= copy_input_size
+ continue
+ }
+
+ if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {
+ injectBytePaddingBlock(s)
+ continue
+ }
+
+ /* Compress data only when stream is not
+ finished and there is no pending flush request. */
+ if s.stream_state_ == streamProcessing {
+ if remaining_block_size == 0 || op != int(operationProcess) {
+ var is_last bool = ((*available_in == 0) && op == int(operationFinish))
+ var force_flush bool = ((*available_in == 0) && op == int(operationFlush))
+ var result bool
+ updateSizeHint(s, *available_in)
+ result = encodeData(s, is_last, force_flush)
+ if !result {
+ return false
+ }
+ if force_flush {
+ s.stream_state_ = streamFlushRequested
+ }
+ if is_last {
+ s.stream_state_ = streamFinished
+ }
+ continue
+ }
+ }
+
+ break
+ }
+
+ checkFlushComplete(s)
+ return true
+}
+
+func (w *Writer) writeOutput(data []byte) {
+ if w.err != nil {
+ return
+ }
+
+ _, w.err = w.dst.Write(data)
+ if w.err == nil {
+ checkFlushComplete(w)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/encoder_dict.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/encoder_dict.go
new file mode 100644
index 000000000000..55c051c6238b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/encoder_dict.go
@@ -0,0 +1,22 @@
+package brotli
+
+/* Dictionary data (words and transforms) for 1 possible context */
+type encoderDictionary struct {
+ words *dictionary
+ cutoffTransformsCount uint32
+ cutoffTransforms uint64
+ hash_table []uint16
+ buckets []uint16
+ dict_words []dictWord
+}
+
+func initEncoderDictionary(dict *encoderDictionary) {
+ dict.words = getDictionary()
+
+ dict.hash_table = kStaticDictionaryHash[:]
+ dict.buckets = kStaticDictionaryBuckets[:]
+ dict.dict_words = kStaticDictionaryWords[:]
+
+ dict.cutoffTransformsCount = kCutoffTransformsCount
+ dict.cutoffTransforms = kCutoffTransforms
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/entropy_encode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/entropy_encode.go
new file mode 100644
index 000000000000..3f469a3dd94a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/entropy_encode.go
@@ -0,0 +1,592 @@
+package brotli
+
+import "math"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Entropy encoding (Huffman) utilities. */
+
+/* A node of a Huffman tree. */
+type huffmanTree struct {
+ total_count_ uint32
+ index_left_ int16
+ index_right_or_value_ int16
+}
+
+func initHuffmanTree(self *huffmanTree, count uint32, left int16, right int16) {
+ self.total_count_ = count
+ self.index_left_ = left
+ self.index_right_or_value_ = right
+}
+
+/* Input size optimized Shell sort. */
+type huffmanTreeComparator func(huffmanTree, huffmanTree) bool
+
+var sortHuffmanTreeItems_gaps = []uint{132, 57, 23, 10, 4, 1}
+
+func sortHuffmanTreeItems(items []huffmanTree, n uint, comparator huffmanTreeComparator) {
+ if n < 13 {
+ /* Insertion sort. */
+ var i uint
+ for i = 1; i < n; i++ {
+ var tmp huffmanTree = items[i]
+ var k uint = i
+ var j uint = i - 1
+ for comparator(tmp, items[j]) {
+ items[k] = items[j]
+ k = j
+ if j == 0 {
+ break
+ }
+ j--
+ }
+
+ items[k] = tmp
+ }
+
+ return
+ } else {
+ var g int
+ if n < 57 {
+ g = 2
+ } else {
+ g = 0
+ }
+ for ; g < 6; g++ {
+ var gap uint = sortHuffmanTreeItems_gaps[g]
+ var i uint
+ for i = gap; i < n; i++ {
+ var j uint = i
+ var tmp huffmanTree = items[i]
+ for ; j >= gap && comparator(tmp, items[j-gap]); j -= gap {
+ items[j] = items[j-gap]
+ }
+
+ items[j] = tmp
+ }
+ }
+ }
+}
+
+/* Returns 1 if assignment of depths succeeded, otherwise 0. */
+func setDepth(p0 int, pool []huffmanTree, depth []byte, max_depth int) bool {
+ var stack [16]int
+ var level int = 0
+ var p int = p0
+ assert(max_depth <= 15)
+ stack[0] = -1
+ for {
+ if pool[p].index_left_ >= 0 {
+ level++
+ if level > max_depth {
+ return false
+ }
+ stack[level] = int(pool[p].index_right_or_value_)
+ p = int(pool[p].index_left_)
+ continue
+ } else {
+ depth[pool[p].index_right_or_value_] = byte(level)
+ }
+
+ for level >= 0 && stack[level] == -1 {
+ level--
+ }
+ if level < 0 {
+ return true
+ }
+ p = stack[level]
+ stack[level] = -1
+ }
+}
+
+/* Sort the root nodes, least popular first. */
+func sortHuffmanTree(v0 huffmanTree, v1 huffmanTree) bool {
+ if v0.total_count_ != v1.total_count_ {
+ return v0.total_count_ < v1.total_count_
+ }
+
+ return v0.index_right_or_value_ > v1.index_right_or_value_
+}
+
+/* This function will create a Huffman tree.
+
+ The catch here is that the tree cannot be arbitrarily deep.
+ Brotli specifies a maximum depth of 15 bits for "code trees"
+ and 7 bits for "code length code trees."
+
+ count_limit is the value that is to be faked as the minimum value
+ and this minimum value is raised until the tree matches the
+ maximum length requirement.
+
+ This algorithm is not of excellent performance for very long data blocks,
+ especially when population counts are longer than 2**tree_limit, but
+ we are not planning to use this with extremely long blocks.
+
+ See http://en.wikipedia.org/wiki/Huffman_coding */
+func createHuffmanTree(data []uint32, length uint, tree_limit int, tree []huffmanTree, depth []byte) {
+ var count_limit uint32
+ var sentinel huffmanTree
+ initHuffmanTree(&sentinel, math.MaxUint32, -1, -1)
+
+ /* For block sizes below 64 kB, we never need to do a second iteration
+ of this loop. Probably all of our block sizes will be smaller than
+ that, so this loop is mostly of academic interest. If we actually
+ would need this, we would be better off with the Katajainen algorithm. */
+ for count_limit = 1; ; count_limit *= 2 {
+ var n uint = 0
+ var i uint
+ var j uint
+ var k uint
+ for i = length; i != 0; {
+ i--
+ if data[i] != 0 {
+ var count uint32 = brotli_max_uint32_t(data[i], count_limit)
+ initHuffmanTree(&tree[n], count, -1, int16(i))
+ n++
+ }
+ }
+
+ if n == 1 {
+ depth[tree[0].index_right_or_value_] = 1 /* Only one element. */
+ break
+ }
+
+ sortHuffmanTreeItems(tree, n, huffmanTreeComparator(sortHuffmanTree))
+
+ /* The nodes are:
+ [0, n): the sorted leaf nodes that we start with.
+ [n]: we add a sentinel here.
+ [n + 1, 2n): new parent nodes are added here, starting from
+ (n+1). These are naturally in ascending order.
+ [2n]: we add a sentinel at the end as well.
+ There will be (2n+1) elements at the end. */
+ tree[n] = sentinel
+
+ tree[n+1] = sentinel
+
+ i = 0 /* Points to the next leaf node. */
+ j = n + 1 /* Points to the next non-leaf node. */
+ for k = n - 1; k != 0; k-- {
+ var left uint
+ var right uint
+ if tree[i].total_count_ <= tree[j].total_count_ {
+ left = i
+ i++
+ } else {
+ left = j
+ j++
+ }
+
+ if tree[i].total_count_ <= tree[j].total_count_ {
+ right = i
+ i++
+ } else {
+ right = j
+ j++
+ }
+ {
+ /* The sentinel node becomes the parent node. */
+ var j_end uint = 2*n - k
+ tree[j_end].total_count_ = tree[left].total_count_ + tree[right].total_count_
+ tree[j_end].index_left_ = int16(left)
+ tree[j_end].index_right_or_value_ = int16(right)
+
+ /* Add back the last sentinel node. */
+ tree[j_end+1] = sentinel
+ }
+ }
+
+ if setDepth(int(2*n-1), tree[0:], depth, tree_limit) {
+ /* We need to pack the Huffman tree in tree_limit bits. If this was not
+ successful, add fake entities to the lowest values and retry. */
+ break
+ }
+ }
+}
+
+func reverse(v []byte, start uint, end uint) {
+ end--
+ for start < end {
+ var tmp byte = v[start]
+ v[start] = v[end]
+ v[end] = tmp
+ start++
+ end--
+ }
+}
+
+func writeHuffmanTreeRepetitions(previous_value byte, value byte, repetitions uint, tree_size *uint, tree []byte, extra_bits_data []byte) {
+ assert(repetitions > 0)
+ if previous_value != value {
+ tree[*tree_size] = value
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ repetitions--
+ }
+
+ if repetitions == 7 {
+ tree[*tree_size] = value
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ repetitions--
+ }
+
+ if repetitions < 3 {
+ var i uint
+ for i = 0; i < repetitions; i++ {
+ tree[*tree_size] = value
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ }
+ } else {
+ var start uint = *tree_size
+ repetitions -= 3
+ for {
+ tree[*tree_size] = repeatPreviousCodeLength
+ extra_bits_data[*tree_size] = byte(repetitions & 0x3)
+ (*tree_size)++
+ repetitions >>= 2
+ if repetitions == 0 {
+ break
+ }
+
+ repetitions--
+ }
+
+ reverse(tree, start, *tree_size)
+ reverse(extra_bits_data, start, *tree_size)
+ }
+}
+
+func writeHuffmanTreeRepetitionsZeros(repetitions uint, tree_size *uint, tree []byte, extra_bits_data []byte) {
+ if repetitions == 11 {
+ tree[*tree_size] = 0
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ repetitions--
+ }
+
+ if repetitions < 3 {
+ var i uint
+ for i = 0; i < repetitions; i++ {
+ tree[*tree_size] = 0
+ extra_bits_data[*tree_size] = 0
+ (*tree_size)++
+ }
+ } else {
+ var start uint = *tree_size
+ repetitions -= 3
+ for {
+ tree[*tree_size] = repeatZeroCodeLength
+ extra_bits_data[*tree_size] = byte(repetitions & 0x7)
+ (*tree_size)++
+ repetitions >>= 3
+ if repetitions == 0 {
+ break
+ }
+
+ repetitions--
+ }
+
+ reverse(tree, start, *tree_size)
+ reverse(extra_bits_data, start, *tree_size)
+ }
+}
+
+/* Change the population counts in a way that the consequent
+ Huffman tree compression, especially its RLE-part will be more
+ likely to compress this data more efficiently.
+
+ length contains the size of the histogram.
+ counts contains the population counts.
+ good_for_rle is a buffer of at least length size */
+func optimizeHuffmanCountsForRLE(length uint, counts []uint32, good_for_rle []byte) {
+ var nonzero_count uint = 0
+ var stride uint
+ var limit uint
+ var sum uint
+ var streak_limit uint = 1240
+ var i uint
+ /* Let's make the Huffman code more compatible with RLE encoding. */
+ for i = 0; i < length; i++ {
+ if counts[i] != 0 {
+ nonzero_count++
+ }
+ }
+
+ if nonzero_count < 16 {
+ return
+ }
+
+ for length != 0 && counts[length-1] == 0 {
+ length--
+ }
+
+ if length == 0 {
+ return /* All zeros. */
+ }
+
+ /* Now counts[0..length - 1] does not have trailing zeros. */
+ {
+ var nonzeros uint = 0
+ var smallest_nonzero uint32 = 1 << 30
+ for i = 0; i < length; i++ {
+ if counts[i] != 0 {
+ nonzeros++
+ if smallest_nonzero > counts[i] {
+ smallest_nonzero = counts[i]
+ }
+ }
+ }
+
+ if nonzeros < 5 {
+ /* Small histogram will model it well. */
+ return
+ }
+
+ if smallest_nonzero < 4 {
+ var zeros uint = length - nonzeros
+ if zeros < 6 {
+ for i = 1; i < length-1; i++ {
+ if counts[i-1] != 0 && counts[i] == 0 && counts[i+1] != 0 {
+ counts[i] = 1
+ }
+ }
+ }
+ }
+
+ if nonzeros < 28 {
+ return
+ }
+ }
+
+ /* 2) Let's mark all population counts that already can be encoded
+ with an RLE code. */
+ for i := 0; i < int(length); i++ {
+ good_for_rle[i] = 0
+ }
+ {
+ var symbol uint32 = counts[0]
+ /* Let's not spoil any of the existing good RLE codes.
+ Mark any seq of 0's that is longer as 5 as a good_for_rle.
+ Mark any seq of non-0's that is longer as 7 as a good_for_rle. */
+
+ var step uint = 0
+ for i = 0; i <= length; i++ {
+ if i == length || counts[i] != symbol {
+ if (symbol == 0 && step >= 5) || (symbol != 0 && step >= 7) {
+ var k uint
+ for k = 0; k < step; k++ {
+ good_for_rle[i-k-1] = 1
+ }
+ }
+
+ step = 1
+ if i != length {
+ symbol = counts[i]
+ }
+ } else {
+ step++
+ }
+ }
+ }
+
+ /* 3) Let's replace those population counts that lead to more RLE codes.
+ Math here is in 24.8 fixed point representation. */
+ stride = 0
+
+ limit = uint(256*(counts[0]+counts[1]+counts[2])/3 + 420)
+ sum = 0
+ for i = 0; i <= length; i++ {
+ if i == length || good_for_rle[i] != 0 || (i != 0 && good_for_rle[i-1] != 0) || (256*counts[i]-uint32(limit)+uint32(streak_limit)) >= uint32(2*streak_limit) {
+ if stride >= 4 || (stride >= 3 && sum == 0) {
+ var k uint
+ var count uint = (sum + stride/2) / stride
+ /* The stride must end, collapse what we have, if we have enough (4). */
+ if count == 0 {
+ count = 1
+ }
+
+ if sum == 0 {
+ /* Don't make an all zeros stride to be upgraded to ones. */
+ count = 0
+ }
+
+ for k = 0; k < stride; k++ {
+ /* We don't want to change value at counts[i],
+ that is already belonging to the next stride. Thus - 1. */
+ counts[i-k-1] = uint32(count)
+ }
+ }
+
+ stride = 0
+ sum = 0
+ if i < length-2 {
+ /* All interesting strides have a count of at least 4, */
+ /* at least when non-zeros. */
+ limit = uint(256*(counts[i]+counts[i+1]+counts[i+2])/3 + 420)
+ } else if i < length {
+ limit = uint(256 * counts[i])
+ } else {
+ limit = 0
+ }
+ }
+
+ stride++
+ if i != length {
+ sum += uint(counts[i])
+ if stride >= 4 {
+ limit = (256*sum + stride/2) / stride
+ }
+
+ if stride == 4 {
+ limit += 120
+ }
+ }
+ }
+}
+
+func decideOverRLEUse(depth []byte, length uint, use_rle_for_non_zero *bool, use_rle_for_zero *bool) {
+ var total_reps_zero uint = 0
+ var total_reps_non_zero uint = 0
+ var count_reps_zero uint = 1
+ var count_reps_non_zero uint = 1
+ var i uint
+ for i = 0; i < length; {
+ var value byte = depth[i]
+ var reps uint = 1
+ var k uint
+ for k = i + 1; k < length && depth[k] == value; k++ {
+ reps++
+ }
+
+ if reps >= 3 && value == 0 {
+ total_reps_zero += reps
+ count_reps_zero++
+ }
+
+ if reps >= 4 && value != 0 {
+ total_reps_non_zero += reps
+ count_reps_non_zero++
+ }
+
+ i += reps
+ }
+
+ *use_rle_for_non_zero = total_reps_non_zero > count_reps_non_zero*2
+ *use_rle_for_zero = total_reps_zero > count_reps_zero*2
+}
+
+/* Write a Huffman tree from bit depths into the bit-stream representation
+ of a Huffman tree. The generated Huffman tree is to be compressed once
+ more using a Huffman tree */
+func writeHuffmanTree(depth []byte, length uint, tree_size *uint, tree []byte, extra_bits_data []byte) {
+ var previous_value byte = initialRepeatedCodeLength
+ var i uint
+ var use_rle_for_non_zero bool = false
+ var use_rle_for_zero bool = false
+ var new_length uint = length
+ /* Throw away trailing zeros. */
+ for i = 0; i < length; i++ {
+ if depth[length-i-1] == 0 {
+ new_length--
+ } else {
+ break
+ }
+ }
+
+ /* First gather statistics on if it is a good idea to do RLE. */
+ if length > 50 {
+ /* Find RLE coding for longer codes.
+ Shorter codes seem not to benefit from RLE. */
+ decideOverRLEUse(depth, new_length, &use_rle_for_non_zero, &use_rle_for_zero)
+ }
+
+ /* Actual RLE coding. */
+ for i = 0; i < new_length; {
+ var value byte = depth[i]
+ var reps uint = 1
+ if (value != 0 && use_rle_for_non_zero) || (value == 0 && use_rle_for_zero) {
+ var k uint
+ for k = i + 1; k < new_length && depth[k] == value; k++ {
+ reps++
+ }
+ }
+
+ if value == 0 {
+ writeHuffmanTreeRepetitionsZeros(reps, tree_size, tree, extra_bits_data)
+ } else {
+ writeHuffmanTreeRepetitions(previous_value, value, reps, tree_size, tree, extra_bits_data)
+ previous_value = value
+ }
+
+ i += reps
+ }
+}
+
+var reverseBits_kLut = [16]uint{
+ 0x00,
+ 0x08,
+ 0x04,
+ 0x0C,
+ 0x02,
+ 0x0A,
+ 0x06,
+ 0x0E,
+ 0x01,
+ 0x09,
+ 0x05,
+ 0x0D,
+ 0x03,
+ 0x0B,
+ 0x07,
+ 0x0F,
+}
+
+func reverseBits(num_bits uint, bits uint16) uint16 {
+ var retval uint = reverseBits_kLut[bits&0x0F]
+ var i uint
+ for i = 4; i < num_bits; i += 4 {
+ retval <<= 4
+ bits = uint16(bits >> 4)
+ retval |= reverseBits_kLut[bits&0x0F]
+ }
+
+ retval >>= ((0 - num_bits) & 0x03)
+ return uint16(retval)
+}
+
+/* 0..15 are values for bits */
+const maxHuffmanBits = 16
+
+/* Get the actual bit values for a tree of bit depths. */
+func convertBitDepthsToSymbols(depth []byte, len uint, bits []uint16) {
+ var bl_count = [maxHuffmanBits]uint16{0}
+ var next_code [maxHuffmanBits]uint16
+ var i uint
+ /* In Brotli, all bit depths are [1..15]
+ 0 bit depth means that the symbol does not exist. */
+
+ var code int = 0
+ for i = 0; i < len; i++ {
+ bl_count[depth[i]]++
+ }
+
+ bl_count[0] = 0
+ next_code[0] = 0
+ for i = 1; i < maxHuffmanBits; i++ {
+ code = (code + int(bl_count[i-1])) << 1
+ next_code[i] = uint16(code)
+ }
+
+ for i = 0; i < len; i++ {
+ if depth[i] != 0 {
+ bits[i] = reverseBits(uint(depth[i]), next_code[depth[i]])
+ next_code[depth[i]]++
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/entropy_encode_static.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/entropy_encode_static.go
new file mode 100644
index 000000000000..5ddf3fcbaef3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/entropy_encode_static.go
@@ -0,0 +1,4394 @@
+package brotli
+
+var kCodeLengthDepth = [18]byte{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4}
+
+var kStaticCommandCodeDepth = [numCommandSymbols]byte{
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 9,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+ 11,
+}
+
+var kStaticDistanceCodeDepth = [64]byte{
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+}
+
+var kCodeLengthBits = [18]uint32{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7}
+
+func storeStaticCodeLengthCode(storage_ix *uint, storage []byte) {
+ writeBits(40, 0x0000FF55555554, storage_ix, storage)
+}
+
+var kZeroRepsBits = [numCommandSymbols]uint64{
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000007,
+ 0x00000017,
+ 0x00000027,
+ 0x00000037,
+ 0x00000047,
+ 0x00000057,
+ 0x00000067,
+ 0x00000077,
+ 0x00000770,
+ 0x00000b87,
+ 0x00001387,
+ 0x00001b87,
+ 0x00002387,
+ 0x00002b87,
+ 0x00003387,
+ 0x00003b87,
+ 0x00000397,
+ 0x00000b97,
+ 0x00001397,
+ 0x00001b97,
+ 0x00002397,
+ 0x00002b97,
+ 0x00003397,
+ 0x00003b97,
+ 0x000003a7,
+ 0x00000ba7,
+ 0x000013a7,
+ 0x00001ba7,
+ 0x000023a7,
+ 0x00002ba7,
+ 0x000033a7,
+ 0x00003ba7,
+ 0x000003b7,
+ 0x00000bb7,
+ 0x000013b7,
+ 0x00001bb7,
+ 0x000023b7,
+ 0x00002bb7,
+ 0x000033b7,
+ 0x00003bb7,
+ 0x000003c7,
+ 0x00000bc7,
+ 0x000013c7,
+ 0x00001bc7,
+ 0x000023c7,
+ 0x00002bc7,
+ 0x000033c7,
+ 0x00003bc7,
+ 0x000003d7,
+ 0x00000bd7,
+ 0x000013d7,
+ 0x00001bd7,
+ 0x000023d7,
+ 0x00002bd7,
+ 0x000033d7,
+ 0x00003bd7,
+ 0x000003e7,
+ 0x00000be7,
+ 0x000013e7,
+ 0x00001be7,
+ 0x000023e7,
+ 0x00002be7,
+ 0x000033e7,
+ 0x00003be7,
+ 0x000003f7,
+ 0x00000bf7,
+ 0x000013f7,
+ 0x00001bf7,
+ 0x000023f7,
+ 0x00002bf7,
+ 0x000033f7,
+ 0x00003bf7,
+ 0x0001c387,
+ 0x0005c387,
+ 0x0009c387,
+ 0x000dc387,
+ 0x0011c387,
+ 0x0015c387,
+ 0x0019c387,
+ 0x001dc387,
+ 0x0001cb87,
+ 0x0005cb87,
+ 0x0009cb87,
+ 0x000dcb87,
+ 0x0011cb87,
+ 0x0015cb87,
+ 0x0019cb87,
+ 0x001dcb87,
+ 0x0001d387,
+ 0x0005d387,
+ 0x0009d387,
+ 0x000dd387,
+ 0x0011d387,
+ 0x0015d387,
+ 0x0019d387,
+ 0x001dd387,
+ 0x0001db87,
+ 0x0005db87,
+ 0x0009db87,
+ 0x000ddb87,
+ 0x0011db87,
+ 0x0015db87,
+ 0x0019db87,
+ 0x001ddb87,
+ 0x0001e387,
+ 0x0005e387,
+ 0x0009e387,
+ 0x000de387,
+ 0x0011e387,
+ 0x0015e387,
+ 0x0019e387,
+ 0x001de387,
+ 0x0001eb87,
+ 0x0005eb87,
+ 0x0009eb87,
+ 0x000deb87,
+ 0x0011eb87,
+ 0x0015eb87,
+ 0x0019eb87,
+ 0x001deb87,
+ 0x0001f387,
+ 0x0005f387,
+ 0x0009f387,
+ 0x000df387,
+ 0x0011f387,
+ 0x0015f387,
+ 0x0019f387,
+ 0x001df387,
+ 0x0001fb87,
+ 0x0005fb87,
+ 0x0009fb87,
+ 0x000dfb87,
+ 0x0011fb87,
+ 0x0015fb87,
+ 0x0019fb87,
+ 0x001dfb87,
+ 0x0001c397,
+ 0x0005c397,
+ 0x0009c397,
+ 0x000dc397,
+ 0x0011c397,
+ 0x0015c397,
+ 0x0019c397,
+ 0x001dc397,
+ 0x0001cb97,
+ 0x0005cb97,
+ 0x0009cb97,
+ 0x000dcb97,
+ 0x0011cb97,
+ 0x0015cb97,
+ 0x0019cb97,
+ 0x001dcb97,
+ 0x0001d397,
+ 0x0005d397,
+ 0x0009d397,
+ 0x000dd397,
+ 0x0011d397,
+ 0x0015d397,
+ 0x0019d397,
+ 0x001dd397,
+ 0x0001db97,
+ 0x0005db97,
+ 0x0009db97,
+ 0x000ddb97,
+ 0x0011db97,
+ 0x0015db97,
+ 0x0019db97,
+ 0x001ddb97,
+ 0x0001e397,
+ 0x0005e397,
+ 0x0009e397,
+ 0x000de397,
+ 0x0011e397,
+ 0x0015e397,
+ 0x0019e397,
+ 0x001de397,
+ 0x0001eb97,
+ 0x0005eb97,
+ 0x0009eb97,
+ 0x000deb97,
+ 0x0011eb97,
+ 0x0015eb97,
+ 0x0019eb97,
+ 0x001deb97,
+ 0x0001f397,
+ 0x0005f397,
+ 0x0009f397,
+ 0x000df397,
+ 0x0011f397,
+ 0x0015f397,
+ 0x0019f397,
+ 0x001df397,
+ 0x0001fb97,
+ 0x0005fb97,
+ 0x0009fb97,
+ 0x000dfb97,
+ 0x0011fb97,
+ 0x0015fb97,
+ 0x0019fb97,
+ 0x001dfb97,
+ 0x0001c3a7,
+ 0x0005c3a7,
+ 0x0009c3a7,
+ 0x000dc3a7,
+ 0x0011c3a7,
+ 0x0015c3a7,
+ 0x0019c3a7,
+ 0x001dc3a7,
+ 0x0001cba7,
+ 0x0005cba7,
+ 0x0009cba7,
+ 0x000dcba7,
+ 0x0011cba7,
+ 0x0015cba7,
+ 0x0019cba7,
+ 0x001dcba7,
+ 0x0001d3a7,
+ 0x0005d3a7,
+ 0x0009d3a7,
+ 0x000dd3a7,
+ 0x0011d3a7,
+ 0x0015d3a7,
+ 0x0019d3a7,
+ 0x001dd3a7,
+ 0x0001dba7,
+ 0x0005dba7,
+ 0x0009dba7,
+ 0x000ddba7,
+ 0x0011dba7,
+ 0x0015dba7,
+ 0x0019dba7,
+ 0x001ddba7,
+ 0x0001e3a7,
+ 0x0005e3a7,
+ 0x0009e3a7,
+ 0x000de3a7,
+ 0x0011e3a7,
+ 0x0015e3a7,
+ 0x0019e3a7,
+ 0x001de3a7,
+ 0x0001eba7,
+ 0x0005eba7,
+ 0x0009eba7,
+ 0x000deba7,
+ 0x0011eba7,
+ 0x0015eba7,
+ 0x0019eba7,
+ 0x001deba7,
+ 0x0001f3a7,
+ 0x0005f3a7,
+ 0x0009f3a7,
+ 0x000df3a7,
+ 0x0011f3a7,
+ 0x0015f3a7,
+ 0x0019f3a7,
+ 0x001df3a7,
+ 0x0001fba7,
+ 0x0005fba7,
+ 0x0009fba7,
+ 0x000dfba7,
+ 0x0011fba7,
+ 0x0015fba7,
+ 0x0019fba7,
+ 0x001dfba7,
+ 0x0001c3b7,
+ 0x0005c3b7,
+ 0x0009c3b7,
+ 0x000dc3b7,
+ 0x0011c3b7,
+ 0x0015c3b7,
+ 0x0019c3b7,
+ 0x001dc3b7,
+ 0x0001cbb7,
+ 0x0005cbb7,
+ 0x0009cbb7,
+ 0x000dcbb7,
+ 0x0011cbb7,
+ 0x0015cbb7,
+ 0x0019cbb7,
+ 0x001dcbb7,
+ 0x0001d3b7,
+ 0x0005d3b7,
+ 0x0009d3b7,
+ 0x000dd3b7,
+ 0x0011d3b7,
+ 0x0015d3b7,
+ 0x0019d3b7,
+ 0x001dd3b7,
+ 0x0001dbb7,
+ 0x0005dbb7,
+ 0x0009dbb7,
+ 0x000ddbb7,
+ 0x0011dbb7,
+ 0x0015dbb7,
+ 0x0019dbb7,
+ 0x001ddbb7,
+ 0x0001e3b7,
+ 0x0005e3b7,
+ 0x0009e3b7,
+ 0x000de3b7,
+ 0x0011e3b7,
+ 0x0015e3b7,
+ 0x0019e3b7,
+ 0x001de3b7,
+ 0x0001ebb7,
+ 0x0005ebb7,
+ 0x0009ebb7,
+ 0x000debb7,
+ 0x0011ebb7,
+ 0x0015ebb7,
+ 0x0019ebb7,
+ 0x001debb7,
+ 0x0001f3b7,
+ 0x0005f3b7,
+ 0x0009f3b7,
+ 0x000df3b7,
+ 0x0011f3b7,
+ 0x0015f3b7,
+ 0x0019f3b7,
+ 0x001df3b7,
+ 0x0001fbb7,
+ 0x0005fbb7,
+ 0x0009fbb7,
+ 0x000dfbb7,
+ 0x0011fbb7,
+ 0x0015fbb7,
+ 0x0019fbb7,
+ 0x001dfbb7,
+ 0x0001c3c7,
+ 0x0005c3c7,
+ 0x0009c3c7,
+ 0x000dc3c7,
+ 0x0011c3c7,
+ 0x0015c3c7,
+ 0x0019c3c7,
+ 0x001dc3c7,
+ 0x0001cbc7,
+ 0x0005cbc7,
+ 0x0009cbc7,
+ 0x000dcbc7,
+ 0x0011cbc7,
+ 0x0015cbc7,
+ 0x0019cbc7,
+ 0x001dcbc7,
+ 0x0001d3c7,
+ 0x0005d3c7,
+ 0x0009d3c7,
+ 0x000dd3c7,
+ 0x0011d3c7,
+ 0x0015d3c7,
+ 0x0019d3c7,
+ 0x001dd3c7,
+ 0x0001dbc7,
+ 0x0005dbc7,
+ 0x0009dbc7,
+ 0x000ddbc7,
+ 0x0011dbc7,
+ 0x0015dbc7,
+ 0x0019dbc7,
+ 0x001ddbc7,
+ 0x0001e3c7,
+ 0x0005e3c7,
+ 0x0009e3c7,
+ 0x000de3c7,
+ 0x0011e3c7,
+ 0x0015e3c7,
+ 0x0019e3c7,
+ 0x001de3c7,
+ 0x0001ebc7,
+ 0x0005ebc7,
+ 0x0009ebc7,
+ 0x000debc7,
+ 0x0011ebc7,
+ 0x0015ebc7,
+ 0x0019ebc7,
+ 0x001debc7,
+ 0x0001f3c7,
+ 0x0005f3c7,
+ 0x0009f3c7,
+ 0x000df3c7,
+ 0x0011f3c7,
+ 0x0015f3c7,
+ 0x0019f3c7,
+ 0x001df3c7,
+ 0x0001fbc7,
+ 0x0005fbc7,
+ 0x0009fbc7,
+ 0x000dfbc7,
+ 0x0011fbc7,
+ 0x0015fbc7,
+ 0x0019fbc7,
+ 0x001dfbc7,
+ 0x0001c3d7,
+ 0x0005c3d7,
+ 0x0009c3d7,
+ 0x000dc3d7,
+ 0x0011c3d7,
+ 0x0015c3d7,
+ 0x0019c3d7,
+ 0x001dc3d7,
+ 0x0001cbd7,
+ 0x0005cbd7,
+ 0x0009cbd7,
+ 0x000dcbd7,
+ 0x0011cbd7,
+ 0x0015cbd7,
+ 0x0019cbd7,
+ 0x001dcbd7,
+ 0x0001d3d7,
+ 0x0005d3d7,
+ 0x0009d3d7,
+ 0x000dd3d7,
+ 0x0011d3d7,
+ 0x0015d3d7,
+ 0x0019d3d7,
+ 0x001dd3d7,
+ 0x0001dbd7,
+ 0x0005dbd7,
+ 0x0009dbd7,
+ 0x000ddbd7,
+ 0x0011dbd7,
+ 0x0015dbd7,
+ 0x0019dbd7,
+ 0x001ddbd7,
+ 0x0001e3d7,
+ 0x0005e3d7,
+ 0x0009e3d7,
+ 0x000de3d7,
+ 0x0011e3d7,
+ 0x0015e3d7,
+ 0x0019e3d7,
+ 0x001de3d7,
+ 0x0001ebd7,
+ 0x0005ebd7,
+ 0x0009ebd7,
+ 0x000debd7,
+ 0x0011ebd7,
+ 0x0015ebd7,
+ 0x0019ebd7,
+ 0x001debd7,
+ 0x0001f3d7,
+ 0x0005f3d7,
+ 0x0009f3d7,
+ 0x000df3d7,
+ 0x0011f3d7,
+ 0x0015f3d7,
+ 0x0019f3d7,
+ 0x001df3d7,
+ 0x0001fbd7,
+ 0x0005fbd7,
+ 0x0009fbd7,
+ 0x000dfbd7,
+ 0x0011fbd7,
+ 0x0015fbd7,
+ 0x0019fbd7,
+ 0x001dfbd7,
+ 0x0001c3e7,
+ 0x0005c3e7,
+ 0x0009c3e7,
+ 0x000dc3e7,
+ 0x0011c3e7,
+ 0x0015c3e7,
+ 0x0019c3e7,
+ 0x001dc3e7,
+ 0x0001cbe7,
+ 0x0005cbe7,
+ 0x0009cbe7,
+ 0x000dcbe7,
+ 0x0011cbe7,
+ 0x0015cbe7,
+ 0x0019cbe7,
+ 0x001dcbe7,
+ 0x0001d3e7,
+ 0x0005d3e7,
+ 0x0009d3e7,
+ 0x000dd3e7,
+ 0x0011d3e7,
+ 0x0015d3e7,
+ 0x0019d3e7,
+ 0x001dd3e7,
+ 0x0001dbe7,
+ 0x0005dbe7,
+ 0x0009dbe7,
+ 0x000ddbe7,
+ 0x0011dbe7,
+ 0x0015dbe7,
+ 0x0019dbe7,
+ 0x001ddbe7,
+ 0x0001e3e7,
+ 0x0005e3e7,
+ 0x0009e3e7,
+ 0x000de3e7,
+ 0x0011e3e7,
+ 0x0015e3e7,
+ 0x0019e3e7,
+ 0x001de3e7,
+ 0x0001ebe7,
+ 0x0005ebe7,
+ 0x0009ebe7,
+ 0x000debe7,
+ 0x0011ebe7,
+ 0x0015ebe7,
+ 0x0019ebe7,
+ 0x001debe7,
+ 0x0001f3e7,
+ 0x0005f3e7,
+ 0x0009f3e7,
+ 0x000df3e7,
+ 0x0011f3e7,
+ 0x0015f3e7,
+ 0x0019f3e7,
+ 0x001df3e7,
+ 0x0001fbe7,
+ 0x0005fbe7,
+ 0x0009fbe7,
+ 0x000dfbe7,
+ 0x0011fbe7,
+ 0x0015fbe7,
+ 0x0019fbe7,
+ 0x001dfbe7,
+ 0x0001c3f7,
+ 0x0005c3f7,
+ 0x0009c3f7,
+ 0x000dc3f7,
+ 0x0011c3f7,
+ 0x0015c3f7,
+ 0x0019c3f7,
+ 0x001dc3f7,
+ 0x0001cbf7,
+ 0x0005cbf7,
+ 0x0009cbf7,
+ 0x000dcbf7,
+ 0x0011cbf7,
+ 0x0015cbf7,
+ 0x0019cbf7,
+ 0x001dcbf7,
+ 0x0001d3f7,
+ 0x0005d3f7,
+ 0x0009d3f7,
+ 0x000dd3f7,
+ 0x0011d3f7,
+ 0x0015d3f7,
+ 0x0019d3f7,
+ 0x001dd3f7,
+ 0x0001dbf7,
+ 0x0005dbf7,
+ 0x0009dbf7,
+ 0x000ddbf7,
+ 0x0011dbf7,
+ 0x0015dbf7,
+ 0x0019dbf7,
+ 0x001ddbf7,
+ 0x0001e3f7,
+ 0x0005e3f7,
+ 0x0009e3f7,
+ 0x000de3f7,
+ 0x0011e3f7,
+ 0x0015e3f7,
+ 0x0019e3f7,
+ 0x001de3f7,
+ 0x0001ebf7,
+ 0x0005ebf7,
+ 0x0009ebf7,
+ 0x000debf7,
+ 0x0011ebf7,
+ 0x0015ebf7,
+ 0x0019ebf7,
+ 0x001debf7,
+ 0x0001f3f7,
+ 0x0005f3f7,
+ 0x0009f3f7,
+ 0x000df3f7,
+ 0x0011f3f7,
+ 0x0015f3f7,
+ 0x0019f3f7,
+ 0x001df3f7,
+ 0x0001fbf7,
+ 0x0005fbf7,
+ 0x0009fbf7,
+ 0x000dfbf7,
+ 0x0011fbf7,
+ 0x0015fbf7,
+ 0x0019fbf7,
+ 0x001dfbf7,
+ 0x00e1c387,
+ 0x02e1c387,
+ 0x04e1c387,
+ 0x06e1c387,
+ 0x08e1c387,
+ 0x0ae1c387,
+ 0x0ce1c387,
+ 0x0ee1c387,
+ 0x00e5c387,
+ 0x02e5c387,
+ 0x04e5c387,
+ 0x06e5c387,
+ 0x08e5c387,
+ 0x0ae5c387,
+ 0x0ce5c387,
+ 0x0ee5c387,
+ 0x00e9c387,
+ 0x02e9c387,
+ 0x04e9c387,
+ 0x06e9c387,
+ 0x08e9c387,
+ 0x0ae9c387,
+ 0x0ce9c387,
+ 0x0ee9c387,
+ 0x00edc387,
+ 0x02edc387,
+ 0x04edc387,
+ 0x06edc387,
+ 0x08edc387,
+ 0x0aedc387,
+ 0x0cedc387,
+ 0x0eedc387,
+ 0x00f1c387,
+ 0x02f1c387,
+ 0x04f1c387,
+ 0x06f1c387,
+ 0x08f1c387,
+ 0x0af1c387,
+ 0x0cf1c387,
+ 0x0ef1c387,
+ 0x00f5c387,
+ 0x02f5c387,
+ 0x04f5c387,
+ 0x06f5c387,
+ 0x08f5c387,
+ 0x0af5c387,
+ 0x0cf5c387,
+ 0x0ef5c387,
+ 0x00f9c387,
+ 0x02f9c387,
+ 0x04f9c387,
+ 0x06f9c387,
+ 0x08f9c387,
+ 0x0af9c387,
+ 0x0cf9c387,
+ 0x0ef9c387,
+ 0x00fdc387,
+ 0x02fdc387,
+ 0x04fdc387,
+ 0x06fdc387,
+ 0x08fdc387,
+ 0x0afdc387,
+ 0x0cfdc387,
+ 0x0efdc387,
+ 0x00e1cb87,
+ 0x02e1cb87,
+ 0x04e1cb87,
+ 0x06e1cb87,
+ 0x08e1cb87,
+ 0x0ae1cb87,
+ 0x0ce1cb87,
+ 0x0ee1cb87,
+ 0x00e5cb87,
+ 0x02e5cb87,
+ 0x04e5cb87,
+ 0x06e5cb87,
+ 0x08e5cb87,
+ 0x0ae5cb87,
+ 0x0ce5cb87,
+ 0x0ee5cb87,
+ 0x00e9cb87,
+ 0x02e9cb87,
+ 0x04e9cb87,
+ 0x06e9cb87,
+ 0x08e9cb87,
+ 0x0ae9cb87,
+ 0x0ce9cb87,
+ 0x0ee9cb87,
+ 0x00edcb87,
+ 0x02edcb87,
+ 0x04edcb87,
+ 0x06edcb87,
+ 0x08edcb87,
+ 0x0aedcb87,
+ 0x0cedcb87,
+ 0x0eedcb87,
+ 0x00f1cb87,
+ 0x02f1cb87,
+ 0x04f1cb87,
+ 0x06f1cb87,
+ 0x08f1cb87,
+ 0x0af1cb87,
+ 0x0cf1cb87,
+ 0x0ef1cb87,
+ 0x00f5cb87,
+ 0x02f5cb87,
+ 0x04f5cb87,
+ 0x06f5cb87,
+ 0x08f5cb87,
+ 0x0af5cb87,
+ 0x0cf5cb87,
+ 0x0ef5cb87,
+ 0x00f9cb87,
+ 0x02f9cb87,
+ 0x04f9cb87,
+ 0x06f9cb87,
+ 0x08f9cb87,
+}
+
+var kZeroRepsDepth = [numCommandSymbols]uint32{
+ 0,
+ 4,
+ 8,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 11,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 21,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+ 28,
+}
+
+var kNonZeroRepsBits = [numCommandSymbols]uint64{
+ 0x0000000b,
+ 0x0000001b,
+ 0x0000002b,
+ 0x0000003b,
+ 0x000002cb,
+ 0x000006cb,
+ 0x00000acb,
+ 0x00000ecb,
+ 0x000002db,
+ 0x000006db,
+ 0x00000adb,
+ 0x00000edb,
+ 0x000002eb,
+ 0x000006eb,
+ 0x00000aeb,
+ 0x00000eeb,
+ 0x000002fb,
+ 0x000006fb,
+ 0x00000afb,
+ 0x00000efb,
+ 0x0000b2cb,
+ 0x0001b2cb,
+ 0x0002b2cb,
+ 0x0003b2cb,
+ 0x0000b6cb,
+ 0x0001b6cb,
+ 0x0002b6cb,
+ 0x0003b6cb,
+ 0x0000bacb,
+ 0x0001bacb,
+ 0x0002bacb,
+ 0x0003bacb,
+ 0x0000becb,
+ 0x0001becb,
+ 0x0002becb,
+ 0x0003becb,
+ 0x0000b2db,
+ 0x0001b2db,
+ 0x0002b2db,
+ 0x0003b2db,
+ 0x0000b6db,
+ 0x0001b6db,
+ 0x0002b6db,
+ 0x0003b6db,
+ 0x0000badb,
+ 0x0001badb,
+ 0x0002badb,
+ 0x0003badb,
+ 0x0000bedb,
+ 0x0001bedb,
+ 0x0002bedb,
+ 0x0003bedb,
+ 0x0000b2eb,
+ 0x0001b2eb,
+ 0x0002b2eb,
+ 0x0003b2eb,
+ 0x0000b6eb,
+ 0x0001b6eb,
+ 0x0002b6eb,
+ 0x0003b6eb,
+ 0x0000baeb,
+ 0x0001baeb,
+ 0x0002baeb,
+ 0x0003baeb,
+ 0x0000beeb,
+ 0x0001beeb,
+ 0x0002beeb,
+ 0x0003beeb,
+ 0x0000b2fb,
+ 0x0001b2fb,
+ 0x0002b2fb,
+ 0x0003b2fb,
+ 0x0000b6fb,
+ 0x0001b6fb,
+ 0x0002b6fb,
+ 0x0003b6fb,
+ 0x0000bafb,
+ 0x0001bafb,
+ 0x0002bafb,
+ 0x0003bafb,
+ 0x0000befb,
+ 0x0001befb,
+ 0x0002befb,
+ 0x0003befb,
+ 0x002cb2cb,
+ 0x006cb2cb,
+ 0x00acb2cb,
+ 0x00ecb2cb,
+ 0x002db2cb,
+ 0x006db2cb,
+ 0x00adb2cb,
+ 0x00edb2cb,
+ 0x002eb2cb,
+ 0x006eb2cb,
+ 0x00aeb2cb,
+ 0x00eeb2cb,
+ 0x002fb2cb,
+ 0x006fb2cb,
+ 0x00afb2cb,
+ 0x00efb2cb,
+ 0x002cb6cb,
+ 0x006cb6cb,
+ 0x00acb6cb,
+ 0x00ecb6cb,
+ 0x002db6cb,
+ 0x006db6cb,
+ 0x00adb6cb,
+ 0x00edb6cb,
+ 0x002eb6cb,
+ 0x006eb6cb,
+ 0x00aeb6cb,
+ 0x00eeb6cb,
+ 0x002fb6cb,
+ 0x006fb6cb,
+ 0x00afb6cb,
+ 0x00efb6cb,
+ 0x002cbacb,
+ 0x006cbacb,
+ 0x00acbacb,
+ 0x00ecbacb,
+ 0x002dbacb,
+ 0x006dbacb,
+ 0x00adbacb,
+ 0x00edbacb,
+ 0x002ebacb,
+ 0x006ebacb,
+ 0x00aebacb,
+ 0x00eebacb,
+ 0x002fbacb,
+ 0x006fbacb,
+ 0x00afbacb,
+ 0x00efbacb,
+ 0x002cbecb,
+ 0x006cbecb,
+ 0x00acbecb,
+ 0x00ecbecb,
+ 0x002dbecb,
+ 0x006dbecb,
+ 0x00adbecb,
+ 0x00edbecb,
+ 0x002ebecb,
+ 0x006ebecb,
+ 0x00aebecb,
+ 0x00eebecb,
+ 0x002fbecb,
+ 0x006fbecb,
+ 0x00afbecb,
+ 0x00efbecb,
+ 0x002cb2db,
+ 0x006cb2db,
+ 0x00acb2db,
+ 0x00ecb2db,
+ 0x002db2db,
+ 0x006db2db,
+ 0x00adb2db,
+ 0x00edb2db,
+ 0x002eb2db,
+ 0x006eb2db,
+ 0x00aeb2db,
+ 0x00eeb2db,
+ 0x002fb2db,
+ 0x006fb2db,
+ 0x00afb2db,
+ 0x00efb2db,
+ 0x002cb6db,
+ 0x006cb6db,
+ 0x00acb6db,
+ 0x00ecb6db,
+ 0x002db6db,
+ 0x006db6db,
+ 0x00adb6db,
+ 0x00edb6db,
+ 0x002eb6db,
+ 0x006eb6db,
+ 0x00aeb6db,
+ 0x00eeb6db,
+ 0x002fb6db,
+ 0x006fb6db,
+ 0x00afb6db,
+ 0x00efb6db,
+ 0x002cbadb,
+ 0x006cbadb,
+ 0x00acbadb,
+ 0x00ecbadb,
+ 0x002dbadb,
+ 0x006dbadb,
+ 0x00adbadb,
+ 0x00edbadb,
+ 0x002ebadb,
+ 0x006ebadb,
+ 0x00aebadb,
+ 0x00eebadb,
+ 0x002fbadb,
+ 0x006fbadb,
+ 0x00afbadb,
+ 0x00efbadb,
+ 0x002cbedb,
+ 0x006cbedb,
+ 0x00acbedb,
+ 0x00ecbedb,
+ 0x002dbedb,
+ 0x006dbedb,
+ 0x00adbedb,
+ 0x00edbedb,
+ 0x002ebedb,
+ 0x006ebedb,
+ 0x00aebedb,
+ 0x00eebedb,
+ 0x002fbedb,
+ 0x006fbedb,
+ 0x00afbedb,
+ 0x00efbedb,
+ 0x002cb2eb,
+ 0x006cb2eb,
+ 0x00acb2eb,
+ 0x00ecb2eb,
+ 0x002db2eb,
+ 0x006db2eb,
+ 0x00adb2eb,
+ 0x00edb2eb,
+ 0x002eb2eb,
+ 0x006eb2eb,
+ 0x00aeb2eb,
+ 0x00eeb2eb,
+ 0x002fb2eb,
+ 0x006fb2eb,
+ 0x00afb2eb,
+ 0x00efb2eb,
+ 0x002cb6eb,
+ 0x006cb6eb,
+ 0x00acb6eb,
+ 0x00ecb6eb,
+ 0x002db6eb,
+ 0x006db6eb,
+ 0x00adb6eb,
+ 0x00edb6eb,
+ 0x002eb6eb,
+ 0x006eb6eb,
+ 0x00aeb6eb,
+ 0x00eeb6eb,
+ 0x002fb6eb,
+ 0x006fb6eb,
+ 0x00afb6eb,
+ 0x00efb6eb,
+ 0x002cbaeb,
+ 0x006cbaeb,
+ 0x00acbaeb,
+ 0x00ecbaeb,
+ 0x002dbaeb,
+ 0x006dbaeb,
+ 0x00adbaeb,
+ 0x00edbaeb,
+ 0x002ebaeb,
+ 0x006ebaeb,
+ 0x00aebaeb,
+ 0x00eebaeb,
+ 0x002fbaeb,
+ 0x006fbaeb,
+ 0x00afbaeb,
+ 0x00efbaeb,
+ 0x002cbeeb,
+ 0x006cbeeb,
+ 0x00acbeeb,
+ 0x00ecbeeb,
+ 0x002dbeeb,
+ 0x006dbeeb,
+ 0x00adbeeb,
+ 0x00edbeeb,
+ 0x002ebeeb,
+ 0x006ebeeb,
+ 0x00aebeeb,
+ 0x00eebeeb,
+ 0x002fbeeb,
+ 0x006fbeeb,
+ 0x00afbeeb,
+ 0x00efbeeb,
+ 0x002cb2fb,
+ 0x006cb2fb,
+ 0x00acb2fb,
+ 0x00ecb2fb,
+ 0x002db2fb,
+ 0x006db2fb,
+ 0x00adb2fb,
+ 0x00edb2fb,
+ 0x002eb2fb,
+ 0x006eb2fb,
+ 0x00aeb2fb,
+ 0x00eeb2fb,
+ 0x002fb2fb,
+ 0x006fb2fb,
+ 0x00afb2fb,
+ 0x00efb2fb,
+ 0x002cb6fb,
+ 0x006cb6fb,
+ 0x00acb6fb,
+ 0x00ecb6fb,
+ 0x002db6fb,
+ 0x006db6fb,
+ 0x00adb6fb,
+ 0x00edb6fb,
+ 0x002eb6fb,
+ 0x006eb6fb,
+ 0x00aeb6fb,
+ 0x00eeb6fb,
+ 0x002fb6fb,
+ 0x006fb6fb,
+ 0x00afb6fb,
+ 0x00efb6fb,
+ 0x002cbafb,
+ 0x006cbafb,
+ 0x00acbafb,
+ 0x00ecbafb,
+ 0x002dbafb,
+ 0x006dbafb,
+ 0x00adbafb,
+ 0x00edbafb,
+ 0x002ebafb,
+ 0x006ebafb,
+ 0x00aebafb,
+ 0x00eebafb,
+ 0x002fbafb,
+ 0x006fbafb,
+ 0x00afbafb,
+ 0x00efbafb,
+ 0x002cbefb,
+ 0x006cbefb,
+ 0x00acbefb,
+ 0x00ecbefb,
+ 0x002dbefb,
+ 0x006dbefb,
+ 0x00adbefb,
+ 0x00edbefb,
+ 0x002ebefb,
+ 0x006ebefb,
+ 0x00aebefb,
+ 0x00eebefb,
+ 0x002fbefb,
+ 0x006fbefb,
+ 0x00afbefb,
+ 0x00efbefb,
+ 0x0b2cb2cb,
+ 0x1b2cb2cb,
+ 0x2b2cb2cb,
+ 0x3b2cb2cb,
+ 0x0b6cb2cb,
+ 0x1b6cb2cb,
+ 0x2b6cb2cb,
+ 0x3b6cb2cb,
+ 0x0bacb2cb,
+ 0x1bacb2cb,
+ 0x2bacb2cb,
+ 0x3bacb2cb,
+ 0x0becb2cb,
+ 0x1becb2cb,
+ 0x2becb2cb,
+ 0x3becb2cb,
+ 0x0b2db2cb,
+ 0x1b2db2cb,
+ 0x2b2db2cb,
+ 0x3b2db2cb,
+ 0x0b6db2cb,
+ 0x1b6db2cb,
+ 0x2b6db2cb,
+ 0x3b6db2cb,
+ 0x0badb2cb,
+ 0x1badb2cb,
+ 0x2badb2cb,
+ 0x3badb2cb,
+ 0x0bedb2cb,
+ 0x1bedb2cb,
+ 0x2bedb2cb,
+ 0x3bedb2cb,
+ 0x0b2eb2cb,
+ 0x1b2eb2cb,
+ 0x2b2eb2cb,
+ 0x3b2eb2cb,
+ 0x0b6eb2cb,
+ 0x1b6eb2cb,
+ 0x2b6eb2cb,
+ 0x3b6eb2cb,
+ 0x0baeb2cb,
+ 0x1baeb2cb,
+ 0x2baeb2cb,
+ 0x3baeb2cb,
+ 0x0beeb2cb,
+ 0x1beeb2cb,
+ 0x2beeb2cb,
+ 0x3beeb2cb,
+ 0x0b2fb2cb,
+ 0x1b2fb2cb,
+ 0x2b2fb2cb,
+ 0x3b2fb2cb,
+ 0x0b6fb2cb,
+ 0x1b6fb2cb,
+ 0x2b6fb2cb,
+ 0x3b6fb2cb,
+ 0x0bafb2cb,
+ 0x1bafb2cb,
+ 0x2bafb2cb,
+ 0x3bafb2cb,
+ 0x0befb2cb,
+ 0x1befb2cb,
+ 0x2befb2cb,
+ 0x3befb2cb,
+ 0x0b2cb6cb,
+ 0x1b2cb6cb,
+ 0x2b2cb6cb,
+ 0x3b2cb6cb,
+ 0x0b6cb6cb,
+ 0x1b6cb6cb,
+ 0x2b6cb6cb,
+ 0x3b6cb6cb,
+ 0x0bacb6cb,
+ 0x1bacb6cb,
+ 0x2bacb6cb,
+ 0x3bacb6cb,
+ 0x0becb6cb,
+ 0x1becb6cb,
+ 0x2becb6cb,
+ 0x3becb6cb,
+ 0x0b2db6cb,
+ 0x1b2db6cb,
+ 0x2b2db6cb,
+ 0x3b2db6cb,
+ 0x0b6db6cb,
+ 0x1b6db6cb,
+ 0x2b6db6cb,
+ 0x3b6db6cb,
+ 0x0badb6cb,
+ 0x1badb6cb,
+ 0x2badb6cb,
+ 0x3badb6cb,
+ 0x0bedb6cb,
+ 0x1bedb6cb,
+ 0x2bedb6cb,
+ 0x3bedb6cb,
+ 0x0b2eb6cb,
+ 0x1b2eb6cb,
+ 0x2b2eb6cb,
+ 0x3b2eb6cb,
+ 0x0b6eb6cb,
+ 0x1b6eb6cb,
+ 0x2b6eb6cb,
+ 0x3b6eb6cb,
+ 0x0baeb6cb,
+ 0x1baeb6cb,
+ 0x2baeb6cb,
+ 0x3baeb6cb,
+ 0x0beeb6cb,
+ 0x1beeb6cb,
+ 0x2beeb6cb,
+ 0x3beeb6cb,
+ 0x0b2fb6cb,
+ 0x1b2fb6cb,
+ 0x2b2fb6cb,
+ 0x3b2fb6cb,
+ 0x0b6fb6cb,
+ 0x1b6fb6cb,
+ 0x2b6fb6cb,
+ 0x3b6fb6cb,
+ 0x0bafb6cb,
+ 0x1bafb6cb,
+ 0x2bafb6cb,
+ 0x3bafb6cb,
+ 0x0befb6cb,
+ 0x1befb6cb,
+ 0x2befb6cb,
+ 0x3befb6cb,
+ 0x0b2cbacb,
+ 0x1b2cbacb,
+ 0x2b2cbacb,
+ 0x3b2cbacb,
+ 0x0b6cbacb,
+ 0x1b6cbacb,
+ 0x2b6cbacb,
+ 0x3b6cbacb,
+ 0x0bacbacb,
+ 0x1bacbacb,
+ 0x2bacbacb,
+ 0x3bacbacb,
+ 0x0becbacb,
+ 0x1becbacb,
+ 0x2becbacb,
+ 0x3becbacb,
+ 0x0b2dbacb,
+ 0x1b2dbacb,
+ 0x2b2dbacb,
+ 0x3b2dbacb,
+ 0x0b6dbacb,
+ 0x1b6dbacb,
+ 0x2b6dbacb,
+ 0x3b6dbacb,
+ 0x0badbacb,
+ 0x1badbacb,
+ 0x2badbacb,
+ 0x3badbacb,
+ 0x0bedbacb,
+ 0x1bedbacb,
+ 0x2bedbacb,
+ 0x3bedbacb,
+ 0x0b2ebacb,
+ 0x1b2ebacb,
+ 0x2b2ebacb,
+ 0x3b2ebacb,
+ 0x0b6ebacb,
+ 0x1b6ebacb,
+ 0x2b6ebacb,
+ 0x3b6ebacb,
+ 0x0baebacb,
+ 0x1baebacb,
+ 0x2baebacb,
+ 0x3baebacb,
+ 0x0beebacb,
+ 0x1beebacb,
+ 0x2beebacb,
+ 0x3beebacb,
+ 0x0b2fbacb,
+ 0x1b2fbacb,
+ 0x2b2fbacb,
+ 0x3b2fbacb,
+ 0x0b6fbacb,
+ 0x1b6fbacb,
+ 0x2b6fbacb,
+ 0x3b6fbacb,
+ 0x0bafbacb,
+ 0x1bafbacb,
+ 0x2bafbacb,
+ 0x3bafbacb,
+ 0x0befbacb,
+ 0x1befbacb,
+ 0x2befbacb,
+ 0x3befbacb,
+ 0x0b2cbecb,
+ 0x1b2cbecb,
+ 0x2b2cbecb,
+ 0x3b2cbecb,
+ 0x0b6cbecb,
+ 0x1b6cbecb,
+ 0x2b6cbecb,
+ 0x3b6cbecb,
+ 0x0bacbecb,
+ 0x1bacbecb,
+ 0x2bacbecb,
+ 0x3bacbecb,
+ 0x0becbecb,
+ 0x1becbecb,
+ 0x2becbecb,
+ 0x3becbecb,
+ 0x0b2dbecb,
+ 0x1b2dbecb,
+ 0x2b2dbecb,
+ 0x3b2dbecb,
+ 0x0b6dbecb,
+ 0x1b6dbecb,
+ 0x2b6dbecb,
+ 0x3b6dbecb,
+ 0x0badbecb,
+ 0x1badbecb,
+ 0x2badbecb,
+ 0x3badbecb,
+ 0x0bedbecb,
+ 0x1bedbecb,
+ 0x2bedbecb,
+ 0x3bedbecb,
+ 0x0b2ebecb,
+ 0x1b2ebecb,
+ 0x2b2ebecb,
+ 0x3b2ebecb,
+ 0x0b6ebecb,
+ 0x1b6ebecb,
+ 0x2b6ebecb,
+ 0x3b6ebecb,
+ 0x0baebecb,
+ 0x1baebecb,
+ 0x2baebecb,
+ 0x3baebecb,
+ 0x0beebecb,
+ 0x1beebecb,
+ 0x2beebecb,
+ 0x3beebecb,
+ 0x0b2fbecb,
+ 0x1b2fbecb,
+ 0x2b2fbecb,
+ 0x3b2fbecb,
+ 0x0b6fbecb,
+ 0x1b6fbecb,
+ 0x2b6fbecb,
+ 0x3b6fbecb,
+ 0x0bafbecb,
+ 0x1bafbecb,
+ 0x2bafbecb,
+ 0x3bafbecb,
+ 0x0befbecb,
+ 0x1befbecb,
+ 0x2befbecb,
+ 0x3befbecb,
+ 0x0b2cb2db,
+ 0x1b2cb2db,
+ 0x2b2cb2db,
+ 0x3b2cb2db,
+ 0x0b6cb2db,
+ 0x1b6cb2db,
+ 0x2b6cb2db,
+ 0x3b6cb2db,
+ 0x0bacb2db,
+ 0x1bacb2db,
+ 0x2bacb2db,
+ 0x3bacb2db,
+ 0x0becb2db,
+ 0x1becb2db,
+ 0x2becb2db,
+ 0x3becb2db,
+ 0x0b2db2db,
+ 0x1b2db2db,
+ 0x2b2db2db,
+ 0x3b2db2db,
+ 0x0b6db2db,
+ 0x1b6db2db,
+ 0x2b6db2db,
+ 0x3b6db2db,
+ 0x0badb2db,
+ 0x1badb2db,
+ 0x2badb2db,
+ 0x3badb2db,
+ 0x0bedb2db,
+ 0x1bedb2db,
+ 0x2bedb2db,
+ 0x3bedb2db,
+ 0x0b2eb2db,
+ 0x1b2eb2db,
+ 0x2b2eb2db,
+ 0x3b2eb2db,
+ 0x0b6eb2db,
+ 0x1b6eb2db,
+ 0x2b6eb2db,
+ 0x3b6eb2db,
+ 0x0baeb2db,
+ 0x1baeb2db,
+ 0x2baeb2db,
+ 0x3baeb2db,
+ 0x0beeb2db,
+ 0x1beeb2db,
+ 0x2beeb2db,
+ 0x3beeb2db,
+ 0x0b2fb2db,
+ 0x1b2fb2db,
+ 0x2b2fb2db,
+ 0x3b2fb2db,
+ 0x0b6fb2db,
+ 0x1b6fb2db,
+ 0x2b6fb2db,
+ 0x3b6fb2db,
+ 0x0bafb2db,
+ 0x1bafb2db,
+ 0x2bafb2db,
+ 0x3bafb2db,
+ 0x0befb2db,
+ 0x1befb2db,
+ 0x2befb2db,
+ 0x3befb2db,
+ 0x0b2cb6db,
+ 0x1b2cb6db,
+ 0x2b2cb6db,
+ 0x3b2cb6db,
+ 0x0b6cb6db,
+ 0x1b6cb6db,
+ 0x2b6cb6db,
+ 0x3b6cb6db,
+ 0x0bacb6db,
+ 0x1bacb6db,
+ 0x2bacb6db,
+ 0x3bacb6db,
+ 0x0becb6db,
+ 0x1becb6db,
+ 0x2becb6db,
+ 0x3becb6db,
+ 0x0b2db6db,
+ 0x1b2db6db,
+ 0x2b2db6db,
+ 0x3b2db6db,
+ 0x0b6db6db,
+ 0x1b6db6db,
+ 0x2b6db6db,
+ 0x3b6db6db,
+ 0x0badb6db,
+ 0x1badb6db,
+ 0x2badb6db,
+ 0x3badb6db,
+ 0x0bedb6db,
+ 0x1bedb6db,
+ 0x2bedb6db,
+ 0x3bedb6db,
+ 0x0b2eb6db,
+ 0x1b2eb6db,
+ 0x2b2eb6db,
+ 0x3b2eb6db,
+ 0x0b6eb6db,
+ 0x1b6eb6db,
+ 0x2b6eb6db,
+ 0x3b6eb6db,
+ 0x0baeb6db,
+ 0x1baeb6db,
+ 0x2baeb6db,
+ 0x3baeb6db,
+}
+
+var kNonZeroRepsDepth = [numCommandSymbols]uint32{
+ 6,
+ 6,
+ 6,
+ 6,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 18,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 24,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+ 30,
+}
+
+var kStaticCommandCodeBits = [numCommandSymbols]uint16{
+ 0,
+ 256,
+ 128,
+ 384,
+ 64,
+ 320,
+ 192,
+ 448,
+ 32,
+ 288,
+ 160,
+ 416,
+ 96,
+ 352,
+ 224,
+ 480,
+ 16,
+ 272,
+ 144,
+ 400,
+ 80,
+ 336,
+ 208,
+ 464,
+ 48,
+ 304,
+ 176,
+ 432,
+ 112,
+ 368,
+ 240,
+ 496,
+ 8,
+ 264,
+ 136,
+ 392,
+ 72,
+ 328,
+ 200,
+ 456,
+ 40,
+ 296,
+ 168,
+ 424,
+ 104,
+ 360,
+ 232,
+ 488,
+ 24,
+ 280,
+ 152,
+ 408,
+ 88,
+ 344,
+ 216,
+ 472,
+ 56,
+ 312,
+ 184,
+ 440,
+ 120,
+ 376,
+ 248,
+ 504,
+ 4,
+ 260,
+ 132,
+ 388,
+ 68,
+ 324,
+ 196,
+ 452,
+ 36,
+ 292,
+ 164,
+ 420,
+ 100,
+ 356,
+ 228,
+ 484,
+ 20,
+ 276,
+ 148,
+ 404,
+ 84,
+ 340,
+ 212,
+ 468,
+ 52,
+ 308,
+ 180,
+ 436,
+ 116,
+ 372,
+ 244,
+ 500,
+ 12,
+ 268,
+ 140,
+ 396,
+ 76,
+ 332,
+ 204,
+ 460,
+ 44,
+ 300,
+ 172,
+ 428,
+ 108,
+ 364,
+ 236,
+ 492,
+ 28,
+ 284,
+ 156,
+ 412,
+ 92,
+ 348,
+ 220,
+ 476,
+ 60,
+ 316,
+ 188,
+ 444,
+ 124,
+ 380,
+ 252,
+ 508,
+ 2,
+ 258,
+ 130,
+ 386,
+ 66,
+ 322,
+ 194,
+ 450,
+ 34,
+ 290,
+ 162,
+ 418,
+ 98,
+ 354,
+ 226,
+ 482,
+ 18,
+ 274,
+ 146,
+ 402,
+ 82,
+ 338,
+ 210,
+ 466,
+ 50,
+ 306,
+ 178,
+ 434,
+ 114,
+ 370,
+ 242,
+ 498,
+ 10,
+ 266,
+ 138,
+ 394,
+ 74,
+ 330,
+ 202,
+ 458,
+ 42,
+ 298,
+ 170,
+ 426,
+ 106,
+ 362,
+ 234,
+ 490,
+ 26,
+ 282,
+ 154,
+ 410,
+ 90,
+ 346,
+ 218,
+ 474,
+ 58,
+ 314,
+ 186,
+ 442,
+ 122,
+ 378,
+ 250,
+ 506,
+ 6,
+ 262,
+ 134,
+ 390,
+ 70,
+ 326,
+ 198,
+ 454,
+ 38,
+ 294,
+ 166,
+ 422,
+ 102,
+ 358,
+ 230,
+ 486,
+ 22,
+ 278,
+ 150,
+ 406,
+ 86,
+ 342,
+ 214,
+ 470,
+ 54,
+ 310,
+ 182,
+ 438,
+ 118,
+ 374,
+ 246,
+ 502,
+ 14,
+ 270,
+ 142,
+ 398,
+ 78,
+ 334,
+ 206,
+ 462,
+ 46,
+ 302,
+ 174,
+ 430,
+ 110,
+ 366,
+ 238,
+ 494,
+ 30,
+ 286,
+ 158,
+ 414,
+ 94,
+ 350,
+ 222,
+ 478,
+ 62,
+ 318,
+ 190,
+ 446,
+ 126,
+ 382,
+ 254,
+ 510,
+ 1,
+ 257,
+ 129,
+ 385,
+ 65,
+ 321,
+ 193,
+ 449,
+ 33,
+ 289,
+ 161,
+ 417,
+ 97,
+ 353,
+ 225,
+ 481,
+ 17,
+ 273,
+ 145,
+ 401,
+ 81,
+ 337,
+ 209,
+ 465,
+ 49,
+ 305,
+ 177,
+ 433,
+ 113,
+ 369,
+ 241,
+ 497,
+ 9,
+ 265,
+ 137,
+ 393,
+ 73,
+ 329,
+ 201,
+ 457,
+ 41,
+ 297,
+ 169,
+ 425,
+ 105,
+ 361,
+ 233,
+ 489,
+ 25,
+ 281,
+ 153,
+ 409,
+ 89,
+ 345,
+ 217,
+ 473,
+ 57,
+ 313,
+ 185,
+ 441,
+ 121,
+ 377,
+ 249,
+ 505,
+ 5,
+ 261,
+ 133,
+ 389,
+ 69,
+ 325,
+ 197,
+ 453,
+ 37,
+ 293,
+ 165,
+ 421,
+ 101,
+ 357,
+ 229,
+ 485,
+ 21,
+ 277,
+ 149,
+ 405,
+ 85,
+ 341,
+ 213,
+ 469,
+ 53,
+ 309,
+ 181,
+ 437,
+ 117,
+ 373,
+ 245,
+ 501,
+ 13,
+ 269,
+ 141,
+ 397,
+ 77,
+ 333,
+ 205,
+ 461,
+ 45,
+ 301,
+ 173,
+ 429,
+ 109,
+ 365,
+ 237,
+ 493,
+ 29,
+ 285,
+ 157,
+ 413,
+ 93,
+ 349,
+ 221,
+ 477,
+ 61,
+ 317,
+ 189,
+ 445,
+ 125,
+ 381,
+ 253,
+ 509,
+ 3,
+ 259,
+ 131,
+ 387,
+ 67,
+ 323,
+ 195,
+ 451,
+ 35,
+ 291,
+ 163,
+ 419,
+ 99,
+ 355,
+ 227,
+ 483,
+ 19,
+ 275,
+ 147,
+ 403,
+ 83,
+ 339,
+ 211,
+ 467,
+ 51,
+ 307,
+ 179,
+ 435,
+ 115,
+ 371,
+ 243,
+ 499,
+ 11,
+ 267,
+ 139,
+ 395,
+ 75,
+ 331,
+ 203,
+ 459,
+ 43,
+ 299,
+ 171,
+ 427,
+ 107,
+ 363,
+ 235,
+ 491,
+ 27,
+ 283,
+ 155,
+ 411,
+ 91,
+ 347,
+ 219,
+ 475,
+ 59,
+ 315,
+ 187,
+ 443,
+ 123,
+ 379,
+ 251,
+ 507,
+ 7,
+ 1031,
+ 519,
+ 1543,
+ 263,
+ 1287,
+ 775,
+ 1799,
+ 135,
+ 1159,
+ 647,
+ 1671,
+ 391,
+ 1415,
+ 903,
+ 1927,
+ 71,
+ 1095,
+ 583,
+ 1607,
+ 327,
+ 1351,
+ 839,
+ 1863,
+ 199,
+ 1223,
+ 711,
+ 1735,
+ 455,
+ 1479,
+ 967,
+ 1991,
+ 39,
+ 1063,
+ 551,
+ 1575,
+ 295,
+ 1319,
+ 807,
+ 1831,
+ 167,
+ 1191,
+ 679,
+ 1703,
+ 423,
+ 1447,
+ 935,
+ 1959,
+ 103,
+ 1127,
+ 615,
+ 1639,
+ 359,
+ 1383,
+ 871,
+ 1895,
+ 231,
+ 1255,
+ 743,
+ 1767,
+ 487,
+ 1511,
+ 999,
+ 2023,
+ 23,
+ 1047,
+ 535,
+ 1559,
+ 279,
+ 1303,
+ 791,
+ 1815,
+ 151,
+ 1175,
+ 663,
+ 1687,
+ 407,
+ 1431,
+ 919,
+ 1943,
+ 87,
+ 1111,
+ 599,
+ 1623,
+ 343,
+ 1367,
+ 855,
+ 1879,
+ 215,
+ 1239,
+ 727,
+ 1751,
+ 471,
+ 1495,
+ 983,
+ 2007,
+ 55,
+ 1079,
+ 567,
+ 1591,
+ 311,
+ 1335,
+ 823,
+ 1847,
+ 183,
+ 1207,
+ 695,
+ 1719,
+ 439,
+ 1463,
+ 951,
+ 1975,
+ 119,
+ 1143,
+ 631,
+ 1655,
+ 375,
+ 1399,
+ 887,
+ 1911,
+ 247,
+ 1271,
+ 759,
+ 1783,
+ 503,
+ 1527,
+ 1015,
+ 2039,
+ 15,
+ 1039,
+ 527,
+ 1551,
+ 271,
+ 1295,
+ 783,
+ 1807,
+ 143,
+ 1167,
+ 655,
+ 1679,
+ 399,
+ 1423,
+ 911,
+ 1935,
+ 79,
+ 1103,
+ 591,
+ 1615,
+ 335,
+ 1359,
+ 847,
+ 1871,
+ 207,
+ 1231,
+ 719,
+ 1743,
+ 463,
+ 1487,
+ 975,
+ 1999,
+ 47,
+ 1071,
+ 559,
+ 1583,
+ 303,
+ 1327,
+ 815,
+ 1839,
+ 175,
+ 1199,
+ 687,
+ 1711,
+ 431,
+ 1455,
+ 943,
+ 1967,
+ 111,
+ 1135,
+ 623,
+ 1647,
+ 367,
+ 1391,
+ 879,
+ 1903,
+ 239,
+ 1263,
+ 751,
+ 1775,
+ 495,
+ 1519,
+ 1007,
+ 2031,
+ 31,
+ 1055,
+ 543,
+ 1567,
+ 287,
+ 1311,
+ 799,
+ 1823,
+ 159,
+ 1183,
+ 671,
+ 1695,
+ 415,
+ 1439,
+ 927,
+ 1951,
+ 95,
+ 1119,
+ 607,
+ 1631,
+ 351,
+ 1375,
+ 863,
+ 1887,
+ 223,
+ 1247,
+ 735,
+ 1759,
+ 479,
+ 1503,
+ 991,
+ 2015,
+ 63,
+ 1087,
+ 575,
+ 1599,
+ 319,
+ 1343,
+ 831,
+ 1855,
+ 191,
+ 1215,
+ 703,
+ 1727,
+ 447,
+ 1471,
+ 959,
+ 1983,
+ 127,
+ 1151,
+ 639,
+ 1663,
+ 383,
+ 1407,
+ 895,
+ 1919,
+ 255,
+ 1279,
+ 767,
+ 1791,
+ 511,
+ 1535,
+ 1023,
+ 2047,
+}
+
+func storeStaticCommandHuffmanTree(storage_ix *uint, storage []byte) {
+ writeBits(56, 0x92624416307003, storage_ix, storage)
+ writeBits(3, 0x00000000, storage_ix, storage)
+}
+
+var kStaticDistanceCodeBits = [64]uint16{
+ 0,
+ 32,
+ 16,
+ 48,
+ 8,
+ 40,
+ 24,
+ 56,
+ 4,
+ 36,
+ 20,
+ 52,
+ 12,
+ 44,
+ 28,
+ 60,
+ 2,
+ 34,
+ 18,
+ 50,
+ 10,
+ 42,
+ 26,
+ 58,
+ 6,
+ 38,
+ 22,
+ 54,
+ 14,
+ 46,
+ 30,
+ 62,
+ 1,
+ 33,
+ 17,
+ 49,
+ 9,
+ 41,
+ 25,
+ 57,
+ 5,
+ 37,
+ 21,
+ 53,
+ 13,
+ 45,
+ 29,
+ 61,
+ 3,
+ 35,
+ 19,
+ 51,
+ 11,
+ 43,
+ 27,
+ 59,
+ 7,
+ 39,
+ 23,
+ 55,
+ 15,
+ 47,
+ 31,
+ 63,
+}
+
+func storeStaticDistanceHuffmanTree(storage_ix *uint, storage []byte) {
+ writeBits(28, 0x0369DC03, storage_ix, storage)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/fast_log.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/fast_log.go
new file mode 100644
index 000000000000..9d6607f7e2ff
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/fast_log.go
@@ -0,0 +1,290 @@
+package brotli
+
+import (
+ "math"
+ "math/bits"
+)
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for fast computation of logarithms. */
+
+func log2FloorNonZero(n uint) uint32 {
+ return uint32(bits.Len(n)) - 1
+}
+
+/* A lookup table for small values of log2(int) to be used in entropy
+ computation.
+
+ ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
+var kLog2Table = []float32{
+ 0.0000000000000000,
+ 0.0000000000000000,
+ 1.0000000000000000,
+ 1.5849625007211563,
+ 2.0000000000000000,
+ 2.3219280948873622,
+ 2.5849625007211561,
+ 2.8073549220576042,
+ 3.0000000000000000,
+ 3.1699250014423126,
+ 3.3219280948873626,
+ 3.4594316186372978,
+ 3.5849625007211565,
+ 3.7004397181410922,
+ 3.8073549220576037,
+ 3.9068905956085187,
+ 4.0000000000000000,
+ 4.0874628412503400,
+ 4.1699250014423122,
+ 4.2479275134435852,
+ 4.3219280948873626,
+ 4.3923174227787607,
+ 4.4594316186372973,
+ 4.5235619560570131,
+ 4.5849625007211570,
+ 4.6438561897747244,
+ 4.7004397181410926,
+ 4.7548875021634691,
+ 4.8073549220576037,
+ 4.8579809951275728,
+ 4.9068905956085187,
+ 4.9541963103868758,
+ 5.0000000000000000,
+ 5.0443941193584534,
+ 5.0874628412503400,
+ 5.1292830169449664,
+ 5.1699250014423122,
+ 5.2094533656289501,
+ 5.2479275134435852,
+ 5.2854022188622487,
+ 5.3219280948873626,
+ 5.3575520046180838,
+ 5.3923174227787607,
+ 5.4262647547020979,
+ 5.4594316186372973,
+ 5.4918530963296748,
+ 5.5235619560570131,
+ 5.5545888516776376,
+ 5.5849625007211570,
+ 5.6147098441152083,
+ 5.6438561897747244,
+ 5.6724253419714961,
+ 5.7004397181410926,
+ 5.7279204545631996,
+ 5.7548875021634691,
+ 5.7813597135246599,
+ 5.8073549220576046,
+ 5.8328900141647422,
+ 5.8579809951275719,
+ 5.8826430493618416,
+ 5.9068905956085187,
+ 5.9307373375628867,
+ 5.9541963103868758,
+ 5.9772799234999168,
+ 6.0000000000000000,
+ 6.0223678130284544,
+ 6.0443941193584534,
+ 6.0660891904577721,
+ 6.0874628412503400,
+ 6.1085244567781700,
+ 6.1292830169449672,
+ 6.1497471195046822,
+ 6.1699250014423122,
+ 6.1898245588800176,
+ 6.2094533656289510,
+ 6.2288186904958804,
+ 6.2479275134435861,
+ 6.2667865406949019,
+ 6.2854022188622487,
+ 6.3037807481771031,
+ 6.3219280948873617,
+ 6.3398500028846252,
+ 6.3575520046180847,
+ 6.3750394313469254,
+ 6.3923174227787598,
+ 6.4093909361377026,
+ 6.4262647547020979,
+ 6.4429434958487288,
+ 6.4594316186372982,
+ 6.4757334309663976,
+ 6.4918530963296748,
+ 6.5077946401986964,
+ 6.5235619560570131,
+ 6.5391588111080319,
+ 6.5545888516776376,
+ 6.5698556083309478,
+ 6.5849625007211561,
+ 6.5999128421871278,
+ 6.6147098441152092,
+ 6.6293566200796095,
+ 6.6438561897747253,
+ 6.6582114827517955,
+ 6.6724253419714952,
+ 6.6865005271832185,
+ 6.7004397181410917,
+ 6.7142455176661224,
+ 6.7279204545631988,
+ 6.7414669864011465,
+ 6.7548875021634691,
+ 6.7681843247769260,
+ 6.7813597135246599,
+ 6.7944158663501062,
+ 6.8073549220576037,
+ 6.8201789624151887,
+ 6.8328900141647422,
+ 6.8454900509443757,
+ 6.8579809951275719,
+ 6.8703647195834048,
+ 6.8826430493618416,
+ 6.8948177633079437,
+ 6.9068905956085187,
+ 6.9188632372745955,
+ 6.9307373375628867,
+ 6.9425145053392399,
+ 6.9541963103868758,
+ 6.9657842846620879,
+ 6.9772799234999168,
+ 6.9886846867721664,
+ 7.0000000000000000,
+ 7.0112272554232540,
+ 7.0223678130284544,
+ 7.0334230015374501,
+ 7.0443941193584534,
+ 7.0552824355011898,
+ 7.0660891904577721,
+ 7.0768155970508317,
+ 7.0874628412503400,
+ 7.0980320829605272,
+ 7.1085244567781700,
+ 7.1189410727235076,
+ 7.1292830169449664,
+ 7.1395513523987937,
+ 7.1497471195046822,
+ 7.1598713367783891,
+ 7.1699250014423130,
+ 7.1799090900149345,
+ 7.1898245588800176,
+ 7.1996723448363644,
+ 7.2094533656289492,
+ 7.2191685204621621,
+ 7.2288186904958804,
+ 7.2384047393250794,
+ 7.2479275134435861,
+ 7.2573878426926521,
+ 7.2667865406949019,
+ 7.2761244052742384,
+ 7.2854022188622487,
+ 7.2946207488916270,
+ 7.3037807481771031,
+ 7.3128829552843557,
+ 7.3219280948873617,
+ 7.3309168781146177,
+ 7.3398500028846243,
+ 7.3487281542310781,
+ 7.3575520046180847,
+ 7.3663222142458151,
+ 7.3750394313469254,
+ 7.3837042924740528,
+ 7.3923174227787607,
+ 7.4008794362821844,
+ 7.4093909361377026,
+ 7.4178525148858991,
+ 7.4262647547020979,
+ 7.4346282276367255,
+ 7.4429434958487288,
+ 7.4512111118323299,
+ 7.4594316186372973,
+ 7.4676055500829976,
+ 7.4757334309663976,
+ 7.4838157772642564,
+ 7.4918530963296748,
+ 7.4998458870832057,
+ 7.5077946401986964,
+ 7.5156998382840436,
+ 7.5235619560570131,
+ 7.5313814605163119,
+ 7.5391588111080319,
+ 7.5468944598876373,
+ 7.5545888516776376,
+ 7.5622424242210728,
+ 7.5698556083309478,
+ 7.5774288280357487,
+ 7.5849625007211561,
+ 7.5924570372680806,
+ 7.5999128421871278,
+ 7.6073303137496113,
+ 7.6147098441152075,
+ 7.6220518194563764,
+ 7.6293566200796095,
+ 7.6366246205436488,
+ 7.6438561897747244,
+ 7.6510516911789290,
+ 7.6582114827517955,
+ 7.6653359171851765,
+ 7.6724253419714952,
+ 7.6794800995054464,
+ 7.6865005271832185,
+ 7.6934869574993252,
+ 7.7004397181410926,
+ 7.7073591320808825,
+ 7.7142455176661224,
+ 7.7210991887071856,
+ 7.7279204545631996,
+ 7.7347096202258392,
+ 7.7414669864011465,
+ 7.7481928495894596,
+ 7.7548875021634691,
+ 7.7615512324444795,
+ 7.7681843247769260,
+ 7.7747870596011737,
+ 7.7813597135246608,
+ 7.7879025593914317,
+ 7.7944158663501062,
+ 7.8008998999203047,
+ 7.8073549220576037,
+ 7.8137811912170374,
+ 7.8201789624151887,
+ 7.8265484872909159,
+ 7.8328900141647422,
+ 7.8392037880969445,
+ 7.8454900509443757,
+ 7.8517490414160571,
+ 7.8579809951275719,
+ 7.8641861446542798,
+ 7.8703647195834048,
+ 7.8765169465650002,
+ 7.8826430493618425,
+ 7.8887432488982601,
+ 7.8948177633079446,
+ 7.9008668079807496,
+ 7.9068905956085187,
+ 7.9128893362299619,
+ 7.9188632372745955,
+ 7.9248125036057813,
+ 7.9307373375628867,
+ 7.9366379390025719,
+ 7.9425145053392399,
+ 7.9483672315846778,
+ 7.9541963103868758,
+ 7.9600019320680806,
+ 7.9657842846620870,
+ 7.9715435539507720,
+ 7.9772799234999168,
+ 7.9829935746943104,
+ 7.9886846867721664,
+ 7.9943534368588578,
+}
+
+/* Faster logarithm for small integers, with the property of log2(0) == 0. */
+func fastLog2(v uint) float64 {
+ if v < uint(len(kLog2Table)) {
+ return float64(kLog2Table[v])
+ }
+
+ return math.Log2(float64(v))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/find_match_length.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/find_match_length.go
new file mode 100644
index 000000000000..09d2ae672683
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/find_match_length.go
@@ -0,0 +1,45 @@
+package brotli
+
+import (
+ "encoding/binary"
+ "math/bits"
+ "runtime"
+)
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Function to find maximal matching prefixes of strings. */
+func findMatchLengthWithLimit(s1 []byte, s2 []byte, limit uint) uint {
+ var matched uint = 0
+ _, _ = s1[limit-1], s2[limit-1] // bounds check
+ switch runtime.GOARCH {
+ case "amd64":
+ // Compare 8 bytes at at time.
+ for matched+8 <= limit {
+ w1 := binary.LittleEndian.Uint64(s1[matched:])
+ w2 := binary.LittleEndian.Uint64(s2[matched:])
+ if w1 != w2 {
+ return matched + uint(bits.TrailingZeros64(w1^w2)>>3)
+ }
+ matched += 8
+ }
+ case "386":
+ // Compare 4 bytes at at time.
+ for matched+4 <= limit {
+ w1 := binary.LittleEndian.Uint32(s1[matched:])
+ w2 := binary.LittleEndian.Uint32(s2[matched:])
+ if w1 != w2 {
+ return matched + uint(bits.TrailingZeros32(w1^w2)>>3)
+ }
+ matched += 4
+ }
+ }
+ for matched < limit && s1[matched] == s2[matched] {
+ matched++
+ }
+ return matched
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h10.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h10.go
new file mode 100644
index 000000000000..5662fbbbb52c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h10.go
@@ -0,0 +1,287 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func (*h10) HashTypeLength() uint {
+ return 4
+}
+
+func (*h10) StoreLookahead() uint {
+ return 128
+}
+
+func hashBytesH10(data []byte) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - 17)
+}
+
+/* A (forgetful) hash table where each hash bucket contains a binary tree of
+ sequences whose first 4 bytes share the same hash code.
+ Each sequence is 128 long and is identified by its starting
+ position in the input data. The binary tree is sorted by the lexicographic
+ order of the sequences, and it is also a max-heap with respect to the
+ starting positions. */
+type h10 struct {
+ hasherCommon
+ window_mask_ uint
+ buckets_ [1 << 17]uint32
+ invalid_pos_ uint32
+ forest []uint32
+}
+
+func (h *h10) Initialize(params *encoderParams) {
+ h.window_mask_ = (1 << params.lgwin) - 1
+ h.invalid_pos_ = uint32(0 - h.window_mask_)
+ var num_nodes uint = uint(1) << params.lgwin
+ h.forest = make([]uint32, 2*num_nodes)
+}
+
+func (h *h10) Prepare(one_shot bool, input_size uint, data []byte) {
+ var invalid_pos uint32 = h.invalid_pos_
+ var i uint32
+ for i = 0; i < 1<<17; i++ {
+ h.buckets_[i] = invalid_pos
+ }
+}
+
+func leftChildIndexH10(self *h10, pos uint) uint {
+ return 2 * (pos & self.window_mask_)
+}
+
+func rightChildIndexH10(self *h10, pos uint) uint {
+ return 2*(pos&self.window_mask_) + 1
+}
+
+/* Stores the hash of the next 4 bytes and in a single tree-traversal, the
+ hash bucket's binary tree is searched for matches and is re-rooted at the
+ current position.
+
+ If less than 128 data is available, the hash bucket of the
+ current position is searched for matches, but the state of the hash table
+ is not changed, since we can not know the final sorting order of the
+ current (incomplete) sequence.
+
+ This function must be called with increasing cur_ix positions. */
+func storeAndFindMatchesH10(self *h10, data []byte, cur_ix uint, ring_buffer_mask uint, max_length uint, max_backward uint, best_len *uint, matches []backwardMatch) []backwardMatch {
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var max_comp_len uint = brotli_min_size_t(max_length, 128)
+ var should_reroot_tree bool = (max_length >= 128)
+ var key uint32 = hashBytesH10(data[cur_ix_masked:])
+ var forest []uint32 = self.forest
+ var prev_ix uint = uint(self.buckets_[key])
+ var node_left uint = leftChildIndexH10(self, cur_ix)
+ var node_right uint = rightChildIndexH10(self, cur_ix)
+ var best_len_left uint = 0
+ var best_len_right uint = 0
+ var depth_remaining uint
+ /* The forest index of the rightmost node of the left subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+
+ /* The forest index of the leftmost node of the right subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+
+ /* The match length of the rightmost node of the left subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+
+ /* The match length of the leftmost node of the right subtree of the new
+ root, updated as we traverse and re-root the tree of the hash bucket. */
+ if should_reroot_tree {
+ self.buckets_[key] = uint32(cur_ix)
+ }
+
+ for depth_remaining = 64; ; depth_remaining-- {
+ var backward uint = cur_ix - prev_ix
+ var prev_ix_masked uint = prev_ix & ring_buffer_mask
+ if backward == 0 || backward > max_backward || depth_remaining == 0 {
+ if should_reroot_tree {
+ forest[node_left] = self.invalid_pos_
+ forest[node_right] = self.invalid_pos_
+ }
+
+ break
+ }
+ {
+ var cur_len uint = brotli_min_size_t(best_len_left, best_len_right)
+ var len uint
+ assert(cur_len <= 128)
+ len = cur_len + findMatchLengthWithLimit(data[cur_ix_masked+cur_len:], data[prev_ix_masked+cur_len:], max_length-cur_len)
+ if matches != nil && len > *best_len {
+ *best_len = uint(len)
+ initBackwardMatch(&matches[0], backward, uint(len))
+ matches = matches[1:]
+ }
+
+ if len >= max_comp_len {
+ if should_reroot_tree {
+ forest[node_left] = forest[leftChildIndexH10(self, prev_ix)]
+ forest[node_right] = forest[rightChildIndexH10(self, prev_ix)]
+ }
+
+ break
+ }
+
+ if data[cur_ix_masked+len] > data[prev_ix_masked+len] {
+ best_len_left = uint(len)
+ if should_reroot_tree {
+ forest[node_left] = uint32(prev_ix)
+ }
+
+ node_left = rightChildIndexH10(self, prev_ix)
+ prev_ix = uint(forest[node_left])
+ } else {
+ best_len_right = uint(len)
+ if should_reroot_tree {
+ forest[node_right] = uint32(prev_ix)
+ }
+
+ node_right = leftChildIndexH10(self, prev_ix)
+ prev_ix = uint(forest[node_right])
+ }
+ }
+ }
+
+ return matches
+}
+
+/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the
+ length of max_length and stores the position cur_ix in the hash table.
+
+ Sets *num_matches to the number of matches found, and stores the found
+ matches in matches[0] to matches[*num_matches - 1]. The matches will be
+ sorted by strictly increasing length and (non-strictly) increasing
+ distance. */
+func findAllMatchesH10(handle *h10, dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, cur_ix uint, max_length uint, max_backward uint, gap uint, params *encoderParams, matches []backwardMatch) uint {
+ var orig_matches []backwardMatch = matches
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var best_len uint = 1
+ var short_match_max_backward uint
+ if params.quality != hqZopflificationQuality {
+ short_match_max_backward = 16
+ } else {
+ short_match_max_backward = 64
+ }
+ var stop uint = cur_ix - short_match_max_backward
+ var dict_matches [maxStaticDictionaryMatchLen + 1]uint32
+ var i uint
+ if cur_ix < short_match_max_backward {
+ stop = 0
+ }
+ for i = cur_ix - 1; i > stop && best_len <= 2; i-- {
+ var prev_ix uint = i
+ var backward uint = cur_ix - prev_ix
+ if backward > max_backward {
+ break
+ }
+
+ prev_ix &= ring_buffer_mask
+ if data[cur_ix_masked] != data[prev_ix] || data[cur_ix_masked+1] != data[prev_ix+1] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len > best_len {
+ best_len = uint(len)
+ initBackwardMatch(&matches[0], backward, uint(len))
+ matches = matches[1:]
+ }
+ }
+ }
+
+ if best_len < max_length {
+ matches = storeAndFindMatchesH10(handle, data, cur_ix, ring_buffer_mask, max_length, max_backward, &best_len, matches)
+ }
+
+ for i = 0; i <= maxStaticDictionaryMatchLen; i++ {
+ dict_matches[i] = kInvalidMatch
+ }
+ {
+ var minlen uint = brotli_max_size_t(4, best_len+1)
+ if findAllStaticDictionaryMatches(dictionary, data[cur_ix_masked:], minlen, max_length, dict_matches[0:]) {
+ var maxlen uint = brotli_min_size_t(maxStaticDictionaryMatchLen, max_length)
+ var l uint
+ for l = minlen; l <= maxlen; l++ {
+ var dict_id uint32 = dict_matches[l]
+ if dict_id < kInvalidMatch {
+ var distance uint = max_backward + gap + uint(dict_id>>5) + 1
+ if distance <= params.dist.max_distance {
+ initDictionaryBackwardMatch(&matches[0], distance, l, uint(dict_id&31))
+ matches = matches[1:]
+ }
+ }
+ }
+ }
+ }
+
+ return uint(-cap(matches) + cap(orig_matches))
+}
+
+/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
+ current sequence, without returning any matches.
+ REQUIRES: ix + 128 <= end-of-current-block */
+func (h *h10) Store(data []byte, mask uint, ix uint) {
+ var max_backward uint = h.window_mask_ - windowGap + 1
+ /* Maximum distance is window size - 16, see section 9.1. of the spec. */
+ storeAndFindMatchesH10(h, data, ix, mask, 128, max_backward, nil, nil)
+}
+
+func (h *h10) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ var i uint = ix_start
+ var j uint = ix_start
+ if ix_start+63 <= ix_end {
+ i = ix_end - 63
+ }
+
+ if ix_start+512 <= i {
+ for ; j < i; j += 8 {
+ h.Store(data, mask, j)
+ }
+ }
+
+ for ; i < ix_end; i++ {
+ h.Store(data, mask, i)
+ }
+}
+
+func (h *h10) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {
+ if num_bytes >= h.HashTypeLength()-1 && position >= 128 {
+ var i_start uint = position - 128 + 1
+ var i_end uint = brotli_min_size_t(position, i_start+num_bytes)
+ /* Store the last `128 - 1` positions in the hasher.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+
+ var i uint
+ for i = i_start; i < i_end; i++ {
+ /* Maximum distance is window size - 16, see section 9.1. of the spec.
+ Furthermore, we have to make sure that we don't look further back
+ from the start of the next block than the window size, otherwise we
+ could access already overwritten areas of the ring-buffer. */
+ var max_backward uint = h.window_mask_ - brotli_max_size_t(windowGap-1, position-i)
+
+ /* We know that i + 128 <= position + num_bytes, i.e. the
+ end of the current block and that we have at least
+ 128 tail in the ring-buffer. */
+ storeAndFindMatchesH10(h, ringbuffer, i, ringbuffer_mask, 128, max_backward, nil, nil)
+ }
+ }
+}
+
+/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
+const maxNumMatchesH10 = 128
+
+func (*h10) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ panic("unimplemented")
+}
+
+func (*h10) PrepareDistanceCache(distance_cache []int) {
+ panic("unimplemented")
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h5.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h5.go
new file mode 100644
index 000000000000..f391b73fdd78
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h5.go
@@ -0,0 +1,214 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (bucket_size_) to a ring buffer of
+ fixed size (block_size_). The ring buffer contains the last block_size_
+ index positions of the given hash key in the compressed data. */
+func (*h5) HashTypeLength() uint {
+ return 4
+}
+
+func (*h5) StoreLookahead() uint {
+ return 4
+}
+
+/* HashBytes is the function that chooses the bucket to place the address in. */
+func hashBytesH5(data []byte, shift int) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint32(h >> uint(shift))
+}
+
+type h5 struct {
+ hasherCommon
+ bucket_size_ uint
+ block_size_ uint
+ hash_shift_ int
+ block_mask_ uint32
+ num []uint16
+ buckets []uint32
+}
+
+func (h *h5) Initialize(params *encoderParams) {
+ h.hash_shift_ = 32 - h.params.bucket_bits
+ h.bucket_size_ = uint(1) << uint(h.params.bucket_bits)
+ h.block_size_ = uint(1) << uint(h.params.block_bits)
+ h.block_mask_ = uint32(h.block_size_ - 1)
+ h.num = make([]uint16, h.bucket_size_)
+ h.buckets = make([]uint32, h.block_size_*h.bucket_size_)
+}
+
+func (h *h5) Prepare(one_shot bool, input_size uint, data []byte) {
+ var num []uint16 = h.num
+ var partial_prepare_threshold uint = h.bucket_size_ >> 6
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var key uint32 = hashBytesH5(data[i:], h.hash_shift_)
+ num[key] = 0
+ }
+ } else {
+ for i := 0; i < int(h.bucket_size_); i++ {
+ num[i] = 0
+ }
+ }
+}
+
+/* Look at 4 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value of ix at that position. */
+func (h *h5) Store(data []byte, mask uint, ix uint) {
+ var num []uint16 = h.num
+ var key uint32 = hashBytesH5(data[ix&mask:], h.hash_shift_)
+ var minor_ix uint = uint(num[key]) & uint(h.block_mask_)
+ var offset uint = minor_ix + uint(key<= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ringbuffer_mask, position-3)
+ h.Store(ringbuffer, ringbuffer_mask, position-2)
+ h.Store(ringbuffer, ringbuffer_mask, position-1)
+ }
+}
+
+func (h *h5) PrepareDistanceCache(distance_cache []int) {
+ prepareDistanceCache(distance_cache, h.params.num_last_distances_to_check)
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: PrepareDistanceCacheH5 must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke PrepareDistanceCacheH5 once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *h5) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var num []uint16 = h.num
+ var buckets []uint32 = h.buckets
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = out.len
+ var i uint
+ var bucket []uint32
+ /* Don't accept a short copy from far away. */
+ out.len = 0
+
+ out.len_code_delta = 0
+
+ /* Try last distance first. */
+ for i = 0; i < uint(h.params.num_last_distances_to_check); i++ {
+ var backward uint = uint(distance_cache[i])
+ var prev_ix uint = uint(cur_ix - backward)
+ if prev_ix >= cur_ix {
+ continue
+ }
+
+ if backward > max_backward {
+ continue
+ }
+
+ prev_ix &= ring_buffer_mask
+
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 3 || (len == 2 && i < 2) {
+ /* Comparing for >= 2 does not change the semantics, but just saves for
+ a few unnecessary binary logarithms in backward reference score,
+ since we are not interested in such short matches. */
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ if i != 0 {
+ score -= backwardReferencePenaltyUsingLastDistance(i)
+ }
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+ }
+ {
+ var key uint32 = hashBytesH5(data[cur_ix_masked:], h.hash_shift_)
+ bucket = buckets[key< h.block_size_ {
+ down = uint(num[key]) - h.block_size_
+ } else {
+ down = 0
+ }
+ for i = uint(num[key]); i > down; {
+ var prev_ix uint
+ i--
+ prev_ix = uint(bucket[uint32(i)&h.block_mask_])
+ var backward uint = cur_ix - prev_ix
+ if backward > max_backward {
+ break
+ }
+
+ prev_ix &= ring_buffer_mask
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+
+ bucket[uint32(num[key])&h.block_mask_] = uint32(cur_ix)
+ num[key]++
+ }
+
+ if min_score == out.score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h6.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h6.go
new file mode 100644
index 000000000000..80bb224aa875
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/h6.go
@@ -0,0 +1,216 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (bucket_size_) to a ring buffer of
+ fixed size (block_size_). The ring buffer contains the last block_size_
+ index positions of the given hash key in the compressed data. */
+func (*h6) HashTypeLength() uint {
+ return 8
+}
+
+func (*h6) StoreLookahead() uint {
+ return 8
+}
+
+/* HashBytes is the function that chooses the bucket to place the address in. */
+func hashBytesH6(data []byte, mask uint64, shift int) uint32 {
+ var h uint64 = (binary.LittleEndian.Uint64(data) & mask) * kHashMul64Long
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint32(h >> uint(shift))
+}
+
+type h6 struct {
+ hasherCommon
+ bucket_size_ uint
+ block_size_ uint
+ hash_shift_ int
+ hash_mask_ uint64
+ block_mask_ uint32
+ num []uint16
+ buckets []uint32
+}
+
+func (h *h6) Initialize(params *encoderParams) {
+ h.hash_shift_ = 64 - h.params.bucket_bits
+ h.hash_mask_ = (^(uint64(0))) >> uint(64-8*h.params.hash_len)
+ h.bucket_size_ = uint(1) << uint(h.params.bucket_bits)
+ h.block_size_ = uint(1) << uint(h.params.block_bits)
+ h.block_mask_ = uint32(h.block_size_ - 1)
+ h.num = make([]uint16, h.bucket_size_)
+ h.buckets = make([]uint32, h.block_size_*h.bucket_size_)
+}
+
+func (h *h6) Prepare(one_shot bool, input_size uint, data []byte) {
+ var num []uint16 = h.num
+ var partial_prepare_threshold uint = h.bucket_size_ >> 6
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var key uint32 = hashBytesH6(data[i:], h.hash_mask_, h.hash_shift_)
+ num[key] = 0
+ }
+ } else {
+ for i := 0; i < int(h.bucket_size_); i++ {
+ num[i] = 0
+ }
+ }
+}
+
+/* Look at 4 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value of ix at that position. */
+func (h *h6) Store(data []byte, mask uint, ix uint) {
+ var num []uint16 = h.num
+ var key uint32 = hashBytesH6(data[ix&mask:], h.hash_mask_, h.hash_shift_)
+ var minor_ix uint = uint(num[key]) & uint(h.block_mask_)
+ var offset uint = minor_ix + uint(key<= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ringbuffer_mask, position-3)
+ h.Store(ringbuffer, ringbuffer_mask, position-2)
+ h.Store(ringbuffer, ringbuffer_mask, position-1)
+ }
+}
+
+func (h *h6) PrepareDistanceCache(distance_cache []int) {
+ prepareDistanceCache(distance_cache, h.params.num_last_distances_to_check)
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: PrepareDistanceCacheH6 must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke PrepareDistanceCacheH6 once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *h6) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var num []uint16 = h.num
+ var buckets []uint32 = h.buckets
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = out.len
+ var i uint
+ var bucket []uint32
+ /* Don't accept a short copy from far away. */
+ out.len = 0
+
+ out.len_code_delta = 0
+
+ /* Try last distance first. */
+ for i = 0; i < uint(h.params.num_last_distances_to_check); i++ {
+ var backward uint = uint(distance_cache[i])
+ var prev_ix uint = uint(cur_ix - backward)
+ if prev_ix >= cur_ix {
+ continue
+ }
+
+ if backward > max_backward {
+ continue
+ }
+
+ prev_ix &= ring_buffer_mask
+
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 3 || (len == 2 && i < 2) {
+ /* Comparing for >= 2 does not change the semantics, but just saves for
+ a few unnecessary binary logarithms in backward reference score,
+ since we are not interested in such short matches. */
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ if i != 0 {
+ score -= backwardReferencePenaltyUsingLastDistance(i)
+ }
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+ }
+ {
+ var key uint32 = hashBytesH6(data[cur_ix_masked:], h.hash_mask_, h.hash_shift_)
+ bucket = buckets[key< h.block_size_ {
+ down = uint(num[key]) - h.block_size_
+ } else {
+ down = 0
+ }
+ for i = uint(num[key]); i > down; {
+ var prev_ix uint
+ i--
+ prev_ix = uint(bucket[uint32(i)&h.block_mask_])
+ var backward uint = cur_ix - prev_ix
+ if backward > max_backward {
+ break
+ }
+
+ prev_ix &= ring_buffer_mask
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+
+ bucket[uint32(num[key])&h.block_mask_] = uint32(cur_ix)
+ num[key]++
+ }
+
+ if min_score == out.score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash.go
new file mode 100644
index 000000000000..00f812e87ec8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash.go
@@ -0,0 +1,342 @@
+package brotli
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+type hasherCommon struct {
+ params hasherParams
+ is_prepared_ bool
+ dict_num_lookups uint
+ dict_num_matches uint
+}
+
+func (h *hasherCommon) Common() *hasherCommon {
+ return h
+}
+
+type hasherHandle interface {
+ Common() *hasherCommon
+ Initialize(params *encoderParams)
+ Prepare(one_shot bool, input_size uint, data []byte)
+ StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint)
+ HashTypeLength() uint
+ StoreLookahead() uint
+ PrepareDistanceCache(distance_cache []int)
+ FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult)
+ StoreRange(data []byte, mask uint, ix_start uint, ix_end uint)
+ Store(data []byte, mask uint, ix uint)
+}
+
+const kCutoffTransformsCount uint32 = 10
+
+/* 0, 12, 27, 23, 42, 63, 56, 48, 59, 64 */
+/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */
+const kCutoffTransforms uint64 = 0x071B520ADA2D3200
+
+type hasherSearchResult struct {
+ len uint
+ distance uint
+ score uint
+ len_code_delta int
+}
+
+/* kHashMul32 multiplier has these properties:
+ * The multiplier must be odd. Otherwise we may lose the highest bit.
+ * No long streaks of ones or zeros.
+ * There is no effort to ensure that it is a prime, the oddity is enough
+ for this use.
+ * The number has been tuned heuristically against compression benchmarks. */
+const kHashMul32 uint32 = 0x1E35A7BD
+
+const kHashMul64 uint64 = 0x1E35A7BD1E35A7BD
+
+const kHashMul64Long uint64 = 0x1FE35A7BD3579BD3
+
+func hash14(data []byte) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> (32 - 14)
+}
+
+func prepareDistanceCache(distance_cache []int, num_distances int) {
+ if num_distances > 4 {
+ var last_distance int = distance_cache[0]
+ distance_cache[4] = last_distance - 1
+ distance_cache[5] = last_distance + 1
+ distance_cache[6] = last_distance - 2
+ distance_cache[7] = last_distance + 2
+ distance_cache[8] = last_distance - 3
+ distance_cache[9] = last_distance + 3
+ if num_distances > 10 {
+ var next_last_distance int = distance_cache[1]
+ distance_cache[10] = next_last_distance - 1
+ distance_cache[11] = next_last_distance + 1
+ distance_cache[12] = next_last_distance - 2
+ distance_cache[13] = next_last_distance + 2
+ distance_cache[14] = next_last_distance - 3
+ distance_cache[15] = next_last_distance + 3
+ }
+ }
+}
+
+const literalByteScore = 135
+
+const distanceBitPenalty = 30
+
+/* Score must be positive after applying maximal penalty. */
+const scoreBase = (distanceBitPenalty * 8 * 8)
+
+/* Usually, we always choose the longest backward reference. This function
+ allows for the exception of that rule.
+
+ If we choose a backward reference that is further away, it will
+ usually be coded with more bits. We approximate this by assuming
+ log2(distance). If the distance can be expressed in terms of the
+ last four distances, we use some heuristic constants to estimate
+ the bits cost. For the first up to four literals we use the bit
+ cost of the literals from the literal cost model, after that we
+ use the average bit cost of the cost model.
+
+ This function is used to sometimes discard a longer backward reference
+ when it is not much longer and the bit cost for encoding it is more
+ than the saved literals.
+
+ backward_reference_offset MUST be positive. */
+func backwardReferenceScore(copy_length uint, backward_reference_offset uint) uint {
+ return scoreBase + literalByteScore*uint(copy_length) - distanceBitPenalty*uint(log2FloorNonZero(backward_reference_offset))
+}
+
+func backwardReferenceScoreUsingLastDistance(copy_length uint) uint {
+ return literalByteScore*uint(copy_length) + scoreBase + 15
+}
+
+func backwardReferencePenaltyUsingLastDistance(distance_short_code uint) uint {
+ return uint(39) + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE)
+}
+
+func testStaticDictionaryItem(dictionary *encoderDictionary, item uint, data []byte, max_length uint, max_backward uint, max_distance uint, out *hasherSearchResult) bool {
+ var len uint
+ var word_idx uint
+ var offset uint
+ var matchlen uint
+ var backward uint
+ var score uint
+ len = item & 0x1F
+ word_idx = item >> 5
+ offset = uint(dictionary.words.offsets_by_length[len]) + len*word_idx
+ if len > max_length {
+ return false
+ }
+
+ matchlen = findMatchLengthWithLimit(data, dictionary.words.data[offset:], uint(len))
+ if matchlen+uint(dictionary.cutoffTransformsCount) <= len || matchlen == 0 {
+ return false
+ }
+ {
+ var cut uint = len - matchlen
+ var transform_id uint = (cut << 2) + uint((dictionary.cutoffTransforms>>(cut*6))&0x3F)
+ backward = max_backward + 1 + word_idx + (transform_id << dictionary.words.size_bits_by_length[len])
+ }
+
+ if backward > max_distance {
+ return false
+ }
+
+ score = backwardReferenceScore(matchlen, backward)
+ if score < out.score {
+ return false
+ }
+
+ out.len = matchlen
+ out.len_code_delta = int(len) - int(matchlen)
+ out.distance = backward
+ out.score = score
+ return true
+}
+
+func searchInStaticDictionary(dictionary *encoderDictionary, handle hasherHandle, data []byte, max_length uint, max_backward uint, max_distance uint, out *hasherSearchResult, shallow bool) {
+ var key uint
+ var i uint
+ var self *hasherCommon = handle.Common()
+ if self.dict_num_matches < self.dict_num_lookups>>7 {
+ return
+ }
+
+ key = uint(hash14(data) << 1)
+ for i = 0; ; (func() { i++; key++ })() {
+ var tmp uint
+ if shallow {
+ tmp = 1
+ } else {
+ tmp = 2
+ }
+ if i >= tmp {
+ break
+ }
+ var item uint = uint(dictionary.hash_table[key])
+ self.dict_num_lookups++
+ if item != 0 {
+ var item_matches bool = testStaticDictionaryItem(dictionary, item, data, max_length, max_backward, max_distance, out)
+ if item_matches {
+ self.dict_num_matches++
+ }
+ }
+ }
+}
+
+type backwardMatch struct {
+ distance uint32
+ length_and_code uint32
+}
+
+func initBackwardMatch(self *backwardMatch, dist uint, len uint) {
+ self.distance = uint32(dist)
+ self.length_and_code = uint32(len << 5)
+}
+
+func initDictionaryBackwardMatch(self *backwardMatch, dist uint, len uint, len_code uint) {
+ self.distance = uint32(dist)
+ var tmp uint
+ if len == len_code {
+ tmp = 0
+ } else {
+ tmp = len_code
+ }
+ self.length_and_code = uint32(len<<5 | tmp)
+}
+
+func backwardMatchLength(self *backwardMatch) uint {
+ return uint(self.length_and_code >> 5)
+}
+
+func backwardMatchLengthCode(self *backwardMatch) uint {
+ var code uint = uint(self.length_and_code) & 31
+ if code != 0 {
+ return code
+ } else {
+ return backwardMatchLength(self)
+ }
+}
+
+func hasherReset(handle hasherHandle) {
+ if handle == nil {
+ return
+ }
+ handle.Common().is_prepared_ = false
+}
+
+func newHasher(typ int) hasherHandle {
+ switch typ {
+ case 2:
+ return &hashLongestMatchQuickly{
+ bucketBits: 16,
+ bucketSweep: 1,
+ hashLen: 5,
+ useDictionary: true,
+ }
+ case 3:
+ return &hashLongestMatchQuickly{
+ bucketBits: 16,
+ bucketSweep: 2,
+ hashLen: 5,
+ useDictionary: false,
+ }
+ case 4:
+ return &hashLongestMatchQuickly{
+ bucketBits: 17,
+ bucketSweep: 4,
+ hashLen: 5,
+ useDictionary: true,
+ }
+ case 5:
+ return new(h5)
+ case 6:
+ return new(h6)
+ case 10:
+ return new(h10)
+ case 35:
+ return &hashComposite{
+ ha: newHasher(3),
+ hb: &hashRolling{jump: 4},
+ }
+ case 40:
+ return &hashForgetfulChain{
+ bucketBits: 15,
+ numBanks: 1,
+ bankBits: 16,
+ numLastDistancesToCheck: 4,
+ }
+ case 41:
+ return &hashForgetfulChain{
+ bucketBits: 15,
+ numBanks: 1,
+ bankBits: 16,
+ numLastDistancesToCheck: 10,
+ }
+ case 42:
+ return &hashForgetfulChain{
+ bucketBits: 15,
+ numBanks: 512,
+ bankBits: 9,
+ numLastDistancesToCheck: 16,
+ }
+ case 54:
+ return &hashLongestMatchQuickly{
+ bucketBits: 20,
+ bucketSweep: 4,
+ hashLen: 7,
+ useDictionary: false,
+ }
+ case 55:
+ return &hashComposite{
+ ha: newHasher(54),
+ hb: &hashRolling{jump: 4},
+ }
+ case 65:
+ return &hashComposite{
+ ha: newHasher(6),
+ hb: &hashRolling{jump: 1},
+ }
+ }
+
+ panic(fmt.Sprintf("unknown hasher type: %d", typ))
+}
+
+func hasherSetup(handle *hasherHandle, params *encoderParams, data []byte, position uint, input_size uint, is_last bool) {
+ var self hasherHandle = nil
+ var common *hasherCommon = nil
+ var one_shot bool = (position == 0 && is_last)
+ if *handle == nil {
+ chooseHasher(params, ¶ms.hasher)
+ self = newHasher(params.hasher.type_)
+
+ *handle = self
+ common = self.Common()
+ common.params = params.hasher
+ self.Initialize(params)
+ }
+
+ self = *handle
+ common = self.Common()
+ if !common.is_prepared_ {
+ self.Prepare(one_shot, input_size, data)
+
+ if position == 0 {
+ common.dict_num_lookups = 0
+ common.dict_num_matches = 0
+ }
+
+ common.is_prepared_ = true
+ }
+}
+
+func initOrStitchToPreviousBlock(handle *hasherHandle, data []byte, mask uint, params *encoderParams, position uint, input_size uint, is_last bool) {
+ var self hasherHandle
+ hasherSetup(handle, params, data, position, input_size, is_last)
+ self = *handle
+ self.StitchToPreviousBlock(input_size, position, data, mask)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_composite.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_composite.go
new file mode 100644
index 000000000000..a65fe2e6a9a2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_composite.go
@@ -0,0 +1,93 @@
+package brotli
+
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func (h *hashComposite) HashTypeLength() uint {
+ var a uint = h.ha.HashTypeLength()
+ var b uint = h.hb.HashTypeLength()
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func (h *hashComposite) StoreLookahead() uint {
+ var a uint = h.ha.StoreLookahead()
+ var b uint = h.hb.StoreLookahead()
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A
+ and HASHER_B. */
+type hashComposite struct {
+ hasherCommon
+ ha hasherHandle
+ hb hasherHandle
+ params *encoderParams
+}
+
+func (h *hashComposite) Initialize(params *encoderParams) {
+ h.params = params
+}
+
+/* TODO: Initialize of the hashers is defered to Prepare (and params
+ remembered here) because we don't get the one_shot and input_size params
+ here that are needed to know the memory size of them. Instead provide
+ those params to all hashers InitializehashComposite */
+func (h *hashComposite) Prepare(one_shot bool, input_size uint, data []byte) {
+ if h.ha == nil {
+ var common_a *hasherCommon
+ var common_b *hasherCommon
+
+ common_a = h.ha.Common()
+ common_a.params = h.params.hasher
+ common_a.is_prepared_ = false
+ common_a.dict_num_lookups = 0
+ common_a.dict_num_matches = 0
+ h.ha.Initialize(h.params)
+
+ common_b = h.hb.Common()
+ common_b.params = h.params.hasher
+ common_b.is_prepared_ = false
+ common_b.dict_num_lookups = 0
+ common_b.dict_num_matches = 0
+ h.hb.Initialize(h.params)
+ }
+
+ h.ha.Prepare(one_shot, input_size, data)
+ h.hb.Prepare(one_shot, input_size, data)
+}
+
+func (h *hashComposite) Store(data []byte, mask uint, ix uint) {
+ h.ha.Store(data, mask, ix)
+ h.hb.Store(data, mask, ix)
+}
+
+func (h *hashComposite) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ h.ha.StoreRange(data, mask, ix_start, ix_end)
+ h.hb.StoreRange(data, mask, ix_start, ix_end)
+}
+
+func (h *hashComposite) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {
+ h.ha.StitchToPreviousBlock(num_bytes, position, ringbuffer, ring_buffer_mask)
+ h.hb.StitchToPreviousBlock(num_bytes, position, ringbuffer, ring_buffer_mask)
+}
+
+func (h *hashComposite) PrepareDistanceCache(distance_cache []int) {
+ h.ha.PrepareDistanceCache(distance_cache)
+ h.hb.PrepareDistanceCache(distance_cache)
+}
+
+func (h *hashComposite) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ h.ha.FindLongestMatch(dictionary, data, ring_buffer_mask, distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out)
+ h.hb.FindLongestMatch(dictionary, data, ring_buffer_mask, distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go
new file mode 100644
index 000000000000..306e46d3dba9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go
@@ -0,0 +1,252 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func (*hashForgetfulChain) HashTypeLength() uint {
+ return 4
+}
+
+func (*hashForgetfulChain) StoreLookahead() uint {
+ return 4
+}
+
+/* HashBytes is the function that chooses the bucket to place the address in.*/
+func (h *hashForgetfulChain) HashBytes(data []byte) uint {
+ var hash uint32 = binary.LittleEndian.Uint32(data) * kHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint(hash >> (32 - h.bucketBits))
+}
+
+type slot struct {
+ delta uint16
+ next uint16
+}
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ Hashes are stored in chains which are bucketed to groups. Group of chains
+ share a storage "bank". When more than "bank size" chain nodes are added,
+ oldest nodes are replaced; this way several chains may share a tail. */
+type hashForgetfulChain struct {
+ hasherCommon
+
+ bucketBits uint
+ numBanks uint
+ bankBits uint
+ numLastDistancesToCheck int
+
+ addr []uint32
+ head []uint16
+ tiny_hash [65536]byte
+ banks [][]slot
+ free_slot_idx []uint16
+ max_hops uint
+}
+
+func (h *hashForgetfulChain) Initialize(params *encoderParams) {
+ var q uint
+ if params.quality > 6 {
+ q = 7
+ } else {
+ q = 8
+ }
+ h.max_hops = q << uint(params.quality-4)
+
+ bankSize := 1 << h.bankBits
+ bucketSize := 1 << h.bucketBits
+
+ h.addr = make([]uint32, bucketSize)
+ h.head = make([]uint16, bucketSize)
+ h.banks = make([][]slot, h.numBanks)
+ for i := range h.banks {
+ h.banks[i] = make([]slot, bankSize)
+ }
+ h.free_slot_idx = make([]uint16, h.numBanks)
+}
+
+func (h *hashForgetfulChain) Prepare(one_shot bool, input_size uint, data []byte) {
+ var partial_prepare_threshold uint = (1 << h.bucketBits) >> 6
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var bucket uint = h.HashBytes(data[i:])
+
+ /* See InitEmpty comment. */
+ h.addr[bucket] = 0xCCCCCCCC
+
+ h.head[bucket] = 0xCCCC
+ }
+ } else {
+ /* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
+ processed by hasher never reaches 3GB + 64M; this makes all new chains
+ to be terminated after the first node. */
+ for i := range h.addr {
+ h.addr[i] = 0xCCCCCCCC
+ }
+
+ for i := range h.head {
+ h.head[i] = 0
+ }
+ }
+
+ h.tiny_hash = [65536]byte{}
+ for i := range h.free_slot_idx {
+ h.free_slot_idx[i] = 0
+ }
+}
+
+/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
+ node to corresponding chain; also update tiny_hash for current position. */
+func (h *hashForgetfulChain) Store(data []byte, mask uint, ix uint) {
+ var key uint = h.HashBytes(data[ix&mask:])
+ var bank uint = key & (h.numBanks - 1)
+ idx := uint(h.free_slot_idx[bank]) & ((1 << h.bankBits) - 1)
+ h.free_slot_idx[bank]++
+ var delta uint = ix - uint(h.addr[key])
+ h.tiny_hash[uint16(ix)] = byte(key)
+ if delta > 0xFFFF {
+ delta = 0xFFFF
+ }
+ h.banks[bank][idx].delta = uint16(delta)
+ h.banks[bank][idx].next = h.head[key]
+ h.addr[key] = uint32(ix)
+ h.head[key] = uint16(idx)
+}
+
+func (h *hashForgetfulChain) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ var i uint
+ for i = ix_start; i < ix_end; i++ {
+ h.Store(data, mask, i)
+ }
+}
+
+func (h *hashForgetfulChain) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {
+ if num_bytes >= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ring_buffer_mask, position-3)
+ h.Store(ringbuffer, ring_buffer_mask, position-2)
+ h.Store(ringbuffer, ring_buffer_mask, position-1)
+ }
+}
+
+func (h *hashForgetfulChain) PrepareDistanceCache(distance_cache []int) {
+ prepareDistanceCache(distance_cache, h.numLastDistancesToCheck)
+}
+
+/* Find a longest backward match of &data[cur_ix] up to the length of
+ max_length and stores the position cur_ix in the hash table.
+
+ REQUIRES: PrepareDistanceCachehashForgetfulChain must be invoked for current distance cache
+ values; if this method is invoked repeatedly with the same distance
+ cache values, it is enough to invoke PrepareDistanceCachehashForgetfulChain once.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *hashForgetfulChain) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = out.len
+ var key uint = h.HashBytes(data[cur_ix_masked:])
+ var tiny_hash byte = byte(key)
+ /* Don't accept a short copy from far away. */
+ out.len = 0
+
+ out.len_code_delta = 0
+
+ /* Try last distance first. */
+ for i := 0; i < h.numLastDistancesToCheck; i++ {
+ var backward uint = uint(distance_cache[i])
+ var prev_ix uint = (cur_ix - backward)
+
+ /* For distance code 0 we want to consider 2-byte matches. */
+ if i > 0 && h.tiny_hash[uint16(prev_ix)] != tiny_hash {
+ continue
+ }
+ if prev_ix >= cur_ix || backward > max_backward {
+ continue
+ }
+
+ prev_ix &= ring_buffer_mask
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 2 {
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ if i != 0 {
+ score -= backwardReferencePenaltyUsingLastDistance(uint(i))
+ }
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+ }
+ {
+ var bank uint = key & (h.numBanks - 1)
+ var backward uint = 0
+ var hops uint = h.max_hops
+ var delta uint = cur_ix - uint(h.addr[key])
+ var slot uint = uint(h.head[key])
+ for {
+ tmp6 := hops
+ hops--
+ if tmp6 == 0 {
+ break
+ }
+ var prev_ix uint
+ var last uint = slot
+ backward += delta
+ if backward > max_backward {
+ break
+ }
+ prev_ix = (cur_ix - backward) & ring_buffer_mask
+ slot = uint(h.banks[bank][last].next)
+ delta = uint(h.banks[bank][last].delta)
+ if cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {
+ continue
+ }
+ {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ /* Comparing for >= 3 does not change the semantics, but just saves
+ for a few unnecessary binary logarithms in backward reference
+ score, since we are not interested in such short matches. */
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = best_score
+ }
+ }
+ }
+ }
+
+ h.Store(data, ring_buffer_mask, cur_ix)
+ }
+
+ if out.score == min_score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go
new file mode 100644
index 000000000000..9375dc155398
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go
@@ -0,0 +1,214 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
+ a little faster (0.5% - 1%) and it compresses 0.15% better on small text
+ and HTML inputs. */
+
+func (*hashLongestMatchQuickly) HashTypeLength() uint {
+ return 8
+}
+
+func (*hashLongestMatchQuickly) StoreLookahead() uint {
+ return 8
+}
+
+/* HashBytes is the function that chooses the bucket to place
+ the address in. The HashLongestMatch and hashLongestMatchQuickly
+ classes have separate, different implementations of hashing. */
+func (h *hashLongestMatchQuickly) HashBytes(data []byte) uint32 {
+ var hash uint64 = ((binary.LittleEndian.Uint64(data) << (64 - 8*h.hashLen)) * kHashMul64)
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return uint32(hash >> (64 - h.bucketBits))
+}
+
+/* A (forgetful) hash table to the data seen by the compressor, to
+ help create backward references to previous data.
+
+ This is a hash map of fixed size (1 << 16). Starting from the
+ given index, 1 buckets are used to store values of a key. */
+type hashLongestMatchQuickly struct {
+ hasherCommon
+
+ bucketBits uint
+ bucketSweep int
+ hashLen uint
+ useDictionary bool
+
+ buckets []uint32
+}
+
+func (h *hashLongestMatchQuickly) Initialize(params *encoderParams) {
+ h.buckets = make([]uint32, 1<> 7
+ /* Partial preparation is 100 times slower (per socket). */
+ if one_shot && input_size <= partial_prepare_threshold {
+ var i uint
+ for i = 0; i < input_size; i++ {
+ var key uint32 = h.HashBytes(data[i:])
+ for j := 0; j < h.bucketSweep; j++ {
+ h.buckets[key+uint32(j)] = 0
+ }
+ }
+ } else {
+ /* It is not strictly necessary to fill this buffer here, but
+ not filling will make the results of the compression stochastic
+ (but correct). This is because random data would cause the
+ system to find accidentally good backward references here and there. */
+ for i := range h.buckets {
+ h.buckets[i] = 0
+ }
+ }
+}
+
+/* Look at 5 bytes at &data[ix & mask].
+ Compute a hash from these, and store the value somewhere within
+ [ix .. ix+3]. */
+func (h *hashLongestMatchQuickly) Store(data []byte, mask uint, ix uint) {
+ var key uint32 = h.HashBytes(data[ix&mask:])
+ var off uint32 = uint32(ix>>3) % uint32(h.bucketSweep)
+ /* Wiggle the value with the bucket sweep range. */
+ h.buckets[key+off] = uint32(ix)
+}
+
+func (h *hashLongestMatchQuickly) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+ var i uint
+ for i = ix_start; i < ix_end; i++ {
+ h.Store(data, mask, i)
+ }
+}
+
+func (h *hashLongestMatchQuickly) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {
+ if num_bytes >= h.HashTypeLength()-1 && position >= 3 {
+ /* Prepare the hashes for three last bytes of the last write.
+ These could not be calculated before, since they require knowledge
+ of both the previous and the current block. */
+ h.Store(ringbuffer, ringbuffer_mask, position-3)
+ h.Store(ringbuffer, ringbuffer_mask, position-2)
+ h.Store(ringbuffer, ringbuffer_mask, position-1)
+ }
+}
+
+func (*hashLongestMatchQuickly) PrepareDistanceCache(distance_cache []int) {
+}
+
+/* Find a longest backward match of &data[cur_ix & ring_buffer_mask]
+ up to the length of max_length and stores the position cur_ix in the
+ hash table.
+
+ Does not look for matches longer than max_length.
+ Does not look for matches further away than max_backward.
+ Writes the best match into |out|.
+ |out|->score is updated only if a better match is found. */
+func (h *hashLongestMatchQuickly) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var best_len_in uint = out.len
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var key uint32 = h.HashBytes(data[cur_ix_masked:])
+ var compare_char int = int(data[cur_ix_masked+best_len_in])
+ var min_score uint = out.score
+ var best_score uint = out.score
+ var best_len uint = best_len_in
+ var cached_backward uint = uint(distance_cache[0])
+ var prev_ix uint = cur_ix - cached_backward
+ var bucket []uint32
+ out.len_code_delta = 0
+ if prev_ix < cur_ix {
+ prev_ix &= uint(uint32(ring_buffer_mask))
+ if compare_char == int(data[prev_ix+best_len]) {
+ var len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ var score uint = backwardReferenceScoreUsingLastDistance(uint(len))
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = uint(len)
+ out.distance = cached_backward
+ out.score = best_score
+ compare_char = int(data[cur_ix_masked+best_len])
+ if h.bucketSweep == 1 {
+ h.buckets[key] = uint32(cur_ix)
+ return
+ }
+ }
+ }
+ }
+ }
+
+ if h.bucketSweep == 1 {
+ var backward uint
+ var len uint
+
+ /* Only one to look for, don't bother to prepare for a loop. */
+ prev_ix = uint(h.buckets[key])
+
+ h.buckets[key] = uint32(cur_ix)
+ backward = cur_ix - prev_ix
+ prev_ix &= uint(uint32(ring_buffer_mask))
+ if compare_char != int(data[prev_ix+best_len_in]) {
+ return
+ }
+
+ if backward == 0 || backward > max_backward {
+ return
+ }
+
+ len = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ out.len = uint(len)
+ out.distance = backward
+ out.score = score
+ return
+ }
+ }
+ } else {
+ bucket = h.buckets[key:]
+ var i int
+ prev_ix = uint(bucket[0])
+ bucket = bucket[1:]
+ for i = 0; i < h.bucketSweep; (func() { i++; tmp3 := bucket; bucket = bucket[1:]; prev_ix = uint(tmp3[0]) })() {
+ var backward uint = cur_ix - prev_ix
+ var len uint
+ prev_ix &= uint(uint32(ring_buffer_mask))
+ if compare_char != int(data[prev_ix+best_len]) {
+ continue
+ }
+
+ if backward == 0 || backward > max_backward {
+ continue
+ }
+
+ len = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)
+ if len >= 4 {
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if best_score < score {
+ best_score = score
+ best_len = uint(len)
+ out.len = best_len
+ out.distance = backward
+ out.score = score
+ compare_char = int(data[cur_ix_masked+best_len])
+ }
+ }
+ }
+ }
+
+ if h.useDictionary && min_score == out.score {
+ searchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, true)
+ }
+
+ h.buckets[key+uint32((cur_ix>>3)%uint(h.bucketSweep))] = uint32(cur_ix)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_rolling.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_rolling.go
new file mode 100644
index 000000000000..6630fc07e4bb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/hash_rolling.go
@@ -0,0 +1,168 @@
+package brotli
+
+/* Copyright 2018 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* NOTE: this hasher does not search in the dictionary. It is used as
+ backup-hasher, the main hasher already searches in it. */
+
+const kRollingHashMul32 uint32 = 69069
+
+const kInvalidPosHashRolling uint32 = 0xffffffff
+
+/* This hasher uses a longer forward length, but returning a higher value here
+ will hurt compression by the main hasher when combined with a composite
+ hasher. The hasher tests for forward itself instead. */
+func (*hashRolling) HashTypeLength() uint {
+ return 4
+}
+
+func (*hashRolling) StoreLookahead() uint {
+ return 4
+}
+
+/* Computes a code from a single byte. A lookup table of 256 values could be
+ used, but simply adding 1 works about as good. */
+func (*hashRolling) HashByte(b byte) uint32 {
+ return uint32(b) + 1
+}
+
+func (h *hashRolling) HashRollingFunctionInitial(state uint32, add byte, factor uint32) uint32 {
+ return uint32(factor*state + h.HashByte(add))
+}
+
+func (h *hashRolling) HashRollingFunction(state uint32, add byte, rem byte, factor uint32, factor_remove uint32) uint32 {
+ return uint32(factor*state + h.HashByte(add) - factor_remove*h.HashByte(rem))
+}
+
+/* Rolling hash for long distance long string matches. Stores one position
+ per bucket, bucket key is computed over a long region. */
+type hashRolling struct {
+ hasherCommon
+
+ jump int
+
+ state uint32
+ table []uint32
+ next_ix uint
+ factor uint32
+ factor_remove uint32
+}
+
+func (h *hashRolling) Initialize(params *encoderParams) {
+ h.state = 0
+ h.next_ix = 0
+
+ h.factor = kRollingHashMul32
+
+ /* Compute the factor of the oldest byte to remove: factor**steps modulo
+ 0xffffffff (the multiplications rely on 32-bit overflow) */
+ h.factor_remove = 1
+
+ for i := 0; i < 32; i += h.jump {
+ h.factor_remove *= h.factor
+ }
+
+ h.table = make([]uint32, 16777216)
+ for i := 0; i < 16777216; i++ {
+ h.table[i] = kInvalidPosHashRolling
+ }
+}
+
+func (h *hashRolling) Prepare(one_shot bool, input_size uint, data []byte) {
+ /* Too small size, cannot use this hasher. */
+ if input_size < 32 {
+ return
+ }
+ h.state = 0
+ for i := 0; i < 32; i += h.jump {
+ h.state = h.HashRollingFunctionInitial(h.state, data[i], h.factor)
+ }
+}
+
+func (*hashRolling) Store(data []byte, mask uint, ix uint) {
+}
+
+func (*hashRolling) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {
+}
+
+func (h *hashRolling) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {
+ var position_masked uint
+ /* In this case we must re-initialize the hasher from scratch from the
+ current position. */
+
+ var available uint = num_bytes
+ if position&uint(h.jump-1) != 0 {
+ var diff uint = uint(h.jump) - (position & uint(h.jump-1))
+ if diff > available {
+ available = 0
+ } else {
+ available = available - diff
+ }
+ position += diff
+ }
+
+ position_masked = position & ring_buffer_mask
+
+ /* wrapping around ringbuffer not handled. */
+ if available > ring_buffer_mask-position_masked {
+ available = ring_buffer_mask - position_masked
+ }
+
+ h.Prepare(false, available, ringbuffer[position&ring_buffer_mask:])
+ h.next_ix = position
+}
+
+func (*hashRolling) PrepareDistanceCache(distance_cache []int) {
+}
+
+func (h *hashRolling) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {
+ var cur_ix_masked uint = cur_ix & ring_buffer_mask
+ var pos uint = h.next_ix
+
+ if cur_ix&uint(h.jump-1) != 0 {
+ return
+ }
+
+ /* Not enough lookahead */
+ if max_length < 32 {
+ return
+ }
+
+ for pos = h.next_ix; pos <= cur_ix; pos += uint(h.jump) {
+ var code uint32 = h.state & ((16777216 * 64) - 1)
+ var rem byte = data[pos&ring_buffer_mask]
+ var add byte = data[(pos+32)&ring_buffer_mask]
+ var found_ix uint = uint(kInvalidPosHashRolling)
+
+ h.state = h.HashRollingFunction(h.state, add, rem, h.factor, h.factor_remove)
+
+ if code < 16777216 {
+ found_ix = uint(h.table[code])
+ h.table[code] = uint32(pos)
+ if pos == cur_ix && uint32(found_ix) != kInvalidPosHashRolling {
+ /* The cast to 32-bit makes backward distances up to 4GB work even
+ if cur_ix is above 4GB, despite using 32-bit values in the table. */
+ var backward uint = uint(uint32(cur_ix - found_ix))
+ if backward <= max_backward {
+ var found_ix_masked uint = found_ix & ring_buffer_mask
+ var len uint = findMatchLengthWithLimit(data[found_ix_masked:], data[cur_ix_masked:], max_length)
+ if len >= 4 && len > out.len {
+ var score uint = backwardReferenceScore(uint(len), backward)
+ if score > out.score {
+ out.len = uint(len)
+ out.distance = backward
+ out.score = score
+ out.len_code_delta = 0
+ }
+ }
+ }
+ }
+ }
+ }
+
+ h.next_ix = cur_ix + uint(h.jump)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/histogram.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/histogram.go
new file mode 100644
index 000000000000..0346622beb31
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/histogram.go
@@ -0,0 +1,226 @@
+package brotli
+
+import "math"
+
+/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */
+const numHistogramDistanceSymbols = 544
+
+type histogramLiteral struct {
+ data_ [numLiteralSymbols]uint32
+ total_count_ uint
+ bit_cost_ float64
+}
+
+func histogramClearLiteral(self *histogramLiteral) {
+ self.data_ = [numLiteralSymbols]uint32{}
+ self.total_count_ = 0
+ self.bit_cost_ = math.MaxFloat64
+}
+
+func clearHistogramsLiteral(array []histogramLiteral, length uint) {
+ var i uint
+ for i = 0; i < length; i++ {
+ histogramClearLiteral(&array[i:][0])
+ }
+}
+
+func histogramAddLiteral(self *histogramLiteral, val uint) {
+ self.data_[val]++
+ self.total_count_++
+}
+
+func histogramAddVectorLiteral(self *histogramLiteral, p []byte, n uint) {
+ self.total_count_ += n
+ n += 1
+ for {
+ n--
+ if n == 0 {
+ break
+ }
+ self.data_[p[0]]++
+ p = p[1:]
+ }
+}
+
+func histogramAddHistogramLiteral(self *histogramLiteral, v *histogramLiteral) {
+ var i uint
+ self.total_count_ += v.total_count_
+ for i = 0; i < numLiteralSymbols; i++ {
+ self.data_[i] += v.data_[i]
+ }
+}
+
+func histogramDataSizeLiteral() uint {
+ return numLiteralSymbols
+}
+
+type histogramCommand struct {
+ data_ [numCommandSymbols]uint32
+ total_count_ uint
+ bit_cost_ float64
+}
+
+func histogramClearCommand(self *histogramCommand) {
+ self.data_ = [numCommandSymbols]uint32{}
+ self.total_count_ = 0
+ self.bit_cost_ = math.MaxFloat64
+}
+
+func clearHistogramsCommand(array []histogramCommand, length uint) {
+ var i uint
+ for i = 0; i < length; i++ {
+ histogramClearCommand(&array[i:][0])
+ }
+}
+
+func histogramAddCommand(self *histogramCommand, val uint) {
+ self.data_[val]++
+ self.total_count_++
+}
+
+func histogramAddVectorCommand(self *histogramCommand, p []uint16, n uint) {
+ self.total_count_ += n
+ n += 1
+ for {
+ n--
+ if n == 0 {
+ break
+ }
+ self.data_[p[0]]++
+ p = p[1:]
+ }
+}
+
+func histogramAddHistogramCommand(self *histogramCommand, v *histogramCommand) {
+ var i uint
+ self.total_count_ += v.total_count_
+ for i = 0; i < numCommandSymbols; i++ {
+ self.data_[i] += v.data_[i]
+ }
+}
+
+func histogramDataSizeCommand() uint {
+ return numCommandSymbols
+}
+
+type histogramDistance struct {
+ data_ [numDistanceSymbols]uint32
+ total_count_ uint
+ bit_cost_ float64
+}
+
+func histogramClearDistance(self *histogramDistance) {
+ self.data_ = [numDistanceSymbols]uint32{}
+ self.total_count_ = 0
+ self.bit_cost_ = math.MaxFloat64
+}
+
+func clearHistogramsDistance(array []histogramDistance, length uint) {
+ var i uint
+ for i = 0; i < length; i++ {
+ histogramClearDistance(&array[i:][0])
+ }
+}
+
+func histogramAddDistance(self *histogramDistance, val uint) {
+ self.data_[val]++
+ self.total_count_++
+}
+
+func histogramAddVectorDistance(self *histogramDistance, p []uint16, n uint) {
+ self.total_count_ += n
+ n += 1
+ for {
+ n--
+ if n == 0 {
+ break
+ }
+ self.data_[p[0]]++
+ p = p[1:]
+ }
+}
+
+func histogramAddHistogramDistance(self *histogramDistance, v *histogramDistance) {
+ var i uint
+ self.total_count_ += v.total_count_
+ for i = 0; i < numDistanceSymbols; i++ {
+ self.data_[i] += v.data_[i]
+ }
+}
+
+func histogramDataSizeDistance() uint {
+ return numDistanceSymbols
+}
+
+type blockSplitIterator struct {
+ split_ *blockSplit
+ idx_ uint
+ type_ uint
+ length_ uint
+}
+
+func initBlockSplitIterator(self *blockSplitIterator, split *blockSplit) {
+ self.split_ = split
+ self.idx_ = 0
+ self.type_ = 0
+ if len(split.lengths) > 0 {
+ self.length_ = uint(split.lengths[0])
+ } else {
+ self.length_ = 0
+ }
+}
+
+func blockSplitIteratorNext(self *blockSplitIterator) {
+ if self.length_ == 0 {
+ self.idx_++
+ self.type_ = uint(self.split_.types[self.idx_])
+ self.length_ = uint(self.split_.lengths[self.idx_])
+ }
+
+ self.length_--
+}
+
+func buildHistogramsWithContext(cmds []command, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit, ringbuffer []byte, start_pos uint, mask uint, prev_byte byte, prev_byte2 byte, context_modes []int, literal_histograms []histogramLiteral, insert_and_copy_histograms []histogramCommand, copy_dist_histograms []histogramDistance) {
+ var pos uint = start_pos
+ var literal_it blockSplitIterator
+ var insert_and_copy_it blockSplitIterator
+ var dist_it blockSplitIterator
+
+ initBlockSplitIterator(&literal_it, literal_split)
+ initBlockSplitIterator(&insert_and_copy_it, insert_and_copy_split)
+ initBlockSplitIterator(&dist_it, dist_split)
+ for i := range cmds {
+ var cmd *command = &cmds[i]
+ var j uint
+ blockSplitIteratorNext(&insert_and_copy_it)
+ histogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_], uint(cmd.cmd_prefix_))
+
+ /* TODO: unwrap iterator blocks. */
+ for j = uint(cmd.insert_len_); j != 0; j-- {
+ var context uint
+ blockSplitIteratorNext(&literal_it)
+ context = literal_it.type_
+ if context_modes != nil {
+ var lut contextLUT = getContextLUT(context_modes[context])
+ context = (context << literalContextBits) + uint(getContext(prev_byte, prev_byte2, lut))
+ }
+
+ histogramAddLiteral(&literal_histograms[context], uint(ringbuffer[pos&mask]))
+ prev_byte2 = prev_byte
+ prev_byte = ringbuffer[pos&mask]
+ pos++
+ }
+
+ pos += uint(commandCopyLen(cmd))
+ if commandCopyLen(cmd) != 0 {
+ prev_byte2 = ringbuffer[(pos-2)&mask]
+ prev_byte = ringbuffer[(pos-1)&mask]
+ if cmd.cmd_prefix_ >= 128 {
+ var context uint
+ blockSplitIteratorNext(&dist_it)
+ context = uint(uint32(dist_it.type_< bestQ &&
+ (spec.Value == "*" || spec.Value == offer) {
+ bestQ = spec.Q
+ bestOffer = offer
+ }
+ }
+ }
+ if bestQ == 0 {
+ bestOffer = ""
+ }
+ return bestOffer
+}
+
+// acceptSpec describes an Accept* header.
+type acceptSpec struct {
+ Value string
+ Q float64
+}
+
+// parseAccept parses Accept* headers.
+func parseAccept(header http.Header, key string) (specs []acceptSpec) {
+loop:
+ for _, s := range header[key] {
+ for {
+ var spec acceptSpec
+ spec.Value, s = expectTokenSlash(s)
+ if spec.Value == "" {
+ continue loop
+ }
+ spec.Q = 1.0
+ s = skipSpace(s)
+ if strings.HasPrefix(s, ";") {
+ s = skipSpace(s[1:])
+ if !strings.HasPrefix(s, "q=") {
+ continue loop
+ }
+ spec.Q, s = expectQuality(s[2:])
+ if spec.Q < 0.0 {
+ continue loop
+ }
+ }
+ specs = append(specs, spec)
+ s = skipSpace(s)
+ if !strings.HasPrefix(s, ",") {
+ continue loop
+ }
+ s = skipSpace(s[1:])
+ }
+ }
+ return
+}
+
+func skipSpace(s string) (rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if octetTypes[s[i]]&isSpace == 0 {
+ break
+ }
+ }
+ return s[i:]
+}
+
+func expectTokenSlash(s string) (token, rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ b := s[i]
+ if (octetTypes[b]&isToken == 0) && b != '/' {
+ break
+ }
+ }
+ return s[:i], s[i:]
+}
+
+func expectQuality(s string) (q float64, rest string) {
+ switch {
+ case len(s) == 0:
+ return -1, ""
+ case s[0] == '0':
+ q = 0
+ case s[0] == '1':
+ q = 1
+ default:
+ return -1, ""
+ }
+ s = s[1:]
+ if !strings.HasPrefix(s, ".") {
+ return q, s
+ }
+ s = s[1:]
+ i := 0
+ n := 0
+ d := 1
+ for ; i < len(s); i++ {
+ b := s[i]
+ if b < '0' || b > '9' {
+ break
+ }
+ n = n*10 + int(b) - '0'
+ d *= 10
+ }
+ return q + float64(n)/float64(d), s[i:]
+}
+
+// Octet types from RFC 2616.
+var octetTypes [256]octetType
+
+type octetType byte
+
+const (
+ isToken octetType = 1 << iota
+ isSpace
+)
+
+func init() {
+ // OCTET =
+ // CHAR =
+ // CTL =
+ // CR =
+ // LF =
+ // SP =
+ // HT =
+ // <"> =
+ // CRLF = CR LF
+ // LWS = [CRLF] 1*( SP | HT )
+ // TEXT =
+ // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
+ // token = 1*
+ // qdtext = >
+
+ for c := 0; c < 256; c++ {
+ var t octetType
+ isCtl := c <= 31 || c == 127
+ isChar := 0 <= c && c <= 127
+ isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
+ if strings.ContainsRune(" \t\r\n", rune(c)) {
+ t |= isSpace
+ }
+ if isChar && !isCtl && !isSeparator {
+ t |= isToken
+ }
+ octetTypes[c] = t
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/huffman.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/huffman.go
new file mode 100644
index 000000000000..182f3d2a5520
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/huffman.go
@@ -0,0 +1,653 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for building Huffman decoding tables. */
+
+const huffmanMaxCodeLength = 15
+
+/* Maximum possible Huffman table size for an alphabet size of (index * 32),
+ max code length 15 and root table bits 8. */
+var kMaxHuffmanTableSize = []uint16{
+ 256,
+ 402,
+ 436,
+ 468,
+ 500,
+ 534,
+ 566,
+ 598,
+ 630,
+ 662,
+ 694,
+ 726,
+ 758,
+ 790,
+ 822,
+ 854,
+ 886,
+ 920,
+ 952,
+ 984,
+ 1016,
+ 1048,
+ 1080,
+ 1112,
+ 1144,
+ 1176,
+ 1208,
+ 1240,
+ 1272,
+ 1304,
+ 1336,
+ 1368,
+ 1400,
+ 1432,
+ 1464,
+ 1496,
+ 1528,
+}
+
+/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
+const huffmanMaxSize26 = 396
+
+/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
+const huffmanMaxSize258 = 632
+
+/* BROTLI_MAX_CONTEXT_MAP_SYMBOLS == 272 */
+const huffmanMaxSize272 = 646
+
+const huffmanMaxCodeLengthCodeLength = 5
+
+/* Do not create this struct directly - use the ConstructHuffmanCode
+ * constructor below! */
+type huffmanCode struct {
+ bits byte
+ value uint16
+}
+
+func constructHuffmanCode(bits byte, value uint16) huffmanCode {
+ var h huffmanCode
+ h.bits = bits
+ h.value = value
+ return h
+}
+
+/* Builds Huffman lookup table assuming code lengths are in symbol order. */
+
+/* Builds Huffman lookup table assuming code lengths are in symbol order.
+ Returns size of resulting table. */
+
+/* Builds a simple Huffman table. The |num_symbols| parameter is to be
+ interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
+ 2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],
+ 4 means 4 symbols with lengths [1, 2, 3, 3]. */
+
+/* Contains a collection of Huffman trees with the same alphabet size. */
+/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
+ greater than log2(max_symbol). */
+type huffmanTreeGroup struct {
+ htrees [][]huffmanCode
+ codes []huffmanCode
+ alphabet_size uint16
+ max_symbol uint16
+ num_htrees uint16
+}
+
+const reverseBitsMax = 8
+
+const reverseBitsBase = 0
+
+var kReverseBits = [1 << reverseBitsMax]byte{
+ 0x00,
+ 0x80,
+ 0x40,
+ 0xC0,
+ 0x20,
+ 0xA0,
+ 0x60,
+ 0xE0,
+ 0x10,
+ 0x90,
+ 0x50,
+ 0xD0,
+ 0x30,
+ 0xB0,
+ 0x70,
+ 0xF0,
+ 0x08,
+ 0x88,
+ 0x48,
+ 0xC8,
+ 0x28,
+ 0xA8,
+ 0x68,
+ 0xE8,
+ 0x18,
+ 0x98,
+ 0x58,
+ 0xD8,
+ 0x38,
+ 0xB8,
+ 0x78,
+ 0xF8,
+ 0x04,
+ 0x84,
+ 0x44,
+ 0xC4,
+ 0x24,
+ 0xA4,
+ 0x64,
+ 0xE4,
+ 0x14,
+ 0x94,
+ 0x54,
+ 0xD4,
+ 0x34,
+ 0xB4,
+ 0x74,
+ 0xF4,
+ 0x0C,
+ 0x8C,
+ 0x4C,
+ 0xCC,
+ 0x2C,
+ 0xAC,
+ 0x6C,
+ 0xEC,
+ 0x1C,
+ 0x9C,
+ 0x5C,
+ 0xDC,
+ 0x3C,
+ 0xBC,
+ 0x7C,
+ 0xFC,
+ 0x02,
+ 0x82,
+ 0x42,
+ 0xC2,
+ 0x22,
+ 0xA2,
+ 0x62,
+ 0xE2,
+ 0x12,
+ 0x92,
+ 0x52,
+ 0xD2,
+ 0x32,
+ 0xB2,
+ 0x72,
+ 0xF2,
+ 0x0A,
+ 0x8A,
+ 0x4A,
+ 0xCA,
+ 0x2A,
+ 0xAA,
+ 0x6A,
+ 0xEA,
+ 0x1A,
+ 0x9A,
+ 0x5A,
+ 0xDA,
+ 0x3A,
+ 0xBA,
+ 0x7A,
+ 0xFA,
+ 0x06,
+ 0x86,
+ 0x46,
+ 0xC6,
+ 0x26,
+ 0xA6,
+ 0x66,
+ 0xE6,
+ 0x16,
+ 0x96,
+ 0x56,
+ 0xD6,
+ 0x36,
+ 0xB6,
+ 0x76,
+ 0xF6,
+ 0x0E,
+ 0x8E,
+ 0x4E,
+ 0xCE,
+ 0x2E,
+ 0xAE,
+ 0x6E,
+ 0xEE,
+ 0x1E,
+ 0x9E,
+ 0x5E,
+ 0xDE,
+ 0x3E,
+ 0xBE,
+ 0x7E,
+ 0xFE,
+ 0x01,
+ 0x81,
+ 0x41,
+ 0xC1,
+ 0x21,
+ 0xA1,
+ 0x61,
+ 0xE1,
+ 0x11,
+ 0x91,
+ 0x51,
+ 0xD1,
+ 0x31,
+ 0xB1,
+ 0x71,
+ 0xF1,
+ 0x09,
+ 0x89,
+ 0x49,
+ 0xC9,
+ 0x29,
+ 0xA9,
+ 0x69,
+ 0xE9,
+ 0x19,
+ 0x99,
+ 0x59,
+ 0xD9,
+ 0x39,
+ 0xB9,
+ 0x79,
+ 0xF9,
+ 0x05,
+ 0x85,
+ 0x45,
+ 0xC5,
+ 0x25,
+ 0xA5,
+ 0x65,
+ 0xE5,
+ 0x15,
+ 0x95,
+ 0x55,
+ 0xD5,
+ 0x35,
+ 0xB5,
+ 0x75,
+ 0xF5,
+ 0x0D,
+ 0x8D,
+ 0x4D,
+ 0xCD,
+ 0x2D,
+ 0xAD,
+ 0x6D,
+ 0xED,
+ 0x1D,
+ 0x9D,
+ 0x5D,
+ 0xDD,
+ 0x3D,
+ 0xBD,
+ 0x7D,
+ 0xFD,
+ 0x03,
+ 0x83,
+ 0x43,
+ 0xC3,
+ 0x23,
+ 0xA3,
+ 0x63,
+ 0xE3,
+ 0x13,
+ 0x93,
+ 0x53,
+ 0xD3,
+ 0x33,
+ 0xB3,
+ 0x73,
+ 0xF3,
+ 0x0B,
+ 0x8B,
+ 0x4B,
+ 0xCB,
+ 0x2B,
+ 0xAB,
+ 0x6B,
+ 0xEB,
+ 0x1B,
+ 0x9B,
+ 0x5B,
+ 0xDB,
+ 0x3B,
+ 0xBB,
+ 0x7B,
+ 0xFB,
+ 0x07,
+ 0x87,
+ 0x47,
+ 0xC7,
+ 0x27,
+ 0xA7,
+ 0x67,
+ 0xE7,
+ 0x17,
+ 0x97,
+ 0x57,
+ 0xD7,
+ 0x37,
+ 0xB7,
+ 0x77,
+ 0xF7,
+ 0x0F,
+ 0x8F,
+ 0x4F,
+ 0xCF,
+ 0x2F,
+ 0xAF,
+ 0x6F,
+ 0xEF,
+ 0x1F,
+ 0x9F,
+ 0x5F,
+ 0xDF,
+ 0x3F,
+ 0xBF,
+ 0x7F,
+ 0xFF,
+}
+
+const reverseBitsLowest = (uint64(1) << (reverseBitsMax - 1 + reverseBitsBase))
+
+/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
+ where reverse(value, len) is the bit-wise reversal of the len least
+ significant bits of value. */
+func reverseBits8(num uint64) uint64 {
+ return uint64(kReverseBits[num])
+}
+
+/* Stores code in table[0], table[step], table[2*step], ..., table[end] */
+/* Assumes that end is an integer multiple of step */
+func replicateValue(table []huffmanCode, step int, end int, code huffmanCode) {
+ for {
+ end -= step
+ table[end] = code
+ if end <= 0 {
+ break
+ }
+ }
+}
+
+/* Returns the table width of the next 2nd level table. |count| is the histogram
+ of bit lengths for the remaining symbols, |len| is the code length of the
+ next processed symbol. */
+func nextTableBitSize(count []uint16, len int, root_bits int) int {
+ var left int = 1 << uint(len-root_bits)
+ for len < huffmanMaxCodeLength {
+ left -= int(count[len])
+ if left <= 0 {
+ break
+ }
+ len++
+ left <<= 1
+ }
+
+ return len - root_bits
+}
+
+func buildCodeLengthsHuffmanTable(table []huffmanCode, code_lengths []byte, count []uint16) {
+ var code huffmanCode /* current table entry */ /* symbol index in original or sorted table */ /* prefix code */ /* prefix code addend */ /* step size to replicate values in current table */ /* size of current table */ /* symbols sorted by code length */
+ var symbol int
+ var key uint64
+ var key_step uint64
+ var step int
+ var table_size int
+ var sorted [codeLengthCodes]int
+ var offset [huffmanMaxCodeLengthCodeLength + 1]int
+ var bits int
+ var bits_count int
+ /* offsets in sorted table for each length */
+ assert(huffmanMaxCodeLengthCodeLength <= reverseBitsMax)
+
+ /* Generate offsets into sorted symbol table by code length. */
+ symbol = -1
+
+ bits = 1
+ var i int
+ for i = 0; i < huffmanMaxCodeLengthCodeLength; i++ {
+ symbol += int(count[bits])
+ offset[bits] = symbol
+ bits++
+ }
+
+ /* Symbols with code length 0 are placed after all other symbols. */
+ offset[0] = codeLengthCodes - 1
+
+ /* Sort symbols by length, by symbol order within each length. */
+ symbol = codeLengthCodes
+
+ for {
+ var i int
+ for i = 0; i < 6; i++ {
+ symbol--
+ sorted[offset[code_lengths[symbol]]] = symbol
+ offset[code_lengths[symbol]]--
+ }
+ if symbol == 0 {
+ break
+ }
+ }
+
+ table_size = 1 << huffmanMaxCodeLengthCodeLength
+
+ /* Special case: all symbols but one have 0 code length. */
+ if offset[0] == 0 {
+ code = constructHuffmanCode(0, uint16(sorted[0]))
+ for key = 0; key < uint64(table_size); key++ {
+ table[key] = code
+ }
+
+ return
+ }
+
+ /* Fill in table. */
+ key = 0
+
+ key_step = reverseBitsLowest
+ symbol = 0
+ bits = 1
+ step = 2
+ for {
+ for bits_count = int(count[bits]); bits_count != 0; bits_count-- {
+ code = constructHuffmanCode(byte(bits), uint16(sorted[symbol]))
+ symbol++
+ replicateValue(table[reverseBits8(key):], step, table_size, code)
+ key += key_step
+ }
+
+ step <<= 1
+ key_step >>= 1
+ bits++
+ if bits > huffmanMaxCodeLengthCodeLength {
+ break
+ }
+ }
+}
+
+func buildHuffmanTable(root_table []huffmanCode, root_bits int, symbol_lists symbolList, count []uint16) uint32 {
+ var code huffmanCode /* current table entry */ /* next available space in table */ /* current code length */ /* symbol index in original or sorted table */ /* prefix code */ /* prefix code addend */ /* 2nd level table prefix code */ /* 2nd level table prefix code addend */ /* step size to replicate values in current table */ /* key length of current table */ /* size of current table */ /* sum of root table size and 2nd level table sizes */
+ var table []huffmanCode
+ var len int
+ var symbol int
+ var key uint64
+ var key_step uint64
+ var sub_key uint64
+ var sub_key_step uint64
+ var step int
+ var table_bits int
+ var table_size int
+ var total_size int
+ var max_length int = -1
+ var bits int
+ var bits_count int
+
+ assert(root_bits <= reverseBitsMax)
+ assert(huffmanMaxCodeLength-root_bits <= reverseBitsMax)
+
+ for symbolListGet(symbol_lists, max_length) == 0xFFFF {
+ max_length--
+ }
+ max_length += huffmanMaxCodeLength + 1
+
+ table = root_table
+ table_bits = root_bits
+ table_size = 1 << uint(table_bits)
+ total_size = table_size
+
+ /* Fill in the root table. Reduce the table size to if possible,
+ and create the repetitions by memcpy. */
+ if table_bits > max_length {
+ table_bits = max_length
+ table_size = 1 << uint(table_bits)
+ }
+
+ key = 0
+ key_step = reverseBitsLowest
+ bits = 1
+ step = 2
+ for {
+ symbol = bits - (huffmanMaxCodeLength + 1)
+ for bits_count = int(count[bits]); bits_count != 0; bits_count-- {
+ symbol = int(symbolListGet(symbol_lists, symbol))
+ code = constructHuffmanCode(byte(bits), uint16(symbol))
+ replicateValue(table[reverseBits8(key):], step, table_size, code)
+ key += key_step
+ }
+
+ step <<= 1
+ key_step >>= 1
+ bits++
+ if bits > table_bits {
+ break
+ }
+ }
+
+ /* If root_bits != table_bits then replicate to fill the remaining slots. */
+ for total_size != table_size {
+ copy(table[table_size:], table[:uint(table_size)])
+ table_size <<= 1
+ }
+
+ /* Fill in 2nd level tables and add pointers to root table. */
+ key_step = reverseBitsLowest >> uint(root_bits-1)
+
+ sub_key = reverseBitsLowest << 1
+ sub_key_step = reverseBitsLowest
+ len = root_bits + 1
+ step = 2
+ for ; len <= max_length; len++ {
+ symbol = len - (huffmanMaxCodeLength + 1)
+ for ; count[len] != 0; count[len]-- {
+ if sub_key == reverseBitsLowest<<1 {
+ table = table[table_size:]
+ table_bits = nextTableBitSize(count, int(len), root_bits)
+ table_size = 1 << uint(table_bits)
+ total_size += table_size
+ sub_key = reverseBits8(key)
+ key += key_step
+ root_table[sub_key] = constructHuffmanCode(byte(table_bits+root_bits), uint16(uint64(uint(-cap(table)+cap(root_table)))-sub_key))
+ sub_key = 0
+ }
+
+ symbol = int(symbolListGet(symbol_lists, symbol))
+ code = constructHuffmanCode(byte(len-root_bits), uint16(symbol))
+ replicateValue(table[reverseBits8(sub_key):], step, table_size, code)
+ sub_key += sub_key_step
+ }
+
+ step <<= 1
+ sub_key_step >>= 1
+ }
+
+ return uint32(total_size)
+}
+
+func buildSimpleHuffmanTable(table []huffmanCode, root_bits int, val []uint16, num_symbols uint32) uint32 {
+ var table_size uint32 = 1
+ var goal_size uint32 = 1 << uint(root_bits)
+ switch num_symbols {
+ case 0:
+ table[0] = constructHuffmanCode(0, val[0])
+
+ case 1:
+ if val[1] > val[0] {
+ table[0] = constructHuffmanCode(1, val[0])
+ table[1] = constructHuffmanCode(1, val[1])
+ } else {
+ table[0] = constructHuffmanCode(1, val[1])
+ table[1] = constructHuffmanCode(1, val[0])
+ }
+
+ table_size = 2
+
+ case 2:
+ table[0] = constructHuffmanCode(1, val[0])
+ table[2] = constructHuffmanCode(1, val[0])
+ if val[2] > val[1] {
+ table[1] = constructHuffmanCode(2, val[1])
+ table[3] = constructHuffmanCode(2, val[2])
+ } else {
+ table[1] = constructHuffmanCode(2, val[2])
+ table[3] = constructHuffmanCode(2, val[1])
+ }
+
+ table_size = 4
+
+ case 3:
+ var i int
+ var k int
+ for i = 0; i < 3; i++ {
+ for k = i + 1; k < 4; k++ {
+ if val[k] < val[i] {
+ var t uint16 = val[k]
+ val[k] = val[i]
+ val[i] = t
+ }
+ }
+ }
+
+ table[0] = constructHuffmanCode(2, val[0])
+ table[2] = constructHuffmanCode(2, val[1])
+ table[1] = constructHuffmanCode(2, val[2])
+ table[3] = constructHuffmanCode(2, val[3])
+ table_size = 4
+
+ case 4:
+ if val[3] < val[2] {
+ var t uint16 = val[3]
+ val[3] = val[2]
+ val[2] = t
+ }
+
+ table[0] = constructHuffmanCode(1, val[0])
+ table[1] = constructHuffmanCode(2, val[1])
+ table[2] = constructHuffmanCode(1, val[0])
+ table[3] = constructHuffmanCode(3, val[2])
+ table[4] = constructHuffmanCode(1, val[0])
+ table[5] = constructHuffmanCode(2, val[1])
+ table[6] = constructHuffmanCode(1, val[0])
+ table[7] = constructHuffmanCode(3, val[3])
+ table_size = 8
+ }
+
+ for table_size != goal_size {
+ copy(table[table_size:], table[:uint(table_size)])
+ table_size <<= 1
+ }
+
+ return goal_size
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/literal_cost.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/literal_cost.go
new file mode 100644
index 000000000000..5a9ace94ee07
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/literal_cost.go
@@ -0,0 +1,182 @@
+package brotli
+
+func utf8Position(last uint, c uint, clamp uint) uint {
+ if c < 128 {
+ return 0 /* Next one is the 'Byte 1' again. */
+ } else if c >= 192 { /* Next one is the 'Byte 2' of utf-8 encoding. */
+ return brotli_min_size_t(1, clamp)
+ } else {
+ /* Let's decide over the last byte if this ends the sequence. */
+ if last < 0xE0 {
+ return 0 /* Completed two or three byte coding. */ /* Next one is the 'Byte 3' of utf-8 encoding. */
+ } else {
+ return brotli_min_size_t(2, clamp)
+ }
+ }
+}
+
+func decideMultiByteStatsLevel(pos uint, len uint, mask uint, data []byte) uint {
+ var counts = [3]uint{0} /* should be 2, but 1 compresses better. */
+ var max_utf8 uint = 1
+ var last_c uint = 0
+ var i uint
+ for i = 0; i < len; i++ {
+ var c uint = uint(data[(pos+i)&mask])
+ counts[utf8Position(last_c, c, 2)]++
+ last_c = c
+ }
+
+ if counts[2] < 500 {
+ max_utf8 = 1
+ }
+
+ if counts[1]+counts[2] < 25 {
+ max_utf8 = 0
+ }
+
+ return max_utf8
+}
+
+func estimateBitCostsForLiteralsUTF8(pos uint, len uint, mask uint, data []byte, cost []float32) {
+ var max_utf8 uint = decideMultiByteStatsLevel(pos, uint(len), mask, data)
+ /* Bootstrap histograms. */
+ var histogram = [3][256]uint{[256]uint{0}}
+ var window_half uint = 495
+ var in_window uint = brotli_min_size_t(window_half, uint(len))
+ var in_window_utf8 = [3]uint{0}
+ /* max_utf8 is 0 (normal ASCII single byte modeling),
+ 1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
+
+ var i uint
+ {
+ var last_c uint = 0
+ var utf8_pos uint = 0
+ for i = 0; i < in_window; i++ {
+ var c uint = uint(data[(pos+i)&mask])
+ histogram[utf8_pos][c]++
+ in_window_utf8[utf8_pos]++
+ utf8_pos = utf8Position(last_c, c, max_utf8)
+ last_c = c
+ }
+ }
+
+ /* Compute bit costs with sliding window. */
+ for i = 0; i < len; i++ {
+ if i >= window_half {
+ var c uint
+ var last_c uint
+ if i < window_half+1 {
+ c = 0
+ } else {
+ c = uint(data[(pos+i-window_half-1)&mask])
+ }
+ if i < window_half+2 {
+ last_c = 0
+ } else {
+ last_c = uint(data[(pos+i-window_half-2)&mask])
+ }
+ /* Remove a byte in the past. */
+
+ var utf8_pos2 uint = utf8Position(last_c, c, max_utf8)
+ histogram[utf8_pos2][data[(pos+i-window_half)&mask]]--
+ in_window_utf8[utf8_pos2]--
+ }
+
+ if i+window_half < len {
+ var c uint = uint(data[(pos+i+window_half-1)&mask])
+ var last_c uint = uint(data[(pos+i+window_half-2)&mask])
+ /* Add a byte in the future. */
+
+ var utf8_pos2 uint = utf8Position(last_c, c, max_utf8)
+ histogram[utf8_pos2][data[(pos+i+window_half)&mask]]++
+ in_window_utf8[utf8_pos2]++
+ }
+ {
+ var c uint
+ var last_c uint
+ if i < 1 {
+ c = 0
+ } else {
+ c = uint(data[(pos+i-1)&mask])
+ }
+ if i < 2 {
+ last_c = 0
+ } else {
+ last_c = uint(data[(pos+i-2)&mask])
+ }
+ var utf8_pos uint = utf8Position(last_c, c, max_utf8)
+ var masked_pos uint = (pos + i) & mask
+ var histo uint = histogram[utf8_pos][data[masked_pos]]
+ var lit_cost float64
+ if histo == 0 {
+ histo = 1
+ }
+
+ lit_cost = fastLog2(in_window_utf8[utf8_pos]) - fastLog2(histo)
+ lit_cost += 0.02905
+ if lit_cost < 1.0 {
+ lit_cost *= 0.5
+ lit_cost += 0.5
+ }
+
+ /* Make the first bytes more expensive -- seems to help, not sure why.
+ Perhaps because the entropy source is changing its properties
+ rapidly in the beginning of the file, perhaps because the beginning
+ of the data is a statistical "anomaly". */
+ if i < 2000 {
+ lit_cost += 0.7 - (float64(2000-i) / 2000.0 * 0.35)
+ }
+
+ cost[i] = float32(lit_cost)
+ }
+ }
+}
+
+func estimateBitCostsForLiterals(pos uint, len uint, mask uint, data []byte, cost []float32) {
+ if isMostlyUTF8(data, pos, mask, uint(len), kMinUTF8Ratio) {
+ estimateBitCostsForLiteralsUTF8(pos, uint(len), mask, data, cost)
+ return
+ } else {
+ var histogram = [256]uint{0}
+ var window_half uint = 2000
+ var in_window uint = brotli_min_size_t(window_half, uint(len))
+ var i uint
+ /* Bootstrap histogram. */
+ for i = 0; i < in_window; i++ {
+ histogram[data[(pos+i)&mask]]++
+ }
+
+ /* Compute bit costs with sliding window. */
+ for i = 0; i < len; i++ {
+ var histo uint
+ if i >= window_half {
+ /* Remove a byte in the past. */
+ histogram[data[(pos+i-window_half)&mask]]--
+
+ in_window--
+ }
+
+ if i+window_half < len {
+ /* Add a byte in the future. */
+ histogram[data[(pos+i+window_half)&mask]]++
+
+ in_window++
+ }
+
+ histo = histogram[data[(pos+i)&mask]]
+ if histo == 0 {
+ histo = 1
+ }
+ {
+ var lit_cost float64 = fastLog2(in_window) - fastLog2(histo)
+ lit_cost += 0.029
+ if lit_cost < 1.0 {
+ lit_cost *= 0.5
+ lit_cost += 0.5
+ }
+
+ cost[i] = float32(lit_cost)
+ }
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/memory.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/memory.go
new file mode 100644
index 000000000000..a07c7050a07f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/memory.go
@@ -0,0 +1,66 @@
+package brotli
+
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/*
+Dynamically grows array capacity to at least the requested size
+T: data type
+A: array
+C: capacity
+R: requested size
+*/
+func brotli_ensure_capacity_uint8_t(a *[]byte, c *uint, r uint) {
+ if *c < r {
+ var new_size uint = *c
+ if new_size == 0 {
+ new_size = r
+ }
+
+ for new_size < r {
+ new_size *= 2
+ }
+
+ if cap(*a) < int(new_size) {
+ var new_array []byte = make([]byte, new_size)
+ if *c != 0 {
+ copy(new_array, (*a)[:*c])
+ }
+
+ *a = new_array
+ } else {
+ *a = (*a)[:new_size]
+ }
+
+ *c = new_size
+ }
+}
+
+func brotli_ensure_capacity_uint32_t(a *[]uint32, c *uint, r uint) {
+ var new_array []uint32
+ if *c < r {
+ var new_size uint = *c
+ if new_size == 0 {
+ new_size = r
+ }
+
+ for new_size < r {
+ new_size *= 2
+ }
+
+ if cap(*a) < int(new_size) {
+ new_array = make([]uint32, new_size)
+ if *c != 0 {
+ copy(new_array, (*a)[:*c])
+ }
+
+ *a = new_array
+ } else {
+ *a = (*a)[:new_size]
+ }
+ *c = new_size
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock.go
new file mode 100644
index 000000000000..3014df8cdf10
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock.go
@@ -0,0 +1,574 @@
+package brotli
+
+import (
+ "sync"
+)
+
+/* Copyright 2014 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Algorithms for distributing the literals and commands of a metablock between
+ block types and contexts. */
+
+type metaBlockSplit struct {
+ literal_split blockSplit
+ command_split blockSplit
+ distance_split blockSplit
+ literal_context_map []uint32
+ literal_context_map_size uint
+ distance_context_map []uint32
+ distance_context_map_size uint
+ literal_histograms []histogramLiteral
+ literal_histograms_size uint
+ command_histograms []histogramCommand
+ command_histograms_size uint
+ distance_histograms []histogramDistance
+ distance_histograms_size uint
+}
+
+var metaBlockPool sync.Pool
+
+func getMetaBlockSplit() *metaBlockSplit {
+ mb, _ := metaBlockPool.Get().(*metaBlockSplit)
+
+ if mb == nil {
+ mb = &metaBlockSplit{}
+ } else {
+ initBlockSplit(&mb.literal_split)
+ initBlockSplit(&mb.command_split)
+ initBlockSplit(&mb.distance_split)
+ mb.literal_context_map = mb.literal_context_map[:0]
+ mb.literal_context_map_size = 0
+ mb.distance_context_map = mb.distance_context_map[:0]
+ mb.distance_context_map_size = 0
+ mb.literal_histograms = mb.literal_histograms[:0]
+ mb.command_histograms = mb.command_histograms[:0]
+ mb.distance_histograms = mb.distance_histograms[:0]
+ }
+ return mb
+}
+
+func freeMetaBlockSplit(mb *metaBlockSplit) {
+ metaBlockPool.Put(mb)
+}
+
+func initDistanceParams(params *encoderParams, npostfix uint32, ndirect uint32) {
+ var dist_params *distanceParams = ¶ms.dist
+ var alphabet_size uint32
+ var max_distance uint32
+
+ dist_params.distance_postfix_bits = npostfix
+ dist_params.num_direct_distance_codes = ndirect
+
+ alphabet_size = uint32(distanceAlphabetSize(uint(npostfix), uint(ndirect), maxDistanceBits))
+ max_distance = ndirect + (1 << (maxDistanceBits + npostfix + 2)) - (1 << (npostfix + 2))
+
+ if params.large_window {
+ var bound = [maxNpostfix + 1]uint32{0, 4, 12, 28}
+ var postfix uint32 = 1 << npostfix
+ alphabet_size = uint32(distanceAlphabetSize(uint(npostfix), uint(ndirect), largeMaxDistanceBits))
+
+ /* The maximum distance is set so that no distance symbol used can encode
+ a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
+ its extra bits set. */
+ if ndirect < bound[npostfix] {
+ max_distance = maxAllowedDistance - (bound[npostfix] - ndirect)
+ } else if ndirect >= bound[npostfix]+postfix {
+ max_distance = (3 << 29) - 4 + (ndirect - bound[npostfix])
+ } else {
+ max_distance = maxAllowedDistance
+ }
+ }
+
+ dist_params.alphabet_size = alphabet_size
+ dist_params.max_distance = uint(max_distance)
+}
+
+func recomputeDistancePrefixes(cmds []command, orig_params *distanceParams, new_params *distanceParams) {
+ if orig_params.distance_postfix_bits == new_params.distance_postfix_bits && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes {
+ return
+ }
+
+ for i := range cmds {
+ var cmd *command = &cmds[i]
+ if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ prefixEncodeCopyDistance(uint(commandRestoreDistanceCode(cmd, orig_params)), uint(new_params.num_direct_distance_codes), uint(new_params.distance_postfix_bits), &cmd.dist_prefix_, &cmd.dist_extra_)
+ }
+ }
+}
+
+func computeDistanceCost(cmds []command, orig_params *distanceParams, new_params *distanceParams, cost *float64) bool {
+ var equal_params bool = false
+ var dist_prefix uint16
+ var dist_extra uint32
+ var extra_bits float64 = 0.0
+ var histo histogramDistance
+ histogramClearDistance(&histo)
+
+ if orig_params.distance_postfix_bits == new_params.distance_postfix_bits && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes {
+ equal_params = true
+ }
+
+ for i := range cmds {
+ cmd := &cmds[i]
+ if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
+ if equal_params {
+ dist_prefix = cmd.dist_prefix_
+ } else {
+ var distance uint32 = commandRestoreDistanceCode(cmd, orig_params)
+ if distance > uint32(new_params.max_distance) {
+ return false
+ }
+
+ prefixEncodeCopyDistance(uint(distance), uint(new_params.num_direct_distance_codes), uint(new_params.distance_postfix_bits), &dist_prefix, &dist_extra)
+ }
+
+ histogramAddDistance(&histo, uint(dist_prefix)&0x3FF)
+ extra_bits += float64(dist_prefix >> 10)
+ }
+ }
+
+ *cost = populationCostDistance(&histo) + extra_bits
+ return true
+}
+
+var buildMetaBlock_kMaxNumberOfHistograms uint = 256
+
+func buildMetaBlock(ringbuffer []byte, pos uint, mask uint, params *encoderParams, prev_byte byte, prev_byte2 byte, cmds []command, literal_context_mode int, mb *metaBlockSplit) {
+ var distance_histograms []histogramDistance
+ var literal_histograms []histogramLiteral
+ var literal_context_modes []int = nil
+ var literal_histograms_size uint
+ var distance_histograms_size uint
+ var i uint
+ var literal_context_multiplier uint = 1
+ var npostfix uint32
+ var ndirect_msb uint32 = 0
+ var check_orig bool = true
+ var best_dist_cost float64 = 1e99
+ var orig_params encoderParams = *params
+ /* Histogram ids need to fit in one byte. */
+
+ var new_params encoderParams = *params
+
+ for npostfix = 0; npostfix <= maxNpostfix; npostfix++ {
+ for ; ndirect_msb < 16; ndirect_msb++ {
+ var ndirect uint32 = ndirect_msb << npostfix
+ var skip bool
+ var dist_cost float64
+ initDistanceParams(&new_params, npostfix, ndirect)
+ if npostfix == orig_params.dist.distance_postfix_bits && ndirect == orig_params.dist.num_direct_distance_codes {
+ check_orig = false
+ }
+
+ skip = !computeDistanceCost(cmds, &orig_params.dist, &new_params.dist, &dist_cost)
+ if skip || (dist_cost > best_dist_cost) {
+ break
+ }
+
+ best_dist_cost = dist_cost
+ params.dist = new_params.dist
+ }
+
+ if ndirect_msb > 0 {
+ ndirect_msb--
+ }
+ ndirect_msb /= 2
+ }
+
+ if check_orig {
+ var dist_cost float64
+ computeDistanceCost(cmds, &orig_params.dist, &orig_params.dist, &dist_cost)
+ if dist_cost < best_dist_cost {
+ /* NB: currently unused; uncomment when more param tuning is added. */
+ /* best_dist_cost = dist_cost; */
+ params.dist = orig_params.dist
+ }
+ }
+
+ recomputeDistancePrefixes(cmds, &orig_params.dist, ¶ms.dist)
+
+ splitBlock(cmds, ringbuffer, pos, mask, params, &mb.literal_split, &mb.command_split, &mb.distance_split)
+
+ if !params.disable_literal_context_modeling {
+ literal_context_multiplier = 1 << literalContextBits
+ literal_context_modes = make([]int, (mb.literal_split.num_types))
+ for i = 0; i < mb.literal_split.num_types; i++ {
+ literal_context_modes[i] = literal_context_mode
+ }
+ }
+
+ literal_histograms_size = mb.literal_split.num_types * literal_context_multiplier
+ literal_histograms = make([]histogramLiteral, literal_histograms_size)
+ clearHistogramsLiteral(literal_histograms, literal_histograms_size)
+
+ distance_histograms_size = mb.distance_split.num_types << distanceContextBits
+ distance_histograms = make([]histogramDistance, distance_histograms_size)
+ clearHistogramsDistance(distance_histograms, distance_histograms_size)
+
+ mb.command_histograms_size = mb.command_split.num_types
+ if cap(mb.command_histograms) < int(mb.command_histograms_size) {
+ mb.command_histograms = make([]histogramCommand, (mb.command_histograms_size))
+ } else {
+ mb.command_histograms = mb.command_histograms[:mb.command_histograms_size]
+ }
+ clearHistogramsCommand(mb.command_histograms, mb.command_histograms_size)
+
+ buildHistogramsWithContext(cmds, &mb.literal_split, &mb.command_split, &mb.distance_split, ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes, literal_histograms, mb.command_histograms, distance_histograms)
+ literal_context_modes = nil
+
+ mb.literal_context_map_size = mb.literal_split.num_types << literalContextBits
+ if cap(mb.literal_context_map) < int(mb.literal_context_map_size) {
+ mb.literal_context_map = make([]uint32, (mb.literal_context_map_size))
+ } else {
+ mb.literal_context_map = mb.literal_context_map[:mb.literal_context_map_size]
+ }
+
+ mb.literal_histograms_size = mb.literal_context_map_size
+ if cap(mb.literal_histograms) < int(mb.literal_histograms_size) {
+ mb.literal_histograms = make([]histogramLiteral, (mb.literal_histograms_size))
+ } else {
+ mb.literal_histograms = mb.literal_histograms[:mb.literal_histograms_size]
+ }
+
+ clusterHistogramsLiteral(literal_histograms, literal_histograms_size, buildMetaBlock_kMaxNumberOfHistograms, mb.literal_histograms, &mb.literal_histograms_size, mb.literal_context_map)
+ literal_histograms = nil
+
+ if params.disable_literal_context_modeling {
+ /* Distribute assignment to all contexts. */
+ for i = mb.literal_split.num_types; i != 0; {
+ var j uint = 0
+ i--
+ for ; j < 1< 0 {
+ var entropy [maxStaticContexts]float64
+ var combined_histo []histogramLiteral = make([]histogramLiteral, (2 * num_contexts))
+ var combined_entropy [2 * maxStaticContexts]float64
+ var diff = [2]float64{0.0}
+ /* Try merging the set of histograms for the current block type with the
+ respective set of histograms for the last and second last block types.
+ Decide over the split based on the total reduction of entropy across
+ all contexts. */
+
+ var i uint
+ for i = 0; i < num_contexts; i++ {
+ var curr_histo_ix uint = self.curr_histogram_ix_ + i
+ var j uint
+ entropy[i] = bitsEntropy(histograms[curr_histo_ix].data_[:], self.alphabet_size_)
+ for j = 0; j < 2; j++ {
+ var jx uint = j*num_contexts + i
+ var last_histogram_ix uint = self.last_histogram_ix_[j] + i
+ combined_histo[jx] = histograms[curr_histo_ix]
+ histogramAddHistogramLiteral(&combined_histo[jx], &histograms[last_histogram_ix])
+ combined_entropy[jx] = bitsEntropy(combined_histo[jx].data_[0:], self.alphabet_size_)
+ diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx]
+ }
+ }
+
+ if split.num_types < self.max_block_types_ && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = split.num_types * num_contexts
+ for i = 0; i < num_contexts; i++ {
+ last_entropy[num_contexts+i] = last_entropy[i]
+ last_entropy[i] = entropy[i]
+ }
+
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_ += num_contexts
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ clearHistogramsLiteral(self.histograms_[self.curr_histogram_ix_:], self.num_contexts_)
+ }
+
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ for i = 0; i < num_contexts; i++ {
+ histograms[self.last_histogram_ix_[0]+i] = combined_histo[num_contexts+i]
+ last_entropy[num_contexts+i] = last_entropy[i]
+ last_entropy[i] = combined_entropy[num_contexts+i]
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_+i])
+ }
+
+ self.num_blocks_++
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ for i = 0; i < num_contexts; i++ {
+ histograms[self.last_histogram_ix_[0]+i] = combined_histo[i]
+ last_entropy[i] = combined_entropy[i]
+ if split.num_types == 1 {
+ last_entropy[num_contexts+i] = last_entropy[i]
+ }
+
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_+i])
+ }
+
+ self.block_size_ = 0
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+
+ combined_histo = nil
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types * num_contexts
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current block type and context. When the
+ current block reaches the target size, decides on merging the block. */
+func contextBlockSplitterAddSymbol(self *contextBlockSplitter, symbol uint, context uint) {
+ histogramAddLiteral(&self.histograms_[self.curr_histogram_ix_+context], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ contextBlockSplitterFinishBlock(self, false) /* is_final = */
+ }
+}
+
+func mapStaticContexts(num_contexts uint, static_context_map []uint32, mb *metaBlockSplit) {
+ var i uint
+ mb.literal_context_map_size = mb.literal_split.num_types << literalContextBits
+ if cap(mb.literal_context_map) < int(mb.literal_context_map_size) {
+ mb.literal_context_map = make([]uint32, (mb.literal_context_map_size))
+ } else {
+ mb.literal_context_map = mb.literal_context_map[:mb.literal_context_map_size]
+ }
+
+ for i = 0; i < mb.literal_split.num_types; i++ {
+ var offset uint32 = uint32(i * num_contexts)
+ var j uint
+ for j = 0; j < 1<= 128 {
+ blockSplitterAddSymbolDistance(&dist_blocks, uint(cmd.dist_prefix_)&0x3FF)
+ }
+ }
+ }
+
+ if num_contexts == 1 {
+ blockSplitterFinishBlockLiteral(&lit_blocks.plain, true) /* is_final = */
+ } else {
+ contextBlockSplitterFinishBlock(&lit_blocks.ctx, true) /* is_final = */
+ }
+
+ blockSplitterFinishBlockCommand(&cmd_blocks, true) /* is_final = */
+ blockSplitterFinishBlockDistance(&dist_blocks, true) /* is_final = */
+
+ if num_contexts > 1 {
+ mapStaticContexts(num_contexts, static_context_map, mb)
+ }
+}
+
+func buildMetaBlockGreedy(ringbuffer []byte, pos uint, mask uint, prev_byte byte, prev_byte2 byte, literal_context_lut contextLUT, num_contexts uint, static_context_map []uint32, commands []command, mb *metaBlockSplit) {
+ if num_contexts == 1 {
+ buildMetaBlockGreedyInternal(ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_lut, 1, nil, commands, mb)
+ } else {
+ buildMetaBlockGreedyInternal(ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_lut, num_contexts, static_context_map, commands, mb)
+ }
+}
+
+func optimizeHistograms(num_distance_codes uint32, mb *metaBlockSplit) {
+ var good_for_rle [numCommandSymbols]byte
+ var i uint
+ for i = 0; i < mb.literal_histograms_size; i++ {
+ optimizeHuffmanCountsForRLE(256, mb.literal_histograms[i].data_[:], good_for_rle[:])
+ }
+
+ for i = 0; i < mb.command_histograms_size; i++ {
+ optimizeHuffmanCountsForRLE(numCommandSymbols, mb.command_histograms[i].data_[:], good_for_rle[:])
+ }
+
+ for i = 0; i < mb.distance_histograms_size; i++ {
+ optimizeHuffmanCountsForRLE(uint(num_distance_codes), mb.distance_histograms[i].data_[:], good_for_rle[:])
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_command.go
new file mode 100644
index 000000000000..14c7b77135da
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_command.go
@@ -0,0 +1,165 @@
+package brotli
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ */
+type blockSplitterCommand struct {
+ alphabet_size_ uint
+ min_block_size_ uint
+ split_threshold_ float64
+ num_blocks_ uint
+ split_ *blockSplit
+ histograms_ []histogramCommand
+ histograms_size_ *uint
+ target_block_size_ uint
+ block_size_ uint
+ curr_histogram_ix_ uint
+ last_histogram_ix_ [2]uint
+ last_entropy_ [2]float64
+ merge_last_count_ uint
+}
+
+func initBlockSplitterCommand(self *blockSplitterCommand, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramCommand, histograms_size *uint) {
+ var max_num_blocks uint = num_symbols/min_block_size + 1
+ var max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ self.alphabet_size_ = alphabet_size
+
+ self.min_block_size_ = min_block_size
+ self.split_threshold_ = split_threshold
+ self.num_blocks_ = 0
+ self.split_ = split
+ self.histograms_size_ = histograms_size
+ self.target_block_size_ = min_block_size
+ self.block_size_ = 0
+ self.curr_histogram_ix_ = 0
+ self.merge_last_count_ = 0
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
+ self.split_.num_blocks = max_num_blocks
+ *histograms_size = max_num_types
+ if histograms == nil || cap(*histograms) < int(*histograms_size) {
+ *histograms = make([]histogramCommand, (*histograms_size))
+ } else {
+ *histograms = (*histograms)[:*histograms_size]
+ }
+ self.histograms_ = *histograms
+
+ /* Clear only current histogram. */
+ histogramClearCommand(&self.histograms_[0])
+
+ self.last_histogram_ix_[1] = 0
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+func blockSplitterFinishBlockCommand(self *blockSplitterCommand, is_final bool) {
+ var split *blockSplit = self.split_
+ var last_entropy []float64 = self.last_entropy_[:]
+ var histograms []histogramCommand = self.histograms_
+ self.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)
+ if self.num_blocks_ == 0 {
+ /* Create first block. */
+ split.lengths[0] = uint32(self.block_size_)
+
+ split.types[0] = 0
+ last_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)
+ last_entropy[1] = last_entropy[0]
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ } else if self.block_size_ > 0 {
+ var entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)
+ var combined_histo [2]histogramCommand
+ var combined_entropy [2]float64
+ var diff [2]float64
+ var j uint
+ for j = 0; j < 2; j++ {
+ var last_histogram_ix uint = self.last_histogram_ix_[j]
+ combined_histo[j] = histograms[self.curr_histogram_ix_]
+ histogramAddHistogramCommand(&combined_histo[j], &histograms[last_histogram_ix])
+ combined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j]
+ }
+
+ if split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = uint(byte(split.num_types))
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = entropy
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ histograms[self.last_histogram_ix_[0]] = combined_histo[1]
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = combined_entropy[1]
+ self.num_blocks_++
+ self.block_size_ = 0
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ histograms[self.last_histogram_ix_[0]] = combined_histo[0]
+ last_entropy[0] = combined_entropy[0]
+ if split.num_types == 1 {
+ last_entropy[1] = last_entropy[0]
+ }
+
+ self.block_size_ = 0
+ histogramClearCommand(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+func blockSplitterAddSymbolCommand(self *blockSplitterCommand, symbol uint) {
+ histogramAddCommand(&self.histograms_[self.curr_histogram_ix_], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ blockSplitterFinishBlockCommand(self, false) /* is_final = */
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_distance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_distance.go
new file mode 100644
index 000000000000..5110a810e96d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_distance.go
@@ -0,0 +1,165 @@
+package brotli
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ */
+type blockSplitterDistance struct {
+ alphabet_size_ uint
+ min_block_size_ uint
+ split_threshold_ float64
+ num_blocks_ uint
+ split_ *blockSplit
+ histograms_ []histogramDistance
+ histograms_size_ *uint
+ target_block_size_ uint
+ block_size_ uint
+ curr_histogram_ix_ uint
+ last_histogram_ix_ [2]uint
+ last_entropy_ [2]float64
+ merge_last_count_ uint
+}
+
+func initBlockSplitterDistance(self *blockSplitterDistance, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramDistance, histograms_size *uint) {
+ var max_num_blocks uint = num_symbols/min_block_size + 1
+ var max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ self.alphabet_size_ = alphabet_size
+
+ self.min_block_size_ = min_block_size
+ self.split_threshold_ = split_threshold
+ self.num_blocks_ = 0
+ self.split_ = split
+ self.histograms_size_ = histograms_size
+ self.target_block_size_ = min_block_size
+ self.block_size_ = 0
+ self.curr_histogram_ix_ = 0
+ self.merge_last_count_ = 0
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
+ self.split_.num_blocks = max_num_blocks
+ *histograms_size = max_num_types
+ if histograms == nil || cap(*histograms) < int(*histograms_size) {
+ *histograms = make([]histogramDistance, *histograms_size)
+ } else {
+ *histograms = (*histograms)[:*histograms_size]
+ }
+ self.histograms_ = *histograms
+
+ /* Clear only current histogram. */
+ histogramClearDistance(&self.histograms_[0])
+
+ self.last_histogram_ix_[1] = 0
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+func blockSplitterFinishBlockDistance(self *blockSplitterDistance, is_final bool) {
+ var split *blockSplit = self.split_
+ var last_entropy []float64 = self.last_entropy_[:]
+ var histograms []histogramDistance = self.histograms_
+ self.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)
+ if self.num_blocks_ == 0 {
+ /* Create first block. */
+ split.lengths[0] = uint32(self.block_size_)
+
+ split.types[0] = 0
+ last_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)
+ last_entropy[1] = last_entropy[0]
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ } else if self.block_size_ > 0 {
+ var entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)
+ var combined_histo [2]histogramDistance
+ var combined_entropy [2]float64
+ var diff [2]float64
+ var j uint
+ for j = 0; j < 2; j++ {
+ var last_histogram_ix uint = self.last_histogram_ix_[j]
+ combined_histo[j] = histograms[self.curr_histogram_ix_]
+ histogramAddHistogramDistance(&combined_histo[j], &histograms[last_histogram_ix])
+ combined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j]
+ }
+
+ if split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = uint(byte(split.num_types))
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = entropy
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ histograms[self.last_histogram_ix_[0]] = combined_histo[1]
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = combined_entropy[1]
+ self.num_blocks_++
+ self.block_size_ = 0
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ histograms[self.last_histogram_ix_[0]] = combined_histo[0]
+ last_entropy[0] = combined_entropy[0]
+ if split.num_types == 1 {
+ last_entropy[1] = last_entropy[0]
+ }
+
+ self.block_size_ = 0
+ histogramClearDistance(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+func blockSplitterAddSymbolDistance(self *blockSplitterDistance, symbol uint) {
+ histogramAddDistance(&self.histograms_[self.curr_histogram_ix_], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ blockSplitterFinishBlockDistance(self, false) /* is_final = */
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_literal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_literal.go
new file mode 100644
index 000000000000..307f8da88f48
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/metablock_literal.go
@@ -0,0 +1,165 @@
+package brotli
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Greedy block splitter for one block category (literal, command or distance).
+ */
+type blockSplitterLiteral struct {
+ alphabet_size_ uint
+ min_block_size_ uint
+ split_threshold_ float64
+ num_blocks_ uint
+ split_ *blockSplit
+ histograms_ []histogramLiteral
+ histograms_size_ *uint
+ target_block_size_ uint
+ block_size_ uint
+ curr_histogram_ix_ uint
+ last_histogram_ix_ [2]uint
+ last_entropy_ [2]float64
+ merge_last_count_ uint
+}
+
+func initBlockSplitterLiteral(self *blockSplitterLiteral, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramLiteral, histograms_size *uint) {
+ var max_num_blocks uint = num_symbols/min_block_size + 1
+ var max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)
+ /* We have to allocate one more histogram than the maximum number of block
+ types for the current histogram when the meta-block is too big. */
+ self.alphabet_size_ = alphabet_size
+
+ self.min_block_size_ = min_block_size
+ self.split_threshold_ = split_threshold
+ self.num_blocks_ = 0
+ self.split_ = split
+ self.histograms_size_ = histograms_size
+ self.target_block_size_ = min_block_size
+ self.block_size_ = 0
+ self.curr_histogram_ix_ = 0
+ self.merge_last_count_ = 0
+ brotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)
+ brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
+ self.split_.num_blocks = max_num_blocks
+ *histograms_size = max_num_types
+ if histograms == nil || cap(*histograms) < int(*histograms_size) {
+ *histograms = make([]histogramLiteral, *histograms_size)
+ } else {
+ *histograms = (*histograms)[:*histograms_size]
+ }
+ self.histograms_ = *histograms
+
+ /* Clear only current histogram. */
+ histogramClearLiteral(&self.histograms_[0])
+
+ self.last_histogram_ix_[1] = 0
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+}
+
+/* Does either of three things:
+ (1) emits the current block with a new block type;
+ (2) emits the current block with the type of the second last block;
+ (3) merges the current block with the last block. */
+func blockSplitterFinishBlockLiteral(self *blockSplitterLiteral, is_final bool) {
+ var split *blockSplit = self.split_
+ var last_entropy []float64 = self.last_entropy_[:]
+ var histograms []histogramLiteral = self.histograms_
+ self.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)
+ if self.num_blocks_ == 0 {
+ /* Create first block. */
+ split.lengths[0] = uint32(self.block_size_)
+
+ split.types[0] = 0
+ last_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)
+ last_entropy[1] = last_entropy[0]
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ } else if self.block_size_ > 0 {
+ var entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)
+ var combined_histo [2]histogramLiteral
+ var combined_entropy [2]float64
+ var diff [2]float64
+ var j uint
+ for j = 0; j < 2; j++ {
+ var last_histogram_ix uint = self.last_histogram_ix_[j]
+ combined_histo[j] = histograms[self.curr_histogram_ix_]
+ histogramAddHistogramLiteral(&combined_histo[j], &histograms[last_histogram_ix])
+ combined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)
+ diff[j] = combined_entropy[j] - entropy - last_entropy[j]
+ }
+
+ if split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {
+ /* Create new block. */
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+
+ split.types[self.num_blocks_] = byte(split.num_types)
+ self.last_histogram_ix_[1] = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = uint(byte(split.num_types))
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = entropy
+ self.num_blocks_++
+ split.num_types++
+ self.curr_histogram_ix_++
+ if self.curr_histogram_ix_ < *self.histograms_size_ {
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ }
+ self.block_size_ = 0
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else if diff[1] < diff[0]-20.0 {
+ split.lengths[self.num_blocks_] = uint32(self.block_size_)
+ split.types[self.num_blocks_] = split.types[self.num_blocks_-2]
+ /* Combine this block with second last block. */
+
+ var tmp uint = self.last_histogram_ix_[0]
+ self.last_histogram_ix_[0] = self.last_histogram_ix_[1]
+ self.last_histogram_ix_[1] = tmp
+ histograms[self.last_histogram_ix_[0]] = combined_histo[1]
+ last_entropy[1] = last_entropy[0]
+ last_entropy[0] = combined_entropy[1]
+ self.num_blocks_++
+ self.block_size_ = 0
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_ = 0
+ self.target_block_size_ = self.min_block_size_
+ } else {
+ /* Combine this block with last block. */
+ split.lengths[self.num_blocks_-1] += uint32(self.block_size_)
+
+ histograms[self.last_histogram_ix_[0]] = combined_histo[0]
+ last_entropy[0] = combined_entropy[0]
+ if split.num_types == 1 {
+ last_entropy[1] = last_entropy[0]
+ }
+
+ self.block_size_ = 0
+ histogramClearLiteral(&histograms[self.curr_histogram_ix_])
+ self.merge_last_count_++
+ if self.merge_last_count_ > 1 {
+ self.target_block_size_ += self.min_block_size_
+ }
+ }
+ }
+
+ if is_final {
+ *self.histograms_size_ = split.num_types
+ split.num_blocks = self.num_blocks_
+ }
+}
+
+/* Adds the next symbol to the current histogram. When the current histogram
+ reaches the target size, decides on merging the block. */
+func blockSplitterAddSymbolLiteral(self *blockSplitterLiteral, symbol uint) {
+ histogramAddLiteral(&self.histograms_[self.curr_histogram_ix_], symbol)
+ self.block_size_++
+ if self.block_size_ == self.target_block_size_ {
+ blockSplitterFinishBlockLiteral(self, false) /* is_final = */
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/params.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/params.go
new file mode 100644
index 000000000000..0a4c6875212a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/params.go
@@ -0,0 +1,37 @@
+package brotli
+
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Parameters for the Brotli encoder with chosen quality levels. */
+type hasherParams struct {
+ type_ int
+ bucket_bits int
+ block_bits int
+ hash_len int
+ num_last_distances_to_check int
+}
+
+type distanceParams struct {
+ distance_postfix_bits uint32
+ num_direct_distance_codes uint32
+ alphabet_size uint32
+ max_distance uint
+}
+
+/* Encoding parameters */
+type encoderParams struct {
+ mode int
+ quality int
+ lgwin uint
+ lgblock int
+ size_hint uint
+ disable_literal_context_modeling bool
+ large_window bool
+ hasher hasherParams
+ dist distanceParams
+ dictionary encoderDictionary
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/platform.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/platform.go
new file mode 100644
index 000000000000..4ebfb1528ba9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/platform.go
@@ -0,0 +1,103 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+func brotli_min_double(a float64, b float64) float64 {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_double(a float64, b float64) float64 {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_float(a float32, b float32) float32 {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_float(a float32, b float32) float32 {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_int(a int, b int) int {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_int(a int, b int) int {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_size_t(a uint, b uint) uint {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_size_t(a uint, b uint) uint {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_uint32_t(a uint32, b uint32) uint32 {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_uint32_t(a uint32, b uint32) uint32 {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_min_uint8_t(a byte, b byte) byte {
+ if a < b {
+ return a
+ } else {
+ return b
+ }
+}
+
+func brotli_max_uint8_t(a byte, b byte) byte {
+ if a > b {
+ return a
+ } else {
+ return b
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/prefix.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/prefix.go
new file mode 100644
index 000000000000..484df0d61ec0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/prefix.go
@@ -0,0 +1,30 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Functions for encoding of integers into prefix codes the amount of extra
+ bits, and the actual values of the extra bits. */
+
+/* Here distance_code is an intermediate code, i.e. one of the special codes or
+ the actual distance increased by BROTLI_NUM_DISTANCE_SHORT_CODES - 1. */
+func prefixEncodeCopyDistance(distance_code uint, num_direct_codes uint, postfix_bits uint, code *uint16, extra_bits *uint32) {
+ if distance_code < numDistanceShortCodes+num_direct_codes {
+ *code = uint16(distance_code)
+ *extra_bits = 0
+ return
+ } else {
+ var dist uint = (uint(1) << (postfix_bits + 2)) + (distance_code - numDistanceShortCodes - num_direct_codes)
+ var bucket uint = uint(log2FloorNonZero(dist) - 1)
+ var postfix_mask uint = (1 << postfix_bits) - 1
+ var postfix uint = dist & postfix_mask
+ var prefix uint = (dist >> bucket) & 1
+ var offset uint = (2 + prefix) << bucket
+ var nbits uint = bucket - postfix_bits
+ *code = uint16(nbits<<10 | (numDistanceShortCodes + num_direct_codes + ((2*(nbits-1) + prefix) << postfix_bits) + postfix))
+ *extra_bits = uint32((dist - offset) >> postfix_bits)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/prefix_dec.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/prefix_dec.go
new file mode 100644
index 000000000000..183f0d53fed5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/prefix_dec.go
@@ -0,0 +1,723 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+type cmdLutElement struct {
+ insert_len_extra_bits byte
+ copy_len_extra_bits byte
+ distance_code int8
+ context byte
+ insert_len_offset uint16
+ copy_len_offset uint16
+}
+
+var kCmdLut = [numCommandSymbols]cmdLutElement{
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0000, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0000, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0000, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0001, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0001, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0001, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0002, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0002, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0002, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0003, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0003, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0003, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0004, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0004, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0004, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0009},
+ cmdLutElement{0x00, 0x00, 0, 0x00, 0x0005, 0x0002},
+ cmdLutElement{0x00, 0x00, 0, 0x01, 0x0005, 0x0003},
+ cmdLutElement{0x00, 0x00, 0, 0x02, 0x0005, 0x0004},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0005},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0006},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0007},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0008},
+ cmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0009},
+ cmdLutElement{0x01, 0x00, 0, 0x00, 0x0006, 0x0002},
+ cmdLutElement{0x01, 0x00, 0, 0x01, 0x0006, 0x0003},
+ cmdLutElement{0x01, 0x00, 0, 0x02, 0x0006, 0x0004},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0005},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0006},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0007},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0008},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0009},
+ cmdLutElement{0x01, 0x00, 0, 0x00, 0x0008, 0x0002},
+ cmdLutElement{0x01, 0x00, 0, 0x01, 0x0008, 0x0003},
+ cmdLutElement{0x01, 0x00, 0, 0x02, 0x0008, 0x0004},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0005},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0006},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0007},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0008},
+ cmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0009},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0000, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0000, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0000, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0000, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0000, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0000, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0000, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0000, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0001, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0001, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0001, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0001, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0001, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0001, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0001, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0001, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0002, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0002, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0002, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0002, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0002, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0002, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0002, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0002, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0003, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0003, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0003, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0003, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0003, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0003, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0003, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0003, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0004, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0004, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0004, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0004, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0004, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0004, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0004, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0004, 0x0036},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0005, 0x000a},
+ cmdLutElement{0x00, 0x01, 0, 0x03, 0x0005, 0x000c},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0005, 0x000e},
+ cmdLutElement{0x00, 0x02, 0, 0x03, 0x0005, 0x0012},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0005, 0x0016},
+ cmdLutElement{0x00, 0x03, 0, 0x03, 0x0005, 0x001e},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0005, 0x0026},
+ cmdLutElement{0x00, 0x04, 0, 0x03, 0x0005, 0x0036},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0006, 0x000a},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0006, 0x000c},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0006, 0x000e},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0006, 0x0012},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0006, 0x0016},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0006, 0x001e},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0006, 0x0026},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0006, 0x0036},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0008, 0x000a},
+ cmdLutElement{0x01, 0x01, 0, 0x03, 0x0008, 0x000c},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0008, 0x000e},
+ cmdLutElement{0x01, 0x02, 0, 0x03, 0x0008, 0x0012},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0008, 0x0016},
+ cmdLutElement{0x01, 0x03, 0, 0x03, 0x0008, 0x001e},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0008, 0x0026},
+ cmdLutElement{0x01, 0x04, 0, 0x03, 0x0008, 0x0036},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0000, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0000, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0000, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0001, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0001, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0001, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0002, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0002, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0002, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0003, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0003, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0003, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0004, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0004, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0004, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0009},
+ cmdLutElement{0x00, 0x00, -1, 0x00, 0x0005, 0x0002},
+ cmdLutElement{0x00, 0x00, -1, 0x01, 0x0005, 0x0003},
+ cmdLutElement{0x00, 0x00, -1, 0x02, 0x0005, 0x0004},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0005},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0006},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0007},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0008},
+ cmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0009},
+ cmdLutElement{0x01, 0x00, -1, 0x00, 0x0006, 0x0002},
+ cmdLutElement{0x01, 0x00, -1, 0x01, 0x0006, 0x0003},
+ cmdLutElement{0x01, 0x00, -1, 0x02, 0x0006, 0x0004},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0005},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0006},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0007},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0008},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0009},
+ cmdLutElement{0x01, 0x00, -1, 0x00, 0x0008, 0x0002},
+ cmdLutElement{0x01, 0x00, -1, 0x01, 0x0008, 0x0003},
+ cmdLutElement{0x01, 0x00, -1, 0x02, 0x0008, 0x0004},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0005},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0006},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0007},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0008},
+ cmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0009},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0000, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0000, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0000, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0000, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0000, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0000, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0000, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0000, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0001, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0001, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0001, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0001, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0001, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0001, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0001, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0001, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0002, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0002, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0002, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0002, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0002, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0002, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0002, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0002, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0003, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0003, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0003, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0003, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0003, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0003, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0003, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0003, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0004, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0004, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0004, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0004, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0004, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0004, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0004, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0004, 0x0036},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0005, 0x000a},
+ cmdLutElement{0x00, 0x01, -1, 0x03, 0x0005, 0x000c},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0005, 0x000e},
+ cmdLutElement{0x00, 0x02, -1, 0x03, 0x0005, 0x0012},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0005, 0x0016},
+ cmdLutElement{0x00, 0x03, -1, 0x03, 0x0005, 0x001e},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0005, 0x0026},
+ cmdLutElement{0x00, 0x04, -1, 0x03, 0x0005, 0x0036},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0006, 0x000a},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0006, 0x000c},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0006, 0x000e},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0006, 0x0012},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0006, 0x0016},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0006, 0x001e},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0006, 0x0026},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0006, 0x0036},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0008, 0x000a},
+ cmdLutElement{0x01, 0x01, -1, 0x03, 0x0008, 0x000c},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0008, 0x000e},
+ cmdLutElement{0x01, 0x02, -1, 0x03, 0x0008, 0x0012},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0008, 0x0016},
+ cmdLutElement{0x01, 0x03, -1, 0x03, 0x0008, 0x001e},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0008, 0x0026},
+ cmdLutElement{0x01, 0x04, -1, 0x03, 0x0008, 0x0036},
+ cmdLutElement{0x02, 0x00, -1, 0x00, 0x000a, 0x0002},
+ cmdLutElement{0x02, 0x00, -1, 0x01, 0x000a, 0x0003},
+ cmdLutElement{0x02, 0x00, -1, 0x02, 0x000a, 0x0004},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0005},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0006},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0007},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0008},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0009},
+ cmdLutElement{0x02, 0x00, -1, 0x00, 0x000e, 0x0002},
+ cmdLutElement{0x02, 0x00, -1, 0x01, 0x000e, 0x0003},
+ cmdLutElement{0x02, 0x00, -1, 0x02, 0x000e, 0x0004},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0005},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0006},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0007},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0008},
+ cmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0009},
+ cmdLutElement{0x03, 0x00, -1, 0x00, 0x0012, 0x0002},
+ cmdLutElement{0x03, 0x00, -1, 0x01, 0x0012, 0x0003},
+ cmdLutElement{0x03, 0x00, -1, 0x02, 0x0012, 0x0004},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0005},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0006},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0007},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0008},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0009},
+ cmdLutElement{0x03, 0x00, -1, 0x00, 0x001a, 0x0002},
+ cmdLutElement{0x03, 0x00, -1, 0x01, 0x001a, 0x0003},
+ cmdLutElement{0x03, 0x00, -1, 0x02, 0x001a, 0x0004},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0005},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0006},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0007},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0008},
+ cmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0009},
+ cmdLutElement{0x04, 0x00, -1, 0x00, 0x0022, 0x0002},
+ cmdLutElement{0x04, 0x00, -1, 0x01, 0x0022, 0x0003},
+ cmdLutElement{0x04, 0x00, -1, 0x02, 0x0022, 0x0004},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0005},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0006},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0007},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0008},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0009},
+ cmdLutElement{0x04, 0x00, -1, 0x00, 0x0032, 0x0002},
+ cmdLutElement{0x04, 0x00, -1, 0x01, 0x0032, 0x0003},
+ cmdLutElement{0x04, 0x00, -1, 0x02, 0x0032, 0x0004},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0005},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0006},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0007},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0008},
+ cmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0009},
+ cmdLutElement{0x05, 0x00, -1, 0x00, 0x0042, 0x0002},
+ cmdLutElement{0x05, 0x00, -1, 0x01, 0x0042, 0x0003},
+ cmdLutElement{0x05, 0x00, -1, 0x02, 0x0042, 0x0004},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0005},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0006},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0007},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0008},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0009},
+ cmdLutElement{0x05, 0x00, -1, 0x00, 0x0062, 0x0002},
+ cmdLutElement{0x05, 0x00, -1, 0x01, 0x0062, 0x0003},
+ cmdLutElement{0x05, 0x00, -1, 0x02, 0x0062, 0x0004},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0005},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0006},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0007},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0008},
+ cmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0009},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000a, 0x000a},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000a, 0x000c},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000a, 0x000e},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000a, 0x0012},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000a, 0x0016},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000a, 0x001e},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000a, 0x0026},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000a, 0x0036},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000e, 0x000a},
+ cmdLutElement{0x02, 0x01, -1, 0x03, 0x000e, 0x000c},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000e, 0x000e},
+ cmdLutElement{0x02, 0x02, -1, 0x03, 0x000e, 0x0012},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000e, 0x0016},
+ cmdLutElement{0x02, 0x03, -1, 0x03, 0x000e, 0x001e},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000e, 0x0026},
+ cmdLutElement{0x02, 0x04, -1, 0x03, 0x000e, 0x0036},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x0012, 0x000a},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x0012, 0x000c},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x0012, 0x000e},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x0012, 0x0012},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x0012, 0x0016},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x0012, 0x001e},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x0012, 0x0026},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x0012, 0x0036},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x001a, 0x000a},
+ cmdLutElement{0x03, 0x01, -1, 0x03, 0x001a, 0x000c},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x001a, 0x000e},
+ cmdLutElement{0x03, 0x02, -1, 0x03, 0x001a, 0x0012},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x001a, 0x0016},
+ cmdLutElement{0x03, 0x03, -1, 0x03, 0x001a, 0x001e},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x001a, 0x0026},
+ cmdLutElement{0x03, 0x04, -1, 0x03, 0x001a, 0x0036},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0022, 0x000a},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0022, 0x000c},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0022, 0x000e},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0022, 0x0012},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0022, 0x0016},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0022, 0x001e},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0022, 0x0026},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0022, 0x0036},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0032, 0x000a},
+ cmdLutElement{0x04, 0x01, -1, 0x03, 0x0032, 0x000c},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0032, 0x000e},
+ cmdLutElement{0x04, 0x02, -1, 0x03, 0x0032, 0x0012},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0032, 0x0016},
+ cmdLutElement{0x04, 0x03, -1, 0x03, 0x0032, 0x001e},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0032, 0x0026},
+ cmdLutElement{0x04, 0x04, -1, 0x03, 0x0032, 0x0036},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0042, 0x000a},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0042, 0x000c},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0042, 0x000e},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0042, 0x0012},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0042, 0x0016},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0042, 0x001e},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0042, 0x0026},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0042, 0x0036},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0062, 0x000a},
+ cmdLutElement{0x05, 0x01, -1, 0x03, 0x0062, 0x000c},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0062, 0x000e},
+ cmdLutElement{0x05, 0x02, -1, 0x03, 0x0062, 0x0012},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0062, 0x0016},
+ cmdLutElement{0x05, 0x03, -1, 0x03, 0x0062, 0x001e},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0062, 0x0026},
+ cmdLutElement{0x05, 0x04, -1, 0x03, 0x0062, 0x0036},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0000, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0000, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0000, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0000, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0000, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0000, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0000, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0000, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0001, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0001, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0001, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0001, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0001, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0001, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0001, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0001, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0002, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0002, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0002, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0002, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0002, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0002, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0002, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0002, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0003, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0003, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0003, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0003, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0003, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0003, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0003, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0003, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0004, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0004, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0004, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0004, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0004, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0004, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0004, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0004, 0x0846},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0005, 0x0046},
+ cmdLutElement{0x00, 0x05, -1, 0x03, 0x0005, 0x0066},
+ cmdLutElement{0x00, 0x06, -1, 0x03, 0x0005, 0x0086},
+ cmdLutElement{0x00, 0x07, -1, 0x03, 0x0005, 0x00c6},
+ cmdLutElement{0x00, 0x08, -1, 0x03, 0x0005, 0x0146},
+ cmdLutElement{0x00, 0x09, -1, 0x03, 0x0005, 0x0246},
+ cmdLutElement{0x00, 0x0a, -1, 0x03, 0x0005, 0x0446},
+ cmdLutElement{0x00, 0x18, -1, 0x03, 0x0005, 0x0846},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0006, 0x0046},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0006, 0x0066},
+ cmdLutElement{0x01, 0x06, -1, 0x03, 0x0006, 0x0086},
+ cmdLutElement{0x01, 0x07, -1, 0x03, 0x0006, 0x00c6},
+ cmdLutElement{0x01, 0x08, -1, 0x03, 0x0006, 0x0146},
+ cmdLutElement{0x01, 0x09, -1, 0x03, 0x0006, 0x0246},
+ cmdLutElement{0x01, 0x0a, -1, 0x03, 0x0006, 0x0446},
+ cmdLutElement{0x01, 0x18, -1, 0x03, 0x0006, 0x0846},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0008, 0x0046},
+ cmdLutElement{0x01, 0x05, -1, 0x03, 0x0008, 0x0066},
+ cmdLutElement{0x01, 0x06, -1, 0x03, 0x0008, 0x0086},
+ cmdLutElement{0x01, 0x07, -1, 0x03, 0x0008, 0x00c6},
+ cmdLutElement{0x01, 0x08, -1, 0x03, 0x0008, 0x0146},
+ cmdLutElement{0x01, 0x09, -1, 0x03, 0x0008, 0x0246},
+ cmdLutElement{0x01, 0x0a, -1, 0x03, 0x0008, 0x0446},
+ cmdLutElement{0x01, 0x18, -1, 0x03, 0x0008, 0x0846},
+ cmdLutElement{0x06, 0x00, -1, 0x00, 0x0082, 0x0002},
+ cmdLutElement{0x06, 0x00, -1, 0x01, 0x0082, 0x0003},
+ cmdLutElement{0x06, 0x00, -1, 0x02, 0x0082, 0x0004},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0005},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0006},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0007},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0008},
+ cmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0009},
+ cmdLutElement{0x07, 0x00, -1, 0x00, 0x00c2, 0x0002},
+ cmdLutElement{0x07, 0x00, -1, 0x01, 0x00c2, 0x0003},
+ cmdLutElement{0x07, 0x00, -1, 0x02, 0x00c2, 0x0004},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0005},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0006},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0007},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0008},
+ cmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0009},
+ cmdLutElement{0x08, 0x00, -1, 0x00, 0x0142, 0x0002},
+ cmdLutElement{0x08, 0x00, -1, 0x01, 0x0142, 0x0003},
+ cmdLutElement{0x08, 0x00, -1, 0x02, 0x0142, 0x0004},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0005},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0006},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0007},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0008},
+ cmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0009},
+ cmdLutElement{0x09, 0x00, -1, 0x00, 0x0242, 0x0002},
+ cmdLutElement{0x09, 0x00, -1, 0x01, 0x0242, 0x0003},
+ cmdLutElement{0x09, 0x00, -1, 0x02, 0x0242, 0x0004},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0005},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0006},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0007},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0008},
+ cmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0009},
+ cmdLutElement{0x0a, 0x00, -1, 0x00, 0x0442, 0x0002},
+ cmdLutElement{0x0a, 0x00, -1, 0x01, 0x0442, 0x0003},
+ cmdLutElement{0x0a, 0x00, -1, 0x02, 0x0442, 0x0004},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0005},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0006},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0007},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0008},
+ cmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0009},
+ cmdLutElement{0x0c, 0x00, -1, 0x00, 0x0842, 0x0002},
+ cmdLutElement{0x0c, 0x00, -1, 0x01, 0x0842, 0x0003},
+ cmdLutElement{0x0c, 0x00, -1, 0x02, 0x0842, 0x0004},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0005},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0006},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0007},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0008},
+ cmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0009},
+ cmdLutElement{0x0e, 0x00, -1, 0x00, 0x1842, 0x0002},
+ cmdLutElement{0x0e, 0x00, -1, 0x01, 0x1842, 0x0003},
+ cmdLutElement{0x0e, 0x00, -1, 0x02, 0x1842, 0x0004},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0005},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0006},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0007},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0008},
+ cmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0009},
+ cmdLutElement{0x18, 0x00, -1, 0x00, 0x5842, 0x0002},
+ cmdLutElement{0x18, 0x00, -1, 0x01, 0x5842, 0x0003},
+ cmdLutElement{0x18, 0x00, -1, 0x02, 0x5842, 0x0004},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0005},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0006},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0007},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0008},
+ cmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0009},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000a, 0x0046},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000a, 0x0066},
+ cmdLutElement{0x02, 0x06, -1, 0x03, 0x000a, 0x0086},
+ cmdLutElement{0x02, 0x07, -1, 0x03, 0x000a, 0x00c6},
+ cmdLutElement{0x02, 0x08, -1, 0x03, 0x000a, 0x0146},
+ cmdLutElement{0x02, 0x09, -1, 0x03, 0x000a, 0x0246},
+ cmdLutElement{0x02, 0x0a, -1, 0x03, 0x000a, 0x0446},
+ cmdLutElement{0x02, 0x18, -1, 0x03, 0x000a, 0x0846},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000e, 0x0046},
+ cmdLutElement{0x02, 0x05, -1, 0x03, 0x000e, 0x0066},
+ cmdLutElement{0x02, 0x06, -1, 0x03, 0x000e, 0x0086},
+ cmdLutElement{0x02, 0x07, -1, 0x03, 0x000e, 0x00c6},
+ cmdLutElement{0x02, 0x08, -1, 0x03, 0x000e, 0x0146},
+ cmdLutElement{0x02, 0x09, -1, 0x03, 0x000e, 0x0246},
+ cmdLutElement{0x02, 0x0a, -1, 0x03, 0x000e, 0x0446},
+ cmdLutElement{0x02, 0x18, -1, 0x03, 0x000e, 0x0846},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x0012, 0x0046},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x0012, 0x0066},
+ cmdLutElement{0x03, 0x06, -1, 0x03, 0x0012, 0x0086},
+ cmdLutElement{0x03, 0x07, -1, 0x03, 0x0012, 0x00c6},
+ cmdLutElement{0x03, 0x08, -1, 0x03, 0x0012, 0x0146},
+ cmdLutElement{0x03, 0x09, -1, 0x03, 0x0012, 0x0246},
+ cmdLutElement{0x03, 0x0a, -1, 0x03, 0x0012, 0x0446},
+ cmdLutElement{0x03, 0x18, -1, 0x03, 0x0012, 0x0846},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x001a, 0x0046},
+ cmdLutElement{0x03, 0x05, -1, 0x03, 0x001a, 0x0066},
+ cmdLutElement{0x03, 0x06, -1, 0x03, 0x001a, 0x0086},
+ cmdLutElement{0x03, 0x07, -1, 0x03, 0x001a, 0x00c6},
+ cmdLutElement{0x03, 0x08, -1, 0x03, 0x001a, 0x0146},
+ cmdLutElement{0x03, 0x09, -1, 0x03, 0x001a, 0x0246},
+ cmdLutElement{0x03, 0x0a, -1, 0x03, 0x001a, 0x0446},
+ cmdLutElement{0x03, 0x18, -1, 0x03, 0x001a, 0x0846},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0022, 0x0046},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0022, 0x0066},
+ cmdLutElement{0x04, 0x06, -1, 0x03, 0x0022, 0x0086},
+ cmdLutElement{0x04, 0x07, -1, 0x03, 0x0022, 0x00c6},
+ cmdLutElement{0x04, 0x08, -1, 0x03, 0x0022, 0x0146},
+ cmdLutElement{0x04, 0x09, -1, 0x03, 0x0022, 0x0246},
+ cmdLutElement{0x04, 0x0a, -1, 0x03, 0x0022, 0x0446},
+ cmdLutElement{0x04, 0x18, -1, 0x03, 0x0022, 0x0846},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0032, 0x0046},
+ cmdLutElement{0x04, 0x05, -1, 0x03, 0x0032, 0x0066},
+ cmdLutElement{0x04, 0x06, -1, 0x03, 0x0032, 0x0086},
+ cmdLutElement{0x04, 0x07, -1, 0x03, 0x0032, 0x00c6},
+ cmdLutElement{0x04, 0x08, -1, 0x03, 0x0032, 0x0146},
+ cmdLutElement{0x04, 0x09, -1, 0x03, 0x0032, 0x0246},
+ cmdLutElement{0x04, 0x0a, -1, 0x03, 0x0032, 0x0446},
+ cmdLutElement{0x04, 0x18, -1, 0x03, 0x0032, 0x0846},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0042, 0x0046},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0042, 0x0066},
+ cmdLutElement{0x05, 0x06, -1, 0x03, 0x0042, 0x0086},
+ cmdLutElement{0x05, 0x07, -1, 0x03, 0x0042, 0x00c6},
+ cmdLutElement{0x05, 0x08, -1, 0x03, 0x0042, 0x0146},
+ cmdLutElement{0x05, 0x09, -1, 0x03, 0x0042, 0x0246},
+ cmdLutElement{0x05, 0x0a, -1, 0x03, 0x0042, 0x0446},
+ cmdLutElement{0x05, 0x18, -1, 0x03, 0x0042, 0x0846},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0062, 0x0046},
+ cmdLutElement{0x05, 0x05, -1, 0x03, 0x0062, 0x0066},
+ cmdLutElement{0x05, 0x06, -1, 0x03, 0x0062, 0x0086},
+ cmdLutElement{0x05, 0x07, -1, 0x03, 0x0062, 0x00c6},
+ cmdLutElement{0x05, 0x08, -1, 0x03, 0x0062, 0x0146},
+ cmdLutElement{0x05, 0x09, -1, 0x03, 0x0062, 0x0246},
+ cmdLutElement{0x05, 0x0a, -1, 0x03, 0x0062, 0x0446},
+ cmdLutElement{0x05, 0x18, -1, 0x03, 0x0062, 0x0846},
+ cmdLutElement{0x06, 0x01, -1, 0x03, 0x0082, 0x000a},
+ cmdLutElement{0x06, 0x01, -1, 0x03, 0x0082, 0x000c},
+ cmdLutElement{0x06, 0x02, -1, 0x03, 0x0082, 0x000e},
+ cmdLutElement{0x06, 0x02, -1, 0x03, 0x0082, 0x0012},
+ cmdLutElement{0x06, 0x03, -1, 0x03, 0x0082, 0x0016},
+ cmdLutElement{0x06, 0x03, -1, 0x03, 0x0082, 0x001e},
+ cmdLutElement{0x06, 0x04, -1, 0x03, 0x0082, 0x0026},
+ cmdLutElement{0x06, 0x04, -1, 0x03, 0x0082, 0x0036},
+ cmdLutElement{0x07, 0x01, -1, 0x03, 0x00c2, 0x000a},
+ cmdLutElement{0x07, 0x01, -1, 0x03, 0x00c2, 0x000c},
+ cmdLutElement{0x07, 0x02, -1, 0x03, 0x00c2, 0x000e},
+ cmdLutElement{0x07, 0x02, -1, 0x03, 0x00c2, 0x0012},
+ cmdLutElement{0x07, 0x03, -1, 0x03, 0x00c2, 0x0016},
+ cmdLutElement{0x07, 0x03, -1, 0x03, 0x00c2, 0x001e},
+ cmdLutElement{0x07, 0x04, -1, 0x03, 0x00c2, 0x0026},
+ cmdLutElement{0x07, 0x04, -1, 0x03, 0x00c2, 0x0036},
+ cmdLutElement{0x08, 0x01, -1, 0x03, 0x0142, 0x000a},
+ cmdLutElement{0x08, 0x01, -1, 0x03, 0x0142, 0x000c},
+ cmdLutElement{0x08, 0x02, -1, 0x03, 0x0142, 0x000e},
+ cmdLutElement{0x08, 0x02, -1, 0x03, 0x0142, 0x0012},
+ cmdLutElement{0x08, 0x03, -1, 0x03, 0x0142, 0x0016},
+ cmdLutElement{0x08, 0x03, -1, 0x03, 0x0142, 0x001e},
+ cmdLutElement{0x08, 0x04, -1, 0x03, 0x0142, 0x0026},
+ cmdLutElement{0x08, 0x04, -1, 0x03, 0x0142, 0x0036},
+ cmdLutElement{0x09, 0x01, -1, 0x03, 0x0242, 0x000a},
+ cmdLutElement{0x09, 0x01, -1, 0x03, 0x0242, 0x000c},
+ cmdLutElement{0x09, 0x02, -1, 0x03, 0x0242, 0x000e},
+ cmdLutElement{0x09, 0x02, -1, 0x03, 0x0242, 0x0012},
+ cmdLutElement{0x09, 0x03, -1, 0x03, 0x0242, 0x0016},
+ cmdLutElement{0x09, 0x03, -1, 0x03, 0x0242, 0x001e},
+ cmdLutElement{0x09, 0x04, -1, 0x03, 0x0242, 0x0026},
+ cmdLutElement{0x09, 0x04, -1, 0x03, 0x0242, 0x0036},
+ cmdLutElement{0x0a, 0x01, -1, 0x03, 0x0442, 0x000a},
+ cmdLutElement{0x0a, 0x01, -1, 0x03, 0x0442, 0x000c},
+ cmdLutElement{0x0a, 0x02, -1, 0x03, 0x0442, 0x000e},
+ cmdLutElement{0x0a, 0x02, -1, 0x03, 0x0442, 0x0012},
+ cmdLutElement{0x0a, 0x03, -1, 0x03, 0x0442, 0x0016},
+ cmdLutElement{0x0a, 0x03, -1, 0x03, 0x0442, 0x001e},
+ cmdLutElement{0x0a, 0x04, -1, 0x03, 0x0442, 0x0026},
+ cmdLutElement{0x0a, 0x04, -1, 0x03, 0x0442, 0x0036},
+ cmdLutElement{0x0c, 0x01, -1, 0x03, 0x0842, 0x000a},
+ cmdLutElement{0x0c, 0x01, -1, 0x03, 0x0842, 0x000c},
+ cmdLutElement{0x0c, 0x02, -1, 0x03, 0x0842, 0x000e},
+ cmdLutElement{0x0c, 0x02, -1, 0x03, 0x0842, 0x0012},
+ cmdLutElement{0x0c, 0x03, -1, 0x03, 0x0842, 0x0016},
+ cmdLutElement{0x0c, 0x03, -1, 0x03, 0x0842, 0x001e},
+ cmdLutElement{0x0c, 0x04, -1, 0x03, 0x0842, 0x0026},
+ cmdLutElement{0x0c, 0x04, -1, 0x03, 0x0842, 0x0036},
+ cmdLutElement{0x0e, 0x01, -1, 0x03, 0x1842, 0x000a},
+ cmdLutElement{0x0e, 0x01, -1, 0x03, 0x1842, 0x000c},
+ cmdLutElement{0x0e, 0x02, -1, 0x03, 0x1842, 0x000e},
+ cmdLutElement{0x0e, 0x02, -1, 0x03, 0x1842, 0x0012},
+ cmdLutElement{0x0e, 0x03, -1, 0x03, 0x1842, 0x0016},
+ cmdLutElement{0x0e, 0x03, -1, 0x03, 0x1842, 0x001e},
+ cmdLutElement{0x0e, 0x04, -1, 0x03, 0x1842, 0x0026},
+ cmdLutElement{0x0e, 0x04, -1, 0x03, 0x1842, 0x0036},
+ cmdLutElement{0x18, 0x01, -1, 0x03, 0x5842, 0x000a},
+ cmdLutElement{0x18, 0x01, -1, 0x03, 0x5842, 0x000c},
+ cmdLutElement{0x18, 0x02, -1, 0x03, 0x5842, 0x000e},
+ cmdLutElement{0x18, 0x02, -1, 0x03, 0x5842, 0x0012},
+ cmdLutElement{0x18, 0x03, -1, 0x03, 0x5842, 0x0016},
+ cmdLutElement{0x18, 0x03, -1, 0x03, 0x5842, 0x001e},
+ cmdLutElement{0x18, 0x04, -1, 0x03, 0x5842, 0x0026},
+ cmdLutElement{0x18, 0x04, -1, 0x03, 0x5842, 0x0036},
+ cmdLutElement{0x06, 0x05, -1, 0x03, 0x0082, 0x0046},
+ cmdLutElement{0x06, 0x05, -1, 0x03, 0x0082, 0x0066},
+ cmdLutElement{0x06, 0x06, -1, 0x03, 0x0082, 0x0086},
+ cmdLutElement{0x06, 0x07, -1, 0x03, 0x0082, 0x00c6},
+ cmdLutElement{0x06, 0x08, -1, 0x03, 0x0082, 0x0146},
+ cmdLutElement{0x06, 0x09, -1, 0x03, 0x0082, 0x0246},
+ cmdLutElement{0x06, 0x0a, -1, 0x03, 0x0082, 0x0446},
+ cmdLutElement{0x06, 0x18, -1, 0x03, 0x0082, 0x0846},
+ cmdLutElement{0x07, 0x05, -1, 0x03, 0x00c2, 0x0046},
+ cmdLutElement{0x07, 0x05, -1, 0x03, 0x00c2, 0x0066},
+ cmdLutElement{0x07, 0x06, -1, 0x03, 0x00c2, 0x0086},
+ cmdLutElement{0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6},
+ cmdLutElement{0x07, 0x08, -1, 0x03, 0x00c2, 0x0146},
+ cmdLutElement{0x07, 0x09, -1, 0x03, 0x00c2, 0x0246},
+ cmdLutElement{0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446},
+ cmdLutElement{0x07, 0x18, -1, 0x03, 0x00c2, 0x0846},
+ cmdLutElement{0x08, 0x05, -1, 0x03, 0x0142, 0x0046},
+ cmdLutElement{0x08, 0x05, -1, 0x03, 0x0142, 0x0066},
+ cmdLutElement{0x08, 0x06, -1, 0x03, 0x0142, 0x0086},
+ cmdLutElement{0x08, 0x07, -1, 0x03, 0x0142, 0x00c6},
+ cmdLutElement{0x08, 0x08, -1, 0x03, 0x0142, 0x0146},
+ cmdLutElement{0x08, 0x09, -1, 0x03, 0x0142, 0x0246},
+ cmdLutElement{0x08, 0x0a, -1, 0x03, 0x0142, 0x0446},
+ cmdLutElement{0x08, 0x18, -1, 0x03, 0x0142, 0x0846},
+ cmdLutElement{0x09, 0x05, -1, 0x03, 0x0242, 0x0046},
+ cmdLutElement{0x09, 0x05, -1, 0x03, 0x0242, 0x0066},
+ cmdLutElement{0x09, 0x06, -1, 0x03, 0x0242, 0x0086},
+ cmdLutElement{0x09, 0x07, -1, 0x03, 0x0242, 0x00c6},
+ cmdLutElement{0x09, 0x08, -1, 0x03, 0x0242, 0x0146},
+ cmdLutElement{0x09, 0x09, -1, 0x03, 0x0242, 0x0246},
+ cmdLutElement{0x09, 0x0a, -1, 0x03, 0x0242, 0x0446},
+ cmdLutElement{0x09, 0x18, -1, 0x03, 0x0242, 0x0846},
+ cmdLutElement{0x0a, 0x05, -1, 0x03, 0x0442, 0x0046},
+ cmdLutElement{0x0a, 0x05, -1, 0x03, 0x0442, 0x0066},
+ cmdLutElement{0x0a, 0x06, -1, 0x03, 0x0442, 0x0086},
+ cmdLutElement{0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6},
+ cmdLutElement{0x0a, 0x08, -1, 0x03, 0x0442, 0x0146},
+ cmdLutElement{0x0a, 0x09, -1, 0x03, 0x0442, 0x0246},
+ cmdLutElement{0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446},
+ cmdLutElement{0x0a, 0x18, -1, 0x03, 0x0442, 0x0846},
+ cmdLutElement{0x0c, 0x05, -1, 0x03, 0x0842, 0x0046},
+ cmdLutElement{0x0c, 0x05, -1, 0x03, 0x0842, 0x0066},
+ cmdLutElement{0x0c, 0x06, -1, 0x03, 0x0842, 0x0086},
+ cmdLutElement{0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6},
+ cmdLutElement{0x0c, 0x08, -1, 0x03, 0x0842, 0x0146},
+ cmdLutElement{0x0c, 0x09, -1, 0x03, 0x0842, 0x0246},
+ cmdLutElement{0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446},
+ cmdLutElement{0x0c, 0x18, -1, 0x03, 0x0842, 0x0846},
+ cmdLutElement{0x0e, 0x05, -1, 0x03, 0x1842, 0x0046},
+ cmdLutElement{0x0e, 0x05, -1, 0x03, 0x1842, 0x0066},
+ cmdLutElement{0x0e, 0x06, -1, 0x03, 0x1842, 0x0086},
+ cmdLutElement{0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6},
+ cmdLutElement{0x0e, 0x08, -1, 0x03, 0x1842, 0x0146},
+ cmdLutElement{0x0e, 0x09, -1, 0x03, 0x1842, 0x0246},
+ cmdLutElement{0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446},
+ cmdLutElement{0x0e, 0x18, -1, 0x03, 0x1842, 0x0846},
+ cmdLutElement{0x18, 0x05, -1, 0x03, 0x5842, 0x0046},
+ cmdLutElement{0x18, 0x05, -1, 0x03, 0x5842, 0x0066},
+ cmdLutElement{0x18, 0x06, -1, 0x03, 0x5842, 0x0086},
+ cmdLutElement{0x18, 0x07, -1, 0x03, 0x5842, 0x00c6},
+ cmdLutElement{0x18, 0x08, -1, 0x03, 0x5842, 0x0146},
+ cmdLutElement{0x18, 0x09, -1, 0x03, 0x5842, 0x0246},
+ cmdLutElement{0x18, 0x0a, -1, 0x03, 0x5842, 0x0446},
+ cmdLutElement{0x18, 0x18, -1, 0x03, 0x5842, 0x0846},
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/quality.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/quality.go
new file mode 100644
index 000000000000..49709a382390
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/quality.go
@@ -0,0 +1,196 @@
+package brotli
+
+const fastOnePassCompressionQuality = 0
+
+const fastTwoPassCompressionQuality = 1
+
+const zopflificationQuality = 10
+
+const hqZopflificationQuality = 11
+
+const maxQualityForStaticEntropyCodes = 2
+
+const minQualityForBlockSplit = 4
+
+const minQualityForNonzeroDistanceParams = 4
+
+const minQualityForOptimizeHistograms = 4
+
+const minQualityForExtensiveReferenceSearch = 5
+
+const minQualityForContextModeling = 5
+
+const minQualityForHqContextModeling = 7
+
+const minQualityForHqBlockSplitting = 10
+
+/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
+ so we buffer at most this much literals and commands. */
+const maxNumDelayedSymbols = 0x2FFF
+
+/* Returns hash-table size for quality levels 0 and 1. */
+func maxHashTableSize(quality int) uint {
+ if quality == fastOnePassCompressionQuality {
+ return 1 << 15
+ } else {
+ return 1 << 17
+ }
+}
+
+/* The maximum length for which the zopflification uses distinct distances. */
+const maxZopfliLenQuality10 = 150
+
+const maxZopfliLenQuality11 = 325
+
+/* Do not thoroughly search when a long copy is found. */
+const longCopyQuickStep = 16384
+
+func maxZopfliLen(params *encoderParams) uint {
+ if params.quality <= 10 {
+ return maxZopfliLenQuality10
+ } else {
+ return maxZopfliLenQuality11
+ }
+}
+
+/* Number of best candidates to evaluate to expand Zopfli chain. */
+func maxZopfliCandidates(params *encoderParams) uint {
+ if params.quality <= 10 {
+ return 1
+ } else {
+ return 5
+ }
+}
+
+func sanitizeParams(params *encoderParams) {
+ params.quality = brotli_min_int(maxQuality, brotli_max_int(minQuality, params.quality))
+ if params.quality <= maxQualityForStaticEntropyCodes {
+ params.large_window = false
+ }
+
+ if params.lgwin < minWindowBits {
+ params.lgwin = minWindowBits
+ } else {
+ var max_lgwin int
+ if params.large_window {
+ max_lgwin = largeMaxWindowBits
+ } else {
+ max_lgwin = maxWindowBits
+ }
+ if params.lgwin > uint(max_lgwin) {
+ params.lgwin = uint(max_lgwin)
+ }
+ }
+}
+
+/* Returns optimized lg_block value. */
+func computeLgBlock(params *encoderParams) int {
+ var lgblock int = params.lgblock
+ if params.quality == fastOnePassCompressionQuality || params.quality == fastTwoPassCompressionQuality {
+ lgblock = int(params.lgwin)
+ } else if params.quality < minQualityForBlockSplit {
+ lgblock = 14
+ } else if lgblock == 0 {
+ lgblock = 16
+ if params.quality >= 9 && params.lgwin > uint(lgblock) {
+ lgblock = brotli_min_int(18, int(params.lgwin))
+ }
+ } else {
+ lgblock = brotli_min_int(maxInputBlockBits, brotli_max_int(minInputBlockBits, lgblock))
+ }
+
+ return lgblock
+}
+
+/* Returns log2 of the size of main ring buffer area.
+ Allocate at least lgwin + 1 bits for the ring buffer so that the newly
+ added block fits there completely and we still get lgwin bits and at least
+ read_block_size_bits + 1 bits because the copy tail length needs to be
+ smaller than ring-buffer size. */
+func computeRbBits(params *encoderParams) int {
+ return 1 + brotli_max_int(int(params.lgwin), params.lgblock)
+}
+
+func maxMetablockSize(params *encoderParams) uint {
+ var bits int = brotli_min_int(computeRbBits(params), maxInputBlockBits)
+ return uint(1) << uint(bits)
+}
+
+/* When searching for backward references and have not seen matches for a long
+ time, we can skip some match lookups. Unsuccessful match lookups are very
+ expensive and this kind of a heuristic speeds up compression quite a lot.
+ At first 8 byte strides are taken and every second byte is put to hasher.
+ After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
+ Applied only to qualities 2 to 9. */
+func literalSpreeLengthForSparseSearch(params *encoderParams) uint {
+ if params.quality < 9 {
+ return 64
+ } else {
+ return 512
+ }
+}
+
+func chooseHasher(params *encoderParams, hparams *hasherParams) {
+ if params.quality > 9 {
+ hparams.type_ = 10
+ } else if params.quality == 4 && params.size_hint >= 1<<20 {
+ hparams.type_ = 54
+ } else if params.quality < 5 {
+ hparams.type_ = params.quality
+ } else if params.lgwin <= 16 {
+ if params.quality < 7 {
+ hparams.type_ = 40
+ } else if params.quality < 9 {
+ hparams.type_ = 41
+ } else {
+ hparams.type_ = 42
+ }
+ } else if params.size_hint >= 1<<20 && params.lgwin >= 19 {
+ hparams.type_ = 6
+ hparams.block_bits = params.quality - 1
+ hparams.bucket_bits = 15
+ hparams.hash_len = 5
+ if params.quality < 7 {
+ hparams.num_last_distances_to_check = 4
+ } else if params.quality < 9 {
+ hparams.num_last_distances_to_check = 10
+ } else {
+ hparams.num_last_distances_to_check = 16
+ }
+ } else {
+ hparams.type_ = 5
+ hparams.block_bits = params.quality - 1
+ if params.quality < 7 {
+ hparams.bucket_bits = 14
+ } else {
+ hparams.bucket_bits = 15
+ }
+ if params.quality < 7 {
+ hparams.num_last_distances_to_check = 4
+ } else if params.quality < 9 {
+ hparams.num_last_distances_to_check = 10
+ } else {
+ hparams.num_last_distances_to_check = 16
+ }
+ }
+
+ if params.lgwin > 24 {
+ /* Different hashers for large window brotli: not for qualities <= 2,
+ these are too fast for large window. Not for qualities >= 10: their
+ hasher already works well with large window. So the changes are:
+ H3 --> H35: for quality 3.
+ H54 --> H55: for quality 4 with size hint > 1MB
+ H6 --> H65: for qualities 5, 6, 7, 8, 9. */
+ if hparams.type_ == 3 {
+ hparams.type_ = 35
+ }
+
+ if hparams.type_ == 54 {
+ hparams.type_ = 55
+ }
+
+ if hparams.type_ == 6 {
+ hparams.type_ = 65
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/reader.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/reader.go
new file mode 100644
index 000000000000..9419c79c17a0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/reader.go
@@ -0,0 +1,108 @@
+package brotli
+
+import (
+ "errors"
+ "io"
+)
+
+type decodeError int
+
+func (err decodeError) Error() string {
+ return "brotli: " + string(decoderErrorString(int(err)))
+}
+
+var errExcessiveInput = errors.New("brotli: excessive input")
+var errInvalidState = errors.New("brotli: invalid state")
+
+// readBufSize is a "good" buffer size that avoids excessive round-trips
+// between C and Go but doesn't waste too much memory on buffering.
+// It is arbitrarily chosen to be equal to the constant used in io.Copy.
+const readBufSize = 32 * 1024
+
+// NewReader creates a new Reader reading the given reader.
+func NewReader(src io.Reader) *Reader {
+ r := new(Reader)
+ r.Reset(src)
+ return r
+}
+
+// Reset discards the Reader's state and makes it equivalent to the result of
+// its original state from NewReader, but reading from src instead.
+// This permits reusing a Reader rather than allocating a new one.
+// Error is always nil
+func (r *Reader) Reset(src io.Reader) error {
+ if r.error_code < 0 {
+ // There was an unrecoverable error, leaving the Reader's state
+ // undefined. Clear out everything but the buffer.
+ *r = Reader{buf: r.buf}
+ }
+
+ decoderStateInit(r)
+ r.src = src
+ if r.buf == nil {
+ r.buf = make([]byte, readBufSize)
+ }
+ return nil
+}
+
+func (r *Reader) Read(p []byte) (n int, err error) {
+ if !decoderHasMoreOutput(r) && len(r.in) == 0 {
+ m, readErr := r.src.Read(r.buf)
+ if m == 0 {
+ // If readErr is `nil`, we just proxy underlying stream behavior.
+ return 0, readErr
+ }
+ r.in = r.buf[:m]
+ }
+
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ for {
+ var written uint
+ in_len := uint(len(r.in))
+ out_len := uint(len(p))
+ in_remaining := in_len
+ out_remaining := out_len
+ result := decoderDecompressStream(r, &in_remaining, &r.in, &out_remaining, &p)
+ written = out_len - out_remaining
+ n = int(written)
+
+ switch result {
+ case decoderResultSuccess:
+ if len(r.in) > 0 {
+ return n, errExcessiveInput
+ }
+ return n, nil
+ case decoderResultError:
+ return n, decodeError(decoderGetErrorCode(r))
+ case decoderResultNeedsMoreOutput:
+ if n == 0 {
+ return 0, io.ErrShortBuffer
+ }
+ return n, nil
+ case decoderNeedsMoreInput:
+ }
+
+ if len(r.in) != 0 {
+ return 0, errInvalidState
+ }
+
+ // Calling r.src.Read may block. Don't block if we have data to return.
+ if n > 0 {
+ return n, nil
+ }
+
+ // Top off the buffer.
+ encN, err := r.src.Read(r.buf)
+ if encN == 0 {
+ // Not enough data to complete decoding.
+ if err == io.EOF {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ r.in = r.buf[:encN]
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/ringbuffer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/ringbuffer.go
new file mode 100644
index 000000000000..1c8f86feece3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/ringbuffer.go
@@ -0,0 +1,134 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* A ringBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of
+ data in a circular manner: writing a byte writes it to:
+ `position() % (1 << window_bits)'.
+ For convenience, the ringBuffer array contains another copy of the
+ first `1 << tail_bits' bytes:
+ buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),
+ and another copy of the last two bytes:
+ buffer_[-1] == buffer_[(1 << window_bits) - 1] and
+ buffer_[-2] == buffer_[(1 << window_bits) - 2]. */
+type ringBuffer struct {
+ size_ uint32
+ mask_ uint32
+ tail_size_ uint32
+ total_size_ uint32
+ cur_size_ uint32
+ pos_ uint32
+ data_ []byte
+ buffer_ []byte
+}
+
+func ringBufferInit(rb *ringBuffer) {
+ rb.pos_ = 0
+}
+
+func ringBufferSetup(params *encoderParams, rb *ringBuffer) {
+ var window_bits int = computeRbBits(params)
+ var tail_bits int = params.lgblock
+ *(*uint32)(&rb.size_) = 1 << uint(window_bits)
+ *(*uint32)(&rb.mask_) = (1 << uint(window_bits)) - 1
+ *(*uint32)(&rb.tail_size_) = 1 << uint(tail_bits)
+ *(*uint32)(&rb.total_size_) = rb.size_ + rb.tail_size_
+}
+
+const kSlackForEightByteHashingEverywhere uint = 7
+
+/* Allocates or re-allocates data_ to the given length + plus some slack
+ region before and after. Fills the slack regions with zeros. */
+func ringBufferInitBuffer(buflen uint32, rb *ringBuffer) {
+ var new_data []byte
+ var i uint
+ size := 2 + int(buflen) + int(kSlackForEightByteHashingEverywhere)
+ if cap(rb.data_) < size {
+ new_data = make([]byte, size)
+ } else {
+ new_data = rb.data_[:size]
+ }
+ if rb.data_ != nil {
+ copy(new_data, rb.data_[:2+rb.cur_size_+uint32(kSlackForEightByteHashingEverywhere)])
+ }
+
+ rb.data_ = new_data
+ rb.cur_size_ = buflen
+ rb.buffer_ = rb.data_[2:]
+ rb.data_[1] = 0
+ rb.data_[0] = rb.data_[1]
+ for i = 0; i < kSlackForEightByteHashingEverywhere; i++ {
+ rb.buffer_[rb.cur_size_+uint32(i)] = 0
+ }
+}
+
+func ringBufferWriteTail(bytes []byte, n uint, rb *ringBuffer) {
+ var masked_pos uint = uint(rb.pos_ & rb.mask_)
+ if uint32(masked_pos) < rb.tail_size_ {
+ /* Just fill the tail buffer with the beginning data. */
+ var p uint = uint(rb.size_ + uint32(masked_pos))
+ copy(rb.buffer_[p:], bytes[:brotli_min_size_t(n, uint(rb.tail_size_-uint32(masked_pos)))])
+ }
+}
+
+/* Push bytes into the ring buffer. */
+func ringBufferWrite(bytes []byte, n uint, rb *ringBuffer) {
+ if rb.pos_ == 0 && uint32(n) < rb.tail_size_ {
+ /* Special case for the first write: to process the first block, we don't
+ need to allocate the whole ring-buffer and we don't need the tail
+ either. However, we do this memory usage optimization only if the
+ first write is less than the tail size, which is also the input block
+ size, otherwise it is likely that other blocks will follow and we
+ will need to reallocate to the full size anyway. */
+ rb.pos_ = uint32(n)
+
+ ringBufferInitBuffer(rb.pos_, rb)
+ copy(rb.buffer_, bytes[:n])
+ return
+ }
+
+ if rb.cur_size_ < rb.total_size_ {
+ /* Lazily allocate the full buffer. */
+ ringBufferInitBuffer(rb.total_size_, rb)
+
+ /* Initialize the last two bytes to zero, so that we don't have to worry
+ later when we copy the last two bytes to the first two positions. */
+ rb.buffer_[rb.size_-2] = 0
+
+ rb.buffer_[rb.size_-1] = 0
+ }
+ {
+ var masked_pos uint = uint(rb.pos_ & rb.mask_)
+
+ /* The length of the writes is limited so that we do not need to worry
+ about a write */
+ ringBufferWriteTail(bytes, n, rb)
+
+ if uint32(masked_pos+n) <= rb.size_ {
+ /* A single write fits. */
+ copy(rb.buffer_[masked_pos:], bytes[:n])
+ } else {
+ /* Split into two writes.
+ Copy into the end of the buffer, including the tail buffer. */
+ copy(rb.buffer_[masked_pos:], bytes[:brotli_min_size_t(n, uint(rb.total_size_-uint32(masked_pos)))])
+
+ /* Copy into the beginning of the buffer */
+ copy(rb.buffer_, bytes[rb.size_-uint32(masked_pos):][:uint32(n)-(rb.size_-uint32(masked_pos))])
+ }
+ }
+ {
+ var not_first_lap bool = rb.pos_&(1<<31) != 0
+ var rb_pos_mask uint32 = (1 << 31) - 1
+ rb.data_[0] = rb.buffer_[rb.size_-2]
+ rb.data_[1] = rb.buffer_[rb.size_-1]
+ rb.pos_ = (rb.pos_ & rb_pos_mask) + uint32(uint32(n)&rb_pos_mask)
+ if not_first_lap {
+ /* Wrap, but preserve not-a-first-lap feature. */
+ rb.pos_ |= 1 << 31
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/state.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/state.go
new file mode 100644
index 000000000000..38d753ebe4d0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/state.go
@@ -0,0 +1,294 @@
+package brotli
+
+import "io"
+
+/* Copyright 2015 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Brotli state for partial streaming decoding. */
+const (
+ stateUninited = iota
+ stateLargeWindowBits
+ stateInitialize
+ stateMetablockBegin
+ stateMetablockHeader
+ stateMetablockHeader2
+ stateContextModes
+ stateCommandBegin
+ stateCommandInner
+ stateCommandPostDecodeLiterals
+ stateCommandPostWrapCopy
+ stateUncompressed
+ stateMetadata
+ stateCommandInnerWrite
+ stateMetablockDone
+ stateCommandPostWrite1
+ stateCommandPostWrite2
+ stateHuffmanCode0
+ stateHuffmanCode1
+ stateHuffmanCode2
+ stateHuffmanCode3
+ stateContextMap1
+ stateContextMap2
+ stateTreeGroup
+ stateDone
+)
+
+const (
+ stateMetablockHeaderNone = iota
+ stateMetablockHeaderEmpty
+ stateMetablockHeaderNibbles
+ stateMetablockHeaderSize
+ stateMetablockHeaderUncompressed
+ stateMetablockHeaderReserved
+ stateMetablockHeaderBytes
+ stateMetablockHeaderMetadata
+)
+
+const (
+ stateUncompressedNone = iota
+ stateUncompressedWrite
+)
+
+const (
+ stateTreeGroupNone = iota
+ stateTreeGroupLoop
+)
+
+const (
+ stateContextMapNone = iota
+ stateContextMapReadPrefix
+ stateContextMapHuffman
+ stateContextMapDecode
+ stateContextMapTransform
+)
+
+const (
+ stateHuffmanNone = iota
+ stateHuffmanSimpleSize
+ stateHuffmanSimpleRead
+ stateHuffmanSimpleBuild
+ stateHuffmanComplex
+ stateHuffmanLengthSymbols
+)
+
+const (
+ stateDecodeUint8None = iota
+ stateDecodeUint8Short
+ stateDecodeUint8Long
+)
+
+const (
+ stateReadBlockLengthNone = iota
+ stateReadBlockLengthSuffix
+)
+
+type Reader struct {
+ src io.Reader
+ buf []byte // scratch space for reading from src
+ in []byte // current chunk to decode; usually aliases buf
+
+ state int
+ loop_counter int
+ br bitReader
+ buffer struct {
+ u64 uint64
+ u8 [8]byte
+ }
+ buffer_length uint32
+ pos int
+ max_backward_distance int
+ max_distance int
+ ringbuffer_size int
+ ringbuffer_mask int
+ dist_rb_idx int
+ dist_rb [4]int
+ error_code int
+ sub_loop_counter uint32
+ ringbuffer []byte
+ ringbuffer_end []byte
+ htree_command []huffmanCode
+ context_lookup []byte
+ context_map_slice []byte
+ dist_context_map_slice []byte
+ literal_hgroup huffmanTreeGroup
+ insert_copy_hgroup huffmanTreeGroup
+ distance_hgroup huffmanTreeGroup
+ block_type_trees []huffmanCode
+ block_len_trees []huffmanCode
+ trivial_literal_context int
+ distance_context int
+ meta_block_remaining_len int
+ block_length_index uint32
+ block_length [3]uint32
+ num_block_types [3]uint32
+ block_type_rb [6]uint32
+ distance_postfix_bits uint32
+ num_direct_distance_codes uint32
+ distance_postfix_mask int
+ num_dist_htrees uint32
+ dist_context_map []byte
+ literal_htree []huffmanCode
+ dist_htree_index byte
+ repeat_code_len uint32
+ prev_code_len uint32
+ copy_length int
+ distance_code int
+ rb_roundtrips uint
+ partial_pos_out uint
+ symbol uint32
+ repeat uint32
+ space uint32
+ table [32]huffmanCode
+ symbol_lists symbolList
+ symbols_lists_array [huffmanMaxCodeLength + 1 + numCommandSymbols]uint16
+ next_symbol [32]int
+ code_length_code_lengths [codeLengthCodes]byte
+ code_length_histo [16]uint16
+ htree_index int
+ next []huffmanCode
+ context_index uint32
+ max_run_length_prefix uint32
+ code uint32
+ context_map_table [huffmanMaxSize272]huffmanCode
+ substate_metablock_header int
+ substate_tree_group int
+ substate_context_map int
+ substate_uncompressed int
+ substate_huffman int
+ substate_decode_uint8 int
+ substate_read_block_length int
+ is_last_metablock uint
+ is_uncompressed uint
+ is_metadata uint
+ should_wrap_ringbuffer uint
+ canny_ringbuffer_allocation uint
+ large_window bool
+ size_nibbles uint
+ window_bits uint32
+ new_ringbuffer_size int
+ num_literal_htrees uint32
+ context_map []byte
+ context_modes []byte
+ dictionary *dictionary
+ transforms *transforms
+ trivial_literal_contexts [8]uint32
+}
+
+func decoderStateInit(s *Reader) bool {
+ s.error_code = 0 /* BROTLI_DECODER_NO_ERROR */
+
+ initBitReader(&s.br)
+ s.state = stateUninited
+ s.large_window = false
+ s.substate_metablock_header = stateMetablockHeaderNone
+ s.substate_tree_group = stateTreeGroupNone
+ s.substate_context_map = stateContextMapNone
+ s.substate_uncompressed = stateUncompressedNone
+ s.substate_huffman = stateHuffmanNone
+ s.substate_decode_uint8 = stateDecodeUint8None
+ s.substate_read_block_length = stateReadBlockLengthNone
+
+ s.buffer_length = 0
+ s.loop_counter = 0
+ s.pos = 0
+ s.rb_roundtrips = 0
+ s.partial_pos_out = 0
+
+ s.block_type_trees = nil
+ s.block_len_trees = nil
+ s.ringbuffer_size = 0
+ s.new_ringbuffer_size = 0
+ s.ringbuffer_mask = 0
+
+ s.context_map = nil
+ s.context_modes = nil
+ s.dist_context_map = nil
+ s.context_map_slice = nil
+ s.dist_context_map_slice = nil
+
+ s.sub_loop_counter = 0
+
+ s.literal_hgroup.codes = nil
+ s.literal_hgroup.htrees = nil
+ s.insert_copy_hgroup.codes = nil
+ s.insert_copy_hgroup.htrees = nil
+ s.distance_hgroup.codes = nil
+ s.distance_hgroup.htrees = nil
+
+ s.is_last_metablock = 0
+ s.is_uncompressed = 0
+ s.is_metadata = 0
+ s.should_wrap_ringbuffer = 0
+ s.canny_ringbuffer_allocation = 1
+
+ s.window_bits = 0
+ s.max_distance = 0
+ s.dist_rb[0] = 16
+ s.dist_rb[1] = 15
+ s.dist_rb[2] = 11
+ s.dist_rb[3] = 4
+ s.dist_rb_idx = 0
+ s.block_type_trees = nil
+ s.block_len_trees = nil
+
+ s.symbol_lists.storage = s.symbols_lists_array[:]
+ s.symbol_lists.offset = huffmanMaxCodeLength + 1
+
+ s.dictionary = getDictionary()
+ s.transforms = getTransforms()
+
+ return true
+}
+
+func decoderStateMetablockBegin(s *Reader) {
+ s.meta_block_remaining_len = 0
+ s.block_length[0] = 1 << 24
+ s.block_length[1] = 1 << 24
+ s.block_length[2] = 1 << 24
+ s.num_block_types[0] = 1
+ s.num_block_types[1] = 1
+ s.num_block_types[2] = 1
+ s.block_type_rb[0] = 1
+ s.block_type_rb[1] = 0
+ s.block_type_rb[2] = 1
+ s.block_type_rb[3] = 0
+ s.block_type_rb[4] = 1
+ s.block_type_rb[5] = 0
+ s.context_map = nil
+ s.context_modes = nil
+ s.dist_context_map = nil
+ s.context_map_slice = nil
+ s.literal_htree = nil
+ s.dist_context_map_slice = nil
+ s.dist_htree_index = 0
+ s.context_lookup = nil
+ s.literal_hgroup.codes = nil
+ s.literal_hgroup.htrees = nil
+ s.insert_copy_hgroup.codes = nil
+ s.insert_copy_hgroup.htrees = nil
+ s.distance_hgroup.codes = nil
+ s.distance_hgroup.htrees = nil
+}
+
+func decoderStateCleanupAfterMetablock(s *Reader) {
+ s.context_modes = nil
+ s.context_map = nil
+ s.dist_context_map = nil
+ s.literal_hgroup.htrees = nil
+ s.insert_copy_hgroup.htrees = nil
+ s.distance_hgroup.htrees = nil
+}
+
+func decoderHuffmanTreeGroupInit(s *Reader, group *huffmanTreeGroup, alphabet_size uint32, max_symbol uint32, ntrees uint32) bool {
+ var max_table_size uint = uint(kMaxHuffmanTableSize[(alphabet_size+31)>>5])
+ group.alphabet_size = uint16(alphabet_size)
+ group.max_symbol = uint16(max_symbol)
+ group.num_htrees = uint16(ntrees)
+ group.htrees = make([][]huffmanCode, ntrees)
+ group.codes = make([]huffmanCode, (uint(ntrees) * max_table_size))
+ return !(group.codes == nil)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/static_dict.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/static_dict.go
new file mode 100644
index 000000000000..bc05566d6f85
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/static_dict.go
@@ -0,0 +1,662 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Class to model the static dictionary. */
+
+const maxStaticDictionaryMatchLen = 37
+
+const kInvalidMatch uint32 = 0xFFFFFFF
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+func hash(data []byte) uint32 {
+ var h uint32 = binary.LittleEndian.Uint32(data) * kDictHashMul32
+
+ /* The higher bits contain more mixture from the multiplication,
+ so we take our results from there. */
+ return h >> uint(32-kDictNumBits)
+}
+
+func addMatch(distance uint, len uint, len_code uint, matches []uint32) {
+ var match uint32 = uint32((distance << 5) + len_code)
+ matches[len] = brotli_min_uint32_t(matches[len], match)
+}
+
+func dictMatchLength(dict *dictionary, data []byte, id uint, len uint, maxlen uint) uint {
+ var offset uint = uint(dict.offsets_by_length[len]) + len*id
+ return findMatchLengthWithLimit(dict.data[offset:], data, brotli_min_size_t(uint(len), maxlen))
+}
+
+func isMatch(d *dictionary, w dictWord, data []byte, max_length uint) bool {
+ if uint(w.len) > max_length {
+ return false
+ } else {
+ var offset uint = uint(d.offsets_by_length[w.len]) + uint(w.len)*uint(w.idx)
+ var dict []byte = d.data[offset:]
+ if w.transform == 0 {
+ /* Match against base dictionary word. */
+ return findMatchLengthWithLimit(dict, data, uint(w.len)) == uint(w.len)
+ } else if w.transform == 10 {
+ /* Match against uppercase first transform.
+ Note that there are only ASCII uppercase words in the lookup table. */
+ return dict[0] >= 'a' && dict[0] <= 'z' && (dict[0]^32) == data[0] && findMatchLengthWithLimit(dict[1:], data[1:], uint(w.len)-1) == uint(w.len-1)
+ } else {
+ /* Match against uppercase all transform.
+ Note that there are only ASCII uppercase words in the lookup table. */
+ var i uint
+ for i = 0; i < uint(w.len); i++ {
+ if dict[i] >= 'a' && dict[i] <= 'z' {
+ if (dict[i] ^ 32) != data[i] {
+ return false
+ }
+ } else {
+ if dict[i] != data[i] {
+ return false
+ }
+ }
+ }
+
+ return true
+ }
+ }
+}
+
+func findAllStaticDictionaryMatches(dict *encoderDictionary, data []byte, min_length uint, max_length uint, matches []uint32) bool {
+ var has_found_match bool = false
+ {
+ var offset uint = uint(dict.buckets[hash(data)])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 {
+ var matchlen uint = dictMatchLength(dict.words, data, id, l, max_length)
+ var s []byte
+ var minlen uint
+ var maxlen uint
+ var len uint
+
+ /* Transform "" + BROTLI_TRANSFORM_IDENTITY + "" */
+ if matchlen == l {
+ addMatch(id, l, l, matches)
+ has_found_match = true
+ }
+
+ /* Transforms "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "" and
+ "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "ing " */
+ if matchlen >= l-1 {
+ addMatch(id+12*n, l-1, l, matches)
+ if l+2 < max_length && data[l-1] == 'i' && data[l] == 'n' && data[l+1] == 'g' && data[l+2] == ' ' {
+ addMatch(id+49*n, l+3, l, matches)
+ }
+
+ has_found_match = true
+ }
+
+ /* Transform "" + BROTLI_TRANSFORM_OMIT_LAST_# + "" (# = 2 .. 9) */
+ minlen = min_length
+
+ if l > 9 {
+ minlen = brotli_max_size_t(minlen, l-9)
+ }
+ maxlen = brotli_min_size_t(matchlen, l-2)
+ for len = minlen; len <= maxlen; len++ {
+ var cut uint = l - len
+ var transform_id uint = (cut << 2) + uint((dict.cutoffTransforms>>(cut*6))&0x3F)
+ addMatch(id+transform_id*n, uint(len), l, matches)
+ has_found_match = true
+ }
+
+ if matchlen < l || l+6 >= max_length {
+ continue
+ }
+
+ s = data[l:]
+
+ /* Transforms "" + BROTLI_TRANSFORM_IDENTITY + */
+ if s[0] == ' ' {
+ addMatch(id+n, l+1, l, matches)
+ if s[1] == 'a' {
+ if s[2] == ' ' {
+ addMatch(id+28*n, l+3, l, matches)
+ } else if s[2] == 's' {
+ if s[3] == ' ' {
+ addMatch(id+46*n, l+4, l, matches)
+ }
+ } else if s[2] == 't' {
+ if s[3] == ' ' {
+ addMatch(id+60*n, l+4, l, matches)
+ }
+ } else if s[2] == 'n' {
+ if s[3] == 'd' && s[4] == ' ' {
+ addMatch(id+10*n, l+5, l, matches)
+ }
+ }
+ } else if s[1] == 'b' {
+ if s[2] == 'y' && s[3] == ' ' {
+ addMatch(id+38*n, l+4, l, matches)
+ }
+ } else if s[1] == 'i' {
+ if s[2] == 'n' {
+ if s[3] == ' ' {
+ addMatch(id+16*n, l+4, l, matches)
+ }
+ } else if s[2] == 's' {
+ if s[3] == ' ' {
+ addMatch(id+47*n, l+4, l, matches)
+ }
+ }
+ } else if s[1] == 'f' {
+ if s[2] == 'o' {
+ if s[3] == 'r' && s[4] == ' ' {
+ addMatch(id+25*n, l+5, l, matches)
+ }
+ } else if s[2] == 'r' {
+ if s[3] == 'o' && s[4] == 'm' && s[5] == ' ' {
+ addMatch(id+37*n, l+6, l, matches)
+ }
+ }
+ } else if s[1] == 'o' {
+ if s[2] == 'f' {
+ if s[3] == ' ' {
+ addMatch(id+8*n, l+4, l, matches)
+ }
+ } else if s[2] == 'n' {
+ if s[3] == ' ' {
+ addMatch(id+45*n, l+4, l, matches)
+ }
+ }
+ } else if s[1] == 'n' {
+ if s[2] == 'o' && s[3] == 't' && s[4] == ' ' {
+ addMatch(id+80*n, l+5, l, matches)
+ }
+ } else if s[1] == 't' {
+ if s[2] == 'h' {
+ if s[3] == 'e' {
+ if s[4] == ' ' {
+ addMatch(id+5*n, l+5, l, matches)
+ }
+ } else if s[3] == 'a' {
+ if s[4] == 't' && s[5] == ' ' {
+ addMatch(id+29*n, l+6, l, matches)
+ }
+ }
+ } else if s[2] == 'o' {
+ if s[3] == ' ' {
+ addMatch(id+17*n, l+4, l, matches)
+ }
+ }
+ } else if s[1] == 'w' {
+ if s[2] == 'i' && s[3] == 't' && s[4] == 'h' && s[5] == ' ' {
+ addMatch(id+35*n, l+6, l, matches)
+ }
+ }
+ } else if s[0] == '"' {
+ addMatch(id+19*n, l+1, l, matches)
+ if s[1] == '>' {
+ addMatch(id+21*n, l+2, l, matches)
+ }
+ } else if s[0] == '.' {
+ addMatch(id+20*n, l+1, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+31*n, l+2, l, matches)
+ if s[2] == 'T' && s[3] == 'h' {
+ if s[4] == 'e' {
+ if s[5] == ' ' {
+ addMatch(id+43*n, l+6, l, matches)
+ }
+ } else if s[4] == 'i' {
+ if s[5] == 's' && s[6] == ' ' {
+ addMatch(id+75*n, l+7, l, matches)
+ }
+ }
+ }
+ }
+ } else if s[0] == ',' {
+ addMatch(id+76*n, l+1, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+14*n, l+2, l, matches)
+ }
+ } else if s[0] == '\n' {
+ addMatch(id+22*n, l+1, l, matches)
+ if s[1] == '\t' {
+ addMatch(id+50*n, l+2, l, matches)
+ }
+ } else if s[0] == ']' {
+ addMatch(id+24*n, l+1, l, matches)
+ } else if s[0] == '\'' {
+ addMatch(id+36*n, l+1, l, matches)
+ } else if s[0] == ':' {
+ addMatch(id+51*n, l+1, l, matches)
+ } else if s[0] == '(' {
+ addMatch(id+57*n, l+1, l, matches)
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ addMatch(id+70*n, l+2, l, matches)
+ } else if s[1] == '\'' {
+ addMatch(id+86*n, l+2, l, matches)
+ }
+ } else if s[0] == 'a' {
+ if s[1] == 'l' && s[2] == ' ' {
+ addMatch(id+84*n, l+3, l, matches)
+ }
+ } else if s[0] == 'e' {
+ if s[1] == 'd' {
+ if s[2] == ' ' {
+ addMatch(id+53*n, l+3, l, matches)
+ }
+ } else if s[1] == 'r' {
+ if s[2] == ' ' {
+ addMatch(id+82*n, l+3, l, matches)
+ }
+ } else if s[1] == 's' {
+ if s[2] == 't' && s[3] == ' ' {
+ addMatch(id+95*n, l+4, l, matches)
+ }
+ }
+ } else if s[0] == 'f' {
+ if s[1] == 'u' && s[2] == 'l' && s[3] == ' ' {
+ addMatch(id+90*n, l+4, l, matches)
+ }
+ } else if s[0] == 'i' {
+ if s[1] == 'v' {
+ if s[2] == 'e' && s[3] == ' ' {
+ addMatch(id+92*n, l+4, l, matches)
+ }
+ } else if s[1] == 'z' {
+ if s[2] == 'e' && s[3] == ' ' {
+ addMatch(id+100*n, l+4, l, matches)
+ }
+ }
+ } else if s[0] == 'l' {
+ if s[1] == 'e' {
+ if s[2] == 's' && s[3] == 's' && s[4] == ' ' {
+ addMatch(id+93*n, l+5, l, matches)
+ }
+ } else if s[1] == 'y' {
+ if s[2] == ' ' {
+ addMatch(id+61*n, l+3, l, matches)
+ }
+ }
+ } else if s[0] == 'o' {
+ if s[1] == 'u' && s[2] == 's' && s[3] == ' ' {
+ addMatch(id+106*n, l+4, l, matches)
+ }
+ }
+ } else {
+ var is_all_caps bool = (w.transform != transformUppercaseFirst)
+ /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
+ is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
+ transform. */
+
+ var s []byte
+ if !isMatch(dict.words, w, data, max_length) {
+ continue
+ }
+
+ /* Transform "" + kUppercase{First,All} + "" */
+ var tmp int
+ if is_all_caps {
+ tmp = 44
+ } else {
+ tmp = 9
+ }
+ addMatch(id+uint(tmp)*n, l, l, matches)
+
+ has_found_match = true
+ if l+1 >= max_length {
+ continue
+ }
+
+ /* Transforms "" + kUppercase{First,All} + */
+ s = data[l:]
+
+ if s[0] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 68
+ } else {
+ tmp = 4
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ } else if s[0] == '"' {
+ var tmp int
+ if is_all_caps {
+ tmp = 87
+ } else {
+ tmp = 66
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ if s[1] == '>' {
+ var tmp int
+ if is_all_caps {
+ tmp = 97
+ } else {
+ tmp = 69
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ } else if s[0] == '.' {
+ var tmp int
+ if is_all_caps {
+ tmp = 101
+ } else {
+ tmp = 79
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 114
+ } else {
+ tmp = 88
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ } else if s[0] == ',' {
+ var tmp int
+ if is_all_caps {
+ tmp = 112
+ } else {
+ tmp = 99
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 107
+ } else {
+ tmp = 58
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ } else if s[0] == '\'' {
+ var tmp int
+ if is_all_caps {
+ tmp = 94
+ } else {
+ tmp = 74
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ } else if s[0] == '(' {
+ var tmp int
+ if is_all_caps {
+ tmp = 113
+ } else {
+ tmp = 78
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ var tmp int
+ if is_all_caps {
+ tmp = 105
+ } else {
+ tmp = 104
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if s[1] == '\'' {
+ var tmp int
+ if is_all_caps {
+ tmp = 116
+ } else {
+ tmp = 108
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ }
+ }
+ }
+ }
+ }
+
+ /* Transforms with prefixes " " and "." */
+ if max_length >= 5 && (data[0] == ' ' || data[0] == '.') {
+ var is_space bool = (data[0] == ' ')
+ var offset uint = uint(dict.buckets[hash(data[1:])])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 {
+ var s []byte
+ if !isMatch(dict.words, w, data[1:], max_length-1) {
+ continue
+ }
+
+ /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + "" and
+ "." + BROTLI_TRANSFORM_IDENTITY + "" */
+ var tmp int
+ if is_space {
+ tmp = 6
+ } else {
+ tmp = 32
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+
+ has_found_match = true
+ if l+2 >= max_length {
+ continue
+ }
+
+ /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + and
+ "." + BROTLI_TRANSFORM_IDENTITY +
+ */
+ s = data[l+1:]
+
+ if s[0] == ' ' {
+ var tmp int
+ if is_space {
+ tmp = 2
+ } else {
+ tmp = 77
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if s[0] == '(' {
+ var tmp int
+ if is_space {
+ tmp = 89
+ } else {
+ tmp = 67
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if is_space {
+ if s[0] == ',' {
+ addMatch(id+103*n, l+2, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+33*n, l+3, l, matches)
+ }
+ } else if s[0] == '.' {
+ addMatch(id+71*n, l+2, l, matches)
+ if s[1] == ' ' {
+ addMatch(id+52*n, l+3, l, matches)
+ }
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ addMatch(id+81*n, l+3, l, matches)
+ } else if s[1] == '\'' {
+ addMatch(id+98*n, l+3, l, matches)
+ }
+ }
+ }
+ } else if is_space {
+ var is_all_caps bool = (w.transform != transformUppercaseFirst)
+ /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
+ is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
+ transform. */
+
+ var s []byte
+ if !isMatch(dict.words, w, data[1:], max_length-1) {
+ continue
+ }
+
+ /* Transforms " " + kUppercase{First,All} + "" */
+ var tmp int
+ if is_all_caps {
+ tmp = 85
+ } else {
+ tmp = 30
+ }
+ addMatch(id+uint(tmp)*n, l+1, l, matches)
+
+ has_found_match = true
+ if l+2 >= max_length {
+ continue
+ }
+
+ /* Transforms " " + kUppercase{First,All} + */
+ s = data[l+1:]
+
+ if s[0] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 83
+ } else {
+ tmp = 15
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ } else if s[0] == ',' {
+ if !is_all_caps {
+ addMatch(id+109*n, l+2, l, matches)
+ }
+
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 111
+ } else {
+ tmp = 65
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ }
+ } else if s[0] == '.' {
+ var tmp int
+ if is_all_caps {
+ tmp = 115
+ } else {
+ tmp = 96
+ }
+ addMatch(id+uint(tmp)*n, l+2, l, matches)
+ if s[1] == ' ' {
+ var tmp int
+ if is_all_caps {
+ tmp = 117
+ } else {
+ tmp = 91
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ }
+ } else if s[0] == '=' {
+ if s[1] == '"' {
+ var tmp int
+ if is_all_caps {
+ tmp = 110
+ } else {
+ tmp = 118
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ } else if s[1] == '\'' {
+ var tmp int
+ if is_all_caps {
+ tmp = 119
+ } else {
+ tmp = 120
+ }
+ addMatch(id+uint(tmp)*n, l+3, l, matches)
+ }
+ }
+ }
+ }
+ }
+
+ if max_length >= 6 {
+ /* Transforms with prefixes "e ", "s ", ", " and "\xC2\xA0" */
+ if (data[1] == ' ' && (data[0] == 'e' || data[0] == 's' || data[0] == ',')) || (data[0] == 0xC2 && data[1] == 0xA0) {
+ var offset uint = uint(dict.buckets[hash(data[2:])])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 && isMatch(dict.words, w, data[2:], max_length-2) {
+ if data[0] == 0xC2 {
+ addMatch(id+102*n, l+2, l, matches)
+ has_found_match = true
+ } else if l+2 < max_length && data[l+2] == ' ' {
+ var t uint = 13
+ if data[0] == 'e' {
+ t = 18
+ } else if data[0] == 's' {
+ t = 7
+ }
+ addMatch(id+t*n, l+3, l, matches)
+ has_found_match = true
+ }
+ }
+ }
+ }
+ }
+
+ if max_length >= 9 {
+ /* Transforms with prefixes " the " and ".com/" */
+ if (data[0] == ' ' && data[1] == 't' && data[2] == 'h' && data[3] == 'e' && data[4] == ' ') || (data[0] == '.' && data[1] == 'c' && data[2] == 'o' && data[3] == 'm' && data[4] == '/') {
+ var offset uint = uint(dict.buckets[hash(data[5:])])
+ var end bool = offset == 0
+ for !end {
+ w := dict.dict_words[offset]
+ offset++
+ var l uint = uint(w.len) & 0x1F
+ var n uint = uint(1) << dict.words.size_bits_by_length[l]
+ var id uint = uint(w.idx)
+ end = !(w.len&0x80 == 0)
+ w.len = byte(l)
+ if w.transform == 0 && isMatch(dict.words, w, data[5:], max_length-5) {
+ var tmp int
+ if data[0] == ' ' {
+ tmp = 41
+ } else {
+ tmp = 72
+ }
+ addMatch(id+uint(tmp)*n, l+5, l, matches)
+ has_found_match = true
+ if l+5 < max_length {
+ var s []byte = data[l+5:]
+ if data[0] == ' ' {
+ if l+8 < max_length && s[0] == ' ' && s[1] == 'o' && s[2] == 'f' && s[3] == ' ' {
+ addMatch(id+62*n, l+9, l, matches)
+ if l+12 < max_length && s[4] == 't' && s[5] == 'h' && s[6] == 'e' && s[7] == ' ' {
+ addMatch(id+73*n, l+13, l, matches)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return has_found_match
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/static_dict_lut.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/static_dict_lut.go
new file mode 100644
index 000000000000..b33963e967a3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/static_dict_lut.go
@@ -0,0 +1,75094 @@
+package brotli
+
+/* Copyright 2017 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Lookup table for static dictionary and transforms. */
+
+type dictWord struct {
+ len byte
+ transform byte
+ idx uint16
+}
+
+const kDictNumBits int = 15
+
+const kDictHashMul32 uint32 = 0x1E35A7BD
+
+var kStaticDictionaryBuckets = [32768]uint16{
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3,
+ 6,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20,
+ 0,
+ 0,
+ 0,
+ 21,
+ 0,
+ 22,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23,
+ 0,
+ 0,
+ 25,
+ 0,
+ 29,
+ 0,
+ 53,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 55,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 61,
+ 76,
+ 0,
+ 0,
+ 0,
+ 94,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 96,
+ 0,
+ 97,
+ 0,
+ 98,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 99,
+ 101,
+ 106,
+ 108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 110,
+ 0,
+ 111,
+ 112,
+ 0,
+ 113,
+ 118,
+ 124,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 125,
+ 128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 129,
+ 0,
+ 0,
+ 131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 132,
+ 0,
+ 0,
+ 135,
+ 0,
+ 0,
+ 0,
+ 137,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 138,
+ 139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 142,
+ 143,
+ 144,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 145,
+ 0,
+ 0,
+ 0,
+ 146,
+ 149,
+ 151,
+ 152,
+ 0,
+ 0,
+ 153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 154,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 155,
+ 0,
+ 0,
+ 0,
+ 0,
+ 160,
+ 182,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 183,
+ 0,
+ 0,
+ 0,
+ 188,
+ 189,
+ 0,
+ 0,
+ 192,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 197,
+ 202,
+ 209,
+ 0,
+ 0,
+ 210,
+ 0,
+ 224,
+ 0,
+ 0,
+ 0,
+ 225,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 231,
+ 0,
+ 0,
+ 0,
+ 232,
+ 0,
+ 240,
+ 0,
+ 0,
+ 242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 244,
+ 0,
+ 0,
+ 0,
+ 246,
+ 0,
+ 0,
+ 249,
+ 251,
+ 253,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 258,
+ 0,
+ 0,
+ 261,
+ 263,
+ 0,
+ 0,
+ 0,
+ 267,
+ 0,
+ 0,
+ 268,
+ 0,
+ 269,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 271,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 272,
+ 0,
+ 273,
+ 0,
+ 277,
+ 0,
+ 278,
+ 286,
+ 0,
+ 0,
+ 0,
+ 0,
+ 287,
+ 0,
+ 289,
+ 290,
+ 291,
+ 0,
+ 0,
+ 0,
+ 295,
+ 0,
+ 0,
+ 296,
+ 297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 298,
+ 0,
+ 0,
+ 0,
+ 299,
+ 0,
+ 0,
+ 305,
+ 0,
+ 324,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 327,
+ 0,
+ 328,
+ 329,
+ 0,
+ 0,
+ 0,
+ 0,
+ 336,
+ 0,
+ 0,
+ 340,
+ 0,
+ 341,
+ 342,
+ 343,
+ 0,
+ 0,
+ 346,
+ 0,
+ 348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 349,
+ 351,
+ 0,
+ 0,
+ 355,
+ 0,
+ 363,
+ 0,
+ 364,
+ 0,
+ 368,
+ 369,
+ 0,
+ 370,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 372,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 373,
+ 0,
+ 375,
+ 0,
+ 0,
+ 0,
+ 0,
+ 376,
+ 377,
+ 0,
+ 0,
+ 394,
+ 395,
+ 396,
+ 0,
+ 0,
+ 398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 400,
+ 0,
+ 0,
+ 408,
+ 0,
+ 0,
+ 0,
+ 0,
+ 420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 421,
+ 0,
+ 0,
+ 422,
+ 423,
+ 0,
+ 0,
+ 429,
+ 435,
+ 436,
+ 442,
+ 0,
+ 0,
+ 443,
+ 0,
+ 444,
+ 445,
+ 453,
+ 456,
+ 0,
+ 457,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 458,
+ 0,
+ 0,
+ 0,
+ 459,
+ 0,
+ 0,
+ 0,
+ 460,
+ 0,
+ 462,
+ 463,
+ 465,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 466,
+ 469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 470,
+ 0,
+ 0,
+ 0,
+ 474,
+ 0,
+ 476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 483,
+ 0,
+ 485,
+ 0,
+ 0,
+ 0,
+ 486,
+ 0,
+ 0,
+ 488,
+ 491,
+ 492,
+ 0,
+ 0,
+ 497,
+ 499,
+ 500,
+ 0,
+ 501,
+ 0,
+ 0,
+ 0,
+ 505,
+ 0,
+ 0,
+ 506,
+ 0,
+ 0,
+ 0,
+ 507,
+ 0,
+ 0,
+ 0,
+ 509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 511,
+ 512,
+ 519,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 529,
+ 530,
+ 0,
+ 0,
+ 0,
+ 534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 543,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 557,
+ 560,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 561,
+ 0,
+ 564,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 565,
+ 566,
+ 0,
+ 575,
+ 0,
+ 619,
+ 0,
+ 620,
+ 0,
+ 0,
+ 623,
+ 624,
+ 0,
+ 0,
+ 0,
+ 625,
+ 0,
+ 0,
+ 626,
+ 627,
+ 0,
+ 0,
+ 628,
+ 0,
+ 0,
+ 0,
+ 0,
+ 630,
+ 0,
+ 631,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 643,
+ 656,
+ 668,
+ 0,
+ 0,
+ 0,
+ 673,
+ 0,
+ 0,
+ 0,
+ 674,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 682,
+ 0,
+ 687,
+ 0,
+ 690,
+ 0,
+ 693,
+ 699,
+ 700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 704,
+ 705,
+ 0,
+ 0,
+ 0,
+ 0,
+ 707,
+ 710,
+ 0,
+ 711,
+ 0,
+ 0,
+ 0,
+ 0,
+ 726,
+ 0,
+ 0,
+ 729,
+ 0,
+ 0,
+ 0,
+ 730,
+ 731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 752,
+ 0,
+ 0,
+ 0,
+ 762,
+ 0,
+ 763,
+ 0,
+ 0,
+ 767,
+ 0,
+ 0,
+ 0,
+ 770,
+ 774,
+ 0,
+ 0,
+ 775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 776,
+ 0,
+ 0,
+ 0,
+ 777,
+ 783,
+ 0,
+ 0,
+ 0,
+ 785,
+ 788,
+ 0,
+ 0,
+ 0,
+ 0,
+ 790,
+ 0,
+ 0,
+ 0,
+ 793,
+ 0,
+ 0,
+ 0,
+ 0,
+ 794,
+ 0,
+ 0,
+ 804,
+ 819,
+ 821,
+ 0,
+ 827,
+ 0,
+ 0,
+ 0,
+ 834,
+ 0,
+ 0,
+ 835,
+ 0,
+ 0,
+ 0,
+ 841,
+ 0,
+ 844,
+ 0,
+ 850,
+ 851,
+ 859,
+ 0,
+ 860,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 874,
+ 0,
+ 876,
+ 0,
+ 877,
+ 890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 893,
+ 894,
+ 898,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 899,
+ 0,
+ 0,
+ 0,
+ 900,
+ 904,
+ 906,
+ 0,
+ 0,
+ 0,
+ 907,
+ 0,
+ 908,
+ 909,
+ 0,
+ 910,
+ 0,
+ 0,
+ 0,
+ 0,
+ 911,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 916,
+ 0,
+ 0,
+ 0,
+ 922,
+ 925,
+ 0,
+ 930,
+ 0,
+ 934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 943,
+ 0,
+ 0,
+ 944,
+ 0,
+ 953,
+ 954,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 955,
+ 0,
+ 962,
+ 963,
+ 0,
+ 0,
+ 976,
+ 0,
+ 0,
+ 977,
+ 978,
+ 979,
+ 980,
+ 0,
+ 981,
+ 0,
+ 0,
+ 0,
+ 0,
+ 984,
+ 0,
+ 0,
+ 985,
+ 0,
+ 0,
+ 987,
+ 989,
+ 991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 992,
+ 0,
+ 0,
+ 0,
+ 993,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 996,
+ 0,
+ 0,
+ 0,
+ 1000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1002,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1005,
+ 1007,
+ 0,
+ 0,
+ 0,
+ 1009,
+ 0,
+ 0,
+ 0,
+ 1010,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1011,
+ 0,
+ 1012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1014,
+ 1016,
+ 0,
+ 0,
+ 0,
+ 1020,
+ 0,
+ 1021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1022,
+ 0,
+ 0,
+ 0,
+ 1024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1025,
+ 0,
+ 0,
+ 1026,
+ 1027,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1031,
+ 0,
+ 1033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1034,
+ 0,
+ 0,
+ 0,
+ 1037,
+ 1040,
+ 0,
+ 0,
+ 0,
+ 1042,
+ 1043,
+ 0,
+ 0,
+ 1053,
+ 0,
+ 1054,
+ 0,
+ 0,
+ 1057,
+ 0,
+ 0,
+ 0,
+ 1058,
+ 0,
+ 0,
+ 1060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1061,
+ 0,
+ 0,
+ 1062,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1065,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1066,
+ 1067,
+ 0,
+ 0,
+ 0,
+ 1069,
+ 1070,
+ 1072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1073,
+ 0,
+ 1075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1080,
+ 1084,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1094,
+ 0,
+ 1095,
+ 0,
+ 1107,
+ 0,
+ 0,
+ 0,
+ 1112,
+ 1114,
+ 0,
+ 1119,
+ 0,
+ 1122,
+ 0,
+ 0,
+ 1126,
+ 0,
+ 1129,
+ 0,
+ 1130,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1132,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1144,
+ 0,
+ 0,
+ 1145,
+ 1146,
+ 0,
+ 1148,
+ 1149,
+ 0,
+ 0,
+ 1150,
+ 1151,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1152,
+ 0,
+ 1153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1154,
+ 0,
+ 1163,
+ 0,
+ 0,
+ 0,
+ 1164,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1165,
+ 0,
+ 1167,
+ 0,
+ 1170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1171,
+ 1172,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1173,
+ 1175,
+ 1177,
+ 0,
+ 1186,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1195,
+ 0,
+ 0,
+ 1221,
+ 0,
+ 0,
+ 1224,
+ 0,
+ 0,
+ 1227,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1228,
+ 1229,
+ 0,
+ 0,
+ 1230,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1231,
+ 0,
+ 0,
+ 0,
+ 1233,
+ 0,
+ 0,
+ 1243,
+ 1244,
+ 1246,
+ 1248,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1254,
+ 1255,
+ 1258,
+ 1259,
+ 0,
+ 0,
+ 0,
+ 1260,
+ 0,
+ 0,
+ 1261,
+ 0,
+ 0,
+ 0,
+ 1262,
+ 1264,
+ 0,
+ 0,
+ 1265,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1266,
+ 0,
+ 1267,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1273,
+ 1274,
+ 1276,
+ 1289,
+ 0,
+ 0,
+ 1291,
+ 1292,
+ 1293,
+ 0,
+ 0,
+ 1294,
+ 1295,
+ 1296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1302,
+ 0,
+ 1304,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1311,
+ 1312,
+ 0,
+ 1314,
+ 0,
+ 1316,
+ 1320,
+ 1321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1322,
+ 1323,
+ 1324,
+ 0,
+ 1335,
+ 0,
+ 1336,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1341,
+ 1342,
+ 0,
+ 1346,
+ 0,
+ 1357,
+ 0,
+ 0,
+ 0,
+ 1358,
+ 1360,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1361,
+ 0,
+ 0,
+ 0,
+ 1362,
+ 1365,
+ 0,
+ 1366,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1379,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1386,
+ 0,
+ 1388,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1403,
+ 0,
+ 1405,
+ 0,
+ 0,
+ 1407,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1408,
+ 1409,
+ 0,
+ 1410,
+ 0,
+ 0,
+ 0,
+ 1412,
+ 1413,
+ 1416,
+ 0,
+ 0,
+ 1429,
+ 1451,
+ 0,
+ 0,
+ 1454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1455,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1459,
+ 1460,
+ 1461,
+ 1475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1477,
+ 0,
+ 1480,
+ 0,
+ 1481,
+ 0,
+ 0,
+ 1486,
+ 0,
+ 0,
+ 1495,
+ 0,
+ 0,
+ 0,
+ 1496,
+ 0,
+ 0,
+ 1498,
+ 1499,
+ 1501,
+ 1520,
+ 1521,
+ 0,
+ 0,
+ 0,
+ 1526,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1528,
+ 1529,
+ 0,
+ 1533,
+ 1536,
+ 0,
+ 0,
+ 0,
+ 1537,
+ 1538,
+ 1549,
+ 0,
+ 1550,
+ 1558,
+ 1559,
+ 1572,
+ 0,
+ 1573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1579,
+ 0,
+ 1599,
+ 0,
+ 1603,
+ 0,
+ 1604,
+ 0,
+ 1605,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1608,
+ 1610,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1611,
+ 0,
+ 1615,
+ 0,
+ 1616,
+ 1618,
+ 0,
+ 1619,
+ 0,
+ 0,
+ 1622,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1634,
+ 0,
+ 0,
+ 0,
+ 1635,
+ 0,
+ 0,
+ 0,
+ 1641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1643,
+ 0,
+ 0,
+ 0,
+ 1650,
+ 0,
+ 0,
+ 1652,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1653,
+ 0,
+ 0,
+ 0,
+ 1654,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1655,
+ 0,
+ 1662,
+ 0,
+ 0,
+ 1663,
+ 1664,
+ 0,
+ 0,
+ 1668,
+ 0,
+ 0,
+ 1669,
+ 1670,
+ 0,
+ 1672,
+ 1673,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1674,
+ 0,
+ 0,
+ 0,
+ 1675,
+ 1676,
+ 1680,
+ 0,
+ 1682,
+ 0,
+ 0,
+ 1687,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1704,
+ 0,
+ 0,
+ 1705,
+ 0,
+ 0,
+ 1721,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1734,
+ 1735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1737,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1739,
+ 0,
+ 0,
+ 1740,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1741,
+ 1743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1745,
+ 0,
+ 0,
+ 0,
+ 1749,
+ 0,
+ 0,
+ 0,
+ 1751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1765,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1784,
+ 0,
+ 1785,
+ 1787,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1788,
+ 1789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1790,
+ 1791,
+ 1793,
+ 0,
+ 1798,
+ 1799,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1801,
+ 0,
+ 1803,
+ 1805,
+ 0,
+ 0,
+ 0,
+ 1806,
+ 1811,
+ 0,
+ 1812,
+ 1814,
+ 0,
+ 1821,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1822,
+ 1833,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1848,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1857,
+ 0,
+ 0,
+ 0,
+ 1859,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1861,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1866,
+ 0,
+ 1921,
+ 1925,
+ 0,
+ 0,
+ 0,
+ 1929,
+ 1930,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1931,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1932,
+ 0,
+ 0,
+ 0,
+ 1934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1946,
+ 0,
+ 0,
+ 1948,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1950,
+ 0,
+ 1957,
+ 0,
+ 1958,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1965,
+ 1967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1968,
+ 0,
+ 1969,
+ 0,
+ 1971,
+ 1972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1973,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1975,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1976,
+ 1979,
+ 0,
+ 1982,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1984,
+ 1988,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1990,
+ 2004,
+ 2008,
+ 0,
+ 0,
+ 0,
+ 2012,
+ 2013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2015,
+ 0,
+ 2016,
+ 2017,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2021,
+ 0,
+ 0,
+ 2025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2029,
+ 2036,
+ 2040,
+ 0,
+ 2042,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2043,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2045,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2046,
+ 2047,
+ 0,
+ 2048,
+ 2049,
+ 0,
+ 2059,
+ 0,
+ 0,
+ 2063,
+ 0,
+ 2064,
+ 2065,
+ 0,
+ 0,
+ 2066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2069,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2070,
+ 0,
+ 2071,
+ 0,
+ 2072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2080,
+ 2082,
+ 2083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2085,
+ 0,
+ 2086,
+ 2088,
+ 2089,
+ 2105,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2107,
+ 0,
+ 0,
+ 2116,
+ 2117,
+ 0,
+ 2120,
+ 0,
+ 0,
+ 2122,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2123,
+ 0,
+ 0,
+ 2125,
+ 2127,
+ 2128,
+ 0,
+ 0,
+ 0,
+ 2130,
+ 0,
+ 0,
+ 0,
+ 2137,
+ 2139,
+ 2140,
+ 2141,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2144,
+ 2145,
+ 0,
+ 0,
+ 2146,
+ 2149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2150,
+ 0,
+ 0,
+ 2151,
+ 2158,
+ 0,
+ 2159,
+ 0,
+ 2160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2161,
+ 2162,
+ 0,
+ 0,
+ 2194,
+ 2202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2205,
+ 2217,
+ 0,
+ 2220,
+ 0,
+ 2221,
+ 0,
+ 2222,
+ 2224,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2237,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2238,
+ 0,
+ 2239,
+ 2241,
+ 0,
+ 0,
+ 2242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2243,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2252,
+ 0,
+ 0,
+ 2253,
+ 0,
+ 0,
+ 0,
+ 2257,
+ 2258,
+ 0,
+ 0,
+ 0,
+ 2260,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2262,
+ 0,
+ 2264,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2269,
+ 2270,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2271,
+ 0,
+ 2273,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2278,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2279,
+ 0,
+ 2280,
+ 0,
+ 2283,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2287,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2289,
+ 2290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2291,
+ 0,
+ 2292,
+ 0,
+ 0,
+ 0,
+ 2293,
+ 2295,
+ 2296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2303,
+ 0,
+ 2305,
+ 0,
+ 0,
+ 2306,
+ 0,
+ 2307,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2313,
+ 2314,
+ 2315,
+ 2316,
+ 0,
+ 0,
+ 2318,
+ 0,
+ 2319,
+ 0,
+ 2322,
+ 0,
+ 0,
+ 2323,
+ 0,
+ 2324,
+ 0,
+ 2326,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2335,
+ 0,
+ 2336,
+ 2338,
+ 2339,
+ 0,
+ 2340,
+ 0,
+ 0,
+ 0,
+ 2355,
+ 0,
+ 2375,
+ 0,
+ 2382,
+ 2386,
+ 0,
+ 2387,
+ 0,
+ 0,
+ 2394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2395,
+ 0,
+ 2397,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2399,
+ 2402,
+ 2404,
+ 2408,
+ 2411,
+ 0,
+ 0,
+ 0,
+ 2413,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2415,
+ 0,
+ 0,
+ 2416,
+ 2417,
+ 2419,
+ 0,
+ 2420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2425,
+ 0,
+ 0,
+ 0,
+ 2426,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2427,
+ 2428,
+ 0,
+ 2429,
+ 0,
+ 0,
+ 2430,
+ 2434,
+ 0,
+ 2436,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2441,
+ 2442,
+ 0,
+ 2445,
+ 0,
+ 0,
+ 2446,
+ 2457,
+ 0,
+ 2459,
+ 0,
+ 0,
+ 2462,
+ 0,
+ 2464,
+ 0,
+ 2477,
+ 0,
+ 2478,
+ 2486,
+ 0,
+ 0,
+ 0,
+ 2491,
+ 0,
+ 0,
+ 2493,
+ 0,
+ 0,
+ 2494,
+ 0,
+ 2495,
+ 0,
+ 2513,
+ 2523,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2524,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2528,
+ 2529,
+ 2530,
+ 0,
+ 0,
+ 2531,
+ 0,
+ 2533,
+ 0,
+ 0,
+ 2534,
+ 2535,
+ 0,
+ 2536,
+ 2537,
+ 0,
+ 2538,
+ 0,
+ 2539,
+ 2540,
+ 0,
+ 0,
+ 0,
+ 2545,
+ 2546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2548,
+ 0,
+ 0,
+ 2549,
+ 0,
+ 2550,
+ 2555,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2557,
+ 0,
+ 2560,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2561,
+ 0,
+ 2576,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2577,
+ 2578,
+ 0,
+ 0,
+ 0,
+ 2579,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2580,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2581,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2583,
+ 0,
+ 2584,
+ 0,
+ 2588,
+ 2590,
+ 0,
+ 0,
+ 0,
+ 2591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2593,
+ 2594,
+ 0,
+ 2595,
+ 0,
+ 2601,
+ 2602,
+ 0,
+ 0,
+ 2603,
+ 0,
+ 2605,
+ 0,
+ 0,
+ 0,
+ 2606,
+ 2607,
+ 2611,
+ 0,
+ 2615,
+ 0,
+ 0,
+ 0,
+ 2617,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2619,
+ 0,
+ 0,
+ 2620,
+ 0,
+ 0,
+ 0,
+ 2621,
+ 0,
+ 2623,
+ 0,
+ 2625,
+ 0,
+ 0,
+ 2628,
+ 2629,
+ 0,
+ 0,
+ 2635,
+ 2636,
+ 2637,
+ 0,
+ 0,
+ 2639,
+ 0,
+ 0,
+ 0,
+ 2642,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2643,
+ 0,
+ 2644,
+ 0,
+ 2649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2655,
+ 2656,
+ 0,
+ 0,
+ 2657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2658,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2659,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2664,
+ 2685,
+ 0,
+ 2687,
+ 0,
+ 2688,
+ 0,
+ 0,
+ 2689,
+ 0,
+ 0,
+ 2694,
+ 0,
+ 2695,
+ 0,
+ 0,
+ 2698,
+ 0,
+ 2701,
+ 2706,
+ 0,
+ 0,
+ 0,
+ 2707,
+ 0,
+ 2709,
+ 2710,
+ 2711,
+ 0,
+ 0,
+ 0,
+ 2720,
+ 2730,
+ 2735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2738,
+ 2740,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2747,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2748,
+ 0,
+ 0,
+ 2749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2750,
+ 0,
+ 0,
+ 2752,
+ 2754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2758,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2762,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2764,
+ 2767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2768,
+ 0,
+ 0,
+ 2770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2773,
+ 2776,
+ 0,
+ 0,
+ 2783,
+ 0,
+ 0,
+ 2784,
+ 0,
+ 2789,
+ 0,
+ 2790,
+ 0,
+ 0,
+ 0,
+ 2792,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2793,
+ 2795,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2796,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2797,
+ 2799,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2803,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2806,
+ 0,
+ 2807,
+ 2808,
+ 2817,
+ 2819,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2821,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2822,
+ 2823,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2824,
+ 0,
+ 0,
+ 2828,
+ 0,
+ 2834,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2836,
+ 0,
+ 2838,
+ 0,
+ 0,
+ 2839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2841,
+ 0,
+ 0,
+ 0,
+ 2842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2843,
+ 2844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2846,
+ 0,
+ 0,
+ 2847,
+ 0,
+ 2849,
+ 0,
+ 2853,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2857,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2858,
+ 0,
+ 2859,
+ 0,
+ 0,
+ 2860,
+ 0,
+ 2862,
+ 2868,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2875,
+ 0,
+ 2876,
+ 0,
+ 0,
+ 2877,
+ 2878,
+ 2884,
+ 2889,
+ 2890,
+ 0,
+ 0,
+ 2891,
+ 0,
+ 0,
+ 2892,
+ 0,
+ 0,
+ 0,
+ 2906,
+ 2912,
+ 0,
+ 2913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2916,
+ 0,
+ 2934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2935,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2939,
+ 0,
+ 2940,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2941,
+ 0,
+ 0,
+ 0,
+ 2946,
+ 0,
+ 2949,
+ 0,
+ 0,
+ 2950,
+ 2954,
+ 2955,
+ 0,
+ 0,
+ 0,
+ 2959,
+ 2961,
+ 0,
+ 0,
+ 2962,
+ 0,
+ 2963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2964,
+ 2965,
+ 2966,
+ 2967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2969,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2970,
+ 2975,
+ 0,
+ 2982,
+ 2983,
+ 2984,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2989,
+ 0,
+ 0,
+ 2990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2998,
+ 0,
+ 3000,
+ 3001,
+ 0,
+ 0,
+ 3002,
+ 0,
+ 0,
+ 0,
+ 3003,
+ 0,
+ 0,
+ 3012,
+ 0,
+ 0,
+ 3022,
+ 0,
+ 0,
+ 3024,
+ 0,
+ 0,
+ 3025,
+ 3027,
+ 0,
+ 0,
+ 0,
+ 3030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3034,
+ 3035,
+ 0,
+ 0,
+ 3036,
+ 0,
+ 3039,
+ 0,
+ 3049,
+ 0,
+ 0,
+ 3050,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3051,
+ 0,
+ 3053,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3057,
+ 0,
+ 3058,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3063,
+ 0,
+ 0,
+ 3073,
+ 3074,
+ 3078,
+ 3079,
+ 0,
+ 3080,
+ 3086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3087,
+ 0,
+ 3092,
+ 0,
+ 3095,
+ 0,
+ 3099,
+ 0,
+ 0,
+ 0,
+ 3100,
+ 0,
+ 3101,
+ 3102,
+ 0,
+ 3122,
+ 0,
+ 0,
+ 0,
+ 3124,
+ 0,
+ 3125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3132,
+ 3134,
+ 0,
+ 0,
+ 3136,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3147,
+ 0,
+ 0,
+ 3149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3150,
+ 3151,
+ 3152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3158,
+ 0,
+ 0,
+ 3160,
+ 0,
+ 0,
+ 3161,
+ 0,
+ 0,
+ 3162,
+ 0,
+ 3163,
+ 3166,
+ 3168,
+ 0,
+ 0,
+ 3169,
+ 3170,
+ 0,
+ 0,
+ 3171,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3182,
+ 0,
+ 3184,
+ 0,
+ 0,
+ 3188,
+ 0,
+ 0,
+ 3194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3216,
+ 3217,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3219,
+ 0,
+ 0,
+ 3220,
+ 3222,
+ 0,
+ 3223,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3224,
+ 0,
+ 3225,
+ 3226,
+ 0,
+ 3228,
+ 3233,
+ 0,
+ 3239,
+ 3241,
+ 3242,
+ 0,
+ 0,
+ 3251,
+ 3252,
+ 3253,
+ 3255,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3260,
+ 0,
+ 0,
+ 3261,
+ 0,
+ 0,
+ 0,
+ 3267,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3271,
+ 0,
+ 0,
+ 0,
+ 3278,
+ 0,
+ 3282,
+ 0,
+ 0,
+ 0,
+ 3284,
+ 0,
+ 0,
+ 0,
+ 3285,
+ 3286,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3287,
+ 3292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3294,
+ 3296,
+ 0,
+ 0,
+ 3299,
+ 3300,
+ 3301,
+ 0,
+ 3302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3304,
+ 3306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3311,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3312,
+ 3314,
+ 3315,
+ 0,
+ 3318,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3319,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3322,
+ 0,
+ 0,
+ 3324,
+ 3325,
+ 0,
+ 0,
+ 3326,
+ 0,
+ 0,
+ 3328,
+ 3329,
+ 3331,
+ 0,
+ 0,
+ 3335,
+ 0,
+ 0,
+ 3337,
+ 0,
+ 3338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3343,
+ 3347,
+ 0,
+ 0,
+ 0,
+ 3348,
+ 0,
+ 0,
+ 3351,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3355,
+ 0,
+ 0,
+ 3365,
+ 3366,
+ 3367,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3368,
+ 3369,
+ 0,
+ 3370,
+ 0,
+ 0,
+ 3373,
+ 0,
+ 0,
+ 3376,
+ 0,
+ 0,
+ 3377,
+ 0,
+ 3379,
+ 3387,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3402,
+ 0,
+ 3403,
+ 3436,
+ 3437,
+ 3439,
+ 0,
+ 0,
+ 3441,
+ 0,
+ 0,
+ 0,
+ 3442,
+ 0,
+ 0,
+ 3449,
+ 0,
+ 0,
+ 0,
+ 3450,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3451,
+ 0,
+ 0,
+ 3452,
+ 0,
+ 3453,
+ 3456,
+ 0,
+ 3457,
+ 0,
+ 0,
+ 3458,
+ 0,
+ 3459,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3460,
+ 0,
+ 0,
+ 3469,
+ 3470,
+ 0,
+ 0,
+ 3475,
+ 0,
+ 0,
+ 0,
+ 3480,
+ 3487,
+ 3489,
+ 0,
+ 3490,
+ 0,
+ 0,
+ 3491,
+ 3499,
+ 0,
+ 3500,
+ 0,
+ 0,
+ 3501,
+ 0,
+ 0,
+ 0,
+ 3502,
+ 0,
+ 3514,
+ 0,
+ 0,
+ 0,
+ 3516,
+ 3517,
+ 0,
+ 0,
+ 0,
+ 3518,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3520,
+ 3521,
+ 3522,
+ 0,
+ 0,
+ 3526,
+ 3530,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3531,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3536,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3539,
+ 3541,
+ 0,
+ 0,
+ 3542,
+ 3544,
+ 0,
+ 3547,
+ 3548,
+ 0,
+ 0,
+ 3550,
+ 0,
+ 3553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3554,
+ 0,
+ 3555,
+ 0,
+ 3558,
+ 0,
+ 3559,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3563,
+ 0,
+ 3581,
+ 0,
+ 0,
+ 0,
+ 3599,
+ 0,
+ 0,
+ 0,
+ 3600,
+ 0,
+ 3601,
+ 0,
+ 3602,
+ 3603,
+ 0,
+ 0,
+ 3606,
+ 3608,
+ 0,
+ 3610,
+ 3611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3612,
+ 3616,
+ 3619,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3624,
+ 3628,
+ 0,
+ 3629,
+ 3634,
+ 3635,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3636,
+ 0,
+ 3637,
+ 0,
+ 0,
+ 3638,
+ 3651,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3652,
+ 3653,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3656,
+ 3657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3658,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3659,
+ 0,
+ 3661,
+ 3663,
+ 3664,
+ 0,
+ 3665,
+ 0,
+ 3692,
+ 0,
+ 0,
+ 0,
+ 3694,
+ 3696,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3698,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3700,
+ 0,
+ 0,
+ 3701,
+ 0,
+ 0,
+ 0,
+ 3708,
+ 3709,
+ 0,
+ 0,
+ 0,
+ 3711,
+ 3712,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3723,
+ 0,
+ 3724,
+ 3725,
+ 0,
+ 0,
+ 3726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3728,
+ 3729,
+ 0,
+ 3734,
+ 3735,
+ 3737,
+ 0,
+ 0,
+ 0,
+ 3743,
+ 0,
+ 3745,
+ 0,
+ 0,
+ 3746,
+ 0,
+ 0,
+ 3747,
+ 3748,
+ 0,
+ 3757,
+ 0,
+ 3759,
+ 3766,
+ 3767,
+ 0,
+ 3768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3769,
+ 0,
+ 0,
+ 3771,
+ 0,
+ 3774,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3776,
+ 0,
+ 3777,
+ 3786,
+ 0,
+ 3788,
+ 3789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3791,
+ 0,
+ 3811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3814,
+ 3815,
+ 3816,
+ 3820,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3821,
+ 0,
+ 0,
+ 3825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3835,
+ 0,
+ 0,
+ 3848,
+ 3849,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3850,
+ 3851,
+ 3853,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3859,
+ 0,
+ 3860,
+ 3862,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3863,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3873,
+ 0,
+ 3874,
+ 0,
+ 3875,
+ 3886,
+ 0,
+ 3887,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3892,
+ 3913,
+ 0,
+ 3914,
+ 0,
+ 0,
+ 0,
+ 3925,
+ 3931,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3934,
+ 3941,
+ 3942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3943,
+ 0,
+ 0,
+ 0,
+ 3944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3945,
+ 0,
+ 3947,
+ 0,
+ 0,
+ 0,
+ 3956,
+ 3957,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3958,
+ 0,
+ 3959,
+ 3965,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3966,
+ 0,
+ 0,
+ 0,
+ 3967,
+ 0,
+ 0,
+ 0,
+ 3968,
+ 3974,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3975,
+ 3977,
+ 3978,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3980,
+ 0,
+ 3985,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 3986,
+ 4011,
+ 0,
+ 0,
+ 4017,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4018,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4019,
+ 0,
+ 4023,
+ 0,
+ 0,
+ 0,
+ 4027,
+ 4028,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4031,
+ 4034,
+ 0,
+ 0,
+ 4035,
+ 4037,
+ 4039,
+ 4040,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4059,
+ 0,
+ 4060,
+ 4061,
+ 0,
+ 4062,
+ 4063,
+ 4066,
+ 0,
+ 0,
+ 4072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4091,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4094,
+ 4095,
+ 0,
+ 0,
+ 4096,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4098,
+ 4099,
+ 0,
+ 0,
+ 0,
+ 4101,
+ 0,
+ 4104,
+ 0,
+ 0,
+ 0,
+ 4105,
+ 4108,
+ 0,
+ 4113,
+ 0,
+ 0,
+ 4115,
+ 4116,
+ 0,
+ 4126,
+ 0,
+ 0,
+ 4127,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4128,
+ 4132,
+ 4133,
+ 0,
+ 4134,
+ 0,
+ 0,
+ 0,
+ 4137,
+ 0,
+ 0,
+ 4141,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4144,
+ 4146,
+ 4147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4148,
+ 0,
+ 0,
+ 4311,
+ 0,
+ 0,
+ 0,
+ 4314,
+ 4329,
+ 0,
+ 4331,
+ 4332,
+ 0,
+ 4333,
+ 0,
+ 4334,
+ 0,
+ 0,
+ 0,
+ 4335,
+ 0,
+ 4336,
+ 0,
+ 0,
+ 0,
+ 4337,
+ 0,
+ 0,
+ 0,
+ 4342,
+ 4345,
+ 4346,
+ 4350,
+ 0,
+ 4351,
+ 4352,
+ 0,
+ 4354,
+ 4355,
+ 0,
+ 0,
+ 4364,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4369,
+ 0,
+ 0,
+ 0,
+ 4373,
+ 0,
+ 4374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4378,
+ 0,
+ 0,
+ 0,
+ 4380,
+ 0,
+ 0,
+ 0,
+ 4381,
+ 4382,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4385,
+ 0,
+ 0,
+ 0,
+ 4386,
+ 0,
+ 0,
+ 0,
+ 4391,
+ 4398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4407,
+ 4409,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4410,
+ 0,
+ 0,
+ 4411,
+ 0,
+ 4414,
+ 4415,
+ 4418,
+ 0,
+ 4427,
+ 4428,
+ 4430,
+ 0,
+ 4431,
+ 0,
+ 4448,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4449,
+ 0,
+ 0,
+ 0,
+ 4451,
+ 4452,
+ 0,
+ 4453,
+ 4454,
+ 0,
+ 4456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4459,
+ 0,
+ 4463,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4466,
+ 0,
+ 4467,
+ 0,
+ 4469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4470,
+ 4471,
+ 0,
+ 4473,
+ 0,
+ 0,
+ 4475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4477,
+ 4478,
+ 0,
+ 0,
+ 0,
+ 4479,
+ 4481,
+ 0,
+ 4482,
+ 0,
+ 4484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4486,
+ 0,
+ 0,
+ 4488,
+ 0,
+ 0,
+ 4497,
+ 0,
+ 4508,
+ 0,
+ 0,
+ 4510,
+ 4511,
+ 0,
+ 4520,
+ 4523,
+ 0,
+ 4524,
+ 0,
+ 4525,
+ 0,
+ 4527,
+ 0,
+ 0,
+ 4528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4530,
+ 0,
+ 4531,
+ 0,
+ 0,
+ 4532,
+ 0,
+ 0,
+ 0,
+ 4533,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4535,
+ 0,
+ 0,
+ 0,
+ 4536,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4541,
+ 4543,
+ 4544,
+ 4545,
+ 4547,
+ 0,
+ 4548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4550,
+ 4551,
+ 0,
+ 4553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4562,
+ 0,
+ 0,
+ 4571,
+ 0,
+ 0,
+ 0,
+ 4574,
+ 0,
+ 0,
+ 0,
+ 4575,
+ 0,
+ 4576,
+ 0,
+ 4577,
+ 0,
+ 0,
+ 0,
+ 4581,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4582,
+ 0,
+ 0,
+ 4586,
+ 0,
+ 0,
+ 0,
+ 4588,
+ 0,
+ 0,
+ 4597,
+ 0,
+ 4598,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4616,
+ 4617,
+ 0,
+ 4618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4619,
+ 0,
+ 4620,
+ 0,
+ 0,
+ 4621,
+ 0,
+ 4624,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4657,
+ 0,
+ 4659,
+ 0,
+ 4667,
+ 0,
+ 0,
+ 0,
+ 4668,
+ 4670,
+ 0,
+ 4672,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4673,
+ 4676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4687,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4699,
+ 0,
+ 4701,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4702,
+ 0,
+ 0,
+ 4706,
+ 0,
+ 0,
+ 4713,
+ 0,
+ 0,
+ 0,
+ 4714,
+ 4715,
+ 4716,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4717,
+ 0,
+ 0,
+ 4720,
+ 0,
+ 4721,
+ 4729,
+ 4735,
+ 0,
+ 0,
+ 0,
+ 4737,
+ 0,
+ 0,
+ 0,
+ 4739,
+ 0,
+ 0,
+ 0,
+ 4740,
+ 0,
+ 0,
+ 0,
+ 4741,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4742,
+ 0,
+ 4745,
+ 4746,
+ 4747,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4748,
+ 0,
+ 0,
+ 0,
+ 4749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4751,
+ 4786,
+ 0,
+ 4787,
+ 0,
+ 4788,
+ 4796,
+ 0,
+ 0,
+ 4797,
+ 4798,
+ 0,
+ 4799,
+ 4806,
+ 4807,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4809,
+ 4810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4812,
+ 0,
+ 4813,
+ 0,
+ 0,
+ 4815,
+ 0,
+ 4821,
+ 4822,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4823,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4824,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4826,
+ 0,
+ 0,
+ 0,
+ 4828,
+ 0,
+ 4829,
+ 0,
+ 0,
+ 0,
+ 4843,
+ 0,
+ 0,
+ 4847,
+ 0,
+ 4853,
+ 4855,
+ 4858,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4859,
+ 0,
+ 4864,
+ 0,
+ 0,
+ 4879,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4880,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4881,
+ 0,
+ 4882,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4884,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4886,
+ 4887,
+ 4888,
+ 4894,
+ 4896,
+ 0,
+ 4902,
+ 0,
+ 0,
+ 4905,
+ 0,
+ 0,
+ 4915,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4916,
+ 4917,
+ 4919,
+ 4921,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4926,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4927,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 4929,
+ 0,
+ 4930,
+ 4931,
+ 0,
+ 4938,
+ 0,
+ 4952,
+ 0,
+ 4953,
+ 4957,
+ 4960,
+ 4964,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5019,
+ 5020,
+ 5022,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5023,
+ 0,
+ 0,
+ 0,
+ 5024,
+ 0,
+ 0,
+ 0,
+ 5025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5028,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5029,
+ 5030,
+ 5031,
+ 0,
+ 5033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5034,
+ 5035,
+ 0,
+ 5036,
+ 0,
+ 0,
+ 5037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5038,
+ 0,
+ 0,
+ 5039,
+ 0,
+ 0,
+ 0,
+ 5041,
+ 5042,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5044,
+ 5049,
+ 5054,
+ 0,
+ 5055,
+ 0,
+ 5057,
+ 0,
+ 0,
+ 0,
+ 5060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5063,
+ 0,
+ 5064,
+ 5065,
+ 0,
+ 5067,
+ 0,
+ 0,
+ 0,
+ 5068,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5076,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5077,
+ 0,
+ 0,
+ 5078,
+ 5080,
+ 0,
+ 0,
+ 5083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5098,
+ 5099,
+ 5101,
+ 5105,
+ 5107,
+ 0,
+ 5108,
+ 0,
+ 5109,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5110,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5117,
+ 5118,
+ 0,
+ 5121,
+ 0,
+ 5122,
+ 0,
+ 0,
+ 5130,
+ 0,
+ 0,
+ 0,
+ 5137,
+ 0,
+ 0,
+ 0,
+ 5148,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5151,
+ 5154,
+ 0,
+ 0,
+ 0,
+ 5155,
+ 0,
+ 0,
+ 5156,
+ 5159,
+ 5161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5162,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5163,
+ 5164,
+ 0,
+ 5166,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5167,
+ 0,
+ 0,
+ 0,
+ 5172,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5178,
+ 5179,
+ 0,
+ 0,
+ 5190,
+ 0,
+ 0,
+ 5191,
+ 5192,
+ 5194,
+ 0,
+ 0,
+ 5198,
+ 5201,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5203,
+ 0,
+ 5206,
+ 5209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5213,
+ 0,
+ 5214,
+ 5216,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5217,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5218,
+ 5219,
+ 0,
+ 5231,
+ 0,
+ 0,
+ 5244,
+ 5249,
+ 0,
+ 5254,
+ 0,
+ 5255,
+ 0,
+ 0,
+ 5257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5258,
+ 0,
+ 5260,
+ 5270,
+ 0,
+ 5277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5280,
+ 5281,
+ 5282,
+ 5283,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5284,
+ 0,
+ 5285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5287,
+ 5288,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5289,
+ 5291,
+ 0,
+ 0,
+ 5294,
+ 0,
+ 0,
+ 5295,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5304,
+ 0,
+ 0,
+ 5306,
+ 5307,
+ 5308,
+ 0,
+ 5309,
+ 0,
+ 0,
+ 5310,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5311,
+ 5312,
+ 0,
+ 5313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5316,
+ 0,
+ 0,
+ 0,
+ 5317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5325,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5326,
+ 0,
+ 5327,
+ 5329,
+ 0,
+ 5332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5340,
+ 0,
+ 0,
+ 5341,
+ 0,
+ 0,
+ 0,
+ 5342,
+ 0,
+ 5343,
+ 5344,
+ 0,
+ 0,
+ 5345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5347,
+ 5348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5349,
+ 0,
+ 5350,
+ 0,
+ 5354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5358,
+ 0,
+ 0,
+ 5359,
+ 0,
+ 0,
+ 5361,
+ 0,
+ 0,
+ 5365,
+ 0,
+ 5367,
+ 0,
+ 5373,
+ 0,
+ 0,
+ 0,
+ 5379,
+ 0,
+ 0,
+ 0,
+ 5380,
+ 0,
+ 0,
+ 0,
+ 5382,
+ 0,
+ 5384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5385,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5387,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5388,
+ 5390,
+ 5393,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5396,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5397,
+ 5402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5403,
+ 0,
+ 0,
+ 0,
+ 5404,
+ 5405,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5406,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5410,
+ 0,
+ 0,
+ 5411,
+ 0,
+ 5415,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5416,
+ 5434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5438,
+ 0,
+ 5440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5441,
+ 5442,
+ 0,
+ 0,
+ 0,
+ 5443,
+ 5444,
+ 5447,
+ 0,
+ 0,
+ 5448,
+ 5449,
+ 5451,
+ 0,
+ 0,
+ 0,
+ 5456,
+ 5457,
+ 0,
+ 0,
+ 0,
+ 5459,
+ 0,
+ 0,
+ 0,
+ 5461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5464,
+ 0,
+ 5466,
+ 0,
+ 0,
+ 5467,
+ 0,
+ 5470,
+ 0,
+ 0,
+ 5473,
+ 0,
+ 0,
+ 5474,
+ 0,
+ 0,
+ 5476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5477,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5484,
+ 0,
+ 0,
+ 5485,
+ 5486,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5488,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5507,
+ 0,
+ 0,
+ 0,
+ 5510,
+ 0,
+ 5511,
+ 0,
+ 0,
+ 5512,
+ 0,
+ 0,
+ 0,
+ 5513,
+ 0,
+ 5515,
+ 0,
+ 0,
+ 5516,
+ 5517,
+ 0,
+ 5518,
+ 0,
+ 0,
+ 5522,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5534,
+ 5535,
+ 0,
+ 0,
+ 5536,
+ 0,
+ 5538,
+ 0,
+ 0,
+ 5543,
+ 0,
+ 5544,
+ 0,
+ 0,
+ 5545,
+ 0,
+ 5547,
+ 0,
+ 5557,
+ 0,
+ 0,
+ 5558,
+ 0,
+ 5560,
+ 5567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5568,
+ 0,
+ 0,
+ 0,
+ 5571,
+ 5573,
+ 0,
+ 5574,
+ 0,
+ 5575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5577,
+ 0,
+ 0,
+ 5598,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5600,
+ 5609,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5610,
+ 0,
+ 0,
+ 5612,
+ 0,
+ 5624,
+ 0,
+ 5625,
+ 0,
+ 0,
+ 0,
+ 5629,
+ 0,
+ 5641,
+ 0,
+ 5642,
+ 5643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5651,
+ 0,
+ 0,
+ 0,
+ 5652,
+ 5653,
+ 0,
+ 5661,
+ 5662,
+ 5678,
+ 0,
+ 5679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5685,
+ 5686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5690,
+ 5692,
+ 0,
+ 5703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5706,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5707,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5708,
+ 0,
+ 0,
+ 5709,
+ 0,
+ 5710,
+ 0,
+ 0,
+ 0,
+ 5712,
+ 0,
+ 5733,
+ 0,
+ 5734,
+ 5735,
+ 0,
+ 0,
+ 5744,
+ 5751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5752,
+ 0,
+ 5754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5757,
+ 5758,
+ 0,
+ 5760,
+ 5761,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5763,
+ 5764,
+ 5765,
+ 0,
+ 5766,
+ 0,
+ 5767,
+ 5768,
+ 0,
+ 5770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5776,
+ 5780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5782,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5784,
+ 0,
+ 0,
+ 5788,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5797,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5799,
+ 0,
+ 0,
+ 5801,
+ 0,
+ 0,
+ 0,
+ 5811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5816,
+ 0,
+ 0,
+ 5827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5830,
+ 5831,
+ 0,
+ 0,
+ 5832,
+ 0,
+ 0,
+ 5833,
+ 0,
+ 5835,
+ 5844,
+ 5845,
+ 0,
+ 5846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5850,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5852,
+ 0,
+ 5855,
+ 5857,
+ 0,
+ 0,
+ 5859,
+ 0,
+ 5861,
+ 0,
+ 0,
+ 5863,
+ 0,
+ 5865,
+ 0,
+ 0,
+ 0,
+ 5873,
+ 5875,
+ 0,
+ 0,
+ 0,
+ 5877,
+ 0,
+ 5879,
+ 0,
+ 0,
+ 0,
+ 5888,
+ 0,
+ 0,
+ 5889,
+ 5891,
+ 0,
+ 5894,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5895,
+ 0,
+ 5897,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5907,
+ 0,
+ 5911,
+ 0,
+ 0,
+ 5912,
+ 0,
+ 5913,
+ 5922,
+ 5924,
+ 0,
+ 5927,
+ 5928,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5929,
+ 5930,
+ 0,
+ 5933,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5949,
+ 0,
+ 0,
+ 5951,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5953,
+ 0,
+ 0,
+ 5954,
+ 0,
+ 5959,
+ 5960,
+ 5961,
+ 0,
+ 5964,
+ 0,
+ 0,
+ 0,
+ 5976,
+ 5978,
+ 5987,
+ 5990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 5991,
+ 0,
+ 5992,
+ 0,
+ 0,
+ 0,
+ 5994,
+ 5995,
+ 0,
+ 0,
+ 5996,
+ 0,
+ 0,
+ 6001,
+ 6003,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6007,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6008,
+ 0,
+ 0,
+ 6009,
+ 0,
+ 6010,
+ 0,
+ 0,
+ 0,
+ 6011,
+ 6015,
+ 0,
+ 6017,
+ 0,
+ 6019,
+ 0,
+ 6023,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6026,
+ 0,
+ 6030,
+ 0,
+ 0,
+ 6032,
+ 0,
+ 0,
+ 0,
+ 6033,
+ 6038,
+ 6040,
+ 0,
+ 0,
+ 0,
+ 6041,
+ 6045,
+ 0,
+ 0,
+ 6046,
+ 0,
+ 0,
+ 6053,
+ 0,
+ 0,
+ 6054,
+ 0,
+ 6055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6057,
+ 0,
+ 6063,
+ 0,
+ 0,
+ 0,
+ 6064,
+ 0,
+ 6066,
+ 6071,
+ 6072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6075,
+ 6076,
+ 0,
+ 0,
+ 6077,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6078,
+ 6079,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6080,
+ 0,
+ 6083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6084,
+ 0,
+ 0,
+ 6088,
+ 0,
+ 6089,
+ 0,
+ 0,
+ 6093,
+ 6105,
+ 0,
+ 0,
+ 6107,
+ 0,
+ 6110,
+ 0,
+ 0,
+ 0,
+ 6111,
+ 6125,
+ 6126,
+ 0,
+ 0,
+ 0,
+ 6129,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6130,
+ 0,
+ 0,
+ 0,
+ 6131,
+ 6134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6142,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6144,
+ 0,
+ 0,
+ 6146,
+ 6151,
+ 6153,
+ 0,
+ 6156,
+ 0,
+ 6163,
+ 0,
+ 6180,
+ 6181,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6182,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6184,
+ 6195,
+ 0,
+ 0,
+ 6206,
+ 0,
+ 6208,
+ 0,
+ 0,
+ 6212,
+ 6213,
+ 6214,
+ 0,
+ 6215,
+ 0,
+ 0,
+ 0,
+ 6228,
+ 0,
+ 0,
+ 0,
+ 6234,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6235,
+ 6240,
+ 0,
+ 6242,
+ 6243,
+ 6244,
+ 0,
+ 6250,
+ 6255,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6257,
+ 0,
+ 0,
+ 0,
+ 6258,
+ 6278,
+ 0,
+ 6284,
+ 0,
+ 0,
+ 0,
+ 6285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6286,
+ 0,
+ 0,
+ 0,
+ 6320,
+ 0,
+ 0,
+ 6322,
+ 6332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6334,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6335,
+ 0,
+ 0,
+ 6337,
+ 0,
+ 6338,
+ 0,
+ 6339,
+ 6340,
+ 0,
+ 0,
+ 6356,
+ 6357,
+ 6369,
+ 0,
+ 0,
+ 0,
+ 6370,
+ 6371,
+ 6372,
+ 0,
+ 6373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6376,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6382,
+ 6383,
+ 6384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6386,
+ 0,
+ 6389,
+ 6397,
+ 6400,
+ 6411,
+ 0,
+ 6414,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6415,
+ 6416,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6417,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6418,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6420,
+ 0,
+ 6421,
+ 6423,
+ 6425,
+ 0,
+ 6429,
+ 6430,
+ 0,
+ 6433,
+ 6438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6439,
+ 6440,
+ 0,
+ 0,
+ 6441,
+ 0,
+ 0,
+ 6444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6447,
+ 6448,
+ 0,
+ 0,
+ 6450,
+ 0,
+ 0,
+ 0,
+ 6454,
+ 0,
+ 0,
+ 6455,
+ 0,
+ 6461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6462,
+ 0,
+ 0,
+ 6463,
+ 0,
+ 6464,
+ 0,
+ 6465,
+ 6467,
+ 0,
+ 0,
+ 0,
+ 6468,
+ 0,
+ 6479,
+ 6480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6481,
+ 0,
+ 0,
+ 6485,
+ 6487,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6493,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6494,
+ 6495,
+ 6496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6498,
+ 0,
+ 0,
+ 0,
+ 6507,
+ 6508,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6511,
+ 6512,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6513,
+ 0,
+ 0,
+ 0,
+ 6514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6516,
+ 0,
+ 0,
+ 6517,
+ 6518,
+ 0,
+ 0,
+ 0,
+ 6519,
+ 6520,
+ 6521,
+ 0,
+ 6523,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6524,
+ 6528,
+ 0,
+ 6530,
+ 0,
+ 0,
+ 6532,
+ 0,
+ 6578,
+ 0,
+ 0,
+ 0,
+ 6583,
+ 0,
+ 6584,
+ 0,
+ 0,
+ 0,
+ 6587,
+ 0,
+ 0,
+ 0,
+ 6590,
+ 0,
+ 6591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6593,
+ 6594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6599,
+ 6600,
+ 0,
+ 0,
+ 6601,
+ 6602,
+ 6604,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6608,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6610,
+ 6611,
+ 0,
+ 6615,
+ 0,
+ 6616,
+ 6618,
+ 6620,
+ 0,
+ 6637,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6641,
+ 0,
+ 6642,
+ 0,
+ 0,
+ 0,
+ 6647,
+ 0,
+ 6660,
+ 6663,
+ 0,
+ 6664,
+ 0,
+ 6666,
+ 6669,
+ 0,
+ 6675,
+ 6676,
+ 6677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6678,
+ 0,
+ 0,
+ 0,
+ 6679,
+ 0,
+ 6680,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6693,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6704,
+ 6705,
+ 6706,
+ 0,
+ 0,
+ 6711,
+ 6713,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6716,
+ 0,
+ 0,
+ 0,
+ 6717,
+ 0,
+ 6719,
+ 6724,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6725,
+ 6726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6728,
+ 6729,
+ 6735,
+ 0,
+ 6737,
+ 6742,
+ 0,
+ 0,
+ 6743,
+ 6750,
+ 0,
+ 6751,
+ 0,
+ 0,
+ 6752,
+ 6753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6756,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6763,
+ 0,
+ 0,
+ 6764,
+ 6765,
+ 0,
+ 0,
+ 0,
+ 6770,
+ 0,
+ 0,
+ 0,
+ 6776,
+ 6780,
+ 0,
+ 6781,
+ 0,
+ 0,
+ 0,
+ 6783,
+ 0,
+ 6784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6785,
+ 0,
+ 0,
+ 0,
+ 6792,
+ 0,
+ 0,
+ 0,
+ 6793,
+ 0,
+ 0,
+ 6802,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6803,
+ 0,
+ 0,
+ 0,
+ 6804,
+ 0,
+ 0,
+ 0,
+ 6812,
+ 0,
+ 0,
+ 6823,
+ 0,
+ 6824,
+ 6839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6852,
+ 0,
+ 0,
+ 6854,
+ 0,
+ 6856,
+ 6857,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6867,
+ 0,
+ 6868,
+ 6870,
+ 6872,
+ 0,
+ 0,
+ 0,
+ 6873,
+ 6874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6875,
+ 0,
+ 0,
+ 6877,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6878,
+ 0,
+ 0,
+ 0,
+ 6879,
+ 0,
+ 6880,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6887,
+ 0,
+ 6888,
+ 6891,
+ 6893,
+ 0,
+ 6895,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6899,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6910,
+ 0,
+ 6911,
+ 0,
+ 0,
+ 6912,
+ 0,
+ 0,
+ 6913,
+ 6914,
+ 0,
+ 0,
+ 0,
+ 6915,
+ 0,
+ 0,
+ 0,
+ 6916,
+ 6919,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6924,
+ 0,
+ 6925,
+ 0,
+ 0,
+ 0,
+ 6926,
+ 6927,
+ 6928,
+ 0,
+ 6929,
+ 0,
+ 6930,
+ 0,
+ 0,
+ 6931,
+ 6935,
+ 0,
+ 6936,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6939,
+ 6940,
+ 6941,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6942,
+ 6948,
+ 6949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6952,
+ 6954,
+ 6963,
+ 6965,
+ 6966,
+ 0,
+ 0,
+ 6967,
+ 6968,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6969,
+ 0,
+ 0,
+ 6970,
+ 6979,
+ 0,
+ 0,
+ 6980,
+ 0,
+ 0,
+ 6983,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6984,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6988,
+ 6990,
+ 6992,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 6995,
+ 0,
+ 0,
+ 0,
+ 7012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7019,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7021,
+ 0,
+ 0,
+ 7022,
+ 7023,
+ 7028,
+ 0,
+ 7030,
+ 7033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7038,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7039,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7046,
+ 0,
+ 7047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7048,
+ 7052,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7054,
+ 0,
+ 7060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7061,
+ 0,
+ 7065,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7067,
+ 7069,
+ 0,
+ 7070,
+ 7071,
+ 7072,
+ 0,
+ 0,
+ 7078,
+ 0,
+ 7080,
+ 7081,
+ 0,
+ 7083,
+ 0,
+ 0,
+ 0,
+ 7084,
+ 7087,
+ 7088,
+ 0,
+ 0,
+ 7090,
+ 0,
+ 7093,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7107,
+ 0,
+ 0,
+ 7108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7110,
+ 0,
+ 7114,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7115,
+ 0,
+ 7116,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7117,
+ 0,
+ 0,
+ 7118,
+ 0,
+ 0,
+ 7124,
+ 0,
+ 7125,
+ 0,
+ 0,
+ 7126,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7129,
+ 0,
+ 7130,
+ 0,
+ 7132,
+ 7133,
+ 0,
+ 0,
+ 7134,
+ 0,
+ 0,
+ 7139,
+ 0,
+ 7148,
+ 7150,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7152,
+ 0,
+ 0,
+ 0,
+ 7153,
+ 7156,
+ 7157,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7158,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7163,
+ 7165,
+ 7169,
+ 0,
+ 7171,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7172,
+ 0,
+ 7173,
+ 7181,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7182,
+ 7185,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7187,
+ 0,
+ 7201,
+ 7204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7206,
+ 7207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7211,
+ 7216,
+ 0,
+ 7218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7226,
+ 7228,
+ 7230,
+ 7232,
+ 7233,
+ 7235,
+ 7237,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7238,
+ 7241,
+ 0,
+ 7242,
+ 0,
+ 0,
+ 7247,
+ 0,
+ 0,
+ 0,
+ 7266,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7289,
+ 0,
+ 0,
+ 7290,
+ 7291,
+ 0,
+ 0,
+ 7292,
+ 0,
+ 7297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7300,
+ 0,
+ 7301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7305,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7307,
+ 0,
+ 7308,
+ 0,
+ 7310,
+ 0,
+ 7335,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7337,
+ 0,
+ 7343,
+ 7347,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7348,
+ 0,
+ 7349,
+ 7350,
+ 7352,
+ 7354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7357,
+ 0,
+ 7358,
+ 7366,
+ 0,
+ 7367,
+ 7368,
+ 0,
+ 0,
+ 7373,
+ 0,
+ 0,
+ 0,
+ 7374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7376,
+ 0,
+ 0,
+ 0,
+ 7377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7378,
+ 0,
+ 7379,
+ 7380,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7383,
+ 0,
+ 0,
+ 7386,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7398,
+ 0,
+ 0,
+ 0,
+ 7399,
+ 7400,
+ 0,
+ 7401,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7405,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7406,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7421,
+ 7427,
+ 7429,
+ 0,
+ 0,
+ 0,
+ 7435,
+ 0,
+ 0,
+ 7436,
+ 0,
+ 0,
+ 0,
+ 7437,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7438,
+ 7443,
+ 0,
+ 7446,
+ 0,
+ 7448,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7457,
+ 0,
+ 0,
+ 7461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7462,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7463,
+ 7466,
+ 7472,
+ 0,
+ 7476,
+ 0,
+ 0,
+ 7490,
+ 0,
+ 7491,
+ 0,
+ 0,
+ 7493,
+ 0,
+ 0,
+ 0,
+ 7498,
+ 7499,
+ 0,
+ 0,
+ 7508,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7512,
+ 0,
+ 0,
+ 0,
+ 7513,
+ 7514,
+ 7516,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7518,
+ 0,
+ 0,
+ 7519,
+ 7521,
+ 7522,
+ 0,
+ 0,
+ 0,
+ 7526,
+ 0,
+ 0,
+ 7529,
+ 0,
+ 0,
+ 7531,
+ 0,
+ 7536,
+ 0,
+ 7538,
+ 0,
+ 7539,
+ 0,
+ 0,
+ 7541,
+ 7542,
+ 7546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7547,
+ 0,
+ 7548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7550,
+ 0,
+ 0,
+ 7552,
+ 7553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7554,
+ 7563,
+ 0,
+ 7573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7574,
+ 7576,
+ 0,
+ 7578,
+ 7581,
+ 7583,
+ 0,
+ 0,
+ 0,
+ 7584,
+ 0,
+ 7587,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7589,
+ 0,
+ 0,
+ 0,
+ 7594,
+ 0,
+ 0,
+ 7595,
+ 0,
+ 0,
+ 7600,
+ 7602,
+ 7610,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7612,
+ 0,
+ 7613,
+ 7614,
+ 0,
+ 0,
+ 7615,
+ 0,
+ 0,
+ 7616,
+ 0,
+ 7620,
+ 0,
+ 7621,
+ 7622,
+ 0,
+ 7623,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7626,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7627,
+ 7629,
+ 7631,
+ 0,
+ 0,
+ 7633,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7639,
+ 0,
+ 7640,
+ 7642,
+ 0,
+ 0,
+ 7643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7644,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7645,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7661,
+ 7662,
+ 7663,
+ 7665,
+ 0,
+ 7666,
+ 0,
+ 7667,
+ 0,
+ 7684,
+ 7688,
+ 7690,
+ 0,
+ 7691,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7692,
+ 0,
+ 0,
+ 7700,
+ 0,
+ 7707,
+ 0,
+ 7708,
+ 0,
+ 7709,
+ 0,
+ 7721,
+ 0,
+ 0,
+ 0,
+ 7722,
+ 0,
+ 7724,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7729,
+ 7731,
+ 0,
+ 7732,
+ 0,
+ 7733,
+ 7735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7739,
+ 0,
+ 0,
+ 7741,
+ 7745,
+ 0,
+ 7748,
+ 0,
+ 0,
+ 0,
+ 7751,
+ 0,
+ 0,
+ 0,
+ 7752,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7753,
+ 0,
+ 0,
+ 7756,
+ 0,
+ 7757,
+ 0,
+ 7759,
+ 0,
+ 7760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7761,
+ 7768,
+ 0,
+ 0,
+ 7769,
+ 0,
+ 0,
+ 7770,
+ 0,
+ 0,
+ 7771,
+ 0,
+ 0,
+ 7772,
+ 0,
+ 0,
+ 7773,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7778,
+ 7783,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7784,
+ 7785,
+ 0,
+ 7790,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7792,
+ 0,
+ 7798,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7799,
+ 0,
+ 7810,
+ 0,
+ 0,
+ 7813,
+ 0,
+ 7814,
+ 0,
+ 7816,
+ 0,
+ 7818,
+ 7824,
+ 7825,
+ 7826,
+ 0,
+ 7828,
+ 7830,
+ 0,
+ 0,
+ 0,
+ 7840,
+ 0,
+ 7842,
+ 0,
+ 7843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7856,
+ 7857,
+ 7858,
+ 7862,
+ 0,
+ 7865,
+ 0,
+ 0,
+ 7866,
+ 0,
+ 0,
+ 7913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7914,
+ 0,
+ 0,
+ 7915,
+ 7917,
+ 7918,
+ 7919,
+ 0,
+ 7920,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7921,
+ 7922,
+ 0,
+ 7924,
+ 0,
+ 0,
+ 7925,
+ 0,
+ 0,
+ 7927,
+ 0,
+ 7930,
+ 7935,
+ 0,
+ 0,
+ 7937,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7939,
+ 0,
+ 7940,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7941,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7950,
+ 0,
+ 7953,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7968,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7969,
+ 7972,
+ 7992,
+ 0,
+ 7993,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 7994,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8007,
+ 8008,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8010,
+ 0,
+ 0,
+ 0,
+ 8012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8018,
+ 0,
+ 8028,
+ 8029,
+ 0,
+ 0,
+ 8030,
+ 0,
+ 0,
+ 8032,
+ 8033,
+ 0,
+ 0,
+ 8034,
+ 8036,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8037,
+ 0,
+ 0,
+ 0,
+ 8043,
+ 8052,
+ 8059,
+ 8060,
+ 0,
+ 0,
+ 8061,
+ 0,
+ 0,
+ 0,
+ 8062,
+ 0,
+ 8063,
+ 0,
+ 8064,
+ 0,
+ 8066,
+ 8068,
+ 0,
+ 0,
+ 0,
+ 8080,
+ 8081,
+ 0,
+ 8089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8092,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8093,
+ 8110,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8111,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8112,
+ 8115,
+ 0,
+ 8117,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8120,
+ 8121,
+ 8122,
+ 8128,
+ 8129,
+ 8130,
+ 8131,
+ 0,
+ 0,
+ 8139,
+ 0,
+ 0,
+ 8144,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8145,
+ 8146,
+ 8153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8154,
+ 0,
+ 8157,
+ 8160,
+ 8162,
+ 0,
+ 8164,
+ 8165,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8166,
+ 8167,
+ 0,
+ 0,
+ 8179,
+ 0,
+ 0,
+ 0,
+ 8185,
+ 0,
+ 0,
+ 0,
+ 8186,
+ 0,
+ 0,
+ 8187,
+ 0,
+ 0,
+ 0,
+ 8188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8210,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8213,
+ 0,
+ 8214,
+ 0,
+ 0,
+ 8215,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8219,
+ 0,
+ 8221,
+ 0,
+ 0,
+ 8222,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8225,
+ 0,
+ 0,
+ 0,
+ 8233,
+ 0,
+ 0,
+ 8242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8247,
+ 0,
+ 8248,
+ 8252,
+ 0,
+ 8256,
+ 8257,
+ 0,
+ 0,
+ 8261,
+ 0,
+ 8264,
+ 8265,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8267,
+ 0,
+ 0,
+ 0,
+ 8269,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8270,
+ 0,
+ 0,
+ 0,
+ 8278,
+ 0,
+ 8279,
+ 8283,
+ 0,
+ 0,
+ 8285,
+ 8286,
+ 8289,
+ 8292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8293,
+ 8295,
+ 8299,
+ 8300,
+ 8301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8304,
+ 8307,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8321,
+ 0,
+ 0,
+ 0,
+ 8322,
+ 8323,
+ 8325,
+ 8326,
+ 8327,
+ 0,
+ 0,
+ 8332,
+ 8338,
+ 0,
+ 0,
+ 8340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8350,
+ 0,
+ 0,
+ 8351,
+ 0,
+ 8354,
+ 8355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8360,
+ 8372,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8380,
+ 0,
+ 0,
+ 0,
+ 8383,
+ 0,
+ 8384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8386,
+ 8392,
+ 0,
+ 0,
+ 8394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8396,
+ 8397,
+ 0,
+ 8398,
+ 0,
+ 8399,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8400,
+ 0,
+ 8401,
+ 8410,
+ 8411,
+ 0,
+ 8412,
+ 8413,
+ 8422,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8424,
+ 0,
+ 0,
+ 8425,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8441,
+ 8442,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8443,
+ 0,
+ 0,
+ 8444,
+ 0,
+ 8447,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8451,
+ 0,
+ 8458,
+ 0,
+ 8462,
+ 0,
+ 0,
+ 8468,
+ 0,
+ 8469,
+ 0,
+ 0,
+ 0,
+ 8470,
+ 0,
+ 8473,
+ 8479,
+ 8480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8481,
+ 8483,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8484,
+ 0,
+ 0,
+ 8490,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8491,
+ 8493,
+ 8494,
+ 0,
+ 8528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8530,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8534,
+ 8538,
+ 8540,
+ 0,
+ 0,
+ 8541,
+ 0,
+ 0,
+ 8545,
+ 0,
+ 8557,
+ 0,
+ 0,
+ 8569,
+ 8570,
+ 0,
+ 0,
+ 8571,
+ 8574,
+ 8575,
+ 8579,
+ 0,
+ 8583,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8606,
+ 0,
+ 8607,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8608,
+ 0,
+ 0,
+ 8609,
+ 0,
+ 0,
+ 0,
+ 8610,
+ 0,
+ 0,
+ 0,
+ 8611,
+ 0,
+ 0,
+ 8613,
+ 8617,
+ 8621,
+ 0,
+ 0,
+ 8622,
+ 0,
+ 8623,
+ 0,
+ 8624,
+ 8625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8637,
+ 8638,
+ 8639,
+ 8650,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8652,
+ 8654,
+ 8655,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8656,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8658,
+ 0,
+ 0,
+ 8659,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8660,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8661,
+ 8663,
+ 8664,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8665,
+ 0,
+ 8669,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8671,
+ 8674,
+ 0,
+ 8684,
+ 0,
+ 8686,
+ 0,
+ 0,
+ 0,
+ 8689,
+ 0,
+ 0,
+ 0,
+ 8690,
+ 0,
+ 8706,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8710,
+ 0,
+ 8711,
+ 8713,
+ 8714,
+ 8724,
+ 8727,
+ 8728,
+ 8733,
+ 8736,
+ 0,
+ 8737,
+ 8739,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8742,
+ 8743,
+ 8745,
+ 8754,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8756,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8757,
+ 8760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8762,
+ 8763,
+ 8764,
+ 0,
+ 8766,
+ 8769,
+ 8770,
+ 8773,
+ 0,
+ 8774,
+ 0,
+ 8779,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8780,
+ 0,
+ 0,
+ 8781,
+ 0,
+ 0,
+ 8783,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8785,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8786,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8788,
+ 8790,
+ 0,
+ 0,
+ 0,
+ 8803,
+ 0,
+ 8813,
+ 8814,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8815,
+ 8816,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8818,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8822,
+ 8828,
+ 8829,
+ 0,
+ 8831,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8833,
+ 0,
+ 0,
+ 0,
+ 8834,
+ 0,
+ 0,
+ 0,
+ 8835,
+ 0,
+ 8836,
+ 0,
+ 0,
+ 0,
+ 8837,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8838,
+ 8839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8840,
+ 0,
+ 0,
+ 0,
+ 8841,
+ 0,
+ 8842,
+ 0,
+ 0,
+ 0,
+ 8846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8847,
+ 0,
+ 8848,
+ 0,
+ 0,
+ 8864,
+ 0,
+ 0,
+ 8866,
+ 0,
+ 0,
+ 8870,
+ 8872,
+ 0,
+ 0,
+ 8873,
+ 8874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8875,
+ 0,
+ 8876,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8896,
+ 8900,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8904,
+ 0,
+ 8907,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8911,
+ 8912,
+ 8913,
+ 0,
+ 0,
+ 0,
+ 8914,
+ 0,
+ 8915,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8916,
+ 0,
+ 0,
+ 0,
+ 8929,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8930,
+ 0,
+ 8932,
+ 0,
+ 8943,
+ 0,
+ 0,
+ 0,
+ 8945,
+ 8947,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8949,
+ 0,
+ 8950,
+ 0,
+ 8954,
+ 8957,
+ 0,
+ 0,
+ 8970,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8971,
+ 0,
+ 8996,
+ 0,
+ 0,
+ 0,
+ 0,
+ 8997,
+ 9000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9001,
+ 9002,
+ 0,
+ 9004,
+ 9009,
+ 9024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9027,
+ 9082,
+ 0,
+ 0,
+ 9083,
+ 9089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9090,
+ 0,
+ 0,
+ 0,
+ 9092,
+ 0,
+ 0,
+ 9093,
+ 0,
+ 9095,
+ 0,
+ 0,
+ 9096,
+ 9097,
+ 9101,
+ 9102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9112,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9114,
+ 0,
+ 0,
+ 9120,
+ 0,
+ 9121,
+ 9122,
+ 0,
+ 0,
+ 0,
+ 9123,
+ 9124,
+ 0,
+ 0,
+ 9125,
+ 0,
+ 0,
+ 9126,
+ 0,
+ 9127,
+ 0,
+ 0,
+ 9129,
+ 9131,
+ 0,
+ 0,
+ 0,
+ 9132,
+ 0,
+ 0,
+ 9136,
+ 0,
+ 9144,
+ 0,
+ 0,
+ 9148,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9149,
+ 0,
+ 9152,
+ 9163,
+ 0,
+ 0,
+ 9165,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9166,
+ 0,
+ 9169,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9172,
+ 0,
+ 9174,
+ 9175,
+ 9176,
+ 0,
+ 9177,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9186,
+ 0,
+ 9187,
+ 0,
+ 0,
+ 0,
+ 9188,
+ 9189,
+ 0,
+ 0,
+ 9190,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9191,
+ 0,
+ 0,
+ 0,
+ 9193,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9197,
+ 9198,
+ 0,
+ 0,
+ 0,
+ 9208,
+ 9211,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9216,
+ 9217,
+ 0,
+ 9220,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9221,
+ 9222,
+ 9223,
+ 0,
+ 9224,
+ 9225,
+ 0,
+ 0,
+ 9227,
+ 0,
+ 9228,
+ 9229,
+ 0,
+ 0,
+ 9230,
+ 0,
+ 9232,
+ 0,
+ 9233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9234,
+ 9235,
+ 0,
+ 0,
+ 9237,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9238,
+ 9240,
+ 0,
+ 0,
+ 9241,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9244,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9247,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9248,
+ 0,
+ 0,
+ 0,
+ 9249,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9250,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9251,
+ 0,
+ 0,
+ 9252,
+ 9255,
+ 0,
+ 0,
+ 0,
+ 9256,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9257,
+ 0,
+ 0,
+ 9258,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9262,
+ 9263,
+ 0,
+ 0,
+ 9265,
+ 9266,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9268,
+ 9271,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9273,
+ 0,
+ 0,
+ 0,
+ 9276,
+ 9277,
+ 9279,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9280,
+ 0,
+ 0,
+ 9293,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9297,
+ 9301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9308,
+ 9309,
+ 9313,
+ 9321,
+ 9322,
+ 0,
+ 9326,
+ 9327,
+ 0,
+ 0,
+ 9477,
+ 0,
+ 9479,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9482,
+ 0,
+ 0,
+ 0,
+ 9483,
+ 0,
+ 9484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9485,
+ 0,
+ 0,
+ 9486,
+ 0,
+ 0,
+ 0,
+ 9489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9490,
+ 9491,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9493,
+ 0,
+ 9495,
+ 9496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9500,
+ 0,
+ 9502,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9504,
+ 9507,
+ 0,
+ 9509,
+ 0,
+ 9511,
+ 0,
+ 0,
+ 9513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9515,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9516,
+ 9517,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9532,
+ 0,
+ 0,
+ 9533,
+ 0,
+ 0,
+ 9538,
+ 0,
+ 9539,
+ 9540,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9541,
+ 0,
+ 0,
+ 0,
+ 9542,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9544,
+ 9545,
+ 0,
+ 9546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9547,
+ 9548,
+ 0,
+ 0,
+ 0,
+ 9550,
+ 0,
+ 9557,
+ 0,
+ 9558,
+ 0,
+ 9561,
+ 0,
+ 9563,
+ 9570,
+ 0,
+ 9572,
+ 9574,
+ 9575,
+ 0,
+ 0,
+ 0,
+ 9577,
+ 9592,
+ 0,
+ 0,
+ 9596,
+ 0,
+ 0,
+ 0,
+ 9598,
+ 0,
+ 9600,
+ 0,
+ 9601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9608,
+ 0,
+ 9638,
+ 9639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9641,
+ 0,
+ 0,
+ 9643,
+ 9644,
+ 9645,
+ 9646,
+ 0,
+ 0,
+ 0,
+ 9648,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9650,
+ 9654,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9655,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9656,
+ 0,
+ 9657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9658,
+ 0,
+ 0,
+ 9659,
+ 0,
+ 0,
+ 9664,
+ 0,
+ 0,
+ 9665,
+ 0,
+ 9667,
+ 9669,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9671,
+ 0,
+ 9673,
+ 9681,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9682,
+ 9683,
+ 9684,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9686,
+ 9698,
+ 0,
+ 0,
+ 9700,
+ 9701,
+ 9702,
+ 0,
+ 9703,
+ 9717,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9718,
+ 0,
+ 9726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9727,
+ 0,
+ 0,
+ 0,
+ 9728,
+ 0,
+ 9742,
+ 0,
+ 9744,
+ 0,
+ 0,
+ 0,
+ 9750,
+ 0,
+ 9754,
+ 9755,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9756,
+ 0,
+ 9757,
+ 9768,
+ 0,
+ 9769,
+ 0,
+ 0,
+ 0,
+ 9770,
+ 9771,
+ 0,
+ 9773,
+ 0,
+ 9774,
+ 0,
+ 9775,
+ 0,
+ 0,
+ 0,
+ 9776,
+ 9777,
+ 9784,
+ 0,
+ 0,
+ 0,
+ 9786,
+ 0,
+ 9789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9793,
+ 9794,
+ 0,
+ 0,
+ 0,
+ 9808,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9812,
+ 0,
+ 9820,
+ 0,
+ 9823,
+ 0,
+ 9828,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9830,
+ 0,
+ 0,
+ 9833,
+ 9836,
+ 0,
+ 0,
+ 0,
+ 9840,
+ 0,
+ 0,
+ 0,
+ 9841,
+ 0,
+ 0,
+ 9842,
+ 0,
+ 9845,
+ 0,
+ 0,
+ 0,
+ 9847,
+ 9848,
+ 0,
+ 0,
+ 9855,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9856,
+ 9863,
+ 9865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9866,
+ 9867,
+ 9868,
+ 9873,
+ 9875,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9880,
+ 0,
+ 9886,
+ 0,
+ 0,
+ 0,
+ 9887,
+ 0,
+ 0,
+ 9891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9906,
+ 9907,
+ 9908,
+ 0,
+ 0,
+ 0,
+ 9909,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9910,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9914,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9922,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9923,
+ 9925,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9930,
+ 0,
+ 0,
+ 0,
+ 9931,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9932,
+ 0,
+ 9939,
+ 0,
+ 0,
+ 9940,
+ 9962,
+ 9966,
+ 0,
+ 9969,
+ 9970,
+ 0,
+ 0,
+ 9974,
+ 0,
+ 9979,
+ 9981,
+ 9982,
+ 0,
+ 0,
+ 0,
+ 9985,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9987,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 9988,
+ 9993,
+ 0,
+ 0,
+ 9994,
+ 0,
+ 0,
+ 0,
+ 9997,
+ 0,
+ 10004,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10007,
+ 10019,
+ 10020,
+ 10022,
+ 0,
+ 0,
+ 0,
+ 10031,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10032,
+ 0,
+ 0,
+ 10034,
+ 0,
+ 10036,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10038,
+ 0,
+ 10039,
+ 10040,
+ 10041,
+ 10042,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10043,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10045,
+ 10054,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10055,
+ 0,
+ 0,
+ 10057,
+ 10058,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10059,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10063,
+ 0,
+ 10066,
+ 0,
+ 0,
+ 0,
+ 10070,
+ 0,
+ 10072,
+ 0,
+ 0,
+ 10076,
+ 10077,
+ 0,
+ 0,
+ 10084,
+ 0,
+ 10087,
+ 10090,
+ 10091,
+ 0,
+ 0,
+ 0,
+ 10094,
+ 10097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10103,
+ 0,
+ 10104,
+ 0,
+ 10108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10120,
+ 0,
+ 0,
+ 0,
+ 10122,
+ 0,
+ 0,
+ 10125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10127,
+ 10128,
+ 0,
+ 0,
+ 10134,
+ 0,
+ 10135,
+ 10136,
+ 0,
+ 10137,
+ 0,
+ 0,
+ 10147,
+ 0,
+ 10149,
+ 10150,
+ 0,
+ 0,
+ 10156,
+ 0,
+ 10158,
+ 10159,
+ 10160,
+ 10168,
+ 0,
+ 0,
+ 10171,
+ 0,
+ 10173,
+ 0,
+ 0,
+ 0,
+ 10176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10177,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10178,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10194,
+ 0,
+ 10202,
+ 0,
+ 0,
+ 10203,
+ 10204,
+ 0,
+ 10205,
+ 10206,
+ 0,
+ 10207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10213,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10217,
+ 0,
+ 10229,
+ 0,
+ 10230,
+ 10231,
+ 0,
+ 0,
+ 10232,
+ 0,
+ 0,
+ 10237,
+ 10238,
+ 10244,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10250,
+ 0,
+ 10252,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10255,
+ 0,
+ 0,
+ 10257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10258,
+ 0,
+ 10259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10260,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10284,
+ 10288,
+ 10289,
+ 0,
+ 0,
+ 0,
+ 10290,
+ 0,
+ 10296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10299,
+ 10303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10306,
+ 0,
+ 0,
+ 0,
+ 10307,
+ 0,
+ 10308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10311,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10315,
+ 10317,
+ 0,
+ 0,
+ 0,
+ 10318,
+ 10319,
+ 0,
+ 10321,
+ 0,
+ 10326,
+ 0,
+ 10328,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10329,
+ 0,
+ 0,
+ 10331,
+ 0,
+ 10332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10334,
+ 0,
+ 0,
+ 10335,
+ 10338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10339,
+ 10349,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10351,
+ 0,
+ 10353,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10362,
+ 0,
+ 10368,
+ 0,
+ 10369,
+ 0,
+ 0,
+ 0,
+ 10372,
+ 10373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10374,
+ 0,
+ 0,
+ 0,
+ 10375,
+ 0,
+ 10376,
+ 0,
+ 0,
+ 10386,
+ 10388,
+ 10390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10391,
+ 0,
+ 0,
+ 10392,
+ 10394,
+ 0,
+ 0,
+ 10396,
+ 0,
+ 10397,
+ 0,
+ 10403,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10404,
+ 0,
+ 10405,
+ 10410,
+ 0,
+ 0,
+ 10411,
+ 0,
+ 10412,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10421,
+ 10422,
+ 10423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10425,
+ 0,
+ 0,
+ 10427,
+ 0,
+ 0,
+ 10430,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10432,
+ 0,
+ 10433,
+ 10434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10436,
+ 10437,
+ 0,
+ 10438,
+ 0,
+ 10439,
+ 0,
+ 10444,
+ 10446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10448,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10449,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10451,
+ 0,
+ 10453,
+ 0,
+ 0,
+ 0,
+ 10454,
+ 10457,
+ 0,
+ 0,
+ 10459,
+ 0,
+ 10469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10472,
+ 10481,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10482,
+ 10483,
+ 0,
+ 10492,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10499,
+ 0,
+ 0,
+ 0,
+ 10502,
+ 0,
+ 0,
+ 10510,
+ 0,
+ 10521,
+ 10524,
+ 0,
+ 0,
+ 10525,
+ 10526,
+ 10528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10530,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10533,
+ 0,
+ 10534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10535,
+ 10536,
+ 0,
+ 0,
+ 10544,
+ 0,
+ 10553,
+ 10556,
+ 0,
+ 10557,
+ 10559,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10562,
+ 10563,
+ 10564,
+ 0,
+ 10565,
+ 0,
+ 0,
+ 0,
+ 10566,
+ 0,
+ 10567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10575,
+ 0,
+ 0,
+ 10576,
+ 0,
+ 10578,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10585,
+ 10586,
+ 10587,
+ 10589,
+ 0,
+ 10590,
+ 0,
+ 0,
+ 10594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10598,
+ 0,
+ 0,
+ 10601,
+ 0,
+ 0,
+ 0,
+ 10602,
+ 0,
+ 10603,
+ 0,
+ 10604,
+ 0,
+ 10605,
+ 0,
+ 0,
+ 10607,
+ 0,
+ 10626,
+ 0,
+ 10627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10629,
+ 10630,
+ 10631,
+ 0,
+ 0,
+ 0,
+ 10646,
+ 0,
+ 0,
+ 0,
+ 10647,
+ 0,
+ 10650,
+ 0,
+ 10651,
+ 0,
+ 0,
+ 0,
+ 10652,
+ 10653,
+ 10655,
+ 0,
+ 10658,
+ 0,
+ 0,
+ 10659,
+ 0,
+ 10667,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10669,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10670,
+ 0,
+ 0,
+ 0,
+ 10671,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10672,
+ 10673,
+ 0,
+ 10674,
+ 0,
+ 0,
+ 0,
+ 10676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10678,
+ 0,
+ 10682,
+ 0,
+ 0,
+ 10692,
+ 0,
+ 10697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10698,
+ 0,
+ 0,
+ 0,
+ 10700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10703,
+ 0,
+ 10704,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10705,
+ 0,
+ 10715,
+ 10718,
+ 10720,
+ 0,
+ 0,
+ 10722,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10723,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10727,
+ 10730,
+ 10743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10744,
+ 0,
+ 0,
+ 10745,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10748,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10750,
+ 0,
+ 0,
+ 10752,
+ 10753,
+ 0,
+ 0,
+ 0,
+ 10756,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10758,
+ 0,
+ 0,
+ 0,
+ 10759,
+ 0,
+ 10769,
+ 0,
+ 0,
+ 10772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10773,
+ 0,
+ 0,
+ 0,
+ 10777,
+ 0,
+ 0,
+ 10779,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10780,
+ 10784,
+ 0,
+ 0,
+ 0,
+ 10789,
+ 0,
+ 0,
+ 0,
+ 10791,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10795,
+ 0,
+ 0,
+ 10796,
+ 0,
+ 10808,
+ 0,
+ 10809,
+ 0,
+ 0,
+ 0,
+ 10810,
+ 0,
+ 0,
+ 0,
+ 10812,
+ 0,
+ 0,
+ 10814,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10815,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10816,
+ 10817,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10819,
+ 0,
+ 10820,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10821,
+ 10822,
+ 10823,
+ 0,
+ 10826,
+ 10849,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10850,
+ 0,
+ 0,
+ 10852,
+ 0,
+ 10853,
+ 0,
+ 0,
+ 10856,
+ 0,
+ 0,
+ 10857,
+ 10858,
+ 10859,
+ 10860,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10863,
+ 0,
+ 10866,
+ 10867,
+ 10872,
+ 10890,
+ 0,
+ 0,
+ 10891,
+ 10892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10893,
+ 0,
+ 0,
+ 0,
+ 10896,
+ 10899,
+ 0,
+ 0,
+ 10900,
+ 10902,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10903,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10905,
+ 0,
+ 10906,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10908,
+ 10911,
+ 0,
+ 10912,
+ 0,
+ 0,
+ 10916,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10917,
+ 0,
+ 10918,
+ 0,
+ 0,
+ 0,
+ 10923,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10924,
+ 0,
+ 0,
+ 10928,
+ 10929,
+ 0,
+ 0,
+ 10930,
+ 0,
+ 0,
+ 0,
+ 10932,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10939,
+ 0,
+ 0,
+ 10945,
+ 0,
+ 0,
+ 0,
+ 10947,
+ 0,
+ 0,
+ 10948,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10958,
+ 0,
+ 10960,
+ 10962,
+ 0,
+ 0,
+ 10964,
+ 0,
+ 0,
+ 0,
+ 10966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10967,
+ 0,
+ 0,
+ 0,
+ 10968,
+ 0,
+ 0,
+ 0,
+ 10973,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10975,
+ 0,
+ 0,
+ 0,
+ 10976,
+ 10978,
+ 0,
+ 0,
+ 10982,
+ 10984,
+ 10987,
+ 0,
+ 0,
+ 10988,
+ 0,
+ 10989,
+ 0,
+ 0,
+ 10991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 10992,
+ 0,
+ 0,
+ 0,
+ 10993,
+ 0,
+ 10995,
+ 0,
+ 0,
+ 0,
+ 10996,
+ 10997,
+ 0,
+ 0,
+ 0,
+ 10998,
+ 0,
+ 10999,
+ 0,
+ 11001,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11010,
+ 11012,
+ 0,
+ 11013,
+ 11016,
+ 11017,
+ 0,
+ 0,
+ 11019,
+ 11020,
+ 11021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11022,
+ 0,
+ 0,
+ 11023,
+ 11029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11031,
+ 0,
+ 0,
+ 0,
+ 11034,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11056,
+ 11060,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11061,
+ 0,
+ 0,
+ 11064,
+ 11065,
+ 0,
+ 11066,
+ 0,
+ 11069,
+ 0,
+ 11085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11086,
+ 0,
+ 0,
+ 0,
+ 11088,
+ 0,
+ 0,
+ 0,
+ 11094,
+ 0,
+ 0,
+ 0,
+ 11095,
+ 11096,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11097,
+ 11098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11099,
+ 0,
+ 0,
+ 11102,
+ 11108,
+ 0,
+ 0,
+ 0,
+ 11109,
+ 0,
+ 11114,
+ 11119,
+ 0,
+ 11131,
+ 0,
+ 0,
+ 0,
+ 11142,
+ 0,
+ 0,
+ 11143,
+ 0,
+ 11146,
+ 0,
+ 11147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11148,
+ 0,
+ 11149,
+ 11152,
+ 11153,
+ 11154,
+ 0,
+ 11156,
+ 0,
+ 11157,
+ 0,
+ 0,
+ 0,
+ 11158,
+ 0,
+ 0,
+ 11159,
+ 11160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11163,
+ 0,
+ 0,
+ 11164,
+ 11166,
+ 0,
+ 0,
+ 0,
+ 11172,
+ 11174,
+ 0,
+ 0,
+ 0,
+ 11176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11182,
+ 11183,
+ 0,
+ 0,
+ 0,
+ 11184,
+ 11187,
+ 0,
+ 0,
+ 11188,
+ 11189,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11200,
+ 11202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11203,
+ 0,
+ 11204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11205,
+ 0,
+ 0,
+ 0,
+ 11206,
+ 0,
+ 11207,
+ 0,
+ 0,
+ 11209,
+ 0,
+ 11211,
+ 0,
+ 11214,
+ 0,
+ 0,
+ 11231,
+ 0,
+ 0,
+ 0,
+ 11293,
+ 11295,
+ 0,
+ 0,
+ 11296,
+ 11297,
+ 11302,
+ 0,
+ 0,
+ 0,
+ 11307,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11309,
+ 11310,
+ 0,
+ 11311,
+ 0,
+ 0,
+ 0,
+ 11313,
+ 0,
+ 11314,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11334,
+ 0,
+ 11338,
+ 0,
+ 0,
+ 0,
+ 11339,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11340,
+ 0,
+ 11341,
+ 11342,
+ 0,
+ 11344,
+ 0,
+ 11345,
+ 0,
+ 0,
+ 0,
+ 11348,
+ 11349,
+ 0,
+ 0,
+ 11350,
+ 0,
+ 0,
+ 0,
+ 11355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11356,
+ 0,
+ 11357,
+ 11370,
+ 0,
+ 0,
+ 11371,
+ 0,
+ 11374,
+ 11376,
+ 0,
+ 0,
+ 0,
+ 11377,
+ 0,
+ 0,
+ 11378,
+ 11383,
+ 0,
+ 11386,
+ 11399,
+ 0,
+ 11400,
+ 11406,
+ 0,
+ 0,
+ 0,
+ 11408,
+ 0,
+ 0,
+ 11409,
+ 11412,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11417,
+ 0,
+ 0,
+ 0,
+ 11418,
+ 0,
+ 11421,
+ 0,
+ 11426,
+ 11429,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11430,
+ 0,
+ 11437,
+ 0,
+ 11438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11440,
+ 11453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11455,
+ 0,
+ 0,
+ 11456,
+ 11460,
+ 11461,
+ 11463,
+ 0,
+ 11469,
+ 0,
+ 11473,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11474,
+ 0,
+ 0,
+ 0,
+ 11475,
+ 0,
+ 11476,
+ 11477,
+ 11480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11481,
+ 0,
+ 0,
+ 11484,
+ 0,
+ 0,
+ 11487,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11497,
+ 0,
+ 0,
+ 11502,
+ 0,
+ 11509,
+ 0,
+ 0,
+ 11510,
+ 11511,
+ 11513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11515,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11516,
+ 0,
+ 11520,
+ 11521,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11529,
+ 11530,
+ 11531,
+ 11534,
+ 0,
+ 0,
+ 11543,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11547,
+ 0,
+ 11548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11552,
+ 11556,
+ 0,
+ 11557,
+ 0,
+ 0,
+ 11559,
+ 0,
+ 11560,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11561,
+ 0,
+ 0,
+ 11563,
+ 11564,
+ 0,
+ 11565,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11567,
+ 0,
+ 0,
+ 0,
+ 11569,
+ 0,
+ 11574,
+ 0,
+ 11575,
+ 0,
+ 0,
+ 0,
+ 11577,
+ 0,
+ 11578,
+ 0,
+ 0,
+ 0,
+ 11580,
+ 11581,
+ 0,
+ 0,
+ 0,
+ 11582,
+ 11584,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11587,
+ 0,
+ 11588,
+ 11591,
+ 0,
+ 11595,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11596,
+ 0,
+ 11597,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11598,
+ 11601,
+ 0,
+ 0,
+ 0,
+ 11602,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11603,
+ 11604,
+ 0,
+ 11606,
+ 0,
+ 0,
+ 11608,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11610,
+ 0,
+ 0,
+ 11611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11613,
+ 0,
+ 11622,
+ 0,
+ 0,
+ 0,
+ 11623,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11625,
+ 0,
+ 0,
+ 11626,
+ 11627,
+ 11628,
+ 11630,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11639,
+ 0,
+ 0,
+ 11646,
+ 0,
+ 11648,
+ 11649,
+ 0,
+ 11650,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11651,
+ 0,
+ 0,
+ 11652,
+ 11653,
+ 11656,
+ 0,
+ 0,
+ 11677,
+ 11679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11680,
+ 0,
+ 0,
+ 11681,
+ 0,
+ 11685,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11688,
+ 0,
+ 0,
+ 0,
+ 11716,
+ 0,
+ 11719,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11721,
+ 0,
+ 0,
+ 11724,
+ 11743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11745,
+ 11748,
+ 11750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11751,
+ 0,
+ 0,
+ 0,
+ 11752,
+ 11754,
+ 0,
+ 11755,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11759,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11760,
+ 0,
+ 0,
+ 0,
+ 11761,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11766,
+ 11767,
+ 0,
+ 11772,
+ 11773,
+ 0,
+ 11774,
+ 0,
+ 0,
+ 11775,
+ 0,
+ 11777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11778,
+ 11780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11783,
+ 0,
+ 11784,
+ 0,
+ 0,
+ 0,
+ 11785,
+ 0,
+ 0,
+ 0,
+ 11786,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11788,
+ 0,
+ 0,
+ 11789,
+ 11791,
+ 11792,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11795,
+ 11834,
+ 11835,
+ 11836,
+ 0,
+ 0,
+ 11837,
+ 0,
+ 0,
+ 0,
+ 11838,
+ 0,
+ 0,
+ 11846,
+ 11851,
+ 0,
+ 11852,
+ 0,
+ 11869,
+ 0,
+ 0,
+ 0,
+ 11871,
+ 0,
+ 0,
+ 0,
+ 11872,
+ 11874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11875,
+ 0,
+ 11876,
+ 11877,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11884,
+ 0,
+ 11885,
+ 0,
+ 11886,
+ 0,
+ 0,
+ 11887,
+ 0,
+ 11894,
+ 11895,
+ 11897,
+ 11909,
+ 11910,
+ 0,
+ 11912,
+ 11918,
+ 0,
+ 0,
+ 11920,
+ 0,
+ 11922,
+ 11924,
+ 11927,
+ 11928,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11929,
+ 0,
+ 11934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11941,
+ 11943,
+ 11944,
+ 0,
+ 11945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11948,
+ 11949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11953,
+ 0,
+ 11954,
+ 0,
+ 11955,
+ 0,
+ 11956,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11957,
+ 0,
+ 0,
+ 11959,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11961,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11978,
+ 0,
+ 0,
+ 0,
+ 11979,
+ 11980,
+ 11986,
+ 11987,
+ 0,
+ 11992,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 11993,
+ 0,
+ 0,
+ 0,
+ 11994,
+ 0,
+ 11999,
+ 12004,
+ 12005,
+ 12006,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12011,
+ 0,
+ 0,
+ 12012,
+ 12014,
+ 0,
+ 0,
+ 12015,
+ 0,
+ 0,
+ 12019,
+ 12028,
+ 0,
+ 0,
+ 12029,
+ 0,
+ 0,
+ 12032,
+ 12033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12034,
+ 0,
+ 12041,
+ 12043,
+ 0,
+ 0,
+ 12044,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12046,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12054,
+ 12055,
+ 0,
+ 12056,
+ 0,
+ 0,
+ 0,
+ 12060,
+ 12064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12065,
+ 12067,
+ 12068,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12074,
+ 0,
+ 0,
+ 0,
+ 12075,
+ 12076,
+ 0,
+ 0,
+ 0,
+ 12079,
+ 0,
+ 12081,
+ 12086,
+ 12087,
+ 0,
+ 0,
+ 12088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12089,
+ 0,
+ 12092,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12102,
+ 12103,
+ 12104,
+ 12111,
+ 0,
+ 0,
+ 12114,
+ 12116,
+ 0,
+ 0,
+ 0,
+ 12118,
+ 0,
+ 0,
+ 0,
+ 12119,
+ 12120,
+ 12128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12130,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12131,
+ 0,
+ 0,
+ 0,
+ 12132,
+ 12134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12137,
+ 0,
+ 12139,
+ 0,
+ 12141,
+ 0,
+ 0,
+ 12142,
+ 0,
+ 0,
+ 0,
+ 12144,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12145,
+ 0,
+ 12148,
+ 0,
+ 12153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12154,
+ 12171,
+ 12173,
+ 0,
+ 0,
+ 0,
+ 12175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12178,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12183,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12184,
+ 0,
+ 0,
+ 0,
+ 12186,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12187,
+ 12188,
+ 0,
+ 0,
+ 12189,
+ 0,
+ 12196,
+ 0,
+ 12197,
+ 0,
+ 0,
+ 12198,
+ 0,
+ 12201,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12203,
+ 0,
+ 12209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12210,
+ 12211,
+ 12212,
+ 12213,
+ 0,
+ 12217,
+ 12218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12222,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12223,
+ 0,
+ 0,
+ 12229,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12234,
+ 0,
+ 0,
+ 12236,
+ 12242,
+ 0,
+ 0,
+ 0,
+ 12243,
+ 0,
+ 0,
+ 0,
+ 12244,
+ 12253,
+ 0,
+ 12254,
+ 12256,
+ 0,
+ 12257,
+ 0,
+ 0,
+ 12275,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12278,
+ 0,
+ 12289,
+ 0,
+ 0,
+ 12290,
+ 0,
+ 12292,
+ 12293,
+ 0,
+ 0,
+ 12294,
+ 0,
+ 12295,
+ 0,
+ 0,
+ 12296,
+ 0,
+ 12297,
+ 0,
+ 12298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12309,
+ 0,
+ 12338,
+ 12340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12341,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12342,
+ 12343,
+ 0,
+ 12344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12350,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12351,
+ 0,
+ 12355,
+ 12356,
+ 12357,
+ 0,
+ 0,
+ 12367,
+ 12370,
+ 12371,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12372,
+ 12376,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12379,
+ 0,
+ 12382,
+ 0,
+ 12383,
+ 0,
+ 0,
+ 12384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12393,
+ 0,
+ 0,
+ 12394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12398,
+ 12403,
+ 0,
+ 0,
+ 12404,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12410,
+ 0,
+ 0,
+ 0,
+ 12411,
+ 0,
+ 0,
+ 0,
+ 12412,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12420,
+ 0,
+ 12421,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12423,
+ 0,
+ 12425,
+ 12429,
+ 0,
+ 0,
+ 0,
+ 12431,
+ 12432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12435,
+ 12436,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12437,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12445,
+ 0,
+ 0,
+ 0,
+ 12450,
+ 12451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12452,
+ 12475,
+ 0,
+ 0,
+ 12493,
+ 12494,
+ 0,
+ 0,
+ 0,
+ 12495,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12496,
+ 12502,
+ 12509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12510,
+ 0,
+ 12512,
+ 12513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12514,
+ 0,
+ 0,
+ 0,
+ 12515,
+ 0,
+ 12520,
+ 0,
+ 0,
+ 0,
+ 12524,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12527,
+ 0,
+ 0,
+ 0,
+ 12528,
+ 0,
+ 0,
+ 0,
+ 12529,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12530,
+ 0,
+ 12535,
+ 0,
+ 0,
+ 12536,
+ 0,
+ 12538,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12540,
+ 0,
+ 12548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12550,
+ 0,
+ 0,
+ 0,
+ 12551,
+ 12552,
+ 0,
+ 0,
+ 0,
+ 12554,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12555,
+ 0,
+ 0,
+ 12562,
+ 0,
+ 12565,
+ 0,
+ 12566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12569,
+ 0,
+ 0,
+ 0,
+ 12571,
+ 12574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12577,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12578,
+ 12579,
+ 12603,
+ 0,
+ 12608,
+ 0,
+ 0,
+ 12611,
+ 0,
+ 12612,
+ 0,
+ 12615,
+ 0,
+ 12625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12627,
+ 12646,
+ 0,
+ 12648,
+ 0,
+ 0,
+ 12657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12670,
+ 0,
+ 0,
+ 12671,
+ 0,
+ 12673,
+ 12677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12679,
+ 0,
+ 12681,
+ 0,
+ 12682,
+ 12693,
+ 0,
+ 12694,
+ 0,
+ 12697,
+ 0,
+ 12701,
+ 0,
+ 0,
+ 0,
+ 12703,
+ 12704,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12707,
+ 12737,
+ 0,
+ 0,
+ 12739,
+ 0,
+ 0,
+ 12740,
+ 0,
+ 0,
+ 12742,
+ 12743,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12745,
+ 0,
+ 12746,
+ 12747,
+ 0,
+ 12748,
+ 0,
+ 0,
+ 12759,
+ 12767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12773,
+ 0,
+ 12774,
+ 12778,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12779,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12780,
+ 12793,
+ 0,
+ 12824,
+ 0,
+ 12825,
+ 0,
+ 12836,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12839,
+ 0,
+ 12842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12843,
+ 12845,
+ 0,
+ 12846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12847,
+ 0,
+ 0,
+ 12850,
+ 12852,
+ 12853,
+ 0,
+ 0,
+ 0,
+ 12854,
+ 0,
+ 0,
+ 0,
+ 12855,
+ 0,
+ 12856,
+ 0,
+ 12858,
+ 0,
+ 0,
+ 12859,
+ 0,
+ 12862,
+ 0,
+ 12863,
+ 0,
+ 0,
+ 12866,
+ 0,
+ 12869,
+ 12872,
+ 12873,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12875,
+ 0,
+ 12877,
+ 0,
+ 0,
+ 12878,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12884,
+ 12885,
+ 12888,
+ 0,
+ 12889,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12893,
+ 0,
+ 0,
+ 0,
+ 12895,
+ 12896,
+ 12898,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12902,
+ 0,
+ 12909,
+ 12910,
+ 0,
+ 12926,
+ 0,
+ 12928,
+ 0,
+ 0,
+ 0,
+ 12929,
+ 0,
+ 12930,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12931,
+ 0,
+ 12932,
+ 12933,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12934,
+ 0,
+ 12942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12946,
+ 0,
+ 0,
+ 12948,
+ 0,
+ 0,
+ 12949,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12951,
+ 0,
+ 12952,
+ 0,
+ 12953,
+ 0,
+ 0,
+ 0,
+ 12954,
+ 12958,
+ 12959,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12960,
+ 12964,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12970,
+ 0,
+ 12971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 12972,
+ 0,
+ 0,
+ 12982,
+ 0,
+ 0,
+ 0,
+ 12984,
+ 12985,
+ 0,
+ 12986,
+ 12996,
+ 12997,
+ 13001,
+ 13002,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13004,
+ 0,
+ 0,
+ 13005,
+ 0,
+ 0,
+ 13007,
+ 13009,
+ 0,
+ 13017,
+ 0,
+ 0,
+ 0,
+ 13020,
+ 0,
+ 13021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13022,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13024,
+ 13027,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13028,
+ 0,
+ 0,
+ 13029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13032,
+ 0,
+ 13037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13040,
+ 0,
+ 0,
+ 13041,
+ 0,
+ 0,
+ 0,
+ 13043,
+ 13044,
+ 13046,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13049,
+ 13054,
+ 0,
+ 13056,
+ 0,
+ 0,
+ 13060,
+ 13061,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13067,
+ 0,
+ 0,
+ 13068,
+ 0,
+ 13071,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13077,
+ 13078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13079,
+ 13080,
+ 13081,
+ 0,
+ 13082,
+ 0,
+ 0,
+ 0,
+ 13085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13086,
+ 0,
+ 13087,
+ 13088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13094,
+ 0,
+ 13099,
+ 0,
+ 13100,
+ 0,
+ 0,
+ 0,
+ 13101,
+ 0,
+ 13125,
+ 13126,
+ 13128,
+ 13129,
+ 0,
+ 0,
+ 13130,
+ 0,
+ 13131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13150,
+ 0,
+ 13168,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13169,
+ 0,
+ 0,
+ 13170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13174,
+ 0,
+ 0,
+ 0,
+ 13176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13177,
+ 0,
+ 13178,
+ 13183,
+ 13187,
+ 0,
+ 0,
+ 0,
+ 13189,
+ 0,
+ 0,
+ 13190,
+ 0,
+ 0,
+ 13191,
+ 0,
+ 0,
+ 13206,
+ 0,
+ 0,
+ 0,
+ 13207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13212,
+ 0,
+ 0,
+ 13219,
+ 13232,
+ 0,
+ 0,
+ 0,
+ 13241,
+ 0,
+ 13249,
+ 13253,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13255,
+ 13259,
+ 0,
+ 13260,
+ 13261,
+ 0,
+ 13262,
+ 0,
+ 13272,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13276,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13277,
+ 13299,
+ 0,
+ 0,
+ 13301,
+ 13302,
+ 0,
+ 0,
+ 13303,
+ 0,
+ 0,
+ 13305,
+ 0,
+ 13310,
+ 0,
+ 0,
+ 0,
+ 13311,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13325,
+ 0,
+ 13328,
+ 0,
+ 0,
+ 0,
+ 13329,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13330,
+ 0,
+ 0,
+ 13331,
+ 0,
+ 13335,
+ 0,
+ 0,
+ 13342,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13343,
+ 0,
+ 13354,
+ 0,
+ 13362,
+ 0,
+ 13366,
+ 13367,
+ 13369,
+ 0,
+ 0,
+ 13371,
+ 13372,
+ 0,
+ 13373,
+ 13374,
+ 0,
+ 13376,
+ 0,
+ 13380,
+ 13381,
+ 13386,
+ 0,
+ 13387,
+ 13388,
+ 0,
+ 13389,
+ 13391,
+ 13395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13401,
+ 13409,
+ 0,
+ 13410,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13422,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13425,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13427,
+ 0,
+ 0,
+ 0,
+ 13428,
+ 0,
+ 0,
+ 13430,
+ 13438,
+ 0,
+ 13439,
+ 0,
+ 13445,
+ 0,
+ 13448,
+ 13449,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13451,
+ 0,
+ 13457,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13458,
+ 13459,
+ 0,
+ 13460,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13464,
+ 13465,
+ 13466,
+ 13470,
+ 0,
+ 13471,
+ 13472,
+ 13474,
+ 13475,
+ 0,
+ 13476,
+ 0,
+ 0,
+ 13478,
+ 13479,
+ 0,
+ 13481,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13487,
+ 0,
+ 13490,
+ 0,
+ 13493,
+ 0,
+ 0,
+ 13494,
+ 0,
+ 0,
+ 13495,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13496,
+ 13497,
+ 0,
+ 13500,
+ 0,
+ 0,
+ 13516,
+ 13522,
+ 0,
+ 0,
+ 13525,
+ 13528,
+ 0,
+ 0,
+ 0,
+ 13530,
+ 13535,
+ 0,
+ 13537,
+ 13539,
+ 0,
+ 13540,
+ 0,
+ 13543,
+ 0,
+ 13544,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13545,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13547,
+ 0,
+ 0,
+ 0,
+ 13549,
+ 13555,
+ 0,
+ 0,
+ 0,
+ 13556,
+ 13557,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13558,
+ 0,
+ 13563,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13564,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13569,
+ 0,
+ 0,
+ 13571,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13578,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13581,
+ 0,
+ 13586,
+ 0,
+ 13595,
+ 0,
+ 13600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13601,
+ 13603,
+ 0,
+ 13604,
+ 13605,
+ 13606,
+ 13607,
+ 0,
+ 0,
+ 13617,
+ 13618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13623,
+ 0,
+ 13625,
+ 13627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13629,
+ 0,
+ 0,
+ 0,
+ 13634,
+ 0,
+ 0,
+ 0,
+ 13638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13654,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13656,
+ 0,
+ 13659,
+ 0,
+ 0,
+ 13660,
+ 0,
+ 0,
+ 13662,
+ 0,
+ 0,
+ 0,
+ 13663,
+ 0,
+ 13664,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13668,
+ 0,
+ 13669,
+ 13671,
+ 0,
+ 0,
+ 13672,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13675,
+ 13685,
+ 0,
+ 13686,
+ 0,
+ 0,
+ 0,
+ 13687,
+ 0,
+ 0,
+ 0,
+ 13692,
+ 13694,
+ 13697,
+ 0,
+ 0,
+ 0,
+ 13702,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13705,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13707,
+ 0,
+ 0,
+ 0,
+ 13714,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13715,
+ 0,
+ 13716,
+ 13717,
+ 0,
+ 0,
+ 13719,
+ 13724,
+ 13730,
+ 13731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13732,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13734,
+ 0,
+ 13736,
+ 0,
+ 0,
+ 13737,
+ 13738,
+ 13747,
+ 0,
+ 13751,
+ 0,
+ 0,
+ 13752,
+ 0,
+ 0,
+ 0,
+ 13753,
+ 0,
+ 13757,
+ 0,
+ 0,
+ 13762,
+ 13763,
+ 0,
+ 13764,
+ 13765,
+ 0,
+ 13766,
+ 0,
+ 0,
+ 13767,
+ 0,
+ 0,
+ 0,
+ 13768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13769,
+ 0,
+ 0,
+ 13772,
+ 0,
+ 13775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13776,
+ 13778,
+ 13787,
+ 0,
+ 0,
+ 0,
+ 13797,
+ 0,
+ 13798,
+ 0,
+ 13801,
+ 0,
+ 13804,
+ 13806,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13816,
+ 13817,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13834,
+ 0,
+ 13836,
+ 0,
+ 0,
+ 13838,
+ 0,
+ 0,
+ 13839,
+ 0,
+ 13840,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13858,
+ 0,
+ 0,
+ 13860,
+ 0,
+ 0,
+ 13861,
+ 0,
+ 0,
+ 13862,
+ 13863,
+ 0,
+ 13868,
+ 0,
+ 13869,
+ 13870,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13872,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13873,
+ 13878,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13886,
+ 0,
+ 13888,
+ 13889,
+ 13890,
+ 0,
+ 0,
+ 13891,
+ 13894,
+ 0,
+ 13897,
+ 13899,
+ 13900,
+ 13904,
+ 0,
+ 0,
+ 13906,
+ 0,
+ 0,
+ 0,
+ 13909,
+ 0,
+ 0,
+ 0,
+ 13910,
+ 0,
+ 0,
+ 0,
+ 13911,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13912,
+ 13917,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13918,
+ 0,
+ 13919,
+ 0,
+ 0,
+ 13920,
+ 0,
+ 0,
+ 0,
+ 13921,
+ 0,
+ 0,
+ 13922,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13924,
+ 0,
+ 13927,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13932,
+ 0,
+ 13933,
+ 0,
+ 13934,
+ 0,
+ 0,
+ 13935,
+ 0,
+ 13944,
+ 0,
+ 0,
+ 0,
+ 13954,
+ 0,
+ 0,
+ 13955,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13956,
+ 0,
+ 13957,
+ 0,
+ 13967,
+ 13969,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13970,
+ 13990,
+ 0,
+ 13991,
+ 13994,
+ 0,
+ 13995,
+ 0,
+ 0,
+ 0,
+ 0,
+ 13996,
+ 0,
+ 0,
+ 13999,
+ 0,
+ 0,
+ 0,
+ 14018,
+ 0,
+ 14019,
+ 0,
+ 14021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14041,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14043,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14046,
+ 0,
+ 0,
+ 0,
+ 14048,
+ 14049,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14051,
+ 0,
+ 0,
+ 14052,
+ 14056,
+ 0,
+ 14063,
+ 0,
+ 14064,
+ 14066,
+ 0,
+ 0,
+ 14067,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14068,
+ 0,
+ 0,
+ 0,
+ 14072,
+ 0,
+ 14074,
+ 14075,
+ 0,
+ 14076,
+ 14079,
+ 14085,
+ 14086,
+ 14087,
+ 14093,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14095,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14096,
+ 14097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14098,
+ 0,
+ 14102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14103,
+ 0,
+ 0,
+ 0,
+ 14104,
+ 0,
+ 0,
+ 14105,
+ 0,
+ 0,
+ 0,
+ 14107,
+ 14108,
+ 0,
+ 0,
+ 14109,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14117,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14118,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14119,
+ 0,
+ 0,
+ 14120,
+ 0,
+ 0,
+ 14121,
+ 0,
+ 14122,
+ 14127,
+ 0,
+ 14128,
+ 14136,
+ 0,
+ 0,
+ 14138,
+ 0,
+ 14140,
+ 0,
+ 0,
+ 0,
+ 14141,
+ 14142,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14146,
+ 0,
+ 0,
+ 14149,
+ 0,
+ 14151,
+ 0,
+ 0,
+ 0,
+ 14152,
+ 0,
+ 0,
+ 14153,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14154,
+ 0,
+ 14156,
+ 14157,
+ 0,
+ 0,
+ 14159,
+ 0,
+ 14161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14162,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14163,
+ 0,
+ 0,
+ 14173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14174,
+ 0,
+ 0,
+ 14176,
+ 0,
+ 0,
+ 14178,
+ 0,
+ 0,
+ 14179,
+ 14181,
+ 0,
+ 0,
+ 14182,
+ 14185,
+ 14187,
+ 0,
+ 14190,
+ 0,
+ 0,
+ 14197,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14199,
+ 14200,
+ 0,
+ 0,
+ 0,
+ 14204,
+ 0,
+ 0,
+ 14208,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14231,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14234,
+ 0,
+ 0,
+ 14235,
+ 0,
+ 0,
+ 0,
+ 14240,
+ 14241,
+ 0,
+ 0,
+ 0,
+ 14246,
+ 0,
+ 0,
+ 0,
+ 14247,
+ 0,
+ 14250,
+ 0,
+ 0,
+ 14251,
+ 0,
+ 0,
+ 14254,
+ 0,
+ 0,
+ 14256,
+ 0,
+ 0,
+ 0,
+ 14260,
+ 0,
+ 14261,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14262,
+ 14267,
+ 14269,
+ 0,
+ 0,
+ 14277,
+ 0,
+ 0,
+ 14278,
+ 0,
+ 14279,
+ 14282,
+ 0,
+ 0,
+ 0,
+ 14283,
+ 0,
+ 0,
+ 0,
+ 14284,
+ 14285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14286,
+ 0,
+ 0,
+ 0,
+ 14288,
+ 0,
+ 0,
+ 0,
+ 14289,
+ 0,
+ 14290,
+ 0,
+ 14293,
+ 14301,
+ 14302,
+ 14304,
+ 14305,
+ 0,
+ 14307,
+ 0,
+ 14308,
+ 14309,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14311,
+ 14312,
+ 0,
+ 0,
+ 14317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14318,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14321,
+ 14322,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14326,
+ 14329,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14330,
+ 14331,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14332,
+ 0,
+ 0,
+ 0,
+ 14333,
+ 0,
+ 0,
+ 14337,
+ 14340,
+ 0,
+ 14341,
+ 0,
+ 0,
+ 14342,
+ 0,
+ 14345,
+ 14346,
+ 0,
+ 0,
+ 14347,
+ 0,
+ 14362,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14364,
+ 14365,
+ 14371,
+ 0,
+ 14373,
+ 0,
+ 0,
+ 14374,
+ 0,
+ 14379,
+ 0,
+ 14400,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14401,
+ 0,
+ 0,
+ 14405,
+ 0,
+ 14406,
+ 0,
+ 14408,
+ 14409,
+ 0,
+ 0,
+ 0,
+ 14417,
+ 0,
+ 0,
+ 14424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14430,
+ 0,
+ 0,
+ 0,
+ 14431,
+ 0,
+ 0,
+ 14435,
+ 0,
+ 14440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14442,
+ 0,
+ 0,
+ 14443,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14454,
+ 0,
+ 14457,
+ 0,
+ 14460,
+ 0,
+ 0,
+ 14466,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14469,
+ 0,
+ 14477,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14478,
+ 14482,
+ 0,
+ 0,
+ 0,
+ 14483,
+ 0,
+ 0,
+ 0,
+ 14485,
+ 14486,
+ 0,
+ 0,
+ 0,
+ 14487,
+ 14488,
+ 14489,
+ 14492,
+ 14493,
+ 14494,
+ 14495,
+ 14496,
+ 14497,
+ 0,
+ 14499,
+ 0,
+ 14501,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14502,
+ 0,
+ 14507,
+ 14512,
+ 14513,
+ 14514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14515,
+ 14526,
+ 14530,
+ 0,
+ 14537,
+ 0,
+ 14544,
+ 0,
+ 14547,
+ 0,
+ 0,
+ 14548,
+ 14550,
+ 14551,
+ 0,
+ 0,
+ 14552,
+ 0,
+ 0,
+ 0,
+ 14553,
+ 0,
+ 14554,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14556,
+ 14564,
+ 0,
+ 0,
+ 14565,
+ 14566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14568,
+ 0,
+ 0,
+ 14569,
+ 0,
+ 0,
+ 0,
+ 14571,
+ 14576,
+ 0,
+ 0,
+ 14577,
+ 14578,
+ 14579,
+ 0,
+ 0,
+ 14580,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14582,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14583,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14587,
+ 0,
+ 14588,
+ 0,
+ 0,
+ 14600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14601,
+ 0,
+ 0,
+ 14604,
+ 14605,
+ 14611,
+ 0,
+ 14613,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14627,
+ 0,
+ 14628,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14631,
+ 0,
+ 14633,
+ 14634,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14635,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14636,
+ 0,
+ 0,
+ 14639,
+ 14642,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14644,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14645,
+ 14646,
+ 0,
+ 14653,
+ 0,
+ 0,
+ 14654,
+ 0,
+ 14658,
+ 0,
+ 14661,
+ 0,
+ 0,
+ 0,
+ 14665,
+ 0,
+ 0,
+ 0,
+ 14668,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14669,
+ 0,
+ 0,
+ 14670,
+ 0,
+ 0,
+ 0,
+ 14680,
+ 0,
+ 0,
+ 14681,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14682,
+ 14683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14687,
+ 14697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14699,
+ 14705,
+ 14711,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14712,
+ 0,
+ 0,
+ 0,
+ 14713,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14719,
+ 0,
+ 14720,
+ 14721,
+ 14726,
+ 0,
+ 0,
+ 0,
+ 14728,
+ 14729,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14733,
+ 14736,
+ 14737,
+ 0,
+ 0,
+ 14740,
+ 14742,
+ 0,
+ 0,
+ 0,
+ 14744,
+ 14753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14755,
+ 14758,
+ 14760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14761,
+ 14762,
+ 14765,
+ 14771,
+ 0,
+ 14772,
+ 0,
+ 14773,
+ 14774,
+ 0,
+ 0,
+ 14775,
+ 0,
+ 0,
+ 14776,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14777,
+ 0,
+ 14779,
+ 0,
+ 0,
+ 14782,
+ 0,
+ 0,
+ 14785,
+ 14786,
+ 14788,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14795,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14798,
+ 0,
+ 14803,
+ 14804,
+ 14806,
+ 0,
+ 0,
+ 0,
+ 14809,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14811,
+ 0,
+ 14812,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14815,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14816,
+ 0,
+ 14818,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14819,
+ 0,
+ 14820,
+ 0,
+ 14823,
+ 0,
+ 0,
+ 0,
+ 14824,
+ 0,
+ 0,
+ 14826,
+ 14827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14830,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14833,
+ 0,
+ 14845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14846,
+ 0,
+ 0,
+ 14847,
+ 14871,
+ 0,
+ 14873,
+ 0,
+ 14876,
+ 0,
+ 14877,
+ 14878,
+ 14880,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14881,
+ 0,
+ 14882,
+ 14894,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14895,
+ 0,
+ 14907,
+ 0,
+ 14908,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14911,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14920,
+ 0,
+ 0,
+ 14931,
+ 0,
+ 14932,
+ 14934,
+ 14935,
+ 0,
+ 0,
+ 14936,
+ 0,
+ 14945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14947,
+ 0,
+ 0,
+ 14948,
+ 14949,
+ 14951,
+ 0,
+ 0,
+ 14952,
+ 0,
+ 0,
+ 0,
+ 14964,
+ 14973,
+ 0,
+ 0,
+ 14990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 14995,
+ 0,
+ 0,
+ 14998,
+ 15001,
+ 0,
+ 0,
+ 15002,
+ 15020,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15021,
+ 0,
+ 15022,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15023,
+ 0,
+ 0,
+ 15025,
+ 15029,
+ 15033,
+ 0,
+ 0,
+ 0,
+ 15034,
+ 0,
+ 0,
+ 0,
+ 15035,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15043,
+ 15044,
+ 0,
+ 0,
+ 0,
+ 15045,
+ 15046,
+ 15048,
+ 15050,
+ 0,
+ 15065,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15066,
+ 0,
+ 0,
+ 15075,
+ 15082,
+ 15084,
+ 0,
+ 0,
+ 15085,
+ 15086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15088,
+ 0,
+ 0,
+ 0,
+ 15089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15094,
+ 0,
+ 15096,
+ 0,
+ 15097,
+ 0,
+ 15100,
+ 0,
+ 0,
+ 15102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15105,
+ 0,
+ 0,
+ 15106,
+ 0,
+ 15109,
+ 15113,
+ 0,
+ 0,
+ 0,
+ 15115,
+ 0,
+ 15118,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15119,
+ 0,
+ 0,
+ 15120,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15123,
+ 15129,
+ 0,
+ 0,
+ 0,
+ 15130,
+ 0,
+ 15131,
+ 0,
+ 0,
+ 15134,
+ 0,
+ 15135,
+ 0,
+ 0,
+ 0,
+ 15137,
+ 15138,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15140,
+ 0,
+ 0,
+ 15154,
+ 15162,
+ 0,
+ 15169,
+ 15170,
+ 0,
+ 15175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15177,
+ 0,
+ 15178,
+ 15179,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15183,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15185,
+ 15187,
+ 0,
+ 15194,
+ 15195,
+ 15196,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15206,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15213,
+ 0,
+ 15214,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15232,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15234,
+ 0,
+ 15238,
+ 15240,
+ 0,
+ 15248,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15250,
+ 15251,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15252,
+ 0,
+ 0,
+ 0,
+ 15255,
+ 15262,
+ 15266,
+ 0,
+ 0,
+ 0,
+ 15267,
+ 0,
+ 0,
+ 0,
+ 15277,
+ 15279,
+ 0,
+ 0,
+ 0,
+ 15280,
+ 15281,
+ 15282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15285,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15289,
+ 0,
+ 0,
+ 15291,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15296,
+ 15297,
+ 0,
+ 0,
+ 15304,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15307,
+ 15308,
+ 0,
+ 15309,
+ 0,
+ 0,
+ 15311,
+ 0,
+ 0,
+ 15312,
+ 15313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15314,
+ 15317,
+ 0,
+ 0,
+ 0,
+ 15318,
+ 15319,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15324,
+ 0,
+ 15325,
+ 15326,
+ 0,
+ 15330,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15334,
+ 0,
+ 15335,
+ 0,
+ 15341,
+ 0,
+ 0,
+ 15342,
+ 0,
+ 0,
+ 15343,
+ 15344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15347,
+ 0,
+ 0,
+ 15348,
+ 15349,
+ 15350,
+ 0,
+ 15356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15357,
+ 0,
+ 15358,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15359,
+ 15360,
+ 15364,
+ 0,
+ 15380,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15392,
+ 0,
+ 0,
+ 15393,
+ 0,
+ 15395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15396,
+ 0,
+ 0,
+ 15397,
+ 15398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15399,
+ 0,
+ 15400,
+ 0,
+ 0,
+ 0,
+ 15402,
+ 0,
+ 15405,
+ 15410,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15411,
+ 0,
+ 0,
+ 0,
+ 15412,
+ 0,
+ 15416,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15428,
+ 0,
+ 15435,
+ 0,
+ 0,
+ 15438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15439,
+ 0,
+ 0,
+ 0,
+ 15440,
+ 0,
+ 0,
+ 0,
+ 15441,
+ 15449,
+ 15451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15452,
+ 0,
+ 0,
+ 15455,
+ 0,
+ 0,
+ 0,
+ 15456,
+ 0,
+ 0,
+ 15458,
+ 0,
+ 15460,
+ 15461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15462,
+ 15464,
+ 0,
+ 15465,
+ 0,
+ 0,
+ 15466,
+ 0,
+ 0,
+ 15467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15468,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15481,
+ 0,
+ 0,
+ 15484,
+ 0,
+ 15485,
+ 15486,
+ 0,
+ 0,
+ 0,
+ 15487,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15488,
+ 0,
+ 15492,
+ 15498,
+ 0,
+ 0,
+ 0,
+ 15499,
+ 0,
+ 0,
+ 0,
+ 15500,
+ 0,
+ 15501,
+ 0,
+ 0,
+ 15512,
+ 0,
+ 15522,
+ 0,
+ 0,
+ 0,
+ 15524,
+ 0,
+ 15525,
+ 15526,
+ 0,
+ 0,
+ 15527,
+ 0,
+ 0,
+ 15545,
+ 15546,
+ 0,
+ 15548,
+ 15552,
+ 0,
+ 15553,
+ 0,
+ 0,
+ 0,
+ 15554,
+ 0,
+ 15555,
+ 0,
+ 15557,
+ 15565,
+ 15573,
+ 15577,
+ 15578,
+ 0,
+ 15582,
+ 0,
+ 15583,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15586,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15593,
+ 15594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15595,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15596,
+ 0,
+ 0,
+ 0,
+ 15597,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15600,
+ 0,
+ 0,
+ 15601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15602,
+ 15603,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15604,
+ 0,
+ 15609,
+ 0,
+ 0,
+ 15612,
+ 0,
+ 0,
+ 15613,
+ 0,
+ 0,
+ 15615,
+ 15617,
+ 15618,
+ 0,
+ 0,
+ 15620,
+ 0,
+ 15636,
+ 15637,
+ 0,
+ 0,
+ 15649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15650,
+ 0,
+ 0,
+ 15651,
+ 0,
+ 0,
+ 0,
+ 15656,
+ 0,
+ 15658,
+ 0,
+ 0,
+ 0,
+ 15664,
+ 0,
+ 0,
+ 15665,
+ 0,
+ 0,
+ 15668,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15669,
+ 0,
+ 0,
+ 15674,
+ 0,
+ 0,
+ 15675,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15678,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15679,
+ 0,
+ 0,
+ 15681,
+ 0,
+ 15686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15687,
+ 0,
+ 15688,
+ 0,
+ 0,
+ 15690,
+ 0,
+ 0,
+ 0,
+ 15697,
+ 0,
+ 15699,
+ 15700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15701,
+ 0,
+ 15702,
+ 15703,
+ 0,
+ 15704,
+ 0,
+ 15705,
+ 0,
+ 15707,
+ 0,
+ 15709,
+ 0,
+ 15712,
+ 15716,
+ 0,
+ 15717,
+ 0,
+ 15718,
+ 15720,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15724,
+ 0,
+ 0,
+ 0,
+ 15725,
+ 0,
+ 15726,
+ 0,
+ 0,
+ 0,
+ 15740,
+ 0,
+ 15745,
+ 15746,
+ 0,
+ 0,
+ 15747,
+ 0,
+ 15748,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15749,
+ 0,
+ 0,
+ 0,
+ 15752,
+ 0,
+ 15753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15759,
+ 0,
+ 0,
+ 0,
+ 15765,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15767,
+ 0,
+ 0,
+ 0,
+ 15771,
+ 0,
+ 0,
+ 15784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15785,
+ 15790,
+ 15791,
+ 0,
+ 0,
+ 15792,
+ 0,
+ 0,
+ 0,
+ 15807,
+ 0,
+ 15811,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15818,
+ 0,
+ 0,
+ 0,
+ 15819,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15821,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15822,
+ 15824,
+ 0,
+ 0,
+ 15827,
+ 0,
+ 0,
+ 15829,
+ 15831,
+ 0,
+ 15832,
+ 0,
+ 0,
+ 15833,
+ 0,
+ 15835,
+ 15838,
+ 15839,
+ 15843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15845,
+ 15851,
+ 15856,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15858,
+ 15860,
+ 0,
+ 15861,
+ 0,
+ 0,
+ 0,
+ 15864,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15866,
+ 0,
+ 15872,
+ 0,
+ 0,
+ 15876,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15877,
+ 15878,
+ 15883,
+ 15885,
+ 0,
+ 0,
+ 15888,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15889,
+ 15890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15893,
+ 0,
+ 0,
+ 15894,
+ 0,
+ 0,
+ 0,
+ 15895,
+ 0,
+ 15896,
+ 15897,
+ 0,
+ 15898,
+ 15901,
+ 15902,
+ 0,
+ 15911,
+ 15915,
+ 0,
+ 15916,
+ 0,
+ 15924,
+ 15935,
+ 0,
+ 15937,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15958,
+ 0,
+ 0,
+ 0,
+ 15961,
+ 0,
+ 0,
+ 15966,
+ 0,
+ 15967,
+ 0,
+ 0,
+ 15977,
+ 0,
+ 0,
+ 15978,
+ 0,
+ 0,
+ 15981,
+ 15982,
+ 15983,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 15986,
+ 0,
+ 0,
+ 0,
+ 15990,
+ 0,
+ 15991,
+ 15995,
+ 15998,
+ 0,
+ 15999,
+ 0,
+ 16000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16008,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16009,
+ 16011,
+ 0,
+ 16013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16014,
+ 0,
+ 0,
+ 16015,
+ 16023,
+ 16024,
+ 16025,
+ 0,
+ 0,
+ 16026,
+ 0,
+ 16030,
+ 0,
+ 16032,
+ 0,
+ 16033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16035,
+ 16036,
+ 16037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16039,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16041,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16043,
+ 16044,
+ 0,
+ 0,
+ 16047,
+ 0,
+ 0,
+ 0,
+ 16048,
+ 0,
+ 0,
+ 16049,
+ 16050,
+ 16052,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16056,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16058,
+ 16060,
+ 16061,
+ 0,
+ 0,
+ 16063,
+ 0,
+ 0,
+ 16064,
+ 0,
+ 0,
+ 0,
+ 16067,
+ 16068,
+ 0,
+ 0,
+ 16069,
+ 16078,
+ 0,
+ 0,
+ 0,
+ 16079,
+ 0,
+ 0,
+ 0,
+ 16080,
+ 0,
+ 16081,
+ 0,
+ 0,
+ 0,
+ 16088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16089,
+ 16093,
+ 0,
+ 16097,
+ 0,
+ 16103,
+ 0,
+ 16104,
+ 16105,
+ 0,
+ 0,
+ 16256,
+ 0,
+ 0,
+ 16259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16260,
+ 16261,
+ 0,
+ 0,
+ 16262,
+ 0,
+ 0,
+ 16263,
+ 0,
+ 16268,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16269,
+ 0,
+ 0,
+ 16270,
+ 16273,
+ 0,
+ 16274,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16275,
+ 16276,
+ 16277,
+ 16280,
+ 0,
+ 0,
+ 0,
+ 16281,
+ 16284,
+ 0,
+ 0,
+ 0,
+ 16286,
+ 0,
+ 16289,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16291,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16293,
+ 16295,
+ 16297,
+ 0,
+ 16302,
+ 0,
+ 16304,
+ 0,
+ 16305,
+ 0,
+ 16306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16307,
+ 16308,
+ 16312,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16313,
+ 16315,
+ 0,
+ 16318,
+ 0,
+ 0,
+ 0,
+ 16321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16326,
+ 16333,
+ 16336,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16337,
+ 16340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16345,
+ 0,
+ 0,
+ 16346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16347,
+ 0,
+ 0,
+ 16348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16349,
+ 0,
+ 0,
+ 0,
+ 16350,
+ 0,
+ 16357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16359,
+ 16360,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16362,
+ 16363,
+ 16364,
+ 16365,
+ 0,
+ 0,
+ 16366,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16367,
+ 16368,
+ 0,
+ 16369,
+ 16374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16376,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16378,
+ 16379,
+ 0,
+ 16380,
+ 0,
+ 0,
+ 0,
+ 16381,
+ 16383,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16390,
+ 0,
+ 0,
+ 0,
+ 16399,
+ 0,
+ 16402,
+ 16404,
+ 16406,
+ 16407,
+ 0,
+ 0,
+ 0,
+ 16409,
+ 16411,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16412,
+ 0,
+ 16413,
+ 16415,
+ 16423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16424,
+ 0,
+ 0,
+ 0,
+ 16428,
+ 16434,
+ 16435,
+ 16449,
+ 0,
+ 16450,
+ 16451,
+ 0,
+ 0,
+ 0,
+ 16453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16454,
+ 0,
+ 0,
+ 16456,
+ 16458,
+ 0,
+ 0,
+ 16459,
+ 0,
+ 0,
+ 16460,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16462,
+ 0,
+ 16463,
+ 0,
+ 0,
+ 16466,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16479,
+ 0,
+ 0,
+ 16480,
+ 0,
+ 16481,
+ 16484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16491,
+ 0,
+ 0,
+ 16498,
+ 0,
+ 0,
+ 16503,
+ 0,
+ 16505,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16506,
+ 0,
+ 0,
+ 0,
+ 16508,
+ 16509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16511,
+ 16513,
+ 0,
+ 0,
+ 0,
+ 16516,
+ 0,
+ 16517,
+ 0,
+ 16519,
+ 0,
+ 16529,
+ 0,
+ 0,
+ 16531,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16534,
+ 0,
+ 0,
+ 16541,
+ 16542,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16543,
+ 16547,
+ 16548,
+ 0,
+ 0,
+ 0,
+ 16551,
+ 0,
+ 16552,
+ 0,
+ 0,
+ 0,
+ 16553,
+ 0,
+ 0,
+ 16558,
+ 0,
+ 0,
+ 16562,
+ 16565,
+ 0,
+ 0,
+ 0,
+ 16570,
+ 0,
+ 0,
+ 0,
+ 16573,
+ 16585,
+ 0,
+ 0,
+ 0,
+ 16586,
+ 16587,
+ 16595,
+ 0,
+ 16596,
+ 0,
+ 16598,
+ 0,
+ 0,
+ 0,
+ 16600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16603,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16604,
+ 16612,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16613,
+ 0,
+ 16618,
+ 0,
+ 0,
+ 0,
+ 16640,
+ 0,
+ 0,
+ 16641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16645,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16646,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16651,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16653,
+ 16654,
+ 0,
+ 0,
+ 0,
+ 16655,
+ 0,
+ 0,
+ 16656,
+ 16667,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16671,
+ 0,
+ 16672,
+ 0,
+ 0,
+ 0,
+ 16673,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16676,
+ 0,
+ 16686,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16689,
+ 0,
+ 16690,
+ 0,
+ 16692,
+ 0,
+ 16693,
+ 0,
+ 16694,
+ 0,
+ 16696,
+ 0,
+ 0,
+ 0,
+ 16705,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16707,
+ 0,
+ 0,
+ 0,
+ 16709,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16711,
+ 0,
+ 16712,
+ 16713,
+ 0,
+ 0,
+ 0,
+ 16715,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16716,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16718,
+ 16724,
+ 0,
+ 0,
+ 16726,
+ 16727,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16728,
+ 0,
+ 16729,
+ 0,
+ 0,
+ 16730,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16731,
+ 0,
+ 0,
+ 0,
+ 16732,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16734,
+ 16738,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16743,
+ 0,
+ 0,
+ 16745,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16749,
+ 0,
+ 16752,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16756,
+ 0,
+ 0,
+ 16758,
+ 0,
+ 16759,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16762,
+ 0,
+ 16769,
+ 0,
+ 16770,
+ 0,
+ 16772,
+ 0,
+ 0,
+ 0,
+ 16777,
+ 16780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16781,
+ 0,
+ 0,
+ 16782,
+ 0,
+ 16784,
+ 0,
+ 0,
+ 16785,
+ 16787,
+ 16792,
+ 0,
+ 0,
+ 16794,
+ 0,
+ 0,
+ 0,
+ 16798,
+ 0,
+ 0,
+ 16809,
+ 0,
+ 0,
+ 16814,
+ 16816,
+ 16817,
+ 0,
+ 16819,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16820,
+ 0,
+ 0,
+ 16836,
+ 16839,
+ 0,
+ 0,
+ 16841,
+ 16851,
+ 16857,
+ 0,
+ 0,
+ 16858,
+ 16859,
+ 0,
+ 0,
+ 16860,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16862,
+ 0,
+ 16863,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16864,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16876,
+ 0,
+ 16881,
+ 16882,
+ 0,
+ 16885,
+ 16886,
+ 0,
+ 16887,
+ 0,
+ 0,
+ 0,
+ 16889,
+ 16891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16894,
+ 16895,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16897,
+ 0,
+ 16898,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16913,
+ 0,
+ 0,
+ 16924,
+ 16925,
+ 16926,
+ 0,
+ 0,
+ 16927,
+ 0,
+ 0,
+ 0,
+ 16937,
+ 16938,
+ 0,
+ 0,
+ 0,
+ 16940,
+ 16941,
+ 0,
+ 0,
+ 0,
+ 16942,
+ 16945,
+ 0,
+ 16946,
+ 16949,
+ 16950,
+ 0,
+ 0,
+ 0,
+ 16952,
+ 16955,
+ 0,
+ 0,
+ 0,
+ 16965,
+ 0,
+ 16969,
+ 0,
+ 0,
+ 16975,
+ 0,
+ 0,
+ 16976,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16978,
+ 0,
+ 0,
+ 16981,
+ 0,
+ 16983,
+ 16989,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16990,
+ 0,
+ 0,
+ 16991,
+ 0,
+ 0,
+ 0,
+ 16993,
+ 0,
+ 16994,
+ 16996,
+ 17000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17002,
+ 17004,
+ 0,
+ 17006,
+ 0,
+ 0,
+ 17007,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17008,
+ 17013,
+ 17014,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17021,
+ 0,
+ 17031,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17033,
+ 17036,
+ 0,
+ 17038,
+ 0,
+ 0,
+ 17039,
+ 0,
+ 17045,
+ 0,
+ 0,
+ 17046,
+ 17047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17048,
+ 0,
+ 17049,
+ 17050,
+ 0,
+ 17051,
+ 17053,
+ 0,
+ 17054,
+ 0,
+ 17055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17063,
+ 0,
+ 0,
+ 17064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17065,
+ 0,
+ 0,
+ 17068,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17073,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17074,
+ 0,
+ 17080,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17081,
+ 17083,
+ 17084,
+ 0,
+ 0,
+ 0,
+ 17085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17092,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17093,
+ 0,
+ 17095,
+ 17102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17103,
+ 0,
+ 0,
+ 17105,
+ 0,
+ 17107,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17114,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17115,
+ 17125,
+ 17127,
+ 0,
+ 0,
+ 17128,
+ 0,
+ 0,
+ 0,
+ 17129,
+ 17130,
+ 0,
+ 17131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17132,
+ 17135,
+ 17145,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17146,
+ 0,
+ 17147,
+ 0,
+ 17148,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17149,
+ 17150,
+ 0,
+ 17151,
+ 17153,
+ 0,
+ 17155,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17163,
+ 17171,
+ 0,
+ 17174,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17179,
+ 0,
+ 0,
+ 17182,
+ 17185,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17186,
+ 0,
+ 0,
+ 17188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17189,
+ 17191,
+ 0,
+ 17194,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17195,
+ 17196,
+ 17203,
+ 17204,
+ 0,
+ 0,
+ 17205,
+ 17217,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17219,
+ 0,
+ 17220,
+ 0,
+ 17221,
+ 0,
+ 0,
+ 17230,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17236,
+ 0,
+ 17238,
+ 17239,
+ 0,
+ 0,
+ 0,
+ 17241,
+ 17244,
+ 0,
+ 0,
+ 17245,
+ 0,
+ 17248,
+ 0,
+ 0,
+ 17251,
+ 0,
+ 17252,
+ 0,
+ 0,
+ 17264,
+ 0,
+ 17266,
+ 0,
+ 0,
+ 0,
+ 17268,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17271,
+ 17272,
+ 0,
+ 17273,
+ 0,
+ 17295,
+ 0,
+ 17302,
+ 0,
+ 17305,
+ 0,
+ 0,
+ 0,
+ 17306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17309,
+ 0,
+ 17310,
+ 17313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17314,
+ 17315,
+ 0,
+ 17317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17318,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17334,
+ 0,
+ 17344,
+ 17348,
+ 0,
+ 0,
+ 0,
+ 17350,
+ 17351,
+ 0,
+ 0,
+ 17353,
+ 0,
+ 0,
+ 17354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17356,
+ 17357,
+ 0,
+ 0,
+ 17359,
+ 0,
+ 0,
+ 0,
+ 17371,
+ 0,
+ 17372,
+ 0,
+ 0,
+ 0,
+ 17393,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17394,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17395,
+ 0,
+ 0,
+ 17399,
+ 0,
+ 0,
+ 0,
+ 17401,
+ 17417,
+ 0,
+ 17418,
+ 0,
+ 17419,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17422,
+ 17423,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17428,
+ 17429,
+ 17433,
+ 0,
+ 0,
+ 0,
+ 17437,
+ 0,
+ 0,
+ 17441,
+ 0,
+ 0,
+ 17442,
+ 0,
+ 0,
+ 17453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17454,
+ 17456,
+ 17462,
+ 0,
+ 0,
+ 17466,
+ 0,
+ 0,
+ 17468,
+ 0,
+ 0,
+ 17469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17470,
+ 0,
+ 17475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17479,
+ 0,
+ 0,
+ 0,
+ 17483,
+ 17484,
+ 0,
+ 17485,
+ 0,
+ 17486,
+ 0,
+ 17491,
+ 17492,
+ 0,
+ 0,
+ 17493,
+ 0,
+ 17494,
+ 17495,
+ 0,
+ 0,
+ 0,
+ 17496,
+ 0,
+ 0,
+ 0,
+ 17497,
+ 0,
+ 0,
+ 0,
+ 17502,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17503,
+ 0,
+ 17505,
+ 0,
+ 17507,
+ 0,
+ 0,
+ 0,
+ 17512,
+ 17513,
+ 17514,
+ 0,
+ 0,
+ 17515,
+ 0,
+ 0,
+ 0,
+ 17519,
+ 0,
+ 0,
+ 0,
+ 17522,
+ 0,
+ 0,
+ 17523,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17527,
+ 0,
+ 0,
+ 0,
+ 17528,
+ 0,
+ 0,
+ 0,
+ 17534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17536,
+ 0,
+ 0,
+ 0,
+ 17539,
+ 0,
+ 17540,
+ 17543,
+ 17549,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17556,
+ 0,
+ 0,
+ 17558,
+ 0,
+ 17559,
+ 0,
+ 0,
+ 17560,
+ 0,
+ 0,
+ 0,
+ 17563,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17564,
+ 0,
+ 0,
+ 17565,
+ 17566,
+ 0,
+ 17567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17569,
+ 17570,
+ 0,
+ 17575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17581,
+ 0,
+ 0,
+ 0,
+ 17582,
+ 17583,
+ 0,
+ 17586,
+ 0,
+ 0,
+ 17587,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17596,
+ 17597,
+ 0,
+ 0,
+ 17598,
+ 17600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17601,
+ 0,
+ 0,
+ 0,
+ 17604,
+ 0,
+ 0,
+ 17605,
+ 0,
+ 0,
+ 17607,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17612,
+ 0,
+ 0,
+ 17618,
+ 0,
+ 17621,
+ 17622,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17623,
+ 0,
+ 0,
+ 17624,
+ 0,
+ 0,
+ 17630,
+ 0,
+ 0,
+ 17631,
+ 17633,
+ 17634,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17635,
+ 0,
+ 0,
+ 17636,
+ 0,
+ 0,
+ 17637,
+ 0,
+ 17638,
+ 0,
+ 17640,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17641,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17645,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17646,
+ 17662,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17663,
+ 17664,
+ 0,
+ 17665,
+ 17666,
+ 0,
+ 0,
+ 0,
+ 17669,
+ 17671,
+ 17673,
+ 0,
+ 17679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17684,
+ 0,
+ 0,
+ 0,
+ 17686,
+ 0,
+ 17714,
+ 0,
+ 0,
+ 17720,
+ 17722,
+ 17726,
+ 0,
+ 0,
+ 17728,
+ 0,
+ 0,
+ 17729,
+ 0,
+ 0,
+ 0,
+ 17732,
+ 0,
+ 17733,
+ 0,
+ 17734,
+ 0,
+ 0,
+ 0,
+ 17735,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17737,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17739,
+ 0,
+ 0,
+ 0,
+ 17741,
+ 17742,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17743,
+ 17744,
+ 17745,
+ 0,
+ 0,
+ 0,
+ 17749,
+ 0,
+ 17750,
+ 17751,
+ 17752,
+ 17754,
+ 17761,
+ 17762,
+ 0,
+ 17763,
+ 0,
+ 17766,
+ 0,
+ 17772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17776,
+ 0,
+ 0,
+ 17777,
+ 0,
+ 0,
+ 17778,
+ 17779,
+ 0,
+ 17782,
+ 17783,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17784,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17821,
+ 0,
+ 0,
+ 0,
+ 17822,
+ 0,
+ 0,
+ 0,
+ 17823,
+ 17825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17826,
+ 17831,
+ 17832,
+ 17833,
+ 0,
+ 0,
+ 17845,
+ 0,
+ 0,
+ 0,
+ 17846,
+ 0,
+ 0,
+ 0,
+ 17848,
+ 17850,
+ 17854,
+ 0,
+ 17855,
+ 0,
+ 0,
+ 17859,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17860,
+ 17861,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17870,
+ 17871,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17872,
+ 0,
+ 0,
+ 0,
+ 17879,
+ 0,
+ 0,
+ 0,
+ 17881,
+ 17883,
+ 0,
+ 17884,
+ 0,
+ 17885,
+ 0,
+ 0,
+ 17886,
+ 0,
+ 0,
+ 17887,
+ 17891,
+ 17953,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17954,
+ 0,
+ 0,
+ 17955,
+ 0,
+ 17968,
+ 0,
+ 0,
+ 17972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17974,
+ 0,
+ 0,
+ 0,
+ 0,
+ 17976,
+ 17978,
+ 0,
+ 0,
+ 17983,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18003,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18007,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18009,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18010,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18012,
+ 0,
+ 0,
+ 18014,
+ 0,
+ 0,
+ 0,
+ 18015,
+ 0,
+ 0,
+ 0,
+ 18016,
+ 0,
+ 18017,
+ 0,
+ 0,
+ 0,
+ 18030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18031,
+ 0,
+ 0,
+ 18036,
+ 18037,
+ 18038,
+ 0,
+ 0,
+ 18049,
+ 18056,
+ 0,
+ 18057,
+ 18058,
+ 0,
+ 18059,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18062,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18067,
+ 0,
+ 0,
+ 0,
+ 18068,
+ 0,
+ 0,
+ 18075,
+ 0,
+ 0,
+ 18078,
+ 18093,
+ 18094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18097,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18098,
+ 18100,
+ 0,
+ 0,
+ 0,
+ 18108,
+ 0,
+ 18111,
+ 0,
+ 0,
+ 18112,
+ 0,
+ 18113,
+ 0,
+ 0,
+ 18115,
+ 18116,
+ 0,
+ 18118,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18121,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18123,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18124,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18125,
+ 18126,
+ 0,
+ 18127,
+ 0,
+ 0,
+ 18128,
+ 18135,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18150,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18151,
+ 18152,
+ 0,
+ 0,
+ 18156,
+ 18164,
+ 0,
+ 18166,
+ 18171,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18172,
+ 18183,
+ 0,
+ 18184,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18185,
+ 0,
+ 18187,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18189,
+ 0,
+ 0,
+ 18190,
+ 0,
+ 0,
+ 18191,
+ 18192,
+ 0,
+ 0,
+ 18194,
+ 18195,
+ 18196,
+ 0,
+ 0,
+ 0,
+ 18197,
+ 0,
+ 18203,
+ 0,
+ 18204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18205,
+ 0,
+ 0,
+ 0,
+ 18207,
+ 18208,
+ 0,
+ 0,
+ 18214,
+ 0,
+ 0,
+ 0,
+ 18215,
+ 18216,
+ 0,
+ 0,
+ 0,
+ 18220,
+ 0,
+ 0,
+ 18222,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18223,
+ 0,
+ 18225,
+ 18231,
+ 0,
+ 18234,
+ 0,
+ 18235,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18240,
+ 0,
+ 0,
+ 18241,
+ 18242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18243,
+ 18251,
+ 0,
+ 18253,
+ 0,
+ 18254,
+ 0,
+ 0,
+ 0,
+ 18266,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18269,
+ 18270,
+ 18271,
+ 18273,
+ 18281,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18282,
+ 0,
+ 18283,
+ 0,
+ 18284,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18285,
+ 0,
+ 18287,
+ 18289,
+ 0,
+ 0,
+ 18290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18308,
+ 0,
+ 0,
+ 0,
+ 18310,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18311,
+ 0,
+ 18312,
+ 18313,
+ 0,
+ 18315,
+ 0,
+ 0,
+ 18316,
+ 18320,
+ 0,
+ 18331,
+ 0,
+ 18332,
+ 0,
+ 18336,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18337,
+ 0,
+ 18340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18341,
+ 0,
+ 18344,
+ 18345,
+ 0,
+ 18346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18348,
+ 0,
+ 18351,
+ 0,
+ 0,
+ 18356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18367,
+ 0,
+ 0,
+ 0,
+ 18368,
+ 0,
+ 18369,
+ 0,
+ 18370,
+ 18371,
+ 0,
+ 0,
+ 0,
+ 18437,
+ 18444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18445,
+ 18450,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18451,
+ 0,
+ 18452,
+ 0,
+ 0,
+ 0,
+ 18453,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18455,
+ 0,
+ 0,
+ 0,
+ 18456,
+ 0,
+ 18457,
+ 0,
+ 18460,
+ 0,
+ 0,
+ 18461,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18466,
+ 0,
+ 0,
+ 18467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18473,
+ 0,
+ 0,
+ 0,
+ 18476,
+ 0,
+ 18477,
+ 0,
+ 0,
+ 0,
+ 18478,
+ 18479,
+ 18480,
+ 0,
+ 0,
+ 0,
+ 18485,
+ 0,
+ 0,
+ 0,
+ 18486,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18488,
+ 18490,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18491,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18495,
+ 0,
+ 0,
+ 18496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18505,
+ 0,
+ 18521,
+ 0,
+ 18522,
+ 18523,
+ 0,
+ 0,
+ 0,
+ 18525,
+ 18526,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18527,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18532,
+ 18533,
+ 0,
+ 18534,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18535,
+ 18537,
+ 0,
+ 18538,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18540,
+ 18541,
+ 18542,
+ 18543,
+ 0,
+ 18546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18553,
+ 18556,
+ 0,
+ 0,
+ 18558,
+ 0,
+ 0,
+ 18569,
+ 18571,
+ 0,
+ 0,
+ 0,
+ 18572,
+ 0,
+ 18574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18586,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18588,
+ 0,
+ 0,
+ 18589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18590,
+ 0,
+ 18592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18594,
+ 0,
+ 0,
+ 0,
+ 18596,
+ 0,
+ 0,
+ 18597,
+ 18598,
+ 0,
+ 0,
+ 18601,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18602,
+ 0,
+ 0,
+ 0,
+ 18603,
+ 18604,
+ 0,
+ 18605,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18608,
+ 0,
+ 0,
+ 18611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18612,
+ 0,
+ 18616,
+ 0,
+ 0,
+ 18617,
+ 18619,
+ 0,
+ 0,
+ 0,
+ 18628,
+ 0,
+ 0,
+ 0,
+ 18629,
+ 0,
+ 0,
+ 18630,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18631,
+ 0,
+ 18632,
+ 0,
+ 0,
+ 18635,
+ 18637,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18641,
+ 18643,
+ 18648,
+ 0,
+ 18652,
+ 0,
+ 0,
+ 18653,
+ 0,
+ 18655,
+ 18656,
+ 0,
+ 0,
+ 0,
+ 18657,
+ 0,
+ 0,
+ 18666,
+ 18674,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18677,
+ 18684,
+ 18685,
+ 0,
+ 0,
+ 18686,
+ 0,
+ 0,
+ 18690,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18695,
+ 18696,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18697,
+ 0,
+ 0,
+ 18700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18702,
+ 0,
+ 18708,
+ 0,
+ 0,
+ 18709,
+ 0,
+ 18710,
+ 0,
+ 0,
+ 18711,
+ 0,
+ 18714,
+ 0,
+ 0,
+ 18718,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18719,
+ 0,
+ 0,
+ 18722,
+ 0,
+ 18726,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18739,
+ 18741,
+ 0,
+ 0,
+ 18742,
+ 0,
+ 18743,
+ 18744,
+ 18746,
+ 18748,
+ 0,
+ 18752,
+ 18753,
+ 0,
+ 0,
+ 18754,
+ 18763,
+ 0,
+ 18765,
+ 0,
+ 0,
+ 0,
+ 18766,
+ 0,
+ 0,
+ 0,
+ 18769,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18773,
+ 18778,
+ 18779,
+ 18781,
+ 0,
+ 0,
+ 18784,
+ 18787,
+ 0,
+ 18788,
+ 0,
+ 18793,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18795,
+ 0,
+ 0,
+ 18800,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18801,
+ 18804,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18806,
+ 0,
+ 0,
+ 0,
+ 18811,
+ 18815,
+ 18816,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18825,
+ 0,
+ 0,
+ 18827,
+ 18829,
+ 0,
+ 0,
+ 18830,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18831,
+ 0,
+ 0,
+ 18832,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18833,
+ 0,
+ 18840,
+ 0,
+ 18841,
+ 0,
+ 18842,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18843,
+ 0,
+ 18844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18845,
+ 18846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18848,
+ 0,
+ 0,
+ 0,
+ 18853,
+ 18860,
+ 0,
+ 0,
+ 18862,
+ 18866,
+ 0,
+ 0,
+ 18867,
+ 18869,
+ 0,
+ 0,
+ 18874,
+ 18881,
+ 18891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18895,
+ 0,
+ 18896,
+ 0,
+ 0,
+ 0,
+ 18900,
+ 0,
+ 0,
+ 0,
+ 18901,
+ 0,
+ 18902,
+ 18915,
+ 18916,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18919,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18920,
+ 0,
+ 0,
+ 0,
+ 18921,
+ 18929,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18930,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18932,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18934,
+ 18942,
+ 0,
+ 0,
+ 0,
+ 18951,
+ 18957,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18958,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18959,
+ 18960,
+ 0,
+ 0,
+ 18961,
+ 0,
+ 0,
+ 18962,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18963,
+ 18964,
+ 0,
+ 0,
+ 0,
+ 18965,
+ 0,
+ 18967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18968,
+ 0,
+ 18969,
+ 0,
+ 18970,
+ 18973,
+ 18976,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18977,
+ 0,
+ 0,
+ 0,
+ 18981,
+ 0,
+ 0,
+ 0,
+ 18990,
+ 0,
+ 18998,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 18999,
+ 19003,
+ 0,
+ 0,
+ 19005,
+ 0,
+ 0,
+ 0,
+ 19006,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19008,
+ 19011,
+ 0,
+ 0,
+ 19018,
+ 0,
+ 0,
+ 19019,
+ 0,
+ 19024,
+ 0,
+ 19031,
+ 19032,
+ 0,
+ 19039,
+ 0,
+ 19041,
+ 19050,
+ 0,
+ 0,
+ 0,
+ 19051,
+ 19055,
+ 19056,
+ 0,
+ 19059,
+ 19063,
+ 19064,
+ 0,
+ 0,
+ 19088,
+ 0,
+ 0,
+ 0,
+ 19093,
+ 19094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19095,
+ 0,
+ 19096,
+ 0,
+ 0,
+ 0,
+ 19097,
+ 0,
+ 0,
+ 19098,
+ 0,
+ 19099,
+ 19100,
+ 0,
+ 0,
+ 19103,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19111,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19112,
+ 0,
+ 0,
+ 0,
+ 19116,
+ 19117,
+ 0,
+ 19121,
+ 19122,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19123,
+ 19124,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19125,
+ 19126,
+ 0,
+ 19128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19129,
+ 19130,
+ 19131,
+ 19132,
+ 0,
+ 0,
+ 19146,
+ 0,
+ 0,
+ 19147,
+ 19156,
+ 19158,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19182,
+ 19185,
+ 0,
+ 0,
+ 19187,
+ 0,
+ 0,
+ 0,
+ 19193,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19194,
+ 0,
+ 19197,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19203,
+ 0,
+ 19205,
+ 19210,
+ 0,
+ 0,
+ 0,
+ 19213,
+ 0,
+ 19218,
+ 0,
+ 0,
+ 0,
+ 19223,
+ 19229,
+ 0,
+ 0,
+ 19230,
+ 0,
+ 0,
+ 19231,
+ 19232,
+ 19233,
+ 19239,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19240,
+ 0,
+ 19248,
+ 19249,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19254,
+ 0,
+ 19256,
+ 19258,
+ 19259,
+ 0,
+ 0,
+ 19261,
+ 0,
+ 19266,
+ 0,
+ 0,
+ 0,
+ 19272,
+ 0,
+ 19278,
+ 19281,
+ 19282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19283,
+ 0,
+ 0,
+ 19284,
+ 0,
+ 0,
+ 19285,
+ 19287,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19288,
+ 19291,
+ 0,
+ 19292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19297,
+ 0,
+ 19298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19302,
+ 19303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19304,
+ 19305,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19314,
+ 0,
+ 0,
+ 19315,
+ 0,
+ 0,
+ 19321,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19322,
+ 0,
+ 19333,
+ 0,
+ 19334,
+ 19335,
+ 0,
+ 19336,
+ 19337,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19346,
+ 0,
+ 0,
+ 19353,
+ 0,
+ 19354,
+ 19362,
+ 0,
+ 19366,
+ 19367,
+ 0,
+ 0,
+ 19369,
+ 0,
+ 19375,
+ 0,
+ 19377,
+ 19380,
+ 19388,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19389,
+ 19390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19392,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19412,
+ 0,
+ 0,
+ 19413,
+ 19422,
+ 0,
+ 19424,
+ 0,
+ 0,
+ 0,
+ 19425,
+ 0,
+ 0,
+ 0,
+ 19428,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19431,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19448,
+ 19459,
+ 0,
+ 0,
+ 19461,
+ 0,
+ 19462,
+ 19463,
+ 0,
+ 19467,
+ 19474,
+ 19482,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19494,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19501,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19502,
+ 19504,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19505,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19506,
+ 19507,
+ 0,
+ 0,
+ 0,
+ 19508,
+ 0,
+ 0,
+ 19511,
+ 0,
+ 0,
+ 19514,
+ 0,
+ 19515,
+ 0,
+ 19516,
+ 0,
+ 19518,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19530,
+ 0,
+ 19537,
+ 19538,
+ 0,
+ 19543,
+ 19546,
+ 0,
+ 19547,
+ 19551,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19552,
+ 19553,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19555,
+ 0,
+ 0,
+ 19556,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19560,
+ 19561,
+ 0,
+ 0,
+ 19562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19565,
+ 19567,
+ 0,
+ 19568,
+ 0,
+ 0,
+ 0,
+ 19569,
+ 19570,
+ 0,
+ 19578,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19580,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19581,
+ 19584,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19585,
+ 19586,
+ 0,
+ 0,
+ 0,
+ 19587,
+ 19588,
+ 0,
+ 19589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19592,
+ 19593,
+ 19599,
+ 0,
+ 19600,
+ 0,
+ 0,
+ 19604,
+ 0,
+ 0,
+ 19605,
+ 0,
+ 19606,
+ 19608,
+ 19610,
+ 0,
+ 19613,
+ 19614,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19616,
+ 19617,
+ 0,
+ 0,
+ 19618,
+ 0,
+ 0,
+ 19619,
+ 0,
+ 0,
+ 0,
+ 19620,
+ 19621,
+ 19631,
+ 0,
+ 0,
+ 19632,
+ 19634,
+ 19636,
+ 0,
+ 19643,
+ 0,
+ 0,
+ 19644,
+ 19658,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19659,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19675,
+ 19677,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19679,
+ 0,
+ 19683,
+ 0,
+ 19684,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19687,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19688,
+ 19689,
+ 19692,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19695,
+ 19697,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19698,
+ 19699,
+ 0,
+ 0,
+ 19700,
+ 0,
+ 19702,
+ 0,
+ 0,
+ 19703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19704,
+ 19708,
+ 0,
+ 19710,
+ 0,
+ 19713,
+ 0,
+ 0,
+ 0,
+ 19715,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19718,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19720,
+ 0,
+ 19722,
+ 0,
+ 0,
+ 19725,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19730,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19731,
+ 0,
+ 19734,
+ 19735,
+ 19739,
+ 0,
+ 0,
+ 19740,
+ 0,
+ 19741,
+ 0,
+ 0,
+ 0,
+ 19746,
+ 0,
+ 0,
+ 19747,
+ 0,
+ 19771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19772,
+ 19775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19778,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19779,
+ 0,
+ 0,
+ 19780,
+ 19790,
+ 0,
+ 19791,
+ 0,
+ 0,
+ 19792,
+ 0,
+ 0,
+ 0,
+ 19793,
+ 0,
+ 0,
+ 19796,
+ 19797,
+ 0,
+ 0,
+ 0,
+ 19799,
+ 0,
+ 0,
+ 0,
+ 19801,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19803,
+ 0,
+ 19804,
+ 0,
+ 19805,
+ 0,
+ 0,
+ 19807,
+ 0,
+ 0,
+ 0,
+ 19808,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19809,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19816,
+ 0,
+ 19821,
+ 0,
+ 19822,
+ 19830,
+ 19831,
+ 0,
+ 0,
+ 0,
+ 19833,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19838,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19839,
+ 0,
+ 0,
+ 19843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19847,
+ 0,
+ 0,
+ 19848,
+ 0,
+ 19849,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19851,
+ 0,
+ 0,
+ 0,
+ 19854,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19864,
+ 0,
+ 19865,
+ 0,
+ 19866,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19868,
+ 0,
+ 0,
+ 19870,
+ 0,
+ 0,
+ 19871,
+ 0,
+ 0,
+ 19872,
+ 19873,
+ 19875,
+ 0,
+ 19880,
+ 19882,
+ 19884,
+ 0,
+ 0,
+ 19885,
+ 19886,
+ 19888,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19890,
+ 19892,
+ 19893,
+ 0,
+ 0,
+ 19894,
+ 0,
+ 0,
+ 0,
+ 19895,
+ 0,
+ 19896,
+ 19902,
+ 0,
+ 0,
+ 19903,
+ 0,
+ 0,
+ 19905,
+ 0,
+ 0,
+ 0,
+ 19906,
+ 0,
+ 19908,
+ 0,
+ 19909,
+ 19911,
+ 0,
+ 0,
+ 0,
+ 19913,
+ 19920,
+ 0,
+ 19938,
+ 19939,
+ 19940,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19942,
+ 0,
+ 19943,
+ 0,
+ 19945,
+ 0,
+ 0,
+ 0,
+ 19951,
+ 19952,
+ 19954,
+ 19960,
+ 0,
+ 19965,
+ 0,
+ 19971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 19975,
+ 0,
+ 19976,
+ 0,
+ 19990,
+ 0,
+ 0,
+ 19991,
+ 0,
+ 19993,
+ 0,
+ 19995,
+ 0,
+ 0,
+ 0,
+ 19998,
+ 19999,
+ 20001,
+ 0,
+ 20003,
+ 20005,
+ 0,
+ 20011,
+ 20012,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20014,
+ 0,
+ 20020,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20023,
+ 20024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20025,
+ 0,
+ 0,
+ 20027,
+ 0,
+ 0,
+ 20029,
+ 0,
+ 0,
+ 20032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20044,
+ 20045,
+ 0,
+ 20048,
+ 20049,
+ 0,
+ 0,
+ 20050,
+ 0,
+ 20052,
+ 0,
+ 0,
+ 20054,
+ 20057,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20059,
+ 0,
+ 0,
+ 20061,
+ 0,
+ 20062,
+ 0,
+ 20064,
+ 0,
+ 0,
+ 20066,
+ 0,
+ 0,
+ 20067,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20069,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20070,
+ 20071,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20072,
+ 0,
+ 0,
+ 20073,
+ 20074,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20075,
+ 0,
+ 20078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20080,
+ 0,
+ 20081,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20095,
+ 0,
+ 20098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20107,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20112,
+ 0,
+ 0,
+ 0,
+ 20113,
+ 20114,
+ 0,
+ 0,
+ 0,
+ 20115,
+ 20123,
+ 20124,
+ 0,
+ 0,
+ 0,
+ 20131,
+ 20133,
+ 20134,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20136,
+ 0,
+ 0,
+ 20137,
+ 20138,
+ 20150,
+ 0,
+ 20152,
+ 0,
+ 0,
+ 0,
+ 20153,
+ 0,
+ 0,
+ 20154,
+ 0,
+ 0,
+ 0,
+ 20158,
+ 0,
+ 20163,
+ 0,
+ 0,
+ 20164,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20166,
+ 0,
+ 20168,
+ 0,
+ 20170,
+ 0,
+ 20175,
+ 0,
+ 0,
+ 20178,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20223,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20224,
+ 0,
+ 20226,
+ 0,
+ 0,
+ 20230,
+ 0,
+ 20231,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20232,
+ 0,
+ 0,
+ 20233,
+ 20234,
+ 0,
+ 20244,
+ 0,
+ 20247,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20249,
+ 0,
+ 0,
+ 0,
+ 20250,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20251,
+ 0,
+ 20253,
+ 0,
+ 20254,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20256,
+ 0,
+ 0,
+ 20264,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20266,
+ 0,
+ 0,
+ 0,
+ 20278,
+ 0,
+ 0,
+ 20279,
+ 20282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20283,
+ 0,
+ 20284,
+ 0,
+ 20285,
+ 0,
+ 20287,
+ 20290,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20293,
+ 20297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20299,
+ 0,
+ 20300,
+ 20303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20307,
+ 0,
+ 0,
+ 20308,
+ 0,
+ 20309,
+ 0,
+ 20310,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20312,
+ 0,
+ 0,
+ 0,
+ 20314,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20315,
+ 20316,
+ 0,
+ 20322,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20339,
+ 0,
+ 0,
+ 0,
+ 20342,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20352,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20362,
+ 0,
+ 0,
+ 20365,
+ 0,
+ 20375,
+ 20377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20378,
+ 20379,
+ 0,
+ 20380,
+ 0,
+ 0,
+ 20381,
+ 0,
+ 20382,
+ 0,
+ 20383,
+ 0,
+ 20388,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20390,
+ 20392,
+ 20393,
+ 0,
+ 0,
+ 20395,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20396,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20398,
+ 20415,
+ 0,
+ 0,
+ 0,
+ 20417,
+ 0,
+ 0,
+ 20420,
+ 0,
+ 0,
+ 20426,
+ 20428,
+ 0,
+ 20431,
+ 0,
+ 0,
+ 20432,
+ 0,
+ 20433,
+ 20434,
+ 20435,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20442,
+ 0,
+ 20443,
+ 0,
+ 20446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20448,
+ 0,
+ 20451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20452,
+ 20453,
+ 0,
+ 0,
+ 20454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20457,
+ 0,
+ 20458,
+ 0,
+ 0,
+ 0,
+ 20465,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20469,
+ 0,
+ 0,
+ 0,
+ 20473,
+ 0,
+ 20476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20477,
+ 0,
+ 0,
+ 20485,
+ 0,
+ 0,
+ 20486,
+ 0,
+ 0,
+ 20487,
+ 0,
+ 20496,
+ 0,
+ 20497,
+ 0,
+ 0,
+ 20498,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20499,
+ 20500,
+ 0,
+ 20501,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20520,
+ 20527,
+ 0,
+ 20529,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20539,
+ 0,
+ 0,
+ 20540,
+ 0,
+ 0,
+ 0,
+ 20543,
+ 0,
+ 0,
+ 0,
+ 20546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20548,
+ 0,
+ 0,
+ 20563,
+ 0,
+ 0,
+ 20564,
+ 0,
+ 20566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20590,
+ 0,
+ 0,
+ 20593,
+ 20594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20595,
+ 0,
+ 20597,
+ 20598,
+ 0,
+ 0,
+ 0,
+ 20618,
+ 20620,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20621,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20628,
+ 0,
+ 0,
+ 0,
+ 20629,
+ 0,
+ 20630,
+ 0,
+ 0,
+ 20639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20707,
+ 0,
+ 0,
+ 20709,
+ 0,
+ 0,
+ 0,
+ 20713,
+ 20714,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20724,
+ 20725,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20726,
+ 20728,
+ 20729,
+ 0,
+ 20733,
+ 0,
+ 20734,
+ 0,
+ 20735,
+ 20736,
+ 0,
+ 20737,
+ 0,
+ 0,
+ 20744,
+ 0,
+ 20745,
+ 0,
+ 20748,
+ 0,
+ 0,
+ 20749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20754,
+ 0,
+ 0,
+ 0,
+ 20761,
+ 0,
+ 0,
+ 20763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20766,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20768,
+ 0,
+ 20769,
+ 20777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20785,
+ 0,
+ 0,
+ 0,
+ 20786,
+ 20795,
+ 20801,
+ 0,
+ 20802,
+ 0,
+ 20807,
+ 0,
+ 0,
+ 20808,
+ 0,
+ 0,
+ 20810,
+ 0,
+ 0,
+ 20811,
+ 0,
+ 20812,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20813,
+ 0,
+ 0,
+ 20818,
+ 20820,
+ 20821,
+ 0,
+ 0,
+ 0,
+ 20822,
+ 0,
+ 20823,
+ 0,
+ 0,
+ 0,
+ 20826,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20829,
+ 20830,
+ 20831,
+ 0,
+ 20832,
+ 20836,
+ 0,
+ 0,
+ 20839,
+ 0,
+ 0,
+ 20840,
+ 20842,
+ 0,
+ 20843,
+ 0,
+ 20844,
+ 0,
+ 20854,
+ 0,
+ 0,
+ 0,
+ 20855,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20856,
+ 0,
+ 0,
+ 0,
+ 20869,
+ 0,
+ 0,
+ 20871,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20873,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20876,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20880,
+ 0,
+ 0,
+ 20882,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20883,
+ 20884,
+ 0,
+ 0,
+ 20890,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20905,
+ 0,
+ 20906,
+ 20910,
+ 0,
+ 0,
+ 20912,
+ 20915,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20916,
+ 0,
+ 20917,
+ 0,
+ 20919,
+ 20920,
+ 20922,
+ 0,
+ 20927,
+ 0,
+ 20928,
+ 20929,
+ 20930,
+ 0,
+ 0,
+ 20935,
+ 0,
+ 0,
+ 20939,
+ 0,
+ 0,
+ 20941,
+ 0,
+ 0,
+ 0,
+ 20943,
+ 0,
+ 0,
+ 0,
+ 20946,
+ 20947,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20950,
+ 0,
+ 20954,
+ 0,
+ 0,
+ 20955,
+ 20964,
+ 0,
+ 0,
+ 20967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20973,
+ 20975,
+ 0,
+ 0,
+ 0,
+ 20984,
+ 0,
+ 20987,
+ 20988,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 20989,
+ 0,
+ 0,
+ 0,
+ 20995,
+ 0,
+ 20998,
+ 0,
+ 20999,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21000,
+ 21001,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21008,
+ 0,
+ 21010,
+ 0,
+ 21016,
+ 0,
+ 0,
+ 0,
+ 21017,
+ 21018,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21021,
+ 21026,
+ 21027,
+ 21028,
+ 0,
+ 0,
+ 21029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21031,
+ 21032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21037,
+ 0,
+ 0,
+ 21038,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21039,
+ 0,
+ 21041,
+ 0,
+ 21046,
+ 21047,
+ 0,
+ 0,
+ 0,
+ 21049,
+ 21053,
+ 0,
+ 0,
+ 21057,
+ 21064,
+ 21065,
+ 0,
+ 0,
+ 21066,
+ 21067,
+ 0,
+ 0,
+ 0,
+ 21069,
+ 0,
+ 0,
+ 0,
+ 21071,
+ 21072,
+ 0,
+ 0,
+ 21073,
+ 0,
+ 21074,
+ 0,
+ 0,
+ 21078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21079,
+ 0,
+ 0,
+ 21080,
+ 21081,
+ 0,
+ 0,
+ 21086,
+ 21087,
+ 0,
+ 21089,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21091,
+ 0,
+ 21093,
+ 0,
+ 21094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21095,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21096,
+ 0,
+ 21098,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21099,
+ 0,
+ 0,
+ 21100,
+ 21101,
+ 21102,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21103,
+ 0,
+ 21104,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21105,
+ 21108,
+ 21109,
+ 0,
+ 0,
+ 21112,
+ 21113,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21115,
+ 21122,
+ 21123,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21129,
+ 21131,
+ 0,
+ 0,
+ 21134,
+ 0,
+ 0,
+ 0,
+ 21137,
+ 21142,
+ 0,
+ 21143,
+ 0,
+ 0,
+ 21144,
+ 0,
+ 21145,
+ 21146,
+ 0,
+ 21152,
+ 21154,
+ 21155,
+ 21156,
+ 0,
+ 0,
+ 0,
+ 21160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21161,
+ 0,
+ 21164,
+ 0,
+ 21166,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21170,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21171,
+ 0,
+ 0,
+ 21172,
+ 0,
+ 21174,
+ 0,
+ 21175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21176,
+ 21179,
+ 21188,
+ 0,
+ 0,
+ 0,
+ 21189,
+ 0,
+ 0,
+ 21190,
+ 0,
+ 0,
+ 0,
+ 21192,
+ 0,
+ 0,
+ 21193,
+ 0,
+ 0,
+ 0,
+ 21198,
+ 0,
+ 21212,
+ 0,
+ 0,
+ 21213,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21215,
+ 21216,
+ 0,
+ 0,
+ 21223,
+ 21225,
+ 0,
+ 21226,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21227,
+ 21228,
+ 0,
+ 0,
+ 21229,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21230,
+ 21236,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21237,
+ 0,
+ 0,
+ 21238,
+ 21239,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21256,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21259,
+ 0,
+ 0,
+ 0,
+ 21263,
+ 0,
+ 21272,
+ 0,
+ 21274,
+ 0,
+ 21282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21283,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21294,
+ 0,
+ 0,
+ 21297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21298,
+ 0,
+ 0,
+ 0,
+ 21299,
+ 0,
+ 21300,
+ 21302,
+ 0,
+ 21316,
+ 0,
+ 21318,
+ 21322,
+ 21323,
+ 0,
+ 21324,
+ 0,
+ 21326,
+ 0,
+ 0,
+ 0,
+ 21327,
+ 21328,
+ 0,
+ 0,
+ 0,
+ 21352,
+ 0,
+ 0,
+ 21354,
+ 21361,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21362,
+ 0,
+ 0,
+ 0,
+ 21363,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21366,
+ 0,
+ 0,
+ 21367,
+ 21372,
+ 21374,
+ 0,
+ 0,
+ 0,
+ 21375,
+ 21377,
+ 0,
+ 21378,
+ 0,
+ 0,
+ 0,
+ 21380,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21381,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21382,
+ 0,
+ 21383,
+ 0,
+ 0,
+ 21384,
+ 0,
+ 0,
+ 21385,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21389,
+ 21390,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21397,
+ 21398,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21399,
+ 0,
+ 21400,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21402,
+ 0,
+ 0,
+ 0,
+ 21403,
+ 21404,
+ 0,
+ 21405,
+ 21406,
+ 0,
+ 0,
+ 0,
+ 21407,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21408,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21409,
+ 0,
+ 21421,
+ 0,
+ 21422,
+ 0,
+ 0,
+ 0,
+ 21425,
+ 21428,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21429,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21434,
+ 0,
+ 21443,
+ 0,
+ 21444,
+ 21449,
+ 0,
+ 21452,
+ 0,
+ 21453,
+ 21454,
+ 0,
+ 0,
+ 0,
+ 21457,
+ 0,
+ 0,
+ 21458,
+ 0,
+ 0,
+ 0,
+ 21460,
+ 21461,
+ 0,
+ 0,
+ 21464,
+ 0,
+ 0,
+ 0,
+ 21473,
+ 21478,
+ 0,
+ 0,
+ 21479,
+ 0,
+ 0,
+ 21481,
+ 21483,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21484,
+ 0,
+ 0,
+ 21485,
+ 21486,
+ 0,
+ 0,
+ 21488,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21523,
+ 0,
+ 0,
+ 21525,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21526,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21529,
+ 21530,
+ 0,
+ 0,
+ 21531,
+ 0,
+ 0,
+ 21533,
+ 0,
+ 0,
+ 21539,
+ 21564,
+ 0,
+ 21567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21577,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21591,
+ 0,
+ 0,
+ 21604,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21605,
+ 0,
+ 21606,
+ 0,
+ 0,
+ 21617,
+ 21618,
+ 21619,
+ 21620,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21623,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21631,
+ 0,
+ 21635,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21639,
+ 21646,
+ 21653,
+ 21662,
+ 0,
+ 0,
+ 21663,
+ 21664,
+ 0,
+ 21666,
+ 0,
+ 0,
+ 21667,
+ 0,
+ 21670,
+ 21672,
+ 21673,
+ 0,
+ 21674,
+ 21683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21684,
+ 0,
+ 21694,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21695,
+ 21700,
+ 0,
+ 21703,
+ 0,
+ 21704,
+ 0,
+ 0,
+ 21709,
+ 0,
+ 0,
+ 0,
+ 21710,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21711,
+ 0,
+ 0,
+ 0,
+ 21712,
+ 0,
+ 21717,
+ 0,
+ 21730,
+ 0,
+ 0,
+ 0,
+ 21731,
+ 21733,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21737,
+ 21741,
+ 21742,
+ 0,
+ 21747,
+ 0,
+ 0,
+ 0,
+ 21749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21752,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21755,
+ 21756,
+ 0,
+ 21757,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21760,
+ 0,
+ 0,
+ 21763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21764,
+ 0,
+ 0,
+ 21766,
+ 0,
+ 0,
+ 21767,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21773,
+ 0,
+ 21774,
+ 0,
+ 0,
+ 21775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21776,
+ 0,
+ 0,
+ 21777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21780,
+ 21787,
+ 21788,
+ 21791,
+ 0,
+ 0,
+ 0,
+ 21797,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21805,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21806,
+ 0,
+ 21807,
+ 21809,
+ 0,
+ 21810,
+ 21811,
+ 0,
+ 21817,
+ 21819,
+ 21820,
+ 0,
+ 21823,
+ 0,
+ 21824,
+ 0,
+ 0,
+ 21825,
+ 0,
+ 0,
+ 21826,
+ 21832,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21833,
+ 21848,
+ 21849,
+ 0,
+ 0,
+ 21867,
+ 21870,
+ 21871,
+ 21873,
+ 0,
+ 0,
+ 0,
+ 21874,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21875,
+ 0,
+ 21878,
+ 0,
+ 0,
+ 0,
+ 21879,
+ 0,
+ 21881,
+ 21886,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21887,
+ 0,
+ 0,
+ 21888,
+ 21894,
+ 21895,
+ 21897,
+ 0,
+ 21901,
+ 0,
+ 21904,
+ 0,
+ 0,
+ 21906,
+ 0,
+ 0,
+ 0,
+ 21909,
+ 21910,
+ 21911,
+ 0,
+ 0,
+ 21912,
+ 0,
+ 0,
+ 21913,
+ 21914,
+ 21915,
+ 0,
+ 21919,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21921,
+ 0,
+ 0,
+ 21922,
+ 21933,
+ 21939,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21945,
+ 0,
+ 21947,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21949,
+ 0,
+ 0,
+ 0,
+ 21950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21951,
+ 0,
+ 21952,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21954,
+ 21957,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21958,
+ 0,
+ 21959,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21962,
+ 21963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21964,
+ 21965,
+ 0,
+ 0,
+ 21969,
+ 21970,
+ 0,
+ 0,
+ 0,
+ 21974,
+ 0,
+ 0,
+ 21980,
+ 21981,
+ 0,
+ 21982,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 21985,
+ 0,
+ 21988,
+ 0,
+ 21992,
+ 0,
+ 21999,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22001,
+ 0,
+ 22002,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22003,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22004,
+ 0,
+ 0,
+ 0,
+ 22008,
+ 0,
+ 22009,
+ 22015,
+ 0,
+ 0,
+ 22016,
+ 0,
+ 0,
+ 0,
+ 22017,
+ 22019,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22020,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22021,
+ 22037,
+ 0,
+ 22039,
+ 0,
+ 0,
+ 0,
+ 22040,
+ 0,
+ 0,
+ 0,
+ 22048,
+ 22049,
+ 0,
+ 0,
+ 22053,
+ 22055,
+ 22056,
+ 22059,
+ 0,
+ 0,
+ 22060,
+ 22061,
+ 0,
+ 0,
+ 22064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22073,
+ 0,
+ 0,
+ 0,
+ 22074,
+ 22075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22076,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22077,
+ 22084,
+ 22099,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22104,
+ 0,
+ 0,
+ 22107,
+ 0,
+ 22108,
+ 0,
+ 22109,
+ 0,
+ 22110,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22111,
+ 22119,
+ 0,
+ 22120,
+ 22122,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22125,
+ 0,
+ 0,
+ 0,
+ 22128,
+ 22129,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22141,
+ 0,
+ 0,
+ 0,
+ 22142,
+ 0,
+ 0,
+ 22144,
+ 22146,
+ 0,
+ 22148,
+ 22149,
+ 22151,
+ 22154,
+ 0,
+ 0,
+ 0,
+ 22162,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22164,
+ 22177,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22179,
+ 0,
+ 22182,
+ 22183,
+ 0,
+ 0,
+ 22184,
+ 22188,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22190,
+ 0,
+ 22194,
+ 22201,
+ 0,
+ 0,
+ 22208,
+ 0,
+ 22209,
+ 0,
+ 22212,
+ 0,
+ 0,
+ 22215,
+ 0,
+ 22223,
+ 22231,
+ 0,
+ 0,
+ 22232,
+ 0,
+ 22234,
+ 0,
+ 0,
+ 22235,
+ 22236,
+ 0,
+ 22237,
+ 0,
+ 22240,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22241,
+ 0,
+ 0,
+ 0,
+ 22242,
+ 22246,
+ 22247,
+ 0,
+ 0,
+ 0,
+ 22259,
+ 22268,
+ 0,
+ 22269,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22270,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22271,
+ 0,
+ 22272,
+ 0,
+ 22277,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22278,
+ 22280,
+ 22283,
+ 22286,
+ 0,
+ 0,
+ 22287,
+ 22289,
+ 0,
+ 0,
+ 22290,
+ 0,
+ 22293,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22295,
+ 0,
+ 22301,
+ 22302,
+ 0,
+ 0,
+ 0,
+ 22305,
+ 0,
+ 22308,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22315,
+ 0,
+ 0,
+ 0,
+ 22317,
+ 0,
+ 22334,
+ 0,
+ 0,
+ 0,
+ 22335,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22336,
+ 0,
+ 22338,
+ 22344,
+ 0,
+ 22347,
+ 22349,
+ 0,
+ 22350,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22358,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22359,
+ 22360,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22361,
+ 22366,
+ 0,
+ 0,
+ 22369,
+ 0,
+ 22370,
+ 22373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22375,
+ 0,
+ 22377,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22378,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22381,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22382,
+ 0,
+ 22383,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22391,
+ 0,
+ 0,
+ 22392,
+ 22395,
+ 22396,
+ 22402,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22405,
+ 0,
+ 0,
+ 22406,
+ 0,
+ 0,
+ 22408,
+ 0,
+ 0,
+ 22409,
+ 22410,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22426,
+ 0,
+ 0,
+ 0,
+ 22427,
+ 0,
+ 22428,
+ 0,
+ 22432,
+ 0,
+ 22435,
+ 22442,
+ 22443,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22446,
+ 0,
+ 22454,
+ 0,
+ 22455,
+ 0,
+ 0,
+ 0,
+ 22465,
+ 0,
+ 22470,
+ 0,
+ 22471,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22472,
+ 22473,
+ 0,
+ 22487,
+ 0,
+ 0,
+ 0,
+ 22488,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22489,
+ 0,
+ 0,
+ 22499,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22514,
+ 0,
+ 0,
+ 22515,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22516,
+ 0,
+ 0,
+ 0,
+ 22517,
+ 22520,
+ 0,
+ 0,
+ 0,
+ 22534,
+ 0,
+ 0,
+ 22535,
+ 0,
+ 0,
+ 22536,
+ 0,
+ 22540,
+ 22553,
+ 0,
+ 22555,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22561,
+ 0,
+ 0,
+ 22562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22567,
+ 22568,
+ 0,
+ 0,
+ 22575,
+ 0,
+ 22579,
+ 0,
+ 22582,
+ 22583,
+ 22585,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22586,
+ 0,
+ 0,
+ 22587,
+ 0,
+ 0,
+ 22590,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22591,
+ 0,
+ 22592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22593,
+ 0,
+ 22602,
+ 0,
+ 0,
+ 22604,
+ 0,
+ 0,
+ 22609,
+ 0,
+ 0,
+ 22618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22619,
+ 0,
+ 22624,
+ 22625,
+ 0,
+ 0,
+ 22638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22639,
+ 0,
+ 0,
+ 22640,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22644,
+ 0,
+ 22645,
+ 22647,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22652,
+ 22653,
+ 0,
+ 0,
+ 0,
+ 22654,
+ 0,
+ 22655,
+ 0,
+ 0,
+ 0,
+ 22656,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22673,
+ 22675,
+ 22676,
+ 0,
+ 0,
+ 22678,
+ 22679,
+ 0,
+ 22691,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22693,
+ 0,
+ 0,
+ 22696,
+ 0,
+ 22699,
+ 22707,
+ 22708,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22718,
+ 0,
+ 22719,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22723,
+ 0,
+ 0,
+ 0,
+ 22724,
+ 22725,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22726,
+ 22728,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22729,
+ 0,
+ 0,
+ 22731,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22732,
+ 22735,
+ 22736,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22739,
+ 0,
+ 22749,
+ 0,
+ 0,
+ 22751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22758,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22764,
+ 22765,
+ 22766,
+ 0,
+ 22768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22769,
+ 22770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22771,
+ 0,
+ 0,
+ 22772,
+ 22775,
+ 0,
+ 22776,
+ 22777,
+ 22780,
+ 0,
+ 0,
+ 22782,
+ 22784,
+ 0,
+ 22787,
+ 0,
+ 22789,
+ 22796,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22798,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22802,
+ 0,
+ 22803,
+ 22804,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22805,
+ 0,
+ 0,
+ 22810,
+ 22811,
+ 22814,
+ 22816,
+ 0,
+ 22825,
+ 22826,
+ 0,
+ 22831,
+ 22833,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22834,
+ 0,
+ 22836,
+ 22838,
+ 0,
+ 22839,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22840,
+ 0,
+ 22847,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22856,
+ 22857,
+ 0,
+ 22858,
+ 22859,
+ 0,
+ 0,
+ 22862,
+ 0,
+ 0,
+ 22864,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22866,
+ 0,
+ 22867,
+ 22868,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22869,
+ 0,
+ 22871,
+ 0,
+ 22872,
+ 0,
+ 22873,
+ 22881,
+ 22882,
+ 22884,
+ 22885,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22886,
+ 22887,
+ 0,
+ 22894,
+ 0,
+ 22895,
+ 0,
+ 0,
+ 0,
+ 22900,
+ 0,
+ 22901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22904,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22905,
+ 22907,
+ 0,
+ 0,
+ 0,
+ 22915,
+ 22917,
+ 0,
+ 0,
+ 22918,
+ 0,
+ 0,
+ 0,
+ 22920,
+ 0,
+ 0,
+ 0,
+ 22929,
+ 22930,
+ 0,
+ 0,
+ 0,
+ 22941,
+ 22942,
+ 0,
+ 0,
+ 0,
+ 22943,
+ 0,
+ 0,
+ 0,
+ 22944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22946,
+ 0,
+ 22947,
+ 0,
+ 0,
+ 22954,
+ 0,
+ 22956,
+ 0,
+ 0,
+ 22962,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22963,
+ 0,
+ 0,
+ 22964,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22965,
+ 0,
+ 22968,
+ 0,
+ 0,
+ 0,
+ 22969,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22970,
+ 0,
+ 22971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22978,
+ 0,
+ 0,
+ 22979,
+ 0,
+ 22987,
+ 0,
+ 0,
+ 22989,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 22990,
+ 0,
+ 23005,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23006,
+ 23007,
+ 23008,
+ 0,
+ 0,
+ 23023,
+ 23024,
+ 23029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23035,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23038,
+ 0,
+ 0,
+ 0,
+ 23048,
+ 0,
+ 23049,
+ 23052,
+ 23053,
+ 23060,
+ 23061,
+ 0,
+ 23063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23067,
+ 23068,
+ 0,
+ 0,
+ 0,
+ 23069,
+ 23073,
+ 0,
+ 0,
+ 0,
+ 23127,
+ 0,
+ 23128,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23129,
+ 0,
+ 23138,
+ 23141,
+ 0,
+ 23149,
+ 0,
+ 0,
+ 23150,
+ 0,
+ 0,
+ 0,
+ 23152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23154,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23157,
+ 23159,
+ 23160,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23180,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23181,
+ 0,
+ 0,
+ 23188,
+ 0,
+ 23189,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23195,
+ 0,
+ 0,
+ 23196,
+ 23199,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23202,
+ 0,
+ 23204,
+ 0,
+ 23207,
+ 0,
+ 23209,
+ 23210,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23227,
+ 23229,
+ 0,
+ 0,
+ 23230,
+ 23234,
+ 23238,
+ 0,
+ 0,
+ 0,
+ 23245,
+ 23246,
+ 23248,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23249,
+ 23254,
+ 0,
+ 0,
+ 0,
+ 23265,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23268,
+ 0,
+ 23276,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23277,
+ 0,
+ 23297,
+ 0,
+ 23298,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23299,
+ 0,
+ 23302,
+ 0,
+ 0,
+ 23303,
+ 23312,
+ 0,
+ 0,
+ 23314,
+ 0,
+ 23320,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23324,
+ 0,
+ 23325,
+ 0,
+ 23328,
+ 0,
+ 23334,
+ 0,
+ 0,
+ 0,
+ 23337,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23343,
+ 23344,
+ 23346,
+ 0,
+ 23348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23353,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23355,
+ 0,
+ 23356,
+ 23358,
+ 0,
+ 0,
+ 0,
+ 23359,
+ 23360,
+ 0,
+ 23361,
+ 0,
+ 23367,
+ 0,
+ 23369,
+ 0,
+ 0,
+ 23373,
+ 0,
+ 23378,
+ 23379,
+ 0,
+ 23382,
+ 23383,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23387,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23388,
+ 23390,
+ 0,
+ 0,
+ 23393,
+ 23398,
+ 0,
+ 0,
+ 0,
+ 23399,
+ 0,
+ 0,
+ 0,
+ 23400,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23401,
+ 0,
+ 0,
+ 0,
+ 23415,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23416,
+ 0,
+ 23422,
+ 0,
+ 23443,
+ 23444,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23448,
+ 0,
+ 23454,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23456,
+ 0,
+ 0,
+ 23458,
+ 23464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23465,
+ 0,
+ 0,
+ 0,
+ 23470,
+ 23471,
+ 0,
+ 0,
+ 23472,
+ 0,
+ 0,
+ 0,
+ 23473,
+ 23496,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23497,
+ 0,
+ 23499,
+ 0,
+ 0,
+ 23502,
+ 0,
+ 0,
+ 23503,
+ 0,
+ 0,
+ 23513,
+ 0,
+ 0,
+ 23515,
+ 0,
+ 0,
+ 0,
+ 23517,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23518,
+ 23519,
+ 23521,
+ 23524,
+ 0,
+ 23525,
+ 23528,
+ 23539,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23541,
+ 0,
+ 0,
+ 23544,
+ 0,
+ 0,
+ 23556,
+ 0,
+ 0,
+ 23557,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23559,
+ 0,
+ 23560,
+ 0,
+ 0,
+ 23561,
+ 0,
+ 0,
+ 23566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23568,
+ 23569,
+ 23570,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23571,
+ 0,
+ 23574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23575,
+ 0,
+ 23579,
+ 0,
+ 0,
+ 23581,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23587,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23596,
+ 23598,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23602,
+ 23606,
+ 0,
+ 0,
+ 23607,
+ 0,
+ 23608,
+ 0,
+ 0,
+ 0,
+ 23614,
+ 23616,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23618,
+ 0,
+ 0,
+ 23619,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23621,
+ 23626,
+ 0,
+ 23627,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23629,
+ 0,
+ 23630,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23634,
+ 0,
+ 23636,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23640,
+ 23667,
+ 0,
+ 23669,
+ 0,
+ 0,
+ 0,
+ 23681,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23682,
+ 0,
+ 23683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23684,
+ 0,
+ 0,
+ 0,
+ 23685,
+ 23689,
+ 0,
+ 23693,
+ 23694,
+ 23700,
+ 0,
+ 23702,
+ 0,
+ 23709,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23712,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23714,
+ 0,
+ 0,
+ 23715,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23718,
+ 0,
+ 0,
+ 23720,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23722,
+ 0,
+ 0,
+ 0,
+ 23726,
+ 23729,
+ 0,
+ 23741,
+ 23746,
+ 0,
+ 23748,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23749,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23750,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23751,
+ 0,
+ 23753,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23757,
+ 23765,
+ 0,
+ 0,
+ 0,
+ 23770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23771,
+ 0,
+ 23772,
+ 23781,
+ 0,
+ 0,
+ 23796,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23798,
+ 0,
+ 23799,
+ 0,
+ 0,
+ 0,
+ 23802,
+ 0,
+ 0,
+ 23806,
+ 0,
+ 23807,
+ 0,
+ 0,
+ 23808,
+ 0,
+ 23809,
+ 0,
+ 23819,
+ 0,
+ 0,
+ 0,
+ 23821,
+ 0,
+ 23827,
+ 0,
+ 0,
+ 0,
+ 23829,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23830,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23832,
+ 23833,
+ 23834,
+ 23835,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23837,
+ 23838,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23846,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23847,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23879,
+ 23881,
+ 0,
+ 0,
+ 23882,
+ 23883,
+ 23895,
+ 0,
+ 23899,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23901,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23902,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23903,
+ 23905,
+ 0,
+ 23906,
+ 0,
+ 23907,
+ 23918,
+ 23919,
+ 23920,
+ 0,
+ 23922,
+ 0,
+ 23924,
+ 0,
+ 23927,
+ 0,
+ 23934,
+ 0,
+ 23937,
+ 23941,
+ 0,
+ 23942,
+ 23946,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23955,
+ 23956,
+ 23958,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23959,
+ 0,
+ 23962,
+ 23965,
+ 0,
+ 23966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23967,
+ 23968,
+ 0,
+ 0,
+ 23973,
+ 0,
+ 0,
+ 23974,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23975,
+ 0,
+ 23976,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23977,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23980,
+ 0,
+ 0,
+ 23984,
+ 0,
+ 23985,
+ 0,
+ 0,
+ 23987,
+ 0,
+ 0,
+ 23988,
+ 23990,
+ 23991,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23992,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23994,
+ 0,
+ 0,
+ 0,
+ 23998,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 23999,
+ 0,
+ 0,
+ 24003,
+ 0,
+ 24004,
+ 0,
+ 24006,
+ 0,
+ 0,
+ 0,
+ 24007,
+ 0,
+ 0,
+ 24008,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24009,
+ 0,
+ 0,
+ 24010,
+ 0,
+ 0,
+ 24011,
+ 0,
+ 0,
+ 24013,
+ 24014,
+ 0,
+ 0,
+ 24015,
+ 24016,
+ 24027,
+ 0,
+ 24028,
+ 24029,
+ 0,
+ 24030,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24033,
+ 24034,
+ 0,
+ 24035,
+ 0,
+ 0,
+ 24036,
+ 0,
+ 0,
+ 24044,
+ 0,
+ 24048,
+ 24049,
+ 24063,
+ 24067,
+ 0,
+ 24068,
+ 24070,
+ 0,
+ 0,
+ 24071,
+ 24078,
+ 24087,
+ 0,
+ 24090,
+ 0,
+ 0,
+ 0,
+ 24095,
+ 0,
+ 24098,
+ 24101,
+ 24104,
+ 24106,
+ 0,
+ 24107,
+ 0,
+ 0,
+ 0,
+ 24108,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24110,
+ 24111,
+ 0,
+ 24113,
+ 0,
+ 0,
+ 24115,
+ 24120,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24124,
+ 0,
+ 24125,
+ 0,
+ 24126,
+ 0,
+ 24127,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24135,
+ 0,
+ 0,
+ 24136,
+ 0,
+ 24137,
+ 24142,
+ 0,
+ 0,
+ 0,
+ 24146,
+ 0,
+ 0,
+ 24147,
+ 24149,
+ 24154,
+ 0,
+ 24163,
+ 0,
+ 0,
+ 0,
+ 24165,
+ 24166,
+ 24167,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24169,
+ 24170,
+ 24175,
+ 0,
+ 0,
+ 0,
+ 24178,
+ 0,
+ 0,
+ 24179,
+ 0,
+ 0,
+ 24181,
+ 0,
+ 24184,
+ 24197,
+ 0,
+ 24201,
+ 24204,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24206,
+ 24212,
+ 24220,
+ 0,
+ 0,
+ 0,
+ 24224,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24226,
+ 0,
+ 24234,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24235,
+ 0,
+ 24236,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24239,
+ 24240,
+ 24241,
+ 0,
+ 0,
+ 24248,
+ 0,
+ 0,
+ 24249,
+ 0,
+ 24251,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24253,
+ 0,
+ 24268,
+ 0,
+ 0,
+ 0,
+ 24269,
+ 0,
+ 24271,
+ 24272,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24273,
+ 0,
+ 0,
+ 24274,
+ 0,
+ 0,
+ 24279,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24280,
+ 0,
+ 24293,
+ 24294,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24296,
+ 0,
+ 0,
+ 24323,
+ 0,
+ 0,
+ 0,
+ 24329,
+ 24330,
+ 24331,
+ 24339,
+ 0,
+ 24351,
+ 0,
+ 0,
+ 24369,
+ 24370,
+ 0,
+ 0,
+ 0,
+ 24371,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24372,
+ 24373,
+ 24374,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24378,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24379,
+ 0,
+ 24381,
+ 0,
+ 24383,
+ 24389,
+ 0,
+ 24390,
+ 0,
+ 0,
+ 24394,
+ 24395,
+ 24400,
+ 0,
+ 0,
+ 0,
+ 24401,
+ 24402,
+ 0,
+ 24406,
+ 0,
+ 0,
+ 0,
+ 24411,
+ 0,
+ 0,
+ 0,
+ 24415,
+ 0,
+ 24416,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24417,
+ 0,
+ 24419,
+ 0,
+ 24422,
+ 0,
+ 24423,
+ 24428,
+ 0,
+ 24435,
+ 0,
+ 0,
+ 0,
+ 24439,
+ 0,
+ 0,
+ 0,
+ 24440,
+ 24442,
+ 24446,
+ 0,
+ 0,
+ 0,
+ 24447,
+ 24448,
+ 24449,
+ 24452,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24453,
+ 24457,
+ 0,
+ 0,
+ 24458,
+ 24459,
+ 24460,
+ 0,
+ 24465,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24470,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24471,
+ 0,
+ 24473,
+ 24474,
+ 24475,
+ 24476,
+ 0,
+ 24478,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24480,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24481,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24482,
+ 24485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24486,
+ 0,
+ 0,
+ 0,
+ 24488,
+ 0,
+ 0,
+ 0,
+ 24494,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24497,
+ 0,
+ 0,
+ 24498,
+ 0,
+ 0,
+ 0,
+ 24499,
+ 24506,
+ 0,
+ 0,
+ 0,
+ 24507,
+ 0,
+ 0,
+ 24511,
+ 0,
+ 0,
+ 24513,
+ 24514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24517,
+ 0,
+ 24518,
+ 0,
+ 24520,
+ 0,
+ 24521,
+ 24524,
+ 24525,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24527,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24537,
+ 24539,
+ 0,
+ 24540,
+ 0,
+ 0,
+ 0,
+ 24548,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24549,
+ 24550,
+ 0,
+ 0,
+ 0,
+ 24553,
+ 24554,
+ 0,
+ 24555,
+ 0,
+ 24556,
+ 0,
+ 24558,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24560,
+ 0,
+ 0,
+ 0,
+ 24561,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24567,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24569,
+ 0,
+ 0,
+ 0,
+ 24574,
+ 0,
+ 24575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24577,
+ 24581,
+ 0,
+ 24584,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24585,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24586,
+ 0,
+ 0,
+ 24587,
+ 0,
+ 24588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24590,
+ 24591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24592,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24596,
+ 24597,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24602,
+ 24603,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24604,
+ 0,
+ 0,
+ 24605,
+ 0,
+ 24610,
+ 0,
+ 0,
+ 24611,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24612,
+ 24615,
+ 24616,
+ 24624,
+ 0,
+ 0,
+ 0,
+ 24627,
+ 0,
+ 24638,
+ 24639,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24640,
+ 0,
+ 0,
+ 0,
+ 24655,
+ 24656,
+ 24657,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24662,
+ 0,
+ 24663,
+ 24664,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24665,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24667,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24668,
+ 24669,
+ 0,
+ 24670,
+ 24674,
+ 0,
+ 0,
+ 0,
+ 24675,
+ 0,
+ 24678,
+ 0,
+ 0,
+ 24679,
+ 0,
+ 0,
+ 0,
+ 24681,
+ 0,
+ 24683,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24684,
+ 0,
+ 24685,
+ 0,
+ 0,
+ 24686,
+ 0,
+ 0,
+ 24688,
+ 24689,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24690,
+ 24691,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24697,
+ 0,
+ 24698,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24709,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24710,
+ 0,
+ 24712,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24713,
+ 24714,
+ 0,
+ 24715,
+ 0,
+ 24716,
+ 24718,
+ 0,
+ 24719,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24720,
+ 0,
+ 0,
+ 24725,
+ 0,
+ 0,
+ 24738,
+ 0,
+ 24749,
+ 24750,
+ 0,
+ 0,
+ 0,
+ 24752,
+ 0,
+ 0,
+ 0,
+ 24753,
+ 0,
+ 0,
+ 0,
+ 24758,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24762,
+ 0,
+ 24763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24764,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24765,
+ 24767,
+ 24768,
+ 0,
+ 24772,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24773,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24777,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24785,
+ 0,
+ 24786,
+ 24788,
+ 0,
+ 0,
+ 0,
+ 24789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24794,
+ 24798,
+ 0,
+ 24799,
+ 24800,
+ 0,
+ 0,
+ 0,
+ 24803,
+ 0,
+ 24804,
+ 24806,
+ 0,
+ 24807,
+ 0,
+ 0,
+ 0,
+ 24810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24827,
+ 24828,
+ 0,
+ 24835,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24836,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24839,
+ 0,
+ 24843,
+ 24844,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24847,
+ 0,
+ 0,
+ 24848,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24849,
+ 0,
+ 24850,
+ 24851,
+ 0,
+ 0,
+ 0,
+ 24852,
+ 0,
+ 24853,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24854,
+ 0,
+ 24855,
+ 0,
+ 0,
+ 24868,
+ 0,
+ 0,
+ 0,
+ 24883,
+ 0,
+ 0,
+ 0,
+ 24884,
+ 0,
+ 24895,
+ 24897,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24899,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24900,
+ 0,
+ 24913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24914,
+ 0,
+ 0,
+ 24917,
+ 24930,
+ 24931,
+ 0,
+ 0,
+ 0,
+ 24932,
+ 0,
+ 0,
+ 24939,
+ 0,
+ 0,
+ 24942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24945,
+ 24950,
+ 0,
+ 24951,
+ 0,
+ 0,
+ 24953,
+ 0,
+ 0,
+ 0,
+ 24954,
+ 0,
+ 24959,
+ 0,
+ 0,
+ 0,
+ 24961,
+ 0,
+ 0,
+ 24962,
+ 0,
+ 24964,
+ 24968,
+ 24970,
+ 24972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 24976,
+ 0,
+ 0,
+ 0,
+ 24977,
+ 0,
+ 24982,
+ 0,
+ 0,
+ 24983,
+ 0,
+ 0,
+ 24984,
+ 0,
+ 0,
+ 0,
+ 24993,
+ 0,
+ 0,
+ 0,
+ 24994,
+ 0,
+ 0,
+ 25001,
+ 0,
+ 0,
+ 0,
+ 25003,
+ 0,
+ 0,
+ 25018,
+ 0,
+ 0,
+ 25023,
+ 0,
+ 0,
+ 0,
+ 25034,
+ 0,
+ 0,
+ 25035,
+ 25036,
+ 0,
+ 25037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25039,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25040,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25042,
+ 0,
+ 0,
+ 25043,
+ 25045,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25049,
+ 0,
+ 0,
+ 25051,
+ 0,
+ 25052,
+ 25053,
+ 0,
+ 0,
+ 25054,
+ 0,
+ 0,
+ 0,
+ 25055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25057,
+ 25059,
+ 0,
+ 0,
+ 25060,
+ 25064,
+ 0,
+ 25065,
+ 25069,
+ 25070,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25072,
+ 0,
+ 25073,
+ 0,
+ 25090,
+ 0,
+ 0,
+ 25092,
+ 25093,
+ 25101,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25105,
+ 25108,
+ 0,
+ 0,
+ 25113,
+ 0,
+ 0,
+ 25115,
+ 25116,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25117,
+ 0,
+ 0,
+ 0,
+ 25120,
+ 25121,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25125,
+ 0,
+ 0,
+ 0,
+ 25126,
+ 0,
+ 25130,
+ 25134,
+ 0,
+ 25139,
+ 0,
+ 25143,
+ 0,
+ 0,
+ 0,
+ 25151,
+ 0,
+ 25161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25163,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25174,
+ 0,
+ 25175,
+ 0,
+ 25207,
+ 0,
+ 0,
+ 0,
+ 25209,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25213,
+ 0,
+ 25219,
+ 0,
+ 25223,
+ 0,
+ 25225,
+ 0,
+ 0,
+ 0,
+ 25227,
+ 0,
+ 0,
+ 0,
+ 25228,
+ 0,
+ 0,
+ 0,
+ 25229,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25231,
+ 25233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25237,
+ 25239,
+ 0,
+ 0,
+ 0,
+ 25243,
+ 0,
+ 0,
+ 0,
+ 25252,
+ 0,
+ 25257,
+ 25258,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25260,
+ 25265,
+ 0,
+ 25268,
+ 0,
+ 0,
+ 25273,
+ 25324,
+ 0,
+ 25325,
+ 0,
+ 25326,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25327,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25328,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25332,
+ 0,
+ 0,
+ 0,
+ 25333,
+ 0,
+ 0,
+ 0,
+ 25336,
+ 25337,
+ 25338,
+ 0,
+ 0,
+ 25343,
+ 0,
+ 25350,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25352,
+ 0,
+ 25354,
+ 0,
+ 25375,
+ 0,
+ 25379,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25384,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25386,
+ 0,
+ 25388,
+ 0,
+ 25390,
+ 0,
+ 0,
+ 25399,
+ 0,
+ 0,
+ 25401,
+ 0,
+ 0,
+ 0,
+ 25402,
+ 0,
+ 0,
+ 0,
+ 25407,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25413,
+ 25415,
+ 0,
+ 0,
+ 25417,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25419,
+ 0,
+ 0,
+ 0,
+ 25421,
+ 0,
+ 0,
+ 0,
+ 25424,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25435,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25436,
+ 0,
+ 0,
+ 0,
+ 25437,
+ 0,
+ 0,
+ 25440,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25442,
+ 0,
+ 0,
+ 25443,
+ 0,
+ 25446,
+ 0,
+ 0,
+ 25449,
+ 0,
+ 0,
+ 0,
+ 25450,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25452,
+ 0,
+ 25453,
+ 25454,
+ 25455,
+ 0,
+ 0,
+ 0,
+ 25456,
+ 0,
+ 25457,
+ 0,
+ 0,
+ 0,
+ 25459,
+ 0,
+ 25461,
+ 0,
+ 25468,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25471,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25474,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25477,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25483,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25485,
+ 0,
+ 25497,
+ 0,
+ 0,
+ 25498,
+ 0,
+ 25504,
+ 0,
+ 25510,
+ 0,
+ 25512,
+ 0,
+ 0,
+ 25513,
+ 25514,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25517,
+ 25518,
+ 25519,
+ 0,
+ 25520,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25521,
+ 0,
+ 25522,
+ 25527,
+ 25534,
+ 0,
+ 25536,
+ 0,
+ 25537,
+ 0,
+ 0,
+ 25548,
+ 25550,
+ 0,
+ 0,
+ 25551,
+ 0,
+ 25552,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25554,
+ 0,
+ 25555,
+ 0,
+ 25556,
+ 25557,
+ 25568,
+ 0,
+ 0,
+ 0,
+ 25570,
+ 25571,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25574,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25579,
+ 0,
+ 0,
+ 0,
+ 25581,
+ 0,
+ 0,
+ 0,
+ 25582,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25588,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25590,
+ 0,
+ 25591,
+ 25592,
+ 25593,
+ 0,
+ 25594,
+ 0,
+ 0,
+ 0,
+ 25596,
+ 0,
+ 25597,
+ 25615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25619,
+ 25623,
+ 0,
+ 0,
+ 25629,
+ 0,
+ 0,
+ 25631,
+ 0,
+ 0,
+ 0,
+ 25635,
+ 25636,
+ 0,
+ 0,
+ 25649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25654,
+ 0,
+ 0,
+ 0,
+ 25661,
+ 25663,
+ 0,
+ 0,
+ 25671,
+ 0,
+ 0,
+ 25678,
+ 25698,
+ 0,
+ 25699,
+ 25702,
+ 25703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25704,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25706,
+ 0,
+ 0,
+ 25710,
+ 0,
+ 25711,
+ 0,
+ 25712,
+ 0,
+ 25715,
+ 25716,
+ 25717,
+ 0,
+ 0,
+ 25718,
+ 25728,
+ 25732,
+ 0,
+ 0,
+ 0,
+ 25734,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25737,
+ 0,
+ 0,
+ 25739,
+ 0,
+ 0,
+ 0,
+ 25740,
+ 0,
+ 25741,
+ 25745,
+ 0,
+ 25746,
+ 0,
+ 25748,
+ 25772,
+ 25778,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25780,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25781,
+ 0,
+ 25782,
+ 25784,
+ 25785,
+ 0,
+ 0,
+ 0,
+ 25789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25797,
+ 25801,
+ 0,
+ 0,
+ 0,
+ 25808,
+ 25809,
+ 0,
+ 0,
+ 25811,
+ 25814,
+ 25815,
+ 0,
+ 0,
+ 25817,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25820,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25832,
+ 25833,
+ 0,
+ 0,
+ 0,
+ 25846,
+ 0,
+ 0,
+ 0,
+ 25847,
+ 25848,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25849,
+ 25850,
+ 0,
+ 0,
+ 25851,
+ 0,
+ 0,
+ 25852,
+ 0,
+ 25862,
+ 0,
+ 0,
+ 0,
+ 25863,
+ 25865,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25867,
+ 25868,
+ 0,
+ 25869,
+ 25874,
+ 0,
+ 25875,
+ 0,
+ 25876,
+ 25877,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25878,
+ 25902,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25903,
+ 25904,
+ 25905,
+ 0,
+ 0,
+ 0,
+ 25908,
+ 25909,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25910,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25912,
+ 0,
+ 25913,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25914,
+ 0,
+ 0,
+ 25916,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25917,
+ 25927,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25928,
+ 0,
+ 0,
+ 25930,
+ 0,
+ 0,
+ 0,
+ 25933,
+ 0,
+ 0,
+ 25938,
+ 25942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25945,
+ 0,
+ 25950,
+ 0,
+ 25956,
+ 0,
+ 0,
+ 25961,
+ 25962,
+ 0,
+ 0,
+ 25963,
+ 0,
+ 25964,
+ 25965,
+ 25966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25968,
+ 0,
+ 0,
+ 0,
+ 25969,
+ 25971,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25973,
+ 25975,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25978,
+ 0,
+ 25981,
+ 0,
+ 0,
+ 0,
+ 25982,
+ 0,
+ 0,
+ 0,
+ 25984,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 25993,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26002,
+ 0,
+ 0,
+ 0,
+ 26005,
+ 0,
+ 0,
+ 0,
+ 26006,
+ 26007,
+ 0,
+ 0,
+ 26014,
+ 26015,
+ 26016,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26017,
+ 26018,
+ 26020,
+ 0,
+ 26022,
+ 26023,
+ 0,
+ 0,
+ 0,
+ 26024,
+ 26028,
+ 0,
+ 26029,
+ 26033,
+ 26034,
+ 26044,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26046,
+ 0,
+ 0,
+ 26047,
+ 0,
+ 0,
+ 26049,
+ 0,
+ 26050,
+ 0,
+ 26051,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26053,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26054,
+ 26059,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26060,
+ 0,
+ 26066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26067,
+ 0,
+ 26069,
+ 0,
+ 0,
+ 26071,
+ 0,
+ 0,
+ 0,
+ 26073,
+ 0,
+ 26074,
+ 26077,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26078,
+ 0,
+ 0,
+ 0,
+ 26079,
+ 0,
+ 26090,
+ 0,
+ 0,
+ 26094,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26095,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26096,
+ 26101,
+ 0,
+ 26107,
+ 26122,
+ 0,
+ 26124,
+ 0,
+ 0,
+ 26125,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26136,
+ 26141,
+ 26155,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26164,
+ 26166,
+ 0,
+ 0,
+ 0,
+ 26167,
+ 0,
+ 26170,
+ 26171,
+ 0,
+ 0,
+ 26172,
+ 0,
+ 0,
+ 26174,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26175,
+ 0,
+ 0,
+ 0,
+ 26176,
+ 26177,
+ 0,
+ 26321,
+ 26322,
+ 0,
+ 26323,
+ 0,
+ 0,
+ 26324,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26325,
+ 0,
+ 26331,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26335,
+ 0,
+ 0,
+ 0,
+ 26350,
+ 0,
+ 0,
+ 0,
+ 26379,
+ 0,
+ 0,
+ 26382,
+ 26383,
+ 26385,
+ 0,
+ 0,
+ 26392,
+ 26406,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26411,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26412,
+ 0,
+ 0,
+ 26420,
+ 0,
+ 0,
+ 26423,
+ 0,
+ 26424,
+ 26426,
+ 26432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26435,
+ 0,
+ 26436,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26441,
+ 0,
+ 26444,
+ 0,
+ 0,
+ 0,
+ 26446,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26447,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26449,
+ 0,
+ 26450,
+ 26452,
+ 0,
+ 26453,
+ 26454,
+ 0,
+ 0,
+ 0,
+ 26455,
+ 0,
+ 0,
+ 0,
+ 26456,
+ 0,
+ 0,
+ 26458,
+ 0,
+ 0,
+ 26460,
+ 0,
+ 26463,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26464,
+ 26470,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26473,
+ 0,
+ 0,
+ 26474,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26475,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26477,
+ 0,
+ 26485,
+ 0,
+ 0,
+ 26486,
+ 0,
+ 26487,
+ 0,
+ 0,
+ 26488,
+ 26493,
+ 26494,
+ 0,
+ 0,
+ 26495,
+ 0,
+ 26497,
+ 26504,
+ 26506,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26507,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26509,
+ 0,
+ 0,
+ 26510,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26512,
+ 0,
+ 26513,
+ 26515,
+ 0,
+ 0,
+ 0,
+ 26518,
+ 0,
+ 0,
+ 0,
+ 26519,
+ 0,
+ 26524,
+ 26526,
+ 0,
+ 0,
+ 0,
+ 26527,
+ 0,
+ 26532,
+ 0,
+ 26533,
+ 26537,
+ 26558,
+ 0,
+ 0,
+ 0,
+ 26559,
+ 0,
+ 0,
+ 0,
+ 26571,
+ 0,
+ 0,
+ 26573,
+ 0,
+ 26588,
+ 0,
+ 26593,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26603,
+ 0,
+ 26604,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26606,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26607,
+ 26609,
+ 26611,
+ 26614,
+ 0,
+ 0,
+ 0,
+ 26616,
+ 26620,
+ 0,
+ 26621,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26627,
+ 0,
+ 26629,
+ 0,
+ 0,
+ 26630,
+ 0,
+ 0,
+ 26632,
+ 26643,
+ 0,
+ 0,
+ 0,
+ 26644,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26646,
+ 26647,
+ 0,
+ 0,
+ 0,
+ 26650,
+ 0,
+ 0,
+ 26656,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26663,
+ 26670,
+ 26671,
+ 0,
+ 0,
+ 0,
+ 26685,
+ 26686,
+ 26687,
+ 0,
+ 26689,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26744,
+ 0,
+ 26745,
+ 0,
+ 26747,
+ 26748,
+ 0,
+ 26749,
+ 26750,
+ 26751,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26752,
+ 26755,
+ 0,
+ 0,
+ 0,
+ 26756,
+ 26769,
+ 0,
+ 0,
+ 0,
+ 26774,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26775,
+ 0,
+ 26777,
+ 26778,
+ 0,
+ 26786,
+ 0,
+ 0,
+ 0,
+ 26787,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26788,
+ 0,
+ 0,
+ 26789,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26791,
+ 0,
+ 26792,
+ 26793,
+ 0,
+ 0,
+ 0,
+ 26794,
+ 0,
+ 26797,
+ 26798,
+ 0,
+ 0,
+ 0,
+ 26800,
+ 0,
+ 0,
+ 26803,
+ 0,
+ 26804,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26805,
+ 0,
+ 0,
+ 26808,
+ 0,
+ 0,
+ 26809,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26812,
+ 0,
+ 26825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26826,
+ 0,
+ 0,
+ 26827,
+ 26829,
+ 26834,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26835,
+ 0,
+ 0,
+ 26849,
+ 0,
+ 26851,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26852,
+ 0,
+ 26853,
+ 26857,
+ 0,
+ 26858,
+ 0,
+ 26859,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26876,
+ 0,
+ 26878,
+ 26882,
+ 26883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26890,
+ 26894,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26895,
+ 26896,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26900,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26911,
+ 26913,
+ 26914,
+ 26915,
+ 26916,
+ 26919,
+ 0,
+ 0,
+ 0,
+ 26921,
+ 26922,
+ 0,
+ 0,
+ 26925,
+ 0,
+ 0,
+ 0,
+ 26928,
+ 0,
+ 0,
+ 26929,
+ 26930,
+ 0,
+ 0,
+ 0,
+ 26931,
+ 0,
+ 26932,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26933,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26937,
+ 0,
+ 0,
+ 26943,
+ 0,
+ 0,
+ 26944,
+ 0,
+ 0,
+ 0,
+ 26946,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26956,
+ 0,
+ 26958,
+ 0,
+ 0,
+ 26963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26965,
+ 0,
+ 26969,
+ 26970,
+ 26972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26973,
+ 0,
+ 26974,
+ 0,
+ 26978,
+ 0,
+ 26980,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 26982,
+ 0,
+ 26986,
+ 26987,
+ 0,
+ 26990,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27003,
+ 27006,
+ 0,
+ 0,
+ 27007,
+ 27010,
+ 27012,
+ 27013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27014,
+ 27015,
+ 27018,
+ 0,
+ 27019,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27025,
+ 0,
+ 0,
+ 0,
+ 27026,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27029,
+ 27030,
+ 27031,
+ 27034,
+ 0,
+ 0,
+ 27036,
+ 27037,
+ 0,
+ 0,
+ 0,
+ 27038,
+ 27042,
+ 0,
+ 0,
+ 0,
+ 27044,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27045,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27046,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27047,
+ 27049,
+ 0,
+ 27050,
+ 0,
+ 0,
+ 0,
+ 27051,
+ 27052,
+ 0,
+ 27055,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27056,
+ 27058,
+ 27059,
+ 0,
+ 27061,
+ 0,
+ 27064,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27069,
+ 0,
+ 0,
+ 27070,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27072,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27076,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27078,
+ 0,
+ 27079,
+ 0,
+ 0,
+ 0,
+ 27081,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27082,
+ 0,
+ 27083,
+ 27086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27087,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27088,
+ 27090,
+ 0,
+ 27094,
+ 0,
+ 0,
+ 27095,
+ 0,
+ 27099,
+ 27102,
+ 0,
+ 0,
+ 0,
+ 27103,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27105,
+ 0,
+ 0,
+ 0,
+ 27106,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27107,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27108,
+ 27117,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27118,
+ 0,
+ 0,
+ 27124,
+ 0,
+ 27126,
+ 0,
+ 0,
+ 27130,
+ 27131,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27148,
+ 27149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27150,
+ 27151,
+ 0,
+ 27152,
+ 0,
+ 27159,
+ 0,
+ 0,
+ 0,
+ 27164,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27175,
+ 0,
+ 27189,
+ 0,
+ 0,
+ 27191,
+ 0,
+ 27193,
+ 0,
+ 27195,
+ 0,
+ 27198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27200,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27203,
+ 0,
+ 0,
+ 27204,
+ 0,
+ 0,
+ 27206,
+ 0,
+ 27207,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27209,
+ 0,
+ 0,
+ 0,
+ 27213,
+ 0,
+ 0,
+ 27216,
+ 27219,
+ 27220,
+ 27222,
+ 27223,
+ 0,
+ 27224,
+ 0,
+ 27225,
+ 27226,
+ 0,
+ 0,
+ 27233,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27235,
+ 0,
+ 27237,
+ 0,
+ 27238,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27239,
+ 0,
+ 27242,
+ 27243,
+ 0,
+ 27250,
+ 0,
+ 0,
+ 0,
+ 27251,
+ 0,
+ 27253,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27254,
+ 27255,
+ 27258,
+ 0,
+ 0,
+ 0,
+ 27259,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27267,
+ 0,
+ 27276,
+ 27278,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27296,
+ 27297,
+ 27301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27312,
+ 27313,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27318,
+ 0,
+ 27320,
+ 0,
+ 27329,
+ 0,
+ 27330,
+ 27331,
+ 0,
+ 27332,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27340,
+ 0,
+ 0,
+ 0,
+ 27348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27350,
+ 0,
+ 27351,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27355,
+ 0,
+ 0,
+ 27358,
+ 27359,
+ 27361,
+ 0,
+ 0,
+ 0,
+ 27365,
+ 0,
+ 27367,
+ 0,
+ 27376,
+ 27378,
+ 0,
+ 0,
+ 27379,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27396,
+ 0,
+ 27397,
+ 27404,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27408,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27453,
+ 0,
+ 0,
+ 0,
+ 27456,
+ 0,
+ 0,
+ 0,
+ 27458,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27459,
+ 0,
+ 0,
+ 0,
+ 27460,
+ 0,
+ 0,
+ 27461,
+ 0,
+ 27465,
+ 27467,
+ 0,
+ 0,
+ 27469,
+ 0,
+ 27470,
+ 0,
+ 27471,
+ 0,
+ 27477,
+ 27482,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27493,
+ 0,
+ 27494,
+ 27502,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27511,
+ 27532,
+ 0,
+ 0,
+ 0,
+ 27533,
+ 27545,
+ 0,
+ 0,
+ 0,
+ 27546,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27547,
+ 0,
+ 0,
+ 27549,
+ 27550,
+ 0,
+ 27551,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27555,
+ 0,
+ 0,
+ 27571,
+ 0,
+ 27573,
+ 27574,
+ 27575,
+ 27577,
+ 0,
+ 27578,
+ 0,
+ 0,
+ 27579,
+ 27585,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27586,
+ 0,
+ 0,
+ 27588,
+ 27589,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27596,
+ 0,
+ 0,
+ 27600,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27608,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27610,
+ 0,
+ 0,
+ 0,
+ 27618,
+ 0,
+ 0,
+ 27620,
+ 0,
+ 0,
+ 0,
+ 27631,
+ 0,
+ 0,
+ 27632,
+ 27634,
+ 0,
+ 27636,
+ 27638,
+ 0,
+ 0,
+ 0,
+ 27643,
+ 0,
+ 27644,
+ 27649,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27651,
+ 27660,
+ 0,
+ 27661,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27662,
+ 0,
+ 0,
+ 27664,
+ 0,
+ 27665,
+ 0,
+ 0,
+ 0,
+ 27669,
+ 0,
+ 27671,
+ 0,
+ 0,
+ 0,
+ 27673,
+ 27674,
+ 0,
+ 0,
+ 0,
+ 27682,
+ 0,
+ 0,
+ 0,
+ 27711,
+ 0,
+ 27712,
+ 27713,
+ 27719,
+ 27720,
+ 0,
+ 0,
+ 27728,
+ 0,
+ 27729,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27731,
+ 0,
+ 0,
+ 27732,
+ 0,
+ 27733,
+ 0,
+ 27738,
+ 0,
+ 0,
+ 0,
+ 27742,
+ 0,
+ 0,
+ 0,
+ 27743,
+ 27744,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27745,
+ 27746,
+ 0,
+ 0,
+ 0,
+ 27747,
+ 27748,
+ 27751,
+ 27752,
+ 0,
+ 0,
+ 0,
+ 27768,
+ 27770,
+ 0,
+ 0,
+ 0,
+ 27774,
+ 27775,
+ 0,
+ 27776,
+ 27777,
+ 0,
+ 0,
+ 27781,
+ 0,
+ 27784,
+ 0,
+ 27786,
+ 0,
+ 0,
+ 27791,
+ 0,
+ 27792,
+ 27793,
+ 27804,
+ 0,
+ 27812,
+ 27813,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27814,
+ 0,
+ 27825,
+ 0,
+ 27827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27828,
+ 27861,
+ 27862,
+ 0,
+ 0,
+ 0,
+ 27864,
+ 0,
+ 0,
+ 0,
+ 27865,
+ 27884,
+ 0,
+ 27889,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27890,
+ 0,
+ 27891,
+ 0,
+ 0,
+ 0,
+ 27892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27897,
+ 27898,
+ 0,
+ 0,
+ 27899,
+ 0,
+ 0,
+ 0,
+ 27901,
+ 27905,
+ 0,
+ 0,
+ 27920,
+ 0,
+ 0,
+ 27921,
+ 0,
+ 27922,
+ 0,
+ 0,
+ 0,
+ 27931,
+ 27934,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27941,
+ 0,
+ 27942,
+ 0,
+ 27945,
+ 0,
+ 27947,
+ 27954,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27960,
+ 27963,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 27964,
+ 27965,
+ 0,
+ 0,
+ 0,
+ 27967,
+ 0,
+ 27969,
+ 27975,
+ 0,
+ 27976,
+ 27977,
+ 0,
+ 27981,
+ 0,
+ 27983,
+ 28051,
+ 28052,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28056,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28058,
+ 28059,
+ 0,
+ 0,
+ 28061,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28066,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28069,
+ 28070,
+ 28072,
+ 0,
+ 28073,
+ 0,
+ 0,
+ 28074,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28078,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28085,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28086,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28090,
+ 0,
+ 28097,
+ 28114,
+ 28115,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28116,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28118,
+ 0,
+ 28129,
+ 0,
+ 28131,
+ 0,
+ 0,
+ 28135,
+ 0,
+ 0,
+ 0,
+ 28140,
+ 28141,
+ 0,
+ 0,
+ 0,
+ 28146,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28155,
+ 28157,
+ 28161,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28166,
+ 0,
+ 28167,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28172,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28173,
+ 0,
+ 0,
+ 28175,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28178,
+ 28188,
+ 0,
+ 28190,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28191,
+ 0,
+ 28193,
+ 28206,
+ 0,
+ 0,
+ 28207,
+ 28209,
+ 0,
+ 28211,
+ 0,
+ 28213,
+ 0,
+ 0,
+ 0,
+ 28215,
+ 28216,
+ 28217,
+ 0,
+ 28222,
+ 0,
+ 28223,
+ 28225,
+ 0,
+ 0,
+ 0,
+ 28226,
+ 0,
+ 28227,
+ 28229,
+ 28232,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28235,
+ 0,
+ 28241,
+ 0,
+ 0,
+ 28242,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28243,
+ 0,
+ 0,
+ 0,
+ 28245,
+ 0,
+ 0,
+ 0,
+ 28248,
+ 28250,
+ 0,
+ 28251,
+ 28252,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28253,
+ 0,
+ 0,
+ 28254,
+ 28255,
+ 0,
+ 0,
+ 28256,
+ 0,
+ 0,
+ 28258,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28259,
+ 0,
+ 0,
+ 28260,
+ 0,
+ 0,
+ 28261,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28262,
+ 28263,
+ 0,
+ 0,
+ 28264,
+ 0,
+ 0,
+ 0,
+ 28266,
+ 0,
+ 28268,
+ 28269,
+ 0,
+ 28270,
+ 28272,
+ 28274,
+ 0,
+ 28277,
+ 28278,
+ 0,
+ 0,
+ 0,
+ 28279,
+ 0,
+ 28280,
+ 28281,
+ 28283,
+ 0,
+ 28292,
+ 0,
+ 28294,
+ 0,
+ 28297,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28299,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28300,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28301,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28302,
+ 28303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28304,
+ 0,
+ 0,
+ 28305,
+ 0,
+ 28312,
+ 0,
+ 28313,
+ 28314,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28315,
+ 0,
+ 0,
+ 0,
+ 28320,
+ 28321,
+ 0,
+ 0,
+ 28328,
+ 0,
+ 0,
+ 0,
+ 28329,
+ 28338,
+ 0,
+ 28339,
+ 0,
+ 0,
+ 28344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28347,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28348,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28411,
+ 0,
+ 28412,
+ 28413,
+ 0,
+ 28416,
+ 0,
+ 0,
+ 0,
+ 28420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28421,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28423,
+ 0,
+ 0,
+ 0,
+ 28424,
+ 0,
+ 0,
+ 28428,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28429,
+ 0,
+ 0,
+ 0,
+ 28431,
+ 28434,
+ 0,
+ 28458,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28465,
+ 0,
+ 28467,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28471,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28474,
+ 0,
+ 28480,
+ 0,
+ 28481,
+ 0,
+ 0,
+ 28485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28486,
+ 28488,
+ 0,
+ 0,
+ 28489,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28492,
+ 0,
+ 0,
+ 0,
+ 28495,
+ 0,
+ 28497,
+ 0,
+ 28499,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28500,
+ 0,
+ 0,
+ 28502,
+ 28503,
+ 0,
+ 0,
+ 0,
+ 28508,
+ 0,
+ 0,
+ 0,
+ 28510,
+ 0,
+ 0,
+ 28512,
+ 28513,
+ 28514,
+ 28521,
+ 0,
+ 28526,
+ 0,
+ 28527,
+ 28528,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28529,
+ 0,
+ 0,
+ 28532,
+ 0,
+ 0,
+ 28537,
+ 28538,
+ 0,
+ 0,
+ 0,
+ 28539,
+ 0,
+ 28548,
+ 0,
+ 28553,
+ 28554,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28560,
+ 28563,
+ 0,
+ 0,
+ 28564,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28565,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28566,
+ 28568,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28569,
+ 0,
+ 0,
+ 0,
+ 28570,
+ 0,
+ 28572,
+ 28573,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28575,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28576,
+ 28581,
+ 28588,
+ 0,
+ 0,
+ 28589,
+ 0,
+ 0,
+ 0,
+ 28590,
+ 28595,
+ 0,
+ 28598,
+ 0,
+ 0,
+ 28601,
+ 0,
+ 0,
+ 28605,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28614,
+ 28615,
+ 28619,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28620,
+ 0,
+ 28626,
+ 0,
+ 0,
+ 28628,
+ 0,
+ 28631,
+ 0,
+ 28632,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28635,
+ 0,
+ 0,
+ 0,
+ 28637,
+ 28638,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28639,
+ 0,
+ 28643,
+ 0,
+ 0,
+ 28652,
+ 0,
+ 0,
+ 0,
+ 28662,
+ 0,
+ 28670,
+ 28671,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28672,
+ 28673,
+ 28675,
+ 28676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28691,
+ 0,
+ 0,
+ 0,
+ 28695,
+ 0,
+ 0,
+ 0,
+ 28696,
+ 0,
+ 28697,
+ 28698,
+ 0,
+ 28705,
+ 0,
+ 28707,
+ 28708,
+ 28710,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28711,
+ 28728,
+ 0,
+ 0,
+ 0,
+ 28736,
+ 0,
+ 0,
+ 0,
+ 28737,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28738,
+ 0,
+ 28739,
+ 0,
+ 28741,
+ 0,
+ 0,
+ 28742,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28745,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28749,
+ 28750,
+ 28752,
+ 28754,
+ 28756,
+ 0,
+ 28757,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28759,
+ 28760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28762,
+ 0,
+ 0,
+ 0,
+ 28764,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28766,
+ 0,
+ 28767,
+ 28768,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28769,
+ 28770,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28772,
+ 0,
+ 28773,
+ 0,
+ 28782,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28784,
+ 0,
+ 28785,
+ 0,
+ 28786,
+ 0,
+ 0,
+ 0,
+ 28787,
+ 0,
+ 0,
+ 0,
+ 28797,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28799,
+ 0,
+ 0,
+ 28801,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28802,
+ 0,
+ 28805,
+ 0,
+ 0,
+ 28806,
+ 0,
+ 0,
+ 28807,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28808,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28810,
+ 28812,
+ 0,
+ 0,
+ 28816,
+ 28819,
+ 0,
+ 0,
+ 28821,
+ 0,
+ 28826,
+ 0,
+ 0,
+ 0,
+ 28842,
+ 28852,
+ 0,
+ 0,
+ 28853,
+ 0,
+ 28854,
+ 28855,
+ 0,
+ 0,
+ 0,
+ 28857,
+ 0,
+ 0,
+ 0,
+ 28858,
+ 0,
+ 28867,
+ 28868,
+ 28869,
+ 0,
+ 0,
+ 0,
+ 28874,
+ 28880,
+ 28882,
+ 28890,
+ 28892,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28895,
+ 0,
+ 0,
+ 0,
+ 28898,
+ 28899,
+ 0,
+ 0,
+ 0,
+ 28900,
+ 0,
+ 0,
+ 28904,
+ 0,
+ 28906,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28907,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28908,
+ 0,
+ 0,
+ 0,
+ 28910,
+ 0,
+ 28914,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28915,
+ 28916,
+ 28919,
+ 0,
+ 0,
+ 28920,
+ 0,
+ 28921,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28924,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28926,
+ 28929,
+ 0,
+ 0,
+ 0,
+ 28930,
+ 0,
+ 28936,
+ 0,
+ 28939,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28956,
+ 0,
+ 0,
+ 0,
+ 28966,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28967,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28968,
+ 0,
+ 28971,
+ 0,
+ 28975,
+ 28976,
+ 0,
+ 28982,
+ 28983,
+ 0,
+ 0,
+ 28984,
+ 28989,
+ 28996,
+ 28997,
+ 28998,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 28999,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29000,
+ 0,
+ 29001,
+ 0,
+ 0,
+ 0,
+ 29009,
+ 0,
+ 0,
+ 29011,
+ 0,
+ 0,
+ 29021,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29024,
+ 0,
+ 29025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29026,
+ 0,
+ 0,
+ 0,
+ 29036,
+ 0,
+ 0,
+ 0,
+ 29037,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29038,
+ 0,
+ 29045,
+ 0,
+ 29047,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29051,
+ 0,
+ 0,
+ 0,
+ 29054,
+ 29056,
+ 29062,
+ 0,
+ 29070,
+ 29082,
+ 0,
+ 0,
+ 0,
+ 29083,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29084,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29085,
+ 29088,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29090,
+ 29097,
+ 0,
+ 0,
+ 0,
+ 29103,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29105,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29107,
+ 0,
+ 29109,
+ 0,
+ 0,
+ 0,
+ 29115,
+ 0,
+ 0,
+ 29120,
+ 0,
+ 0,
+ 29138,
+ 29140,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29152,
+ 0,
+ 29160,
+ 29174,
+ 0,
+ 29176,
+ 0,
+ 0,
+ 29180,
+ 0,
+ 29181,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29228,
+ 0,
+ 0,
+ 29229,
+ 0,
+ 0,
+ 29230,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29234,
+ 0,
+ 0,
+ 0,
+ 29241,
+ 0,
+ 29245,
+ 0,
+ 29248,
+ 0,
+ 29250,
+ 29256,
+ 29280,
+ 0,
+ 29282,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29285,
+ 0,
+ 0,
+ 29286,
+ 29291,
+ 29292,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29294,
+ 0,
+ 29295,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29296,
+ 29297,
+ 29298,
+ 29300,
+ 0,
+ 29302,
+ 0,
+ 0,
+ 29304,
+ 29307,
+ 0,
+ 29312,
+ 0,
+ 0,
+ 0,
+ 29322,
+ 0,
+ 0,
+ 29323,
+ 0,
+ 0,
+ 29324,
+ 29326,
+ 29328,
+ 0,
+ 29335,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29338,
+ 29339,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29341,
+ 29343,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29344,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29346,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29347,
+ 29348,
+ 29349,
+ 0,
+ 0,
+ 29354,
+ 0,
+ 0,
+ 29355,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29357,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29364,
+ 0,
+ 29365,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29366,
+ 0,
+ 0,
+ 29368,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29378,
+ 0,
+ 29381,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29386,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29389,
+ 0,
+ 0,
+ 0,
+ 29390,
+ 0,
+ 0,
+ 29391,
+ 29397,
+ 0,
+ 29398,
+ 29412,
+ 29414,
+ 29418,
+ 29419,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29420,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29423,
+ 0,
+ 0,
+ 0,
+ 29435,
+ 0,
+ 0,
+ 0,
+ 29437,
+ 0,
+ 0,
+ 29439,
+ 0,
+ 29441,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29443,
+ 0,
+ 29446,
+ 29450,
+ 29452,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29456,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29461,
+ 0,
+ 0,
+ 0,
+ 29464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29468,
+ 0,
+ 29473,
+ 0,
+ 0,
+ 0,
+ 29486,
+ 0,
+ 0,
+ 0,
+ 29490,
+ 0,
+ 0,
+ 0,
+ 29491,
+ 29492,
+ 0,
+ 0,
+ 29497,
+ 0,
+ 0,
+ 0,
+ 29498,
+ 0,
+ 29499,
+ 0,
+ 29502,
+ 29505,
+ 0,
+ 29509,
+ 0,
+ 0,
+ 0,
+ 29510,
+ 0,
+ 0,
+ 0,
+ 29512,
+ 0,
+ 0,
+ 0,
+ 29516,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29518,
+ 0,
+ 29519,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29520,
+ 29521,
+ 29529,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29530,
+ 0,
+ 0,
+ 29531,
+ 29538,
+ 0,
+ 29540,
+ 0,
+ 0,
+ 0,
+ 29542,
+ 0,
+ 29543,
+ 29544,
+ 29547,
+ 0,
+ 0,
+ 29548,
+ 0,
+ 0,
+ 0,
+ 29549,
+ 0,
+ 0,
+ 0,
+ 29550,
+ 0,
+ 0,
+ 29552,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29558,
+ 29561,
+ 0,
+ 29562,
+ 29564,
+ 0,
+ 0,
+ 29565,
+ 0,
+ 0,
+ 29566,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29578,
+ 29584,
+ 29586,
+ 29591,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29593,
+ 29594,
+ 0,
+ 0,
+ 29597,
+ 0,
+ 0,
+ 29613,
+ 0,
+ 29614,
+ 0,
+ 29615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29616,
+ 29617,
+ 0,
+ 0,
+ 29625,
+ 0,
+ 0,
+ 0,
+ 29632,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29633,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29634,
+ 29635,
+ 29637,
+ 0,
+ 29638,
+ 0,
+ 29641,
+ 29643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29644,
+ 0,
+ 29645,
+ 0,
+ 29649,
+ 0,
+ 0,
+ 0,
+ 29650,
+ 0,
+ 29653,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29656,
+ 29659,
+ 0,
+ 0,
+ 29660,
+ 0,
+ 0,
+ 0,
+ 29661,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29664,
+ 0,
+ 0,
+ 0,
+ 29671,
+ 29673,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29675,
+ 0,
+ 29677,
+ 29679,
+ 0,
+ 0,
+ 29684,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29685,
+ 0,
+ 0,
+ 0,
+ 29687,
+ 0,
+ 0,
+ 0,
+ 29688,
+ 0,
+ 29689,
+ 29690,
+ 29700,
+ 0,
+ 29701,
+ 0,
+ 0,
+ 0,
+ 29702,
+ 0,
+ 29706,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29720,
+ 0,
+ 29721,
+ 0,
+ 29727,
+ 0,
+ 29733,
+ 29734,
+ 0,
+ 29750,
+ 29761,
+ 0,
+ 29763,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29764,
+ 0,
+ 0,
+ 29765,
+ 0,
+ 0,
+ 0,
+ 29771,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29772,
+ 0,
+ 0,
+ 0,
+ 29773,
+ 29774,
+ 29775,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29822,
+ 0,
+ 0,
+ 0,
+ 29824,
+ 0,
+ 29825,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29829,
+ 0,
+ 29832,
+ 29834,
+ 0,
+ 0,
+ 29835,
+ 0,
+ 0,
+ 29837,
+ 29838,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29843,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29844,
+ 29845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29849,
+ 0,
+ 0,
+ 29869,
+ 29872,
+ 29890,
+ 29905,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29907,
+ 29921,
+ 0,
+ 29922,
+ 0,
+ 0,
+ 29923,
+ 29926,
+ 29944,
+ 29946,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29947,
+ 29948,
+ 0,
+ 0,
+ 0,
+ 29951,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29953,
+ 0,
+ 0,
+ 29956,
+ 0,
+ 29957,
+ 0,
+ 0,
+ 29962,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29971,
+ 0,
+ 0,
+ 0,
+ 29972,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 29978,
+ 0,
+ 29979,
+ 29992,
+ 30007,
+ 30008,
+ 30010,
+ 0,
+ 0,
+ 0,
+ 30013,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30014,
+ 30016,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30017,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30023,
+ 30031,
+ 0,
+ 0,
+ 30033,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30034,
+ 0,
+ 30038,
+ 0,
+ 30039,
+ 0,
+ 30040,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30067,
+ 30068,
+ 0,
+ 0,
+ 0,
+ 30069,
+ 0,
+ 30072,
+ 0,
+ 0,
+ 0,
+ 30073,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30075,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30079,
+ 0,
+ 0,
+ 30080,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30082,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30084,
+ 30090,
+ 0,
+ 0,
+ 30091,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30098,
+ 30118,
+ 0,
+ 30119,
+ 0,
+ 30121,
+ 30130,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30131,
+ 30132,
+ 30133,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30135,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30136,
+ 0,
+ 0,
+ 30137,
+ 30138,
+ 0,
+ 0,
+ 0,
+ 30139,
+ 30146,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30147,
+ 0,
+ 0,
+ 30148,
+ 30151,
+ 0,
+ 0,
+ 0,
+ 30168,
+ 0,
+ 30172,
+ 30173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30180,
+ 30181,
+ 0,
+ 30192,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30194,
+ 30196,
+ 0,
+ 0,
+ 30199,
+ 0,
+ 0,
+ 30202,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30203,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30213,
+ 0,
+ 0,
+ 0,
+ 30216,
+ 0,
+ 0,
+ 30217,
+ 0,
+ 0,
+ 0,
+ 30218,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30219,
+ 0,
+ 30220,
+ 0,
+ 30222,
+ 30227,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30231,
+ 0,
+ 0,
+ 30233,
+ 30235,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30238,
+ 0,
+ 30240,
+ 30243,
+ 30245,
+ 0,
+ 30250,
+ 30252,
+ 0,
+ 0,
+ 0,
+ 30269,
+ 0,
+ 0,
+ 30271,
+ 30272,
+ 0,
+ 0,
+ 0,
+ 30278,
+ 30280,
+ 0,
+ 0,
+ 30282,
+ 0,
+ 30284,
+ 0,
+ 30294,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30295,
+ 30296,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30298,
+ 30299,
+ 30302,
+ 30304,
+ 30306,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30316,
+ 30317,
+ 0,
+ 0,
+ 0,
+ 30318,
+ 0,
+ 0,
+ 0,
+ 30319,
+ 0,
+ 30320,
+ 30322,
+ 30326,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30327,
+ 0,
+ 30332,
+ 30348,
+ 30349,
+ 0,
+ 0,
+ 30356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30357,
+ 0,
+ 30358,
+ 0,
+ 30359,
+ 30360,
+ 0,
+ 0,
+ 30365,
+ 30366,
+ 30378,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30379,
+ 0,
+ 0,
+ 30381,
+ 0,
+ 30385,
+ 0,
+ 30388,
+ 30397,
+ 0,
+ 0,
+ 0,
+ 30401,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30403,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30404,
+ 0,
+ 0,
+ 30405,
+ 0,
+ 30406,
+ 30408,
+ 0,
+ 30409,
+ 0,
+ 30410,
+ 0,
+ 0,
+ 0,
+ 30417,
+ 0,
+ 0,
+ 30418,
+ 30419,
+ 0,
+ 30420,
+ 0,
+ 30424,
+ 0,
+ 0,
+ 0,
+ 30427,
+ 30430,
+ 30432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30436,
+ 0,
+ 30437,
+ 30438,
+ 0,
+ 30441,
+ 30442,
+ 0,
+ 0,
+ 0,
+ 30445,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30452,
+ 30456,
+ 30457,
+ 0,
+ 0,
+ 0,
+ 30458,
+ 0,
+ 30464,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30467,
+ 0,
+ 30469,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30477,
+ 0,
+ 0,
+ 30484,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30485,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30486,
+ 30487,
+ 30497,
+ 30498,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30505,
+ 0,
+ 30508,
+ 0,
+ 0,
+ 0,
+ 30509,
+ 30510,
+ 0,
+ 30514,
+ 30516,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30523,
+ 0,
+ 30524,
+ 0,
+ 30525,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30537,
+ 0,
+ 0,
+ 30538,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30553,
+ 0,
+ 0,
+ 30555,
+ 30556,
+ 30558,
+ 30559,
+ 30560,
+ 0,
+ 0,
+ 30561,
+ 0,
+ 30562,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30563,
+ 30570,
+ 30571,
+ 0,
+ 30586,
+ 30587,
+ 0,
+ 0,
+ 30590,
+ 0,
+ 0,
+ 30594,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30611,
+ 30612,
+ 30623,
+ 30634,
+ 0,
+ 0,
+ 30636,
+ 30640,
+ 30655,
+ 30656,
+ 0,
+ 30657,
+ 0,
+ 0,
+ 30658,
+ 30669,
+ 0,
+ 30670,
+ 0,
+ 30676,
+ 30678,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30679,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30695,
+ 0,
+ 0,
+ 30698,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30700,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30701,
+ 0,
+ 30702,
+ 30703,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30707,
+ 0,
+ 0,
+ 0,
+ 30709,
+ 0,
+ 0,
+ 30710,
+ 30719,
+ 30729,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30731,
+ 0,
+ 0,
+ 30733,
+ 0,
+ 0,
+ 0,
+ 30734,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30736,
+ 30737,
+ 0,
+ 0,
+ 0,
+ 30740,
+ 0,
+ 0,
+ 0,
+ 30743,
+ 0,
+ 30746,
+ 0,
+ 30747,
+ 30748,
+ 0,
+ 0,
+ 30751,
+ 30752,
+ 30753,
+ 0,
+ 0,
+ 0,
+ 30754,
+ 0,
+ 0,
+ 30760,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30763,
+ 0,
+ 30764,
+ 0,
+ 0,
+ 30766,
+ 0,
+ 30769,
+ 30770,
+ 30771,
+ 30774,
+ 30777,
+ 0,
+ 0,
+ 30779,
+ 30780,
+ 30781,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30790,
+ 0,
+ 0,
+ 0,
+ 30792,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30810,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30812,
+ 30819,
+ 0,
+ 0,
+ 30823,
+ 30824,
+ 0,
+ 30825,
+ 0,
+ 30827,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30828,
+ 0,
+ 0,
+ 30830,
+ 0,
+ 0,
+ 0,
+ 30834,
+ 0,
+ 30835,
+ 0,
+ 30837,
+ 30838,
+ 0,
+ 30845,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30846,
+ 30847,
+ 0,
+ 0,
+ 30849,
+ 0,
+ 30851,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30852,
+ 30858,
+ 0,
+ 0,
+ 30859,
+ 0,
+ 30865,
+ 0,
+ 0,
+ 30866,
+ 0,
+ 0,
+ 30868,
+ 0,
+ 0,
+ 30869,
+ 0,
+ 0,
+ 0,
+ 30881,
+ 30883,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30889,
+ 0,
+ 30891,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30894,
+ 0,
+ 30895,
+ 0,
+ 30897,
+ 0,
+ 30898,
+ 0,
+ 0,
+ 0,
+ 30904,
+ 30906,
+ 0,
+ 30909,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30910,
+ 0,
+ 0,
+ 0,
+ 30915,
+ 30933,
+ 30942,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30943,
+ 0,
+ 0,
+ 30945,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30946,
+ 0,
+ 0,
+ 30947,
+ 0,
+ 0,
+ 30955,
+ 30956,
+ 0,
+ 0,
+ 30960,
+ 0,
+ 0,
+ 30961,
+ 30962,
+ 30966,
+ 0,
+ 0,
+ 30969,
+ 30974,
+ 0,
+ 0,
+ 0,
+ 30976,
+ 0,
+ 0,
+ 30977,
+ 0,
+ 30978,
+ 30982,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 30994,
+ 30995,
+ 30998,
+ 0,
+ 31000,
+ 0,
+ 0,
+ 31001,
+ 0,
+ 0,
+ 31003,
+ 31005,
+ 0,
+ 0,
+ 31006,
+ 31011,
+ 0,
+ 0,
+ 31014,
+ 0,
+ 31016,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31018,
+ 0,
+ 0,
+ 31020,
+ 31023,
+ 31024,
+ 31025,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31027,
+ 31028,
+ 31029,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31032,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31036,
+ 31037,
+ 31038,
+ 0,
+ 0,
+ 0,
+ 31041,
+ 31043,
+ 31045,
+ 0,
+ 31047,
+ 0,
+ 0,
+ 0,
+ 31048,
+ 0,
+ 31049,
+ 0,
+ 0,
+ 0,
+ 31053,
+ 31054,
+ 31055,
+ 0,
+ 0,
+ 31063,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31066,
+ 0,
+ 31068,
+ 31071,
+ 0,
+ 0,
+ 0,
+ 31072,
+ 31073,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31075,
+ 0,
+ 0,
+ 31076,
+ 0,
+ 0,
+ 0,
+ 31077,
+ 31079,
+ 0,
+ 31080,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31087,
+ 0,
+ 31142,
+ 0,
+ 31144,
+ 0,
+ 0,
+ 31145,
+ 31146,
+ 31147,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31149,
+ 0,
+ 31151,
+ 31152,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31162,
+ 31171,
+ 31174,
+ 31175,
+ 0,
+ 0,
+ 0,
+ 31176,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31179,
+ 0,
+ 0,
+ 0,
+ 31186,
+ 0,
+ 0,
+ 0,
+ 31192,
+ 31195,
+ 0,
+ 0,
+ 31196,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31198,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31199,
+ 0,
+ 0,
+ 0,
+ 31205,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31211,
+ 31215,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31231,
+ 0,
+ 31232,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31233,
+ 31236,
+ 31253,
+ 0,
+ 31254,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31255,
+ 0,
+ 0,
+ 31257,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31258,
+ 31259,
+ 0,
+ 0,
+ 31260,
+ 0,
+ 31261,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31262,
+ 31263,
+ 0,
+ 0,
+ 31264,
+ 0,
+ 31266,
+ 0,
+ 31267,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31281,
+ 0,
+ 31282,
+ 0,
+ 31284,
+ 0,
+ 0,
+ 31285,
+ 31287,
+ 31288,
+ 0,
+ 0,
+ 31290,
+ 0,
+ 0,
+ 0,
+ 31292,
+ 31295,
+ 0,
+ 31299,
+ 0,
+ 31300,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31302,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31304,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31305,
+ 31308,
+ 31309,
+ 31315,
+ 0,
+ 31317,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31323,
+ 0,
+ 31324,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31325,
+ 31327,
+ 0,
+ 0,
+ 31331,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31333,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31336,
+ 0,
+ 0,
+ 31337,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31338,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31339,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31342,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31345,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31347,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31348,
+ 0,
+ 0,
+ 31350,
+ 31351,
+ 0,
+ 31352,
+ 0,
+ 0,
+ 31354,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31355,
+ 0,
+ 0,
+ 31356,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31363,
+ 0,
+ 31372,
+ 0,
+ 0,
+ 31373,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31376,
+ 0,
+ 31388,
+ 0,
+ 31389,
+ 0,
+ 31392,
+ 0,
+ 31401,
+ 0,
+ 31405,
+ 31407,
+ 31408,
+ 0,
+ 31409,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31413,
+ 31415,
+ 0,
+ 0,
+ 0,
+ 31416,
+ 31418,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31422,
+ 31423,
+ 0,
+ 0,
+ 31424,
+ 0,
+ 31425,
+ 31432,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31433,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31434,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31435,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31438,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31442,
+ 0,
+ 31444,
+ 0,
+ 31448,
+ 0,
+ 0,
+ 31451,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31452,
+ 0,
+ 31461,
+ 31465,
+ 0,
+ 0,
+ 31466,
+ 0,
+ 0,
+ 31467,
+ 0,
+ 0,
+ 31468,
+ 0,
+ 0,
+ 0,
+ 31469,
+ 31473,
+ 0,
+ 31476,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31489,
+ 31490,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31492,
+ 31493,
+ 31494,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31501,
+ 31504,
+ 31505,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31509,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31510,
+ 0,
+ 0,
+ 31511,
+ 0,
+ 0,
+ 31513,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31514,
+ 0,
+ 31522,
+ 31536,
+ 31539,
+ 31540,
+ 0,
+ 31541,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31546,
+ 31553,
+ 31559,
+ 0,
+ 0,
+ 0,
+ 31560,
+ 31561,
+ 31562,
+ 0,
+ 0,
+ 31564,
+ 31567,
+ 0,
+ 31569,
+ 0,
+ 0,
+ 0,
+ 31570,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31571,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31572,
+ 31574,
+ 31580,
+ 31581,
+ 0,
+ 0,
+ 31582,
+ 31584,
+ 31585,
+ 31586,
+ 31595,
+ 0,
+ 31596,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31597,
+ 0,
+ 31599,
+ 0,
+ 31600,
+ 31601,
+ 0,
+ 0,
+ 31603,
+ 31604,
+ 0,
+ 0,
+ 31608,
+ 31610,
+ 0,
+ 0,
+ 0,
+ 31611,
+ 0,
+ 31615,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31616,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31617,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31618,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31621,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31622,
+ 31625,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31627,
+ 0,
+ 31641,
+ 0,
+ 0,
+ 31642,
+ 0,
+ 0,
+ 31643,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31644,
+ 0,
+ 31646,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31648,
+ 0,
+ 0,
+ 0,
+ 31652,
+ 0,
+ 0,
+ 0,
+ 31657,
+ 0,
+ 0,
+ 31676,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 31689,
+ 31691,
+ 31692,
+ 0,
+ 31694,
+ 0,
+ 0,
+ 0,
+ 31696,
+ 0,
+ 31702,
+ 0,
+ 31703,
+ 0,
+}
+
+var kStaticDictionaryWords = [31705]dictWord{
+ dictWord{0, 0, 0},
+ dictWord{8, 0, 1002},
+ dictWord{136, 0, 1015},
+ dictWord{4, 0, 683},
+ dictWord{4, 10, 325},
+ dictWord{138, 10, 125},
+ dictWord{7, 11, 572},
+ dictWord{
+ 9,
+ 11,
+ 592,
+ },
+ dictWord{11, 11, 680},
+ dictWord{11, 11, 842},
+ dictWord{11, 11, 924},
+ dictWord{12, 11, 356},
+ dictWord{12, 11, 550},
+ dictWord{13, 11, 317},
+ dictWord{13, 11, 370},
+ dictWord{13, 11, 469},
+ dictWord{13, 11, 471},
+ dictWord{14, 11, 397},
+ dictWord{18, 11, 69},
+ dictWord{146, 11, 145},
+ dictWord{
+ 134,
+ 0,
+ 1265,
+ },
+ dictWord{136, 11, 534},
+ dictWord{134, 0, 1431},
+ dictWord{11, 0, 138},
+ dictWord{140, 0, 40},
+ dictWord{4, 0, 155},
+ dictWord{7, 0, 1689},
+ dictWord{
+ 4,
+ 10,
+ 718,
+ },
+ dictWord{135, 10, 1216},
+ dictWord{4, 0, 245},
+ dictWord{5, 0, 151},
+ dictWord{5, 0, 741},
+ dictWord{6, 0, 1147},
+ dictWord{7, 0, 498},
+ dictWord{7, 0, 870},
+ dictWord{7, 0, 1542},
+ dictWord{12, 0, 213},
+ dictWord{14, 0, 36},
+ dictWord{14, 0, 391},
+ dictWord{17, 0, 111},
+ dictWord{18, 0, 6},
+ dictWord{18, 0, 46},
+ dictWord{
+ 18,
+ 0,
+ 151,
+ },
+ dictWord{19, 0, 36},
+ dictWord{20, 0, 32},
+ dictWord{20, 0, 56},
+ dictWord{20, 0, 69},
+ dictWord{20, 0, 102},
+ dictWord{21, 0, 4},
+ dictWord{22, 0, 8},
+ dictWord{
+ 22,
+ 0,
+ 10,
+ },
+ dictWord{22, 0, 14},
+ dictWord{150, 0, 31},
+ dictWord{4, 0, 624},
+ dictWord{135, 0, 1752},
+ dictWord{5, 10, 124},
+ dictWord{5, 10, 144},
+ dictWord{6, 10, 548},
+ dictWord{7, 10, 15},
+ dictWord{7, 10, 153},
+ dictWord{137, 10, 629},
+ dictWord{6, 0, 503},
+ dictWord{9, 0, 586},
+ dictWord{13, 0, 468},
+ dictWord{14, 0, 66},
+ dictWord{
+ 16,
+ 0,
+ 58,
+ },
+ dictWord{7, 10, 1531},
+ dictWord{8, 10, 416},
+ dictWord{9, 10, 275},
+ dictWord{10, 10, 100},
+ dictWord{11, 10, 658},
+ dictWord{11, 10, 979},
+ dictWord{
+ 12,
+ 10,
+ 86,
+ },
+ dictWord{14, 10, 207},
+ dictWord{15, 10, 20},
+ dictWord{143, 10, 25},
+ dictWord{5, 0, 603},
+ dictWord{7, 0, 1212},
+ dictWord{9, 0, 565},
+ dictWord{
+ 14,
+ 0,
+ 301,
+ },
+ dictWord{5, 10, 915},
+ dictWord{6, 10, 1783},
+ dictWord{7, 10, 211},
+ dictWord{7, 10, 1353},
+ dictWord{9, 10, 83},
+ dictWord{10, 10, 376},
+ dictWord{
+ 10,
+ 10,
+ 431,
+ },
+ dictWord{11, 10, 543},
+ dictWord{12, 10, 664},
+ dictWord{13, 10, 280},
+ dictWord{13, 10, 428},
+ dictWord{14, 10, 128},
+ dictWord{17, 10, 52},
+ dictWord{
+ 145,
+ 10,
+ 81,
+ },
+ dictWord{4, 0, 492},
+ dictWord{133, 0, 451},
+ dictWord{135, 0, 835},
+ dictWord{141, 0, 70},
+ dictWord{132, 0, 539},
+ dictWord{7, 11, 748},
+ dictWord{
+ 139,
+ 11,
+ 700,
+ },
+ dictWord{7, 11, 1517},
+ dictWord{11, 11, 597},
+ dictWord{14, 11, 76},
+ dictWord{14, 11, 335},
+ dictWord{148, 11, 33},
+ dictWord{6, 0, 113},
+ dictWord{135, 0, 436},
+ dictWord{4, 10, 338},
+ dictWord{133, 10, 400},
+ dictWord{136, 0, 718},
+ dictWord{133, 11, 127},
+ dictWord{133, 11, 418},
+ dictWord{
+ 6,
+ 0,
+ 1505,
+ },
+ dictWord{7, 0, 520},
+ dictWord{6, 11, 198},
+ dictWord{11, 10, 892},
+ dictWord{140, 11, 83},
+ dictWord{4, 10, 221},
+ dictWord{5, 10, 659},
+ dictWord{
+ 5,
+ 10,
+ 989,
+ },
+ dictWord{7, 10, 697},
+ dictWord{7, 10, 1211},
+ dictWord{138, 10, 284},
+ dictWord{135, 0, 1070},
+ dictWord{5, 11, 276},
+ dictWord{6, 11, 55},
+ dictWord{
+ 135,
+ 11,
+ 1369,
+ },
+ dictWord{134, 0, 1515},
+ dictWord{6, 11, 1752},
+ dictWord{136, 11, 726},
+ dictWord{138, 10, 507},
+ dictWord{15, 0, 78},
+ dictWord{4, 10, 188},
+ dictWord{135, 10, 805},
+ dictWord{5, 10, 884},
+ dictWord{139, 10, 991},
+ dictWord{133, 11, 764},
+ dictWord{134, 10, 1653},
+ dictWord{6, 11, 309},
+ dictWord{
+ 7,
+ 11,
+ 331,
+ },
+ dictWord{138, 11, 550},
+ dictWord{135, 11, 1861},
+ dictWord{132, 11, 348},
+ dictWord{135, 11, 986},
+ dictWord{135, 11, 1573},
+ dictWord{
+ 12,
+ 0,
+ 610,
+ },
+ dictWord{13, 0, 431},
+ dictWord{144, 0, 59},
+ dictWord{9, 11, 799},
+ dictWord{140, 10, 166},
+ dictWord{134, 0, 1530},
+ dictWord{132, 0, 750},
+ dictWord{132, 0, 307},
+ dictWord{133, 0, 964},
+ dictWord{6, 11, 194},
+ dictWord{7, 11, 133},
+ dictWord{10, 11, 493},
+ dictWord{10, 11, 570},
+ dictWord{139, 11, 664},
+ dictWord{5, 11, 24},
+ dictWord{5, 11, 569},
+ dictWord{6, 11, 3},
+ dictWord{6, 11, 119},
+ dictWord{6, 11, 143},
+ dictWord{6, 11, 440},
+ dictWord{7, 11, 295},
+ dictWord{
+ 7,
+ 11,
+ 599,
+ },
+ dictWord{7, 11, 1686},
+ dictWord{7, 11, 1854},
+ dictWord{8, 11, 424},
+ dictWord{9, 11, 43},
+ dictWord{9, 11, 584},
+ dictWord{9, 11, 760},
+ dictWord{
+ 10,
+ 11,
+ 148,
+ },
+ dictWord{10, 11, 328},
+ dictWord{11, 11, 159},
+ dictWord{11, 11, 253},
+ dictWord{11, 11, 506},
+ dictWord{12, 11, 487},
+ dictWord{12, 11, 531},
+ dictWord{144, 11, 33},
+ dictWord{136, 10, 760},
+ dictWord{5, 11, 14},
+ dictWord{5, 11, 892},
+ dictWord{6, 11, 283},
+ dictWord{7, 11, 234},
+ dictWord{136, 11, 537},
+ dictWord{135, 11, 1251},
+ dictWord{4, 11, 126},
+ dictWord{8, 11, 635},
+ dictWord{147, 11, 34},
+ dictWord{4, 11, 316},
+ dictWord{135, 11, 1561},
+ dictWord{
+ 6,
+ 0,
+ 999,
+ },
+ dictWord{6, 0, 1310},
+ dictWord{137, 11, 861},
+ dictWord{4, 11, 64},
+ dictWord{5, 11, 352},
+ dictWord{5, 11, 720},
+ dictWord{6, 11, 368},
+ dictWord{
+ 139,
+ 11,
+ 359,
+ },
+ dictWord{4, 0, 75},
+ dictWord{5, 0, 180},
+ dictWord{6, 0, 500},
+ dictWord{7, 0, 58},
+ dictWord{7, 0, 710},
+ dictWord{10, 0, 645},
+ dictWord{136, 10, 770},
+ dictWord{133, 0, 649},
+ dictWord{6, 0, 276},
+ dictWord{7, 0, 282},
+ dictWord{7, 0, 879},
+ dictWord{7, 0, 924},
+ dictWord{8, 0, 459},
+ dictWord{9, 0, 599},
+ dictWord{9, 0, 754},
+ dictWord{11, 0, 574},
+ dictWord{12, 0, 128},
+ dictWord{12, 0, 494},
+ dictWord{13, 0, 52},
+ dictWord{13, 0, 301},
+ dictWord{15, 0, 30},
+ dictWord{143, 0, 132},
+ dictWord{132, 0, 200},
+ dictWord{4, 10, 89},
+ dictWord{5, 10, 489},
+ dictWord{6, 10, 315},
+ dictWord{7, 10, 553},
+ dictWord{7, 10, 1745},
+ dictWord{138, 10, 243},
+ dictWord{135, 11, 1050},
+ dictWord{7, 0, 1621},
+ dictWord{6, 10, 1658},
+ dictWord{9, 10, 3},
+ dictWord{10, 10, 154},
+ dictWord{11, 10, 641},
+ dictWord{13, 10, 85},
+ dictWord{13, 10, 201},
+ dictWord{141, 10, 346},
+ dictWord{6, 11, 175},
+ dictWord{137, 11, 289},
+ dictWord{5, 11, 432},
+ dictWord{133, 11, 913},
+ dictWord{
+ 6,
+ 0,
+ 225,
+ },
+ dictWord{137, 0, 211},
+ dictWord{7, 0, 718},
+ dictWord{8, 0, 687},
+ dictWord{139, 0, 374},
+ dictWord{4, 10, 166},
+ dictWord{133, 10, 505},
+ dictWord{
+ 9,
+ 0,
+ 110,
+ },
+ dictWord{134, 10, 1670},
+ dictWord{8, 0, 58},
+ dictWord{9, 0, 724},
+ dictWord{11, 0, 809},
+ dictWord{13, 0, 113},
+ dictWord{145, 0, 72},
+ dictWord{6, 0, 345},
+ dictWord{7, 0, 1247},
+ dictWord{144, 11, 82},
+ dictWord{5, 11, 931},
+ dictWord{134, 11, 1698},
+ dictWord{8, 0, 767},
+ dictWord{8, 0, 803},
+ dictWord{9, 0, 301},
+ dictWord{137, 0, 903},
+ dictWord{139, 0, 203},
+ dictWord{134, 0, 1154},
+ dictWord{7, 0, 1949},
+ dictWord{136, 0, 674},
+ dictWord{134, 0, 259},
+ dictWord{
+ 135,
+ 0,
+ 1275,
+ },
+ dictWord{5, 11, 774},
+ dictWord{6, 11, 1637},
+ dictWord{6, 11, 1686},
+ dictWord{134, 11, 1751},
+ dictWord{134, 0, 1231},
+ dictWord{7, 10, 445},
+ dictWord{8, 10, 307},
+ dictWord{8, 10, 704},
+ dictWord{10, 10, 41},
+ dictWord{10, 10, 439},
+ dictWord{11, 10, 237},
+ dictWord{11, 10, 622},
+ dictWord{140, 10, 201},
+ dictWord{136, 0, 254},
+ dictWord{6, 11, 260},
+ dictWord{135, 11, 1484},
+ dictWord{139, 0, 277},
+ dictWord{135, 10, 1977},
+ dictWord{4, 10, 189},
+ dictWord{
+ 5,
+ 10,
+ 713,
+ },
+ dictWord{6, 11, 573},
+ dictWord{136, 10, 57},
+ dictWord{138, 10, 371},
+ dictWord{132, 10, 552},
+ dictWord{134, 11, 344},
+ dictWord{133, 0, 248},
+ dictWord{9, 0, 800},
+ dictWord{10, 0, 693},
+ dictWord{11, 0, 482},
+ dictWord{11, 0, 734},
+ dictWord{11, 0, 789},
+ dictWord{134, 11, 240},
+ dictWord{4, 0, 116},
+ dictWord{
+ 5,
+ 0,
+ 95,
+ },
+ dictWord{5, 0, 445},
+ dictWord{7, 0, 1688},
+ dictWord{8, 0, 29},
+ dictWord{9, 0, 272},
+ dictWord{11, 0, 509},
+ dictWord{11, 0, 915},
+ dictWord{4, 11, 292},
+ dictWord{4, 11, 736},
+ dictWord{5, 11, 871},
+ dictWord{6, 11, 171},
+ dictWord{6, 11, 1689},
+ dictWord{7, 11, 1324},
+ dictWord{7, 11, 1944},
+ dictWord{9, 11, 415},
+ dictWord{9, 11, 580},
+ dictWord{14, 11, 230},
+ dictWord{146, 11, 68},
+ dictWord{7, 0, 490},
+ dictWord{13, 0, 100},
+ dictWord{143, 0, 75},
+ dictWord{135, 0, 1641},
+ dictWord{133, 0, 543},
+ dictWord{7, 11, 209},
+ dictWord{8, 11, 661},
+ dictWord{10, 11, 42},
+ dictWord{11, 11, 58},
+ dictWord{12, 11, 58},
+ dictWord{12, 11, 118},
+ dictWord{141, 11, 32},
+ dictWord{5, 0, 181},
+ dictWord{8, 0, 41},
+ dictWord{6, 11, 63},
+ dictWord{135, 11, 920},
+ dictWord{133, 0, 657},
+ dictWord{133, 11, 793},
+ dictWord{138, 0, 709},
+ dictWord{7, 0, 25},
+ dictWord{8, 0, 202},
+ dictWord{138, 0, 536},
+ dictWord{5, 11, 665},
+ dictWord{135, 10, 1788},
+ dictWord{145, 10, 49},
+ dictWord{9, 0, 423},
+ dictWord{140, 0, 89},
+ dictWord{5, 11, 67},
+ dictWord{6, 11, 62},
+ dictWord{6, 11, 374},
+ dictWord{135, 11, 1391},
+ dictWord{8, 0, 113},
+ dictWord{
+ 9,
+ 0,
+ 877,
+ },
+ dictWord{10, 0, 554},
+ dictWord{11, 0, 83},
+ dictWord{12, 0, 136},
+ dictWord{19, 0, 109},
+ dictWord{9, 11, 790},
+ dictWord{140, 11, 47},
+ dictWord{
+ 138,
+ 10,
+ 661,
+ },
+ dictWord{4, 0, 963},
+ dictWord{10, 0, 927},
+ dictWord{14, 0, 442},
+ dictWord{135, 10, 1945},
+ dictWord{133, 0, 976},
+ dictWord{132, 0, 206},
+ dictWord{
+ 4,
+ 11,
+ 391,
+ },
+ dictWord{135, 11, 1169},
+ dictWord{134, 0, 2002},
+ dictWord{6, 0, 696},
+ dictWord{134, 0, 1008},
+ dictWord{134, 0, 1170},
+ dictWord{132, 11, 271},
+ dictWord{7, 0, 13},
+ dictWord{8, 0, 226},
+ dictWord{10, 0, 537},
+ dictWord{11, 0, 570},
+ dictWord{11, 0, 605},
+ dictWord{11, 0, 799},
+ dictWord{11, 0, 804},
+ dictWord{
+ 12,
+ 0,
+ 85,
+ },
+ dictWord{12, 0, 516},
+ dictWord{12, 0, 623},
+ dictWord{13, 0, 112},
+ dictWord{13, 0, 361},
+ dictWord{14, 0, 77},
+ dictWord{14, 0, 78},
+ dictWord{17, 0, 28},
+ dictWord{19, 0, 110},
+ dictWord{140, 11, 314},
+ dictWord{132, 0, 769},
+ dictWord{134, 0, 1544},
+ dictWord{4, 0, 551},
+ dictWord{137, 0, 678},
+ dictWord{5, 10, 84},
+ dictWord{134, 10, 163},
+ dictWord{9, 0, 57},
+ dictWord{9, 0, 459},
+ dictWord{10, 0, 425},
+ dictWord{11, 0, 119},
+ dictWord{12, 0, 184},
+ dictWord{12, 0, 371},
+ dictWord{
+ 13,
+ 0,
+ 358,
+ },
+ dictWord{145, 0, 51},
+ dictWord{5, 0, 188},
+ dictWord{5, 0, 814},
+ dictWord{8, 0, 10},
+ dictWord{9, 0, 421},
+ dictWord{9, 0, 729},
+ dictWord{10, 0, 609},
+ dictWord{11, 0, 689},
+ dictWord{4, 11, 253},
+ dictWord{5, 10, 410},
+ dictWord{5, 11, 544},
+ dictWord{7, 11, 300},
+ dictWord{137, 11, 340},
+ dictWord{134, 0, 624},
+ dictWord{138, 11, 321},
+ dictWord{135, 0, 1941},
+ dictWord{18, 0, 130},
+ dictWord{5, 10, 322},
+ dictWord{8, 10, 186},
+ dictWord{9, 10, 262},
+ dictWord{10, 10, 187},
+ dictWord{142, 10, 208},
+ dictWord{5, 11, 53},
+ dictWord{5, 11, 541},
+ dictWord{6, 11, 94},
+ dictWord{6, 11, 499},
+ dictWord{7, 11, 230},
+ dictWord{139, 11, 321},
+ dictWord{133, 10, 227},
+ dictWord{4, 0, 378},
+ dictWord{4, 11, 920},
+ dictWord{5, 11, 25},
+ dictWord{5, 11, 790},
+ dictWord{6, 11, 457},
+ dictWord{135, 11, 853},
+ dictWord{137, 0, 269},
+ dictWord{132, 0, 528},
+ dictWord{134, 0, 1146},
+ dictWord{7, 10, 1395},
+ dictWord{8, 10, 486},
+ dictWord{9, 10, 236},
+ dictWord{9, 10, 878},
+ dictWord{10, 10, 218},
+ dictWord{11, 10, 95},
+ dictWord{19, 10, 17},
+ dictWord{147, 10, 31},
+ dictWord{7, 10, 2043},
+ dictWord{8, 10, 672},
+ dictWord{
+ 141,
+ 10,
+ 448,
+ },
+ dictWord{134, 0, 1105},
+ dictWord{134, 0, 1616},
+ dictWord{134, 11, 1765},
+ dictWord{140, 11, 163},
+ dictWord{5, 10, 412},
+ dictWord{133, 11, 822},
+ dictWord{132, 11, 634},
+ dictWord{6, 0, 656},
+ dictWord{134, 11, 1730},
+ dictWord{134, 0, 1940},
+ dictWord{5, 0, 104},
+ dictWord{6, 0, 173},
+ dictWord{
+ 135,
+ 0,
+ 1631,
+ },
+ dictWord{136, 10, 562},
+ dictWord{6, 11, 36},
+ dictWord{7, 11, 658},
+ dictWord{8, 11, 454},
+ dictWord{147, 11, 86},
+ dictWord{5, 0, 457},
+ dictWord{
+ 134,
+ 10,
+ 1771,
+ },
+ dictWord{7, 0, 810},
+ dictWord{8, 0, 138},
+ dictWord{8, 0, 342},
+ dictWord{9, 0, 84},
+ dictWord{10, 0, 193},
+ dictWord{11, 0, 883},
+ dictWord{140, 0, 359},
+ dictWord{9, 0, 620},
+ dictWord{135, 10, 1190},
+ dictWord{137, 10, 132},
+ dictWord{7, 11, 975},
+ dictWord{137, 11, 789},
+ dictWord{6, 0, 95},
+ dictWord{6, 0, 1934},
+ dictWord{136, 0, 967},
+ dictWord{141, 11, 335},
+ dictWord{6, 0, 406},
+ dictWord{10, 0, 409},
+ dictWord{10, 0, 447},
+ dictWord{11, 0, 44},
+ dictWord{140, 0, 100},
+ dictWord{4, 10, 317},
+ dictWord{135, 10, 1279},
+ dictWord{132, 0, 477},
+ dictWord{134, 0, 1268},
+ dictWord{6, 0, 1941},
+ dictWord{8, 0, 944},
+ dictWord{5, 10, 63},
+ dictWord{133, 10, 509},
+ dictWord{132, 0, 629},
+ dictWord{132, 11, 104},
+ dictWord{4, 0, 246},
+ dictWord{133, 0, 375},
+ dictWord{6, 0, 1636},
+ dictWord{
+ 132,
+ 10,
+ 288,
+ },
+ dictWord{135, 11, 1614},
+ dictWord{9, 0, 49},
+ dictWord{10, 0, 774},
+ dictWord{8, 10, 89},
+ dictWord{8, 10, 620},
+ dictWord{11, 10, 628},
+ dictWord{
+ 12,
+ 10,
+ 322,
+ },
+ dictWord{143, 10, 124},
+ dictWord{4, 0, 282},
+ dictWord{7, 0, 1034},
+ dictWord{11, 0, 398},
+ dictWord{11, 0, 634},
+ dictWord{12, 0, 1},
+ dictWord{12, 0, 79},
+ dictWord{12, 0, 544},
+ dictWord{14, 0, 237},
+ dictWord{17, 0, 10},
+ dictWord{146, 0, 20},
+ dictWord{132, 0, 824},
+ dictWord{7, 11, 45},
+ dictWord{9, 11, 542},
+ dictWord{
+ 9,
+ 11,
+ 566,
+ },
+ dictWord{138, 11, 728},
+ dictWord{5, 0, 118},
+ dictWord{5, 0, 499},
+ dictWord{6, 0, 476},
+ dictWord{6, 0, 665},
+ dictWord{6, 0, 1176},
+ dictWord{
+ 6,
+ 0,
+ 1196,
+ },
+ dictWord{7, 0, 600},
+ dictWord{7, 0, 888},
+ dictWord{135, 0, 1096},
+ dictWord{7, 0, 296},
+ dictWord{7, 0, 596},
+ dictWord{8, 0, 560},
+ dictWord{8, 0, 586},
+ dictWord{9, 0, 612},
+ dictWord{11, 0, 304},
+ dictWord{12, 0, 46},
+ dictWord{13, 0, 89},
+ dictWord{14, 0, 112},
+ dictWord{145, 0, 122},
+ dictWord{5, 0, 894},
+ dictWord{
+ 6,
+ 0,
+ 1772,
+ },
+ dictWord{9, 0, 1009},
+ dictWord{138, 10, 120},
+ dictWord{5, 11, 533},
+ dictWord{7, 11, 755},
+ dictWord{138, 11, 780},
+ dictWord{151, 10, 1},
+ dictWord{
+ 6,
+ 0,
+ 1474,
+ },
+ dictWord{7, 11, 87},
+ dictWord{142, 11, 288},
+ dictWord{139, 0, 366},
+ dictWord{137, 10, 461},
+ dictWord{7, 11, 988},
+ dictWord{7, 11, 1939},
+ dictWord{
+ 9,
+ 11,
+ 64,
+ },
+ dictWord{9, 11, 502},
+ dictWord{12, 11, 7},
+ dictWord{12, 11, 34},
+ dictWord{13, 11, 12},
+ dictWord{13, 11, 234},
+ dictWord{147, 11, 77},
+ dictWord{
+ 7,
+ 0,
+ 1599,
+ },
+ dictWord{7, 0, 1723},
+ dictWord{8, 0, 79},
+ dictWord{8, 0, 106},
+ dictWord{8, 0, 190},
+ dictWord{8, 0, 302},
+ dictWord{8, 0, 383},
+ dictWord{8, 0, 713},
+ dictWord{
+ 9,
+ 0,
+ 119,
+ },
+ dictWord{9, 0, 233},
+ dictWord{9, 0, 419},
+ dictWord{9, 0, 471},
+ dictWord{10, 0, 181},
+ dictWord{10, 0, 406},
+ dictWord{11, 0, 57},
+ dictWord{11, 0, 85},
+ dictWord{11, 0, 120},
+ dictWord{11, 0, 177},
+ dictWord{11, 0, 296},
+ dictWord{11, 0, 382},
+ dictWord{11, 0, 454},
+ dictWord{11, 0, 758},
+ dictWord{11, 0, 999},
+ dictWord{
+ 12,
+ 0,
+ 27,
+ },
+ dictWord{12, 0, 98},
+ dictWord{12, 0, 131},
+ dictWord{12, 0, 245},
+ dictWord{12, 0, 312},
+ dictWord{12, 0, 446},
+ dictWord{12, 0, 454},
+ dictWord{13, 0, 25},
+ dictWord{13, 0, 98},
+ dictWord{13, 0, 426},
+ dictWord{13, 0, 508},
+ dictWord{14, 0, 70},
+ dictWord{14, 0, 163},
+ dictWord{14, 0, 272},
+ dictWord{14, 0, 277},
+ dictWord{
+ 14,
+ 0,
+ 370,
+ },
+ dictWord{15, 0, 95},
+ dictWord{15, 0, 138},
+ dictWord{15, 0, 167},
+ dictWord{17, 0, 38},
+ dictWord{148, 0, 96},
+ dictWord{135, 10, 1346},
+ dictWord{
+ 10,
+ 0,
+ 200,
+ },
+ dictWord{19, 0, 2},
+ dictWord{151, 0, 22},
+ dictWord{135, 11, 141},
+ dictWord{134, 10, 85},
+ dictWord{134, 0, 1759},
+ dictWord{138, 0, 372},
+ dictWord{
+ 145,
+ 0,
+ 16,
+ },
+ dictWord{8, 0, 943},
+ dictWord{132, 11, 619},
+ dictWord{139, 11, 88},
+ dictWord{5, 11, 246},
+ dictWord{8, 11, 189},
+ dictWord{9, 11, 355},
+ dictWord{
+ 9,
+ 11,
+ 512,
+ },
+ dictWord{10, 11, 124},
+ dictWord{10, 11, 453},
+ dictWord{11, 11, 143},
+ dictWord{11, 11, 416},
+ dictWord{11, 11, 859},
+ dictWord{141, 11, 341},
+ dictWord{
+ 5,
+ 0,
+ 258,
+ },
+ dictWord{134, 0, 719},
+ dictWord{6, 0, 1798},
+ dictWord{6, 0, 1839},
+ dictWord{8, 0, 900},
+ dictWord{10, 0, 874},
+ dictWord{10, 0, 886},
+ dictWord{
+ 12,
+ 0,
+ 698,
+ },
+ dictWord{12, 0, 732},
+ dictWord{12, 0, 770},
+ dictWord{16, 0, 106},
+ dictWord{18, 0, 163},
+ dictWord{18, 0, 170},
+ dictWord{18, 0, 171},
+ dictWord{152, 0, 20},
+ dictWord{9, 0, 707},
+ dictWord{11, 0, 326},
+ dictWord{11, 0, 339},
+ dictWord{12, 0, 423},
+ dictWord{12, 0, 502},
+ dictWord{20, 0, 62},
+ dictWord{9, 11, 707},
+ dictWord{
+ 11,
+ 11,
+ 326,
+ },
+ dictWord{11, 11, 339},
+ dictWord{12, 11, 423},
+ dictWord{12, 11, 502},
+ dictWord{148, 11, 62},
+ dictWord{5, 0, 30},
+ dictWord{7, 0, 495},
+ dictWord{
+ 8,
+ 0,
+ 134,
+ },
+ dictWord{9, 0, 788},
+ dictWord{140, 0, 438},
+ dictWord{133, 11, 678},
+ dictWord{5, 10, 279},
+ dictWord{6, 10, 235},
+ dictWord{7, 10, 468},
+ dictWord{
+ 8,
+ 10,
+ 446,
+ },
+ dictWord{9, 10, 637},
+ dictWord{10, 10, 717},
+ dictWord{11, 10, 738},
+ dictWord{140, 10, 514},
+ dictWord{5, 11, 35},
+ dictWord{6, 11, 287},
+ dictWord{
+ 7,
+ 11,
+ 862,
+ },
+ dictWord{7, 11, 1886},
+ dictWord{138, 11, 179},
+ dictWord{7, 0, 1948},
+ dictWord{7, 0, 2004},
+ dictWord{132, 11, 517},
+ dictWord{5, 10, 17},
+ dictWord{
+ 6,
+ 10,
+ 371,
+ },
+ dictWord{137, 10, 528},
+ dictWord{4, 0, 115},
+ dictWord{5, 0, 669},
+ dictWord{6, 0, 407},
+ dictWord{8, 0, 311},
+ dictWord{11, 0, 10},
+ dictWord{141, 0, 5},
+ dictWord{137, 0, 381},
+ dictWord{5, 0, 50},
+ dictWord{6, 0, 439},
+ dictWord{7, 0, 780},
+ dictWord{135, 0, 1040},
+ dictWord{136, 11, 667},
+ dictWord{11, 11, 403},
+ dictWord{146, 11, 83},
+ dictWord{5, 0, 1},
+ dictWord{6, 0, 81},
+ dictWord{138, 0, 520},
+ dictWord{134, 0, 738},
+ dictWord{5, 0, 482},
+ dictWord{8, 0, 98},
+ dictWord{9, 0, 172},
+ dictWord{10, 0, 360},
+ dictWord{10, 0, 700},
+ dictWord{10, 0, 822},
+ dictWord{11, 0, 302},
+ dictWord{11, 0, 778},
+ dictWord{12, 0, 50},
+ dictWord{12, 0, 127},
+ dictWord{
+ 12,
+ 0,
+ 396,
+ },
+ dictWord{13, 0, 62},
+ dictWord{13, 0, 328},
+ dictWord{14, 0, 122},
+ dictWord{147, 0, 72},
+ dictWord{9, 11, 157},
+ dictWord{10, 11, 131},
+ dictWord{
+ 140,
+ 11,
+ 72,
+ },
+ dictWord{135, 11, 714},
+ dictWord{135, 11, 539},
+ dictWord{5, 0, 2},
+ dictWord{6, 0, 512},
+ dictWord{7, 0, 797},
+ dictWord{7, 0, 1494},
+ dictWord{8, 0, 253},
+ dictWord{8, 0, 589},
+ dictWord{9, 0, 77},
+ dictWord{10, 0, 1},
+ dictWord{10, 0, 129},
+ dictWord{10, 0, 225},
+ dictWord{11, 0, 118},
+ dictWord{11, 0, 226},
+ dictWord{
+ 11,
+ 0,
+ 251,
+ },
+ dictWord{11, 0, 430},
+ dictWord{11, 0, 701},
+ dictWord{11, 0, 974},
+ dictWord{11, 0, 982},
+ dictWord{12, 0, 64},
+ dictWord{12, 0, 260},
+ dictWord{12, 0, 488},
+ dictWord{140, 0, 690},
+ dictWord{5, 11, 394},
+ dictWord{7, 11, 367},
+ dictWord{7, 11, 487},
+ dictWord{7, 11, 857},
+ dictWord{7, 11, 1713},
+ dictWord{8, 11, 246},
+ dictWord{9, 11, 537},
+ dictWord{10, 11, 165},
+ dictWord{12, 11, 219},
+ dictWord{140, 11, 561},
+ dictWord{136, 0, 557},
+ dictWord{5, 10, 779},
+ dictWord{5, 10, 807},
+ dictWord{6, 10, 1655},
+ dictWord{134, 10, 1676},
+ dictWord{4, 10, 196},
+ dictWord{5, 10, 558},
+ dictWord{133, 10, 949},
+ dictWord{11, 11, 827},
+ dictWord{
+ 12,
+ 11,
+ 56,
+ },
+ dictWord{14, 11, 34},
+ dictWord{143, 11, 148},
+ dictWord{137, 0, 347},
+ dictWord{133, 0, 572},
+ dictWord{134, 0, 832},
+ dictWord{4, 0, 12},
+ dictWord{
+ 7,
+ 0,
+ 504,
+ },
+ dictWord{7, 0, 522},
+ dictWord{7, 0, 809},
+ dictWord{8, 0, 797},
+ dictWord{141, 0, 88},
+ dictWord{4, 10, 752},
+ dictWord{133, 11, 449},
+ dictWord{7, 11, 86},
+ dictWord{8, 11, 103},
+ dictWord{145, 11, 69},
+ dictWord{7, 11, 2028},
+ dictWord{138, 11, 641},
+ dictWord{5, 0, 528},
+ dictWord{6, 11, 1},
+ dictWord{142, 11, 2},
+ dictWord{134, 0, 861},
+ dictWord{10, 0, 294},
+ dictWord{4, 10, 227},
+ dictWord{5, 10, 159},
+ dictWord{5, 10, 409},
+ dictWord{7, 10, 80},
+ dictWord{10, 10, 479},
+ dictWord{
+ 12,
+ 10,
+ 418,
+ },
+ dictWord{14, 10, 50},
+ dictWord{14, 10, 249},
+ dictWord{142, 10, 295},
+ dictWord{7, 10, 1470},
+ dictWord{8, 10, 66},
+ dictWord{8, 10, 137},
+ dictWord{
+ 8,
+ 10,
+ 761,
+ },
+ dictWord{9, 10, 638},
+ dictWord{11, 10, 80},
+ dictWord{11, 10, 212},
+ dictWord{11, 10, 368},
+ dictWord{11, 10, 418},
+ dictWord{12, 10, 8},
+ dictWord{
+ 13,
+ 10,
+ 15,
+ },
+ dictWord{16, 10, 61},
+ dictWord{17, 10, 59},
+ dictWord{19, 10, 28},
+ dictWord{148, 10, 84},
+ dictWord{20, 0, 109},
+ dictWord{135, 11, 1148},
+ dictWord{
+ 6,
+ 11,
+ 277,
+ },
+ dictWord{7, 11, 1274},
+ dictWord{7, 11, 1386},
+ dictWord{7, 11, 1392},
+ dictWord{12, 11, 129},
+ dictWord{146, 11, 87},
+ dictWord{6, 11, 187},
+ dictWord{7, 11, 39},
+ dictWord{7, 11, 1203},
+ dictWord{8, 11, 380},
+ dictWord{8, 11, 542},
+ dictWord{14, 11, 117},
+ dictWord{149, 11, 28},
+ dictWord{134, 0, 1187},
+ dictWord{5, 0, 266},
+ dictWord{9, 0, 290},
+ dictWord{9, 0, 364},
+ dictWord{10, 0, 293},
+ dictWord{11, 0, 606},
+ dictWord{142, 0, 45},
+ dictWord{6, 11, 297},
+ dictWord{
+ 7,
+ 11,
+ 793,
+ },
+ dictWord{139, 11, 938},
+ dictWord{4, 0, 50},
+ dictWord{6, 0, 594},
+ dictWord{9, 0, 121},
+ dictWord{10, 0, 49},
+ dictWord{10, 0, 412},
+ dictWord{139, 0, 834},
+ dictWord{136, 0, 748},
+ dictWord{7, 11, 464},
+ dictWord{8, 11, 438},
+ dictWord{11, 11, 105},
+ dictWord{11, 11, 363},
+ dictWord{12, 11, 231},
+ dictWord{
+ 14,
+ 11,
+ 386,
+ },
+ dictWord{15, 11, 102},
+ dictWord{148, 11, 75},
+ dictWord{132, 0, 466},
+ dictWord{13, 0, 399},
+ dictWord{14, 0, 337},
+ dictWord{6, 10, 38},
+ dictWord{
+ 7,
+ 10,
+ 1220,
+ },
+ dictWord{8, 10, 185},
+ dictWord{8, 10, 256},
+ dictWord{9, 10, 22},
+ dictWord{9, 10, 331},
+ dictWord{10, 10, 738},
+ dictWord{11, 10, 205},
+ dictWord{
+ 11,
+ 10,
+ 540,
+ },
+ dictWord{11, 10, 746},
+ dictWord{13, 10, 465},
+ dictWord{142, 10, 194},
+ dictWord{9, 0, 378},
+ dictWord{141, 0, 162},
+ dictWord{137, 0, 519},
+ dictWord{
+ 4,
+ 10,
+ 159,
+ },
+ dictWord{6, 10, 115},
+ dictWord{7, 10, 252},
+ dictWord{7, 10, 257},
+ dictWord{7, 10, 1928},
+ dictWord{8, 10, 69},
+ dictWord{9, 10, 384},
+ dictWord{
+ 10,
+ 10,
+ 91,
+ },
+ dictWord{10, 10, 615},
+ dictWord{12, 10, 375},
+ dictWord{14, 10, 235},
+ dictWord{18, 10, 117},
+ dictWord{147, 10, 123},
+ dictWord{5, 11, 604},
+ dictWord{
+ 5,
+ 10,
+ 911,
+ },
+ dictWord{136, 10, 278},
+ dictWord{132, 0, 667},
+ dictWord{8, 0, 351},
+ dictWord{9, 0, 322},
+ dictWord{4, 10, 151},
+ dictWord{135, 10, 1567},
+ dictWord{134, 0, 902},
+ dictWord{133, 10, 990},
+ dictWord{12, 0, 180},
+ dictWord{5, 10, 194},
+ dictWord{7, 10, 1662},
+ dictWord{137, 10, 90},
+ dictWord{4, 0, 869},
+ dictWord{134, 0, 1996},
+ dictWord{134, 0, 813},
+ dictWord{133, 10, 425},
+ dictWord{137, 11, 761},
+ dictWord{132, 0, 260},
+ dictWord{133, 10, 971},
+ dictWord{
+ 5,
+ 11,
+ 20,
+ },
+ dictWord{6, 11, 298},
+ dictWord{7, 11, 659},
+ dictWord{7, 11, 1366},
+ dictWord{137, 11, 219},
+ dictWord{4, 0, 39},
+ dictWord{5, 0, 36},
+ dictWord{
+ 7,
+ 0,
+ 1843,
+ },
+ dictWord{8, 0, 407},
+ dictWord{11, 0, 144},
+ dictWord{140, 0, 523},
+ dictWord{4, 0, 510},
+ dictWord{10, 0, 587},
+ dictWord{139, 10, 752},
+ dictWord{7, 0, 29},
+ dictWord{7, 0, 66},
+ dictWord{7, 0, 1980},
+ dictWord{10, 0, 487},
+ dictWord{138, 0, 809},
+ dictWord{13, 0, 260},
+ dictWord{14, 0, 82},
+ dictWord{18, 0, 63},
+ dictWord{
+ 137,
+ 10,
+ 662,
+ },
+ dictWord{5, 10, 72},
+ dictWord{6, 10, 264},
+ dictWord{7, 10, 21},
+ dictWord{7, 10, 46},
+ dictWord{7, 10, 2013},
+ dictWord{8, 10, 215},
+ dictWord{
+ 8,
+ 10,
+ 513,
+ },
+ dictWord{10, 10, 266},
+ dictWord{139, 10, 22},
+ dictWord{134, 0, 570},
+ dictWord{6, 0, 565},
+ dictWord{7, 0, 1667},
+ dictWord{4, 11, 439},
+ dictWord{
+ 10,
+ 10,
+ 95,
+ },
+ dictWord{11, 10, 603},
+ dictWord{12, 11, 242},
+ dictWord{13, 10, 443},
+ dictWord{14, 10, 160},
+ dictWord{143, 10, 4},
+ dictWord{134, 0, 1464},
+ dictWord{
+ 134,
+ 10,
+ 431,
+ },
+ dictWord{9, 0, 372},
+ dictWord{15, 0, 2},
+ dictWord{19, 0, 10},
+ dictWord{19, 0, 18},
+ dictWord{5, 10, 874},
+ dictWord{6, 10, 1677},
+ dictWord{143, 10, 0},
+ dictWord{132, 0, 787},
+ dictWord{6, 0, 380},
+ dictWord{12, 0, 399},
+ dictWord{21, 0, 19},
+ dictWord{7, 10, 939},
+ dictWord{7, 10, 1172},
+ dictWord{7, 10, 1671},
+ dictWord{9, 10, 540},
+ dictWord{10, 10, 696},
+ dictWord{11, 10, 265},
+ dictWord{11, 10, 732},
+ dictWord{11, 10, 928},
+ dictWord{11, 10, 937},
+ dictWord{
+ 141,
+ 10,
+ 438,
+ },
+ dictWord{137, 0, 200},
+ dictWord{132, 11, 233},
+ dictWord{132, 0, 516},
+ dictWord{134, 11, 577},
+ dictWord{132, 0, 844},
+ dictWord{11, 0, 887},
+ dictWord{14, 0, 365},
+ dictWord{142, 0, 375},
+ dictWord{132, 11, 482},
+ dictWord{8, 0, 821},
+ dictWord{140, 0, 44},
+ dictWord{7, 0, 1655},
+ dictWord{136, 0, 305},
+ dictWord{5, 10, 682},
+ dictWord{135, 10, 1887},
+ dictWord{135, 11, 346},
+ dictWord{132, 10, 696},
+ dictWord{4, 0, 10},
+ dictWord{7, 0, 917},
+ dictWord{139, 0, 786},
+ dictWord{5, 11, 795},
+ dictWord{6, 11, 1741},
+ dictWord{8, 11, 417},
+ dictWord{137, 11, 782},
+ dictWord{4, 0, 1016},
+ dictWord{134, 0, 2031},
+ dictWord{5, 0, 684},
+ dictWord{4, 10, 726},
+ dictWord{133, 10, 630},
+ dictWord{6, 0, 1021},
+ dictWord{134, 0, 1480},
+ dictWord{8, 10, 802},
+ dictWord{136, 10, 838},
+ dictWord{
+ 134,
+ 0,
+ 27,
+ },
+ dictWord{134, 0, 395},
+ dictWord{135, 11, 622},
+ dictWord{7, 11, 625},
+ dictWord{135, 11, 1750},
+ dictWord{4, 11, 203},
+ dictWord{135, 11, 1936},
+ dictWord{6, 10, 118},
+ dictWord{7, 10, 215},
+ dictWord{7, 10, 1521},
+ dictWord{140, 10, 11},
+ dictWord{132, 0, 813},
+ dictWord{136, 0, 511},
+ dictWord{7, 10, 615},
+ dictWord{138, 10, 251},
+ dictWord{135, 10, 1044},
+ dictWord{145, 0, 56},
+ dictWord{133, 10, 225},
+ dictWord{6, 0, 342},
+ dictWord{6, 0, 496},
+ dictWord{8, 0, 275},
+ dictWord{137, 0, 206},
+ dictWord{4, 0, 909},
+ dictWord{133, 0, 940},
+ dictWord{132, 0, 891},
+ dictWord{7, 11, 311},
+ dictWord{9, 11, 308},
+ dictWord{
+ 140,
+ 11,
+ 255,
+ },
+ dictWord{4, 10, 370},
+ dictWord{5, 10, 756},
+ dictWord{135, 10, 1326},
+ dictWord{4, 0, 687},
+ dictWord{134, 0, 1596},
+ dictWord{134, 0, 1342},
+ dictWord{
+ 6,
+ 10,
+ 1662,
+ },
+ dictWord{7, 10, 48},
+ dictWord{8, 10, 771},
+ dictWord{10, 10, 116},
+ dictWord{13, 10, 104},
+ dictWord{14, 10, 105},
+ dictWord{14, 10, 184},
+ dictWord{15, 10, 168},
+ dictWord{19, 10, 92},
+ dictWord{148, 10, 68},
+ dictWord{138, 10, 209},
+ dictWord{4, 11, 400},
+ dictWord{5, 11, 267},
+ dictWord{135, 11, 232},
+ dictWord{151, 11, 12},
+ dictWord{6, 0, 41},
+ dictWord{141, 0, 160},
+ dictWord{141, 11, 314},
+ dictWord{134, 0, 1718},
+ dictWord{136, 0, 778},
+ dictWord{
+ 142,
+ 11,
+ 261,
+ },
+ dictWord{134, 0, 1610},
+ dictWord{133, 0, 115},
+ dictWord{132, 0, 294},
+ dictWord{14, 0, 314},
+ dictWord{132, 10, 120},
+ dictWord{132, 0, 983},
+ dictWord{5, 0, 193},
+ dictWord{140, 0, 178},
+ dictWord{138, 10, 429},
+ dictWord{5, 10, 820},
+ dictWord{135, 10, 931},
+ dictWord{6, 0, 994},
+ dictWord{6, 0, 1051},
+ dictWord{6, 0, 1439},
+ dictWord{7, 0, 174},
+ dictWord{133, 11, 732},
+ dictWord{4, 11, 100},
+ dictWord{7, 11, 679},
+ dictWord{8, 11, 313},
+ dictWord{138, 10, 199},
+ dictWord{6, 10, 151},
+ dictWord{6, 10, 1675},
+ dictWord{7, 10, 383},
+ dictWord{151, 10, 10},
+ dictWord{6, 0, 1796},
+ dictWord{8, 0, 848},
+ dictWord{8, 0, 867},
+ dictWord{
+ 8,
+ 0,
+ 907,
+ },
+ dictWord{10, 0, 855},
+ dictWord{140, 0, 703},
+ dictWord{140, 0, 221},
+ dictWord{4, 0, 122},
+ dictWord{5, 0, 796},
+ dictWord{5, 0, 952},
+ dictWord{6, 0, 1660},
+ dictWord{6, 0, 1671},
+ dictWord{8, 0, 567},
+ dictWord{9, 0, 687},
+ dictWord{9, 0, 742},
+ dictWord{10, 0, 686},
+ dictWord{11, 0, 682},
+ dictWord{11, 0, 909},
+ dictWord{
+ 140,
+ 0,
+ 281,
+ },
+ dictWord{5, 11, 362},
+ dictWord{5, 11, 443},
+ dictWord{6, 11, 318},
+ dictWord{7, 11, 1019},
+ dictWord{139, 11, 623},
+ dictWord{5, 11, 463},
+ dictWord{136, 11, 296},
+ dictWord{11, 0, 583},
+ dictWord{13, 0, 262},
+ dictWord{6, 10, 1624},
+ dictWord{12, 10, 422},
+ dictWord{142, 10, 360},
+ dictWord{5, 0, 179},
+ dictWord{7, 0, 1095},
+ dictWord{135, 0, 1213},
+ dictWord{4, 10, 43},
+ dictWord{4, 11, 454},
+ dictWord{5, 10, 344},
+ dictWord{133, 10, 357},
+ dictWord{4, 0, 66},
+ dictWord{7, 0, 722},
+ dictWord{135, 0, 904},
+ dictWord{134, 0, 773},
+ dictWord{7, 0, 352},
+ dictWord{133, 10, 888},
+ dictWord{5, 11, 48},
+ dictWord{5, 11, 404},
+ dictWord{
+ 6,
+ 11,
+ 557,
+ },
+ dictWord{7, 11, 458},
+ dictWord{8, 11, 597},
+ dictWord{10, 11, 455},
+ dictWord{10, 11, 606},
+ dictWord{11, 11, 49},
+ dictWord{11, 11, 548},
+ dictWord{
+ 12,
+ 11,
+ 476,
+ },
+ dictWord{13, 11, 18},
+ dictWord{141, 11, 450},
+ dictWord{134, 11, 418},
+ dictWord{132, 10, 711},
+ dictWord{5, 11, 442},
+ dictWord{
+ 135,
+ 11,
+ 1984,
+ },
+ dictWord{141, 0, 35},
+ dictWord{137, 0, 152},
+ dictWord{134, 0, 1197},
+ dictWord{135, 11, 1093},
+ dictWord{137, 11, 203},
+ dictWord{137, 10, 440},
+ dictWord{10, 0, 592},
+ dictWord{10, 0, 753},
+ dictWord{12, 0, 317},
+ dictWord{12, 0, 355},
+ dictWord{12, 0, 465},
+ dictWord{12, 0, 469},
+ dictWord{12, 0, 560},
+ dictWord{12, 0, 578},
+ dictWord{141, 0, 243},
+ dictWord{133, 0, 564},
+ dictWord{134, 0, 797},
+ dictWord{5, 10, 958},
+ dictWord{133, 10, 987},
+ dictWord{5, 11, 55},
+ dictWord{7, 11, 376},
+ dictWord{140, 11, 161},
+ dictWord{133, 11, 450},
+ dictWord{134, 0, 556},
+ dictWord{134, 0, 819},
+ dictWord{11, 10, 276},
+ dictWord{
+ 142,
+ 10,
+ 293,
+ },
+ dictWord{7, 0, 544},
+ dictWord{138, 0, 61},
+ dictWord{8, 0, 719},
+ dictWord{4, 10, 65},
+ dictWord{5, 10, 479},
+ dictWord{5, 10, 1004},
+ dictWord{7, 10, 1913},
+ dictWord{8, 10, 317},
+ dictWord{9, 10, 302},
+ dictWord{10, 10, 612},
+ dictWord{141, 10, 22},
+ dictWord{4, 0, 5},
+ dictWord{5, 0, 498},
+ dictWord{8, 0, 637},
+ dictWord{
+ 9,
+ 0,
+ 521,
+ },
+ dictWord{4, 11, 213},
+ dictWord{4, 10, 261},
+ dictWord{7, 11, 223},
+ dictWord{7, 10, 510},
+ dictWord{136, 11, 80},
+ dictWord{5, 0, 927},
+ dictWord{7, 0, 101},
+ dictWord{4, 10, 291},
+ dictWord{7, 11, 381},
+ dictWord{7, 11, 806},
+ dictWord{7, 11, 820},
+ dictWord{8, 11, 354},
+ dictWord{8, 11, 437},
+ dictWord{8, 11, 787},
+ dictWord{9, 10, 515},
+ dictWord{9, 11, 657},
+ dictWord{10, 11, 58},
+ dictWord{10, 11, 339},
+ dictWord{10, 11, 749},
+ dictWord{11, 11, 914},
+ dictWord{12, 10, 152},
+ dictWord{12, 11, 162},
+ dictWord{12, 10, 443},
+ dictWord{13, 11, 75},
+ dictWord{13, 10, 392},
+ dictWord{14, 11, 106},
+ dictWord{14, 11, 198},
+ dictWord{
+ 14,
+ 11,
+ 320,
+ },
+ dictWord{14, 10, 357},
+ dictWord{14, 11, 413},
+ dictWord{146, 11, 43},
+ dictWord{6, 0, 1153},
+ dictWord{7, 0, 1441},
+ dictWord{136, 11, 747},
+ dictWord{
+ 4,
+ 0,
+ 893,
+ },
+ dictWord{5, 0, 780},
+ dictWord{133, 0, 893},
+ dictWord{138, 11, 654},
+ dictWord{133, 11, 692},
+ dictWord{133, 0, 238},
+ dictWord{134, 11, 191},
+ dictWord{4, 10, 130},
+ dictWord{135, 10, 843},
+ dictWord{6, 0, 1296},
+ dictWord{5, 10, 42},
+ dictWord{5, 10, 879},
+ dictWord{7, 10, 245},
+ dictWord{7, 10, 324},
+ dictWord{
+ 7,
+ 10,
+ 1532,
+ },
+ dictWord{11, 10, 463},
+ dictWord{11, 10, 472},
+ dictWord{13, 10, 363},
+ dictWord{144, 10, 52},
+ dictWord{134, 0, 1729},
+ dictWord{6, 0, 1999},
+ dictWord{136, 0, 969},
+ dictWord{4, 10, 134},
+ dictWord{133, 10, 372},
+ dictWord{4, 0, 60},
+ dictWord{7, 0, 941},
+ dictWord{7, 0, 1800},
+ dictWord{8, 0, 314},
+ dictWord{
+ 9,
+ 0,
+ 700,
+ },
+ dictWord{139, 0, 487},
+ dictWord{134, 0, 1144},
+ dictWord{6, 11, 162},
+ dictWord{7, 11, 1960},
+ dictWord{136, 11, 831},
+ dictWord{132, 11, 706},
+ dictWord{135, 0, 1147},
+ dictWord{138, 11, 426},
+ dictWord{138, 11, 89},
+ dictWord{7, 0, 1853},
+ dictWord{138, 0, 437},
+ dictWord{136, 0, 419},
+ dictWord{
+ 135,
+ 10,
+ 1634,
+ },
+ dictWord{133, 0, 828},
+ dictWord{5, 0, 806},
+ dictWord{7, 0, 176},
+ dictWord{7, 0, 178},
+ dictWord{7, 0, 1240},
+ dictWord{7, 0, 1976},
+ dictWord{
+ 132,
+ 10,
+ 644,
+ },
+ dictWord{135, 11, 1877},
+ dictWord{5, 11, 420},
+ dictWord{135, 11, 1449},
+ dictWord{4, 0, 51},
+ dictWord{5, 0, 39},
+ dictWord{6, 0, 4},
+ dictWord{7, 0, 591},
+ dictWord{7, 0, 849},
+ dictWord{7, 0, 951},
+ dictWord{7, 0, 1613},
+ dictWord{7, 0, 1760},
+ dictWord{7, 0, 1988},
+ dictWord{9, 0, 434},
+ dictWord{10, 0, 754},
+ dictWord{
+ 11,
+ 0,
+ 25,
+ },
+ dictWord{139, 0, 37},
+ dictWord{10, 11, 57},
+ dictWord{138, 11, 277},
+ dictWord{135, 10, 540},
+ dictWord{132, 11, 204},
+ dictWord{135, 0, 159},
+ dictWord{139, 11, 231},
+ dictWord{133, 0, 902},
+ dictWord{7, 0, 928},
+ dictWord{7, 11, 366},
+ dictWord{9, 11, 287},
+ dictWord{12, 11, 199},
+ dictWord{12, 11, 556},
+ dictWord{140, 11, 577},
+ dictWord{6, 10, 623},
+ dictWord{136, 10, 789},
+ dictWord{4, 10, 908},
+ dictWord{5, 10, 359},
+ dictWord{5, 10, 508},
+ dictWord{6, 10, 1723},
+ dictWord{7, 10, 343},
+ dictWord{7, 10, 1996},
+ dictWord{135, 10, 2026},
+ dictWord{134, 0, 270},
+ dictWord{4, 10, 341},
+ dictWord{135, 10, 480},
+ dictWord{
+ 5,
+ 11,
+ 356,
+ },
+ dictWord{135, 11, 224},
+ dictWord{11, 11, 588},
+ dictWord{11, 11, 864},
+ dictWord{11, 11, 968},
+ dictWord{143, 11, 160},
+ dictWord{132, 0, 556},
+ dictWord{137, 0, 801},
+ dictWord{132, 0, 416},
+ dictWord{142, 0, 372},
+ dictWord{5, 0, 152},
+ dictWord{5, 0, 197},
+ dictWord{7, 0, 340},
+ dictWord{7, 0, 867},
+ dictWord{
+ 10,
+ 0,
+ 548,
+ },
+ dictWord{10, 0, 581},
+ dictWord{11, 0, 6},
+ dictWord{12, 0, 3},
+ dictWord{12, 0, 19},
+ dictWord{14, 0, 110},
+ dictWord{142, 0, 289},
+ dictWord{139, 0, 369},
+ dictWord{7, 11, 630},
+ dictWord{9, 11, 567},
+ dictWord{11, 11, 150},
+ dictWord{11, 11, 444},
+ dictWord{141, 11, 119},
+ dictWord{134, 11, 539},
+ dictWord{
+ 7,
+ 10,
+ 1995,
+ },
+ dictWord{8, 10, 299},
+ dictWord{11, 10, 890},
+ dictWord{140, 10, 674},
+ dictWord{7, 0, 34},
+ dictWord{7, 0, 190},
+ dictWord{8, 0, 28},
+ dictWord{8, 0, 141},
+ dictWord{8, 0, 444},
+ dictWord{8, 0, 811},
+ dictWord{9, 0, 468},
+ dictWord{11, 0, 334},
+ dictWord{12, 0, 24},
+ dictWord{12, 0, 386},
+ dictWord{140, 0, 576},
+ dictWord{
+ 133,
+ 0,
+ 757,
+ },
+ dictWord{7, 0, 1553},
+ dictWord{136, 0, 898},
+ dictWord{133, 0, 721},
+ dictWord{136, 0, 1012},
+ dictWord{4, 0, 789},
+ dictWord{5, 0, 647},
+ dictWord{
+ 135,
+ 0,
+ 1102,
+ },
+ dictWord{132, 0, 898},
+ dictWord{10, 0, 183},
+ dictWord{4, 10, 238},
+ dictWord{5, 10, 503},
+ dictWord{6, 10, 179},
+ dictWord{7, 10, 2003},
+ dictWord{
+ 8,
+ 10,
+ 381,
+ },
+ dictWord{8, 10, 473},
+ dictWord{9, 10, 149},
+ dictWord{10, 10, 788},
+ dictWord{15, 10, 45},
+ dictWord{15, 10, 86},
+ dictWord{20, 10, 110},
+ dictWord{
+ 150,
+ 10,
+ 57,
+ },
+ dictWord{9, 0, 136},
+ dictWord{19, 0, 107},
+ dictWord{4, 10, 121},
+ dictWord{5, 10, 156},
+ dictWord{5, 10, 349},
+ dictWord{10, 10, 605},
+ dictWord{
+ 142,
+ 10,
+ 342,
+ },
+ dictWord{4, 11, 235},
+ dictWord{135, 11, 255},
+ dictWord{4, 11, 194},
+ dictWord{5, 11, 584},
+ dictWord{6, 11, 384},
+ dictWord{7, 11, 583},
+ dictWord{
+ 10,
+ 11,
+ 761,
+ },
+ dictWord{11, 11, 760},
+ dictWord{139, 11, 851},
+ dictWord{6, 10, 80},
+ dictWord{6, 10, 1694},
+ dictWord{7, 10, 173},
+ dictWord{7, 10, 1974},
+ dictWord{
+ 9,
+ 10,
+ 547,
+ },
+ dictWord{10, 10, 730},
+ dictWord{14, 10, 18},
+ dictWord{150, 10, 39},
+ dictWord{4, 10, 923},
+ dictWord{134, 10, 1711},
+ dictWord{5, 0, 277},
+ dictWord{141, 0, 247},
+ dictWord{132, 0, 435},
+ dictWord{133, 11, 562},
+ dictWord{134, 0, 1311},
+ dictWord{5, 11, 191},
+ dictWord{137, 11, 271},
+ dictWord{
+ 132,
+ 10,
+ 595,
+ },
+ dictWord{7, 11, 1537},
+ dictWord{14, 11, 96},
+ dictWord{143, 11, 73},
+ dictWord{5, 0, 437},
+ dictWord{7, 0, 502},
+ dictWord{7, 0, 519},
+ dictWord{7, 0, 1122},
+ dictWord{7, 0, 1751},
+ dictWord{14, 0, 211},
+ dictWord{6, 10, 459},
+ dictWord{7, 10, 1753},
+ dictWord{7, 10, 1805},
+ dictWord{8, 10, 658},
+ dictWord{9, 10, 1},
+ dictWord{11, 10, 959},
+ dictWord{141, 10, 446},
+ dictWord{6, 0, 814},
+ dictWord{4, 11, 470},
+ dictWord{5, 11, 473},
+ dictWord{6, 11, 153},
+ dictWord{7, 11, 1503},
+ dictWord{7, 11, 1923},
+ dictWord{10, 11, 701},
+ dictWord{11, 11, 132},
+ dictWord{11, 11, 168},
+ dictWord{11, 11, 227},
+ dictWord{11, 11, 320},
+ dictWord{
+ 11,
+ 11,
+ 436,
+ },
+ dictWord{11, 11, 525},
+ dictWord{11, 11, 855},
+ dictWord{12, 11, 41},
+ dictWord{12, 11, 286},
+ dictWord{13, 11, 103},
+ dictWord{13, 11, 284},
+ dictWord{
+ 14,
+ 11,
+ 255,
+ },
+ dictWord{14, 11, 262},
+ dictWord{15, 11, 117},
+ dictWord{143, 11, 127},
+ dictWord{5, 0, 265},
+ dictWord{6, 0, 212},
+ dictWord{135, 0, 28},
+ dictWord{
+ 138,
+ 0,
+ 750,
+ },
+ dictWord{133, 11, 327},
+ dictWord{6, 11, 552},
+ dictWord{7, 11, 1754},
+ dictWord{137, 11, 604},
+ dictWord{134, 0, 2012},
+ dictWord{132, 0, 702},
+ dictWord{5, 11, 80},
+ dictWord{6, 11, 405},
+ dictWord{7, 11, 403},
+ dictWord{7, 11, 1502},
+ dictWord{7, 11, 1626},
+ dictWord{8, 11, 456},
+ dictWord{9, 11, 487},
+ dictWord{9, 11, 853},
+ dictWord{9, 11, 889},
+ dictWord{10, 11, 309},
+ dictWord{11, 11, 721},
+ dictWord{11, 11, 994},
+ dictWord{12, 11, 430},
+ dictWord{
+ 141,
+ 11,
+ 165,
+ },
+ dictWord{5, 0, 808},
+ dictWord{135, 0, 2045},
+ dictWord{5, 0, 166},
+ dictWord{8, 0, 739},
+ dictWord{140, 0, 511},
+ dictWord{134, 10, 490},
+ dictWord{
+ 4,
+ 11,
+ 453,
+ },
+ dictWord{5, 11, 887},
+ dictWord{6, 11, 535},
+ dictWord{8, 11, 6},
+ dictWord{136, 11, 543},
+ dictWord{4, 0, 119},
+ dictWord{5, 0, 170},
+ dictWord{5, 0, 447},
+ dictWord{7, 0, 1708},
+ dictWord{7, 0, 1889},
+ dictWord{9, 0, 357},
+ dictWord{9, 0, 719},
+ dictWord{12, 0, 486},
+ dictWord{140, 0, 596},
+ dictWord{137, 0, 500},
+ dictWord{
+ 7,
+ 10,
+ 250,
+ },
+ dictWord{136, 10, 507},
+ dictWord{132, 10, 158},
+ dictWord{6, 0, 809},
+ dictWord{134, 0, 1500},
+ dictWord{9, 0, 327},
+ dictWord{11, 0, 350},
+ dictWord{11, 0, 831},
+ dictWord{13, 0, 352},
+ dictWord{4, 10, 140},
+ dictWord{7, 10, 362},
+ dictWord{8, 10, 209},
+ dictWord{9, 10, 10},
+ dictWord{9, 10, 503},
+ dictWord{
+ 9,
+ 10,
+ 614,
+ },
+ dictWord{10, 10, 689},
+ dictWord{11, 10, 327},
+ dictWord{11, 10, 725},
+ dictWord{12, 10, 252},
+ dictWord{12, 10, 583},
+ dictWord{13, 10, 192},
+ dictWord{14, 10, 269},
+ dictWord{14, 10, 356},
+ dictWord{148, 10, 50},
+ dictWord{135, 11, 741},
+ dictWord{4, 0, 450},
+ dictWord{7, 0, 1158},
+ dictWord{19, 10, 1},
+ dictWord{19, 10, 26},
+ dictWord{150, 10, 9},
+ dictWord{6, 0, 597},
+ dictWord{135, 0, 1318},
+ dictWord{134, 0, 1602},
+ dictWord{6, 10, 228},
+ dictWord{7, 10, 1341},
+ dictWord{9, 10, 408},
+ dictWord{138, 10, 343},
+ dictWord{7, 0, 1375},
+ dictWord{7, 0, 1466},
+ dictWord{138, 0, 331},
+ dictWord{132, 0, 754},
+ dictWord{
+ 132,
+ 10,
+ 557,
+ },
+ dictWord{5, 11, 101},
+ dictWord{6, 11, 88},
+ dictWord{6, 11, 543},
+ dictWord{7, 11, 1677},
+ dictWord{9, 11, 100},
+ dictWord{10, 11, 677},
+ dictWord{
+ 14,
+ 11,
+ 169,
+ },
+ dictWord{14, 11, 302},
+ dictWord{14, 11, 313},
+ dictWord{15, 11, 48},
+ dictWord{143, 11, 84},
+ dictWord{134, 0, 1368},
+ dictWord{4, 11, 310},
+ dictWord{
+ 9,
+ 11,
+ 795,
+ },
+ dictWord{10, 11, 733},
+ dictWord{11, 11, 451},
+ dictWord{12, 11, 249},
+ dictWord{14, 11, 115},
+ dictWord{14, 11, 286},
+ dictWord{143, 11, 100},
+ dictWord{132, 10, 548},
+ dictWord{10, 0, 557},
+ dictWord{7, 10, 197},
+ dictWord{8, 10, 142},
+ dictWord{8, 10, 325},
+ dictWord{9, 10, 150},
+ dictWord{9, 10, 596},
+ dictWord{10, 10, 353},
+ dictWord{11, 10, 74},
+ dictWord{11, 10, 315},
+ dictWord{12, 10, 662},
+ dictWord{12, 10, 681},
+ dictWord{14, 10, 423},
+ dictWord{
+ 143,
+ 10,
+ 141,
+ },
+ dictWord{133, 11, 587},
+ dictWord{5, 0, 850},
+ dictWord{136, 0, 799},
+ dictWord{10, 0, 908},
+ dictWord{12, 0, 701},
+ dictWord{12, 0, 757},
+ dictWord{
+ 142,
+ 0,
+ 466,
+ },
+ dictWord{4, 0, 62},
+ dictWord{5, 0, 275},
+ dictWord{18, 0, 19},
+ dictWord{6, 10, 399},
+ dictWord{6, 10, 579},
+ dictWord{7, 10, 692},
+ dictWord{7, 10, 846},
+ dictWord{
+ 7,
+ 10,
+ 1015,
+ },
+ dictWord{7, 10, 1799},
+ dictWord{8, 10, 403},
+ dictWord{9, 10, 394},
+ dictWord{10, 10, 133},
+ dictWord{12, 10, 4},
+ dictWord{12, 10, 297},
+ dictWord{12, 10, 452},
+ dictWord{16, 10, 81},
+ dictWord{18, 10, 25},
+ dictWord{21, 10, 14},
+ dictWord{22, 10, 12},
+ dictWord{151, 10, 18},
+ dictWord{12, 0, 459},
+ dictWord{
+ 7,
+ 10,
+ 1546,
+ },
+ dictWord{11, 10, 299},
+ dictWord{142, 10, 407},
+ dictWord{132, 10, 177},
+ dictWord{132, 11, 498},
+ dictWord{7, 11, 217},
+ dictWord{
+ 8,
+ 11,
+ 140,
+ },
+ dictWord{138, 11, 610},
+ dictWord{5, 10, 411},
+ dictWord{135, 10, 653},
+ dictWord{134, 0, 1802},
+ dictWord{7, 10, 439},
+ dictWord{10, 10, 727},
+ dictWord{11, 10, 260},
+ dictWord{139, 10, 684},
+ dictWord{133, 11, 905},
+ dictWord{11, 11, 580},
+ dictWord{142, 11, 201},
+ dictWord{134, 0, 1397},
+ dictWord{
+ 5,
+ 10,
+ 208,
+ },
+ dictWord{7, 10, 753},
+ dictWord{135, 10, 1528},
+ dictWord{7, 0, 238},
+ dictWord{7, 0, 2033},
+ dictWord{8, 0, 120},
+ dictWord{8, 0, 188},
+ dictWord{8, 0, 659},
+ dictWord{9, 0, 598},
+ dictWord{10, 0, 466},
+ dictWord{12, 0, 342},
+ dictWord{12, 0, 588},
+ dictWord{13, 0, 503},
+ dictWord{14, 0, 246},
+ dictWord{143, 0, 92},
+ dictWord{135, 11, 1041},
+ dictWord{4, 11, 456},
+ dictWord{7, 11, 105},
+ dictWord{7, 11, 358},
+ dictWord{7, 11, 1637},
+ dictWord{8, 11, 643},
+ dictWord{139, 11, 483},
+ dictWord{6, 0, 1318},
+ dictWord{134, 0, 1324},
+ dictWord{4, 0, 201},
+ dictWord{7, 0, 1744},
+ dictWord{8, 0, 602},
+ dictWord{11, 0, 247},
+ dictWord{11, 0, 826},
+ dictWord{17, 0, 65},
+ dictWord{133, 10, 242},
+ dictWord{8, 0, 164},
+ dictWord{146, 0, 62},
+ dictWord{133, 10, 953},
+ dictWord{139, 10, 802},
+ dictWord{133, 0, 615},
+ dictWord{7, 11, 1566},
+ dictWord{8, 11, 269},
+ dictWord{9, 11, 212},
+ dictWord{9, 11, 718},
+ dictWord{14, 11, 15},
+ dictWord{14, 11, 132},
+ dictWord{142, 11, 227},
+ dictWord{133, 10, 290},
+ dictWord{132, 10, 380},
+ dictWord{5, 10, 52},
+ dictWord{7, 10, 277},
+ dictWord{9, 10, 368},
+ dictWord{139, 10, 791},
+ dictWord{
+ 135,
+ 0,
+ 1243,
+ },
+ dictWord{133, 11, 539},
+ dictWord{11, 11, 919},
+ dictWord{141, 11, 409},
+ dictWord{136, 0, 968},
+ dictWord{133, 11, 470},
+ dictWord{134, 0, 882},
+ dictWord{132, 0, 907},
+ dictWord{5, 0, 100},
+ dictWord{10, 0, 329},
+ dictWord{12, 0, 416},
+ dictWord{149, 0, 29},
+ dictWord{10, 10, 138},
+ dictWord{139, 10, 476},
+ dictWord{5, 10, 725},
+ dictWord{5, 10, 727},
+ dictWord{6, 11, 91},
+ dictWord{7, 11, 435},
+ dictWord{135, 10, 1811},
+ dictWord{4, 11, 16},
+ dictWord{5, 11, 316},
+ dictWord{5, 11, 842},
+ dictWord{6, 11, 370},
+ dictWord{6, 11, 1778},
+ dictWord{8, 11, 166},
+ dictWord{11, 11, 812},
+ dictWord{12, 11, 206},
+ dictWord{12, 11, 351},
+ dictWord{14, 11, 418},
+ dictWord{16, 11, 15},
+ dictWord{16, 11, 34},
+ dictWord{18, 11, 3},
+ dictWord{19, 11, 3},
+ dictWord{19, 11, 7},
+ dictWord{20, 11, 4},
+ dictWord{
+ 149,
+ 11,
+ 21,
+ },
+ dictWord{132, 0, 176},
+ dictWord{5, 0, 636},
+ dictWord{5, 0, 998},
+ dictWord{7, 0, 9},
+ dictWord{7, 0, 1508},
+ dictWord{8, 0, 26},
+ dictWord{9, 0, 317},
+ dictWord{
+ 9,
+ 0,
+ 358,
+ },
+ dictWord{10, 0, 210},
+ dictWord{10, 0, 292},
+ dictWord{10, 0, 533},
+ dictWord{11, 0, 555},
+ dictWord{12, 0, 526},
+ dictWord{12, 0, 607},
+ dictWord{
+ 13,
+ 0,
+ 263,
+ },
+ dictWord{13, 0, 459},
+ dictWord{142, 0, 271},
+ dictWord{6, 0, 256},
+ dictWord{8, 0, 265},
+ dictWord{4, 10, 38},
+ dictWord{7, 10, 307},
+ dictWord{7, 10, 999},
+ dictWord{7, 10, 1481},
+ dictWord{7, 10, 1732},
+ dictWord{7, 10, 1738},
+ dictWord{9, 10, 414},
+ dictWord{11, 10, 316},
+ dictWord{12, 10, 52},
+ dictWord{13, 10, 420},
+ dictWord{147, 10, 100},
+ dictWord{135, 10, 1296},
+ dictWord{4, 11, 611},
+ dictWord{133, 11, 606},
+ dictWord{4, 0, 643},
+ dictWord{142, 11, 21},
+ dictWord{
+ 133,
+ 11,
+ 715,
+ },
+ dictWord{133, 10, 723},
+ dictWord{6, 0, 610},
+ dictWord{135, 11, 597},
+ dictWord{10, 0, 127},
+ dictWord{141, 0, 27},
+ dictWord{6, 0, 1995},
+ dictWord{
+ 6,
+ 0,
+ 2001,
+ },
+ dictWord{8, 0, 119},
+ dictWord{136, 0, 973},
+ dictWord{4, 11, 149},
+ dictWord{138, 11, 368},
+ dictWord{12, 0, 522},
+ dictWord{4, 11, 154},
+ dictWord{
+ 5,
+ 10,
+ 109,
+ },
+ dictWord{6, 10, 1784},
+ dictWord{7, 11, 1134},
+ dictWord{7, 10, 1895},
+ dictWord{8, 11, 105},
+ dictWord{12, 10, 296},
+ dictWord{140, 10, 302},
+ dictWord{4, 11, 31},
+ dictWord{6, 11, 429},
+ dictWord{7, 11, 962},
+ dictWord{9, 11, 458},
+ dictWord{139, 11, 691},
+ dictWord{10, 0, 553},
+ dictWord{11, 0, 876},
+ dictWord{13, 0, 193},
+ dictWord{13, 0, 423},
+ dictWord{14, 0, 166},
+ dictWord{19, 0, 84},
+ dictWord{4, 11, 312},
+ dictWord{5, 10, 216},
+ dictWord{7, 10, 1879},
+ dictWord{
+ 9,
+ 10,
+ 141,
+ },
+ dictWord{9, 10, 270},
+ dictWord{9, 10, 679},
+ dictWord{10, 10, 159},
+ dictWord{11, 10, 197},
+ dictWord{12, 10, 538},
+ dictWord{12, 10, 559},
+ dictWord{14, 10, 144},
+ dictWord{14, 10, 167},
+ dictWord{143, 10, 67},
+ dictWord{134, 0, 1582},
+ dictWord{7, 0, 1578},
+ dictWord{135, 11, 1578},
+ dictWord{
+ 137,
+ 10,
+ 81,
+ },
+ dictWord{132, 11, 236},
+ dictWord{134, 10, 391},
+ dictWord{134, 0, 795},
+ dictWord{7, 10, 322},
+ dictWord{136, 10, 249},
+ dictWord{5, 11, 836},
+ dictWord{
+ 5,
+ 11,
+ 857,
+ },
+ dictWord{6, 11, 1680},
+ dictWord{7, 11, 59},
+ dictWord{147, 11, 53},
+ dictWord{135, 0, 432},
+ dictWord{10, 11, 68},
+ dictWord{139, 11, 494},
+ dictWord{4, 11, 81},
+ dictWord{139, 11, 867},
+ dictWord{7, 0, 126},
+ dictWord{136, 0, 84},
+ dictWord{142, 11, 280},
+ dictWord{5, 11, 282},
+ dictWord{8, 11, 650},
+ dictWord{
+ 9,
+ 11,
+ 295,
+ },
+ dictWord{9, 11, 907},
+ dictWord{138, 11, 443},
+ dictWord{136, 0, 790},
+ dictWord{5, 10, 632},
+ dictWord{138, 10, 526},
+ dictWord{6, 0, 64},
+ dictWord{12, 0, 377},
+ dictWord{13, 0, 309},
+ dictWord{14, 0, 141},
+ dictWord{14, 0, 429},
+ dictWord{14, 11, 141},
+ dictWord{142, 11, 429},
+ dictWord{134, 0, 1529},
+ dictWord{6, 0, 321},
+ dictWord{7, 0, 1857},
+ dictWord{9, 0, 530},
+ dictWord{19, 0, 99},
+ dictWord{7, 10, 948},
+ dictWord{7, 10, 1042},
+ dictWord{8, 10, 235},
+ dictWord{
+ 8,
+ 10,
+ 461,
+ },
+ dictWord{9, 10, 453},
+ dictWord{10, 10, 354},
+ dictWord{145, 10, 77},
+ dictWord{7, 0, 1104},
+ dictWord{11, 0, 269},
+ dictWord{11, 0, 539},
+ dictWord{
+ 11,
+ 0,
+ 627,
+ },
+ dictWord{11, 0, 706},
+ dictWord{11, 0, 975},
+ dictWord{12, 0, 248},
+ dictWord{12, 0, 434},
+ dictWord{12, 0, 600},
+ dictWord{12, 0, 622},
+ dictWord{
+ 13,
+ 0,
+ 297,
+ },
+ dictWord{13, 0, 485},
+ dictWord{14, 0, 69},
+ dictWord{14, 0, 409},
+ dictWord{143, 0, 108},
+ dictWord{4, 10, 362},
+ dictWord{7, 10, 52},
+ dictWord{7, 10, 303},
+ dictWord{10, 11, 70},
+ dictWord{12, 11, 26},
+ dictWord{14, 11, 17},
+ dictWord{14, 11, 178},
+ dictWord{15, 11, 34},
+ dictWord{149, 11, 12},
+ dictWord{11, 0, 977},
+ dictWord{141, 0, 507},
+ dictWord{9, 0, 34},
+ dictWord{139, 0, 484},
+ dictWord{5, 10, 196},
+ dictWord{6, 10, 486},
+ dictWord{7, 10, 212},
+ dictWord{8, 10, 309},
+ dictWord{136, 10, 346},
+ dictWord{6, 0, 1700},
+ dictWord{7, 0, 26},
+ dictWord{7, 0, 293},
+ dictWord{7, 0, 382},
+ dictWord{7, 0, 1026},
+ dictWord{7, 0, 1087},
+ dictWord{
+ 7,
+ 0,
+ 2027,
+ },
+ dictWord{8, 0, 24},
+ dictWord{8, 0, 114},
+ dictWord{8, 0, 252},
+ dictWord{8, 0, 727},
+ dictWord{8, 0, 729},
+ dictWord{9, 0, 30},
+ dictWord{9, 0, 199},
+ dictWord{
+ 9,
+ 0,
+ 231,
+ },
+ dictWord{9, 0, 251},
+ dictWord{9, 0, 334},
+ dictWord{9, 0, 361},
+ dictWord{9, 0, 712},
+ dictWord{10, 0, 55},
+ dictWord{10, 0, 60},
+ dictWord{10, 0, 232},
+ dictWord{
+ 10,
+ 0,
+ 332,
+ },
+ dictWord{10, 0, 384},
+ dictWord{10, 0, 396},
+ dictWord{10, 0, 504},
+ dictWord{10, 0, 542},
+ dictWord{10, 0, 652},
+ dictWord{11, 0, 20},
+ dictWord{11, 0, 48},
+ dictWord{11, 0, 207},
+ dictWord{11, 0, 291},
+ dictWord{11, 0, 298},
+ dictWord{11, 0, 342},
+ dictWord{11, 0, 365},
+ dictWord{11, 0, 394},
+ dictWord{11, 0, 620},
+ dictWord{11, 0, 705},
+ dictWord{11, 0, 1017},
+ dictWord{12, 0, 123},
+ dictWord{12, 0, 340},
+ dictWord{12, 0, 406},
+ dictWord{12, 0, 643},
+ dictWord{13, 0, 61},
+ dictWord{
+ 13,
+ 0,
+ 269,
+ },
+ dictWord{13, 0, 311},
+ dictWord{13, 0, 319},
+ dictWord{13, 0, 486},
+ dictWord{14, 0, 234},
+ dictWord{15, 0, 62},
+ dictWord{15, 0, 85},
+ dictWord{16, 0, 71},
+ dictWord{18, 0, 119},
+ dictWord{20, 0, 105},
+ dictWord{135, 10, 1912},
+ dictWord{4, 11, 71},
+ dictWord{5, 11, 376},
+ dictWord{7, 11, 119},
+ dictWord{138, 11, 665},
+ dictWord{10, 0, 918},
+ dictWord{10, 0, 926},
+ dictWord{4, 10, 686},
+ dictWord{136, 11, 55},
+ dictWord{138, 10, 625},
+ dictWord{136, 10, 706},
+ dictWord{
+ 132,
+ 11,
+ 479,
+ },
+ dictWord{4, 10, 30},
+ dictWord{133, 10, 43},
+ dictWord{6, 0, 379},
+ dictWord{7, 0, 270},
+ dictWord{8, 0, 176},
+ dictWord{8, 0, 183},
+ dictWord{9, 0, 432},
+ dictWord{
+ 9,
+ 0,
+ 661,
+ },
+ dictWord{12, 0, 247},
+ dictWord{12, 0, 617},
+ dictWord{18, 0, 125},
+ dictWord{7, 11, 607},
+ dictWord{8, 11, 99},
+ dictWord{152, 11, 4},
+ dictWord{
+ 5,
+ 0,
+ 792,
+ },
+ dictWord{133, 0, 900},
+ dictWord{4, 11, 612},
+ dictWord{133, 11, 561},
+ dictWord{4, 11, 41},
+ dictWord{4, 10, 220},
+ dictWord{5, 11, 74},
+ dictWord{
+ 7,
+ 10,
+ 1535,
+ },
+ dictWord{7, 11, 1627},
+ dictWord{11, 11, 871},
+ dictWord{140, 11, 619},
+ dictWord{135, 0, 1920},
+ dictWord{7, 11, 94},
+ dictWord{11, 11, 329},
+ dictWord{11, 11, 965},
+ dictWord{12, 11, 241},
+ dictWord{14, 11, 354},
+ dictWord{15, 11, 22},
+ dictWord{148, 11, 63},
+ dictWord{9, 11, 209},
+ dictWord{137, 11, 300},
+ dictWord{134, 0, 771},
+ dictWord{135, 0, 1979},
+ dictWord{4, 0, 901},
+ dictWord{133, 0, 776},
+ dictWord{142, 0, 254},
+ dictWord{133, 11, 98},
+ dictWord{
+ 9,
+ 11,
+ 16,
+ },
+ dictWord{141, 11, 386},
+ dictWord{133, 11, 984},
+ dictWord{4, 11, 182},
+ dictWord{6, 11, 205},
+ dictWord{135, 11, 220},
+ dictWord{7, 10, 1725},
+ dictWord{
+ 7,
+ 10,
+ 1774,
+ },
+ dictWord{138, 10, 393},
+ dictWord{5, 10, 263},
+ dictWord{134, 10, 414},
+ dictWord{4, 11, 42},
+ dictWord{9, 11, 205},
+ dictWord{9, 11, 786},
+ dictWord{138, 11, 659},
+ dictWord{14, 0, 140},
+ dictWord{148, 0, 41},
+ dictWord{8, 0, 440},
+ dictWord{10, 0, 359},
+ dictWord{6, 10, 178},
+ dictWord{6, 11, 289},
+ dictWord{
+ 6,
+ 10,
+ 1750,
+ },
+ dictWord{7, 11, 1670},
+ dictWord{9, 10, 690},
+ dictWord{10, 10, 155},
+ dictWord{10, 10, 373},
+ dictWord{11, 10, 698},
+ dictWord{12, 11, 57},
+ dictWord{13, 10, 155},
+ dictWord{20, 10, 93},
+ dictWord{151, 11, 4},
+ dictWord{4, 0, 37},
+ dictWord{5, 0, 334},
+ dictWord{7, 0, 1253},
+ dictWord{151, 11, 25},
+ dictWord{
+ 4,
+ 0,
+ 508,
+ },
+ dictWord{4, 11, 635},
+ dictWord{5, 10, 97},
+ dictWord{137, 10, 393},
+ dictWord{139, 11, 533},
+ dictWord{4, 0, 640},
+ dictWord{133, 0, 513},
+ dictWord{
+ 134,
+ 10,
+ 1639,
+ },
+ dictWord{132, 11, 371},
+ dictWord{4, 11, 272},
+ dictWord{7, 11, 836},
+ dictWord{7, 11, 1651},
+ dictWord{145, 11, 89},
+ dictWord{5, 11, 825},
+ dictWord{6, 11, 444},
+ dictWord{6, 11, 1640},
+ dictWord{136, 11, 308},
+ dictWord{4, 10, 191},
+ dictWord{7, 10, 934},
+ dictWord{8, 10, 647},
+ dictWord{145, 10, 97},
+ dictWord{12, 0, 246},
+ dictWord{15, 0, 162},
+ dictWord{19, 0, 64},
+ dictWord{20, 0, 8},
+ dictWord{20, 0, 95},
+ dictWord{22, 0, 24},
+ dictWord{152, 0, 17},
+ dictWord{4, 0, 533},
+ dictWord{5, 10, 165},
+ dictWord{9, 10, 346},
+ dictWord{138, 10, 655},
+ dictWord{5, 11, 737},
+ dictWord{139, 10, 885},
+ dictWord{133, 10, 877},
+ dictWord{
+ 8,
+ 10,
+ 128,
+ },
+ dictWord{139, 10, 179},
+ dictWord{137, 11, 307},
+ dictWord{140, 0, 752},
+ dictWord{133, 0, 920},
+ dictWord{135, 0, 1048},
+ dictWord{5, 0, 153},
+ dictWord{
+ 6,
+ 0,
+ 580,
+ },
+ dictWord{6, 10, 1663},
+ dictWord{7, 10, 132},
+ dictWord{7, 10, 1154},
+ dictWord{7, 10, 1415},
+ dictWord{7, 10, 1507},
+ dictWord{12, 10, 493},
+ dictWord{15, 10, 105},
+ dictWord{151, 10, 15},
+ dictWord{5, 10, 459},
+ dictWord{7, 10, 1073},
+ dictWord{8, 10, 241},
+ dictWord{136, 10, 334},
+ dictWord{138, 0, 391},
+ dictWord{135, 0, 1952},
+ dictWord{133, 11, 525},
+ dictWord{8, 11, 641},
+ dictWord{11, 11, 388},
+ dictWord{140, 11, 580},
+ dictWord{142, 0, 126},
+ dictWord{
+ 134,
+ 0,
+ 640,
+ },
+ dictWord{132, 0, 483},
+ dictWord{7, 0, 1616},
+ dictWord{9, 0, 69},
+ dictWord{6, 10, 324},
+ dictWord{6, 10, 520},
+ dictWord{7, 10, 338},
+ dictWord{
+ 7,
+ 10,
+ 1729,
+ },
+ dictWord{8, 10, 228},
+ dictWord{139, 10, 750},
+ dictWord{5, 11, 493},
+ dictWord{134, 11, 528},
+ dictWord{135, 0, 734},
+ dictWord{4, 11, 174},
+ dictWord{135, 11, 911},
+ dictWord{138, 0, 480},
+ dictWord{9, 0, 495},
+ dictWord{146, 0, 104},
+ dictWord{135, 10, 705},
+ dictWord{9, 0, 472},
+ dictWord{4, 10, 73},
+ dictWord{6, 10, 612},
+ dictWord{7, 10, 927},
+ dictWord{7, 10, 1330},
+ dictWord{7, 10, 1822},
+ dictWord{8, 10, 217},
+ dictWord{9, 10, 765},
+ dictWord{9, 10, 766},
+ dictWord{10, 10, 408},
+ dictWord{11, 10, 51},
+ dictWord{11, 10, 793},
+ dictWord{12, 10, 266},
+ dictWord{15, 10, 158},
+ dictWord{20, 10, 89},
+ dictWord{150, 10, 32},
+ dictWord{7, 11, 548},
+ dictWord{137, 11, 58},
+ dictWord{4, 11, 32},
+ dictWord{5, 11, 215},
+ dictWord{6, 11, 269},
+ dictWord{7, 11, 1782},
+ dictWord{7, 11, 1892},
+ dictWord{10, 11, 16},
+ dictWord{11, 11, 822},
+ dictWord{11, 11, 954},
+ dictWord{141, 11, 481},
+ dictWord{132, 0, 874},
+ dictWord{9, 0, 229},
+ dictWord{5, 10, 389},
+ dictWord{136, 10, 636},
+ dictWord{7, 11, 1749},
+ dictWord{136, 11, 477},
+ dictWord{134, 0, 948},
+ dictWord{5, 11, 308},
+ dictWord{135, 11, 1088},
+ dictWord{
+ 4,
+ 0,
+ 748,
+ },
+ dictWord{139, 0, 1009},
+ dictWord{136, 10, 21},
+ dictWord{6, 0, 555},
+ dictWord{135, 0, 485},
+ dictWord{5, 11, 126},
+ dictWord{8, 11, 297},
+ dictWord{
+ 9,
+ 11,
+ 366,
+ },
+ dictWord{9, 11, 445},
+ dictWord{12, 11, 53},
+ dictWord{12, 11, 374},
+ dictWord{141, 11, 492},
+ dictWord{7, 11, 1551},
+ dictWord{139, 11, 361},
+ dictWord{136, 0, 193},
+ dictWord{136, 0, 472},
+ dictWord{8, 0, 653},
+ dictWord{13, 0, 93},
+ dictWord{147, 0, 14},
+ dictWord{132, 0, 984},
+ dictWord{132, 11, 175},
+ dictWord{5, 0, 172},
+ dictWord{6, 0, 1971},
+ dictWord{132, 11, 685},
+ dictWord{149, 11, 8},
+ dictWord{133, 11, 797},
+ dictWord{13, 0, 83},
+ dictWord{5, 10, 189},
+ dictWord{
+ 7,
+ 10,
+ 442,
+ },
+ dictWord{7, 10, 443},
+ dictWord{8, 10, 281},
+ dictWord{12, 10, 174},
+ dictWord{141, 10, 261},
+ dictWord{134, 0, 1568},
+ dictWord{133, 11, 565},
+ dictWord{139, 0, 384},
+ dictWord{133, 0, 260},
+ dictWord{7, 0, 758},
+ dictWord{7, 0, 880},
+ dictWord{7, 0, 1359},
+ dictWord{9, 0, 164},
+ dictWord{9, 0, 167},
+ dictWord{
+ 10,
+ 0,
+ 156,
+ },
+ dictWord{10, 0, 588},
+ dictWord{12, 0, 101},
+ dictWord{14, 0, 48},
+ dictWord{15, 0, 70},
+ dictWord{6, 10, 2},
+ dictWord{7, 10, 1262},
+ dictWord{
+ 7,
+ 10,
+ 1737,
+ },
+ dictWord{8, 10, 22},
+ dictWord{8, 10, 270},
+ dictWord{8, 10, 612},
+ dictWord{9, 10, 312},
+ dictWord{9, 10, 436},
+ dictWord{10, 10, 311},
+ dictWord{
+ 10,
+ 10,
+ 623,
+ },
+ dictWord{11, 10, 72},
+ dictWord{11, 10, 330},
+ dictWord{11, 10, 455},
+ dictWord{12, 10, 321},
+ dictWord{12, 10, 504},
+ dictWord{12, 10, 530},
+ dictWord{
+ 12,
+ 10,
+ 543,
+ },
+ dictWord{13, 10, 17},
+ dictWord{13, 10, 156},
+ dictWord{13, 10, 334},
+ dictWord{17, 10, 60},
+ dictWord{148, 10, 64},
+ dictWord{4, 11, 252},
+ dictWord{
+ 7,
+ 11,
+ 1068,
+ },
+ dictWord{10, 11, 434},
+ dictWord{11, 11, 228},
+ dictWord{11, 11, 426},
+ dictWord{13, 11, 231},
+ dictWord{18, 11, 106},
+ dictWord{148, 11, 87},
+ dictWord{7, 10, 354},
+ dictWord{10, 10, 410},
+ dictWord{139, 10, 815},
+ dictWord{6, 0, 367},
+ dictWord{7, 10, 670},
+ dictWord{7, 10, 1327},
+ dictWord{8, 10, 411},
+ dictWord{8, 10, 435},
+ dictWord{9, 10, 653},
+ dictWord{9, 10, 740},
+ dictWord{10, 10, 385},
+ dictWord{11, 10, 222},
+ dictWord{11, 10, 324},
+ dictWord{11, 10, 829},
+ dictWord{140, 10, 611},
+ dictWord{7, 0, 1174},
+ dictWord{6, 10, 166},
+ dictWord{135, 10, 374},
+ dictWord{146, 0, 121},
+ dictWord{132, 0, 828},
+ dictWord{
+ 5,
+ 11,
+ 231,
+ },
+ dictWord{138, 11, 509},
+ dictWord{7, 11, 601},
+ dictWord{9, 11, 277},
+ dictWord{9, 11, 674},
+ dictWord{10, 11, 178},
+ dictWord{10, 11, 257},
+ dictWord{
+ 10,
+ 11,
+ 418,
+ },
+ dictWord{11, 11, 531},
+ dictWord{11, 11, 544},
+ dictWord{11, 11, 585},
+ dictWord{12, 11, 113},
+ dictWord{12, 11, 475},
+ dictWord{13, 11, 99},
+ dictWord{142, 11, 428},
+ dictWord{134, 0, 1541},
+ dictWord{135, 11, 1779},
+ dictWord{5, 0, 343},
+ dictWord{134, 10, 398},
+ dictWord{135, 10, 50},
+ dictWord{
+ 135,
+ 11,
+ 1683,
+ },
+ dictWord{4, 0, 440},
+ dictWord{7, 0, 57},
+ dictWord{8, 0, 167},
+ dictWord{8, 0, 375},
+ dictWord{9, 0, 82},
+ dictWord{9, 0, 561},
+ dictWord{9, 0, 744},
+ dictWord{
+ 10,
+ 0,
+ 620,
+ },
+ dictWord{137, 11, 744},
+ dictWord{134, 0, 926},
+ dictWord{6, 10, 517},
+ dictWord{7, 10, 1159},
+ dictWord{10, 10, 621},
+ dictWord{139, 10, 192},
+ dictWord{137, 0, 827},
+ dictWord{8, 0, 194},
+ dictWord{136, 0, 756},
+ dictWord{10, 10, 223},
+ dictWord{139, 10, 645},
+ dictWord{7, 10, 64},
+ dictWord{
+ 136,
+ 10,
+ 245,
+ },
+ dictWord{4, 11, 399},
+ dictWord{5, 11, 119},
+ dictWord{5, 11, 494},
+ dictWord{7, 11, 751},
+ dictWord{137, 11, 556},
+ dictWord{132, 0, 808},
+ dictWord{
+ 135,
+ 0,
+ 22,
+ },
+ dictWord{7, 10, 1763},
+ dictWord{140, 10, 310},
+ dictWord{5, 0, 639},
+ dictWord{7, 0, 1249},
+ dictWord{11, 0, 896},
+ dictWord{134, 11, 584},
+ dictWord{
+ 134,
+ 0,
+ 1614,
+ },
+ dictWord{135, 0, 860},
+ dictWord{135, 11, 1121},
+ dictWord{5, 10, 129},
+ dictWord{6, 10, 61},
+ dictWord{135, 10, 947},
+ dictWord{4, 0, 102},
+ dictWord{
+ 7,
+ 0,
+ 815,
+ },
+ dictWord{7, 0, 1699},
+ dictWord{139, 0, 964},
+ dictWord{13, 10, 505},
+ dictWord{141, 10, 506},
+ dictWord{139, 10, 1000},
+ dictWord{
+ 132,
+ 11,
+ 679,
+ },
+ dictWord{132, 0, 899},
+ dictWord{132, 0, 569},
+ dictWord{5, 11, 694},
+ dictWord{137, 11, 714},
+ dictWord{136, 0, 795},
+ dictWord{6, 0, 2045},
+ dictWord{
+ 139,
+ 11,
+ 7,
+ },
+ dictWord{6, 0, 52},
+ dictWord{9, 0, 104},
+ dictWord{9, 0, 559},
+ dictWord{12, 0, 308},
+ dictWord{147, 0, 87},
+ dictWord{4, 0, 301},
+ dictWord{132, 0, 604},
+ dictWord{133, 10, 637},
+ dictWord{136, 0, 779},
+ dictWord{5, 11, 143},
+ dictWord{5, 11, 769},
+ dictWord{6, 11, 1760},
+ dictWord{7, 11, 682},
+ dictWord{7, 11, 1992},
+ dictWord{136, 11, 736},
+ dictWord{137, 10, 590},
+ dictWord{147, 0, 32},
+ dictWord{137, 11, 527},
+ dictWord{5, 10, 280},
+ dictWord{135, 10, 1226},
+ dictWord{134, 0, 494},
+ dictWord{6, 0, 677},
+ dictWord{6, 0, 682},
+ dictWord{134, 0, 1044},
+ dictWord{133, 10, 281},
+ dictWord{135, 10, 1064},
+ dictWord{7, 0, 508},
+ dictWord{133, 11, 860},
+ dictWord{6, 11, 422},
+ dictWord{7, 11, 0},
+ dictWord{7, 11, 1544},
+ dictWord{9, 11, 577},
+ dictWord{11, 11, 990},
+ dictWord{12, 11, 141},
+ dictWord{12, 11, 453},
+ dictWord{13, 11, 47},
+ dictWord{141, 11, 266},
+ dictWord{134, 0, 1014},
+ dictWord{5, 11, 515},
+ dictWord{137, 11, 131},
+ dictWord{
+ 134,
+ 0,
+ 957,
+ },
+ dictWord{132, 11, 646},
+ dictWord{6, 0, 310},
+ dictWord{7, 0, 1849},
+ dictWord{8, 0, 72},
+ dictWord{8, 0, 272},
+ dictWord{8, 0, 431},
+ dictWord{9, 0, 12},
+ dictWord{
+ 9,
+ 0,
+ 376,
+ },
+ dictWord{10, 0, 563},
+ dictWord{10, 0, 630},
+ dictWord{10, 0, 796},
+ dictWord{10, 0, 810},
+ dictWord{11, 0, 367},
+ dictWord{11, 0, 599},
+ dictWord{
+ 11,
+ 0,
+ 686,
+ },
+ dictWord{140, 0, 672},
+ dictWord{7, 0, 570},
+ dictWord{4, 11, 396},
+ dictWord{7, 10, 120},
+ dictWord{7, 11, 728},
+ dictWord{8, 10, 489},
+ dictWord{9, 11, 117},
+ dictWord{9, 10, 319},
+ dictWord{10, 10, 820},
+ dictWord{11, 10, 1004},
+ dictWord{12, 10, 379},
+ dictWord{12, 10, 679},
+ dictWord{13, 10, 117},
+ dictWord{
+ 13,
+ 11,
+ 202,
+ },
+ dictWord{13, 10, 412},
+ dictWord{14, 10, 25},
+ dictWord{15, 10, 52},
+ dictWord{15, 10, 161},
+ dictWord{16, 10, 47},
+ dictWord{20, 11, 51},
+ dictWord{
+ 149,
+ 10,
+ 2,
+ },
+ dictWord{6, 11, 121},
+ dictWord{6, 11, 124},
+ dictWord{6, 11, 357},
+ dictWord{7, 11, 1138},
+ dictWord{7, 11, 1295},
+ dictWord{8, 11, 162},
+ dictWord{
+ 139,
+ 11,
+ 655,
+ },
+ dictWord{8, 0, 449},
+ dictWord{4, 10, 937},
+ dictWord{5, 10, 801},
+ dictWord{136, 11, 449},
+ dictWord{139, 11, 958},
+ dictWord{6, 0, 181},
+ dictWord{
+ 7,
+ 0,
+ 537,
+ },
+ dictWord{8, 0, 64},
+ dictWord{9, 0, 127},
+ dictWord{10, 0, 496},
+ dictWord{12, 0, 510},
+ dictWord{141, 0, 384},
+ dictWord{138, 11, 253},
+ dictWord{4, 0, 244},
+ dictWord{135, 0, 233},
+ dictWord{133, 11, 237},
+ dictWord{132, 10, 365},
+ dictWord{6, 0, 1650},
+ dictWord{10, 0, 702},
+ dictWord{139, 0, 245},
+ dictWord{
+ 5,
+ 10,
+ 7,
+ },
+ dictWord{139, 10, 774},
+ dictWord{13, 0, 463},
+ dictWord{20, 0, 49},
+ dictWord{13, 11, 463},
+ dictWord{148, 11, 49},
+ dictWord{4, 10, 734},
+ dictWord{
+ 5,
+ 10,
+ 662,
+ },
+ dictWord{134, 10, 430},
+ dictWord{4, 10, 746},
+ dictWord{135, 10, 1090},
+ dictWord{5, 10, 360},
+ dictWord{136, 10, 237},
+ dictWord{137, 0, 338},
+ dictWord{143, 11, 10},
+ dictWord{7, 11, 571},
+ dictWord{138, 11, 366},
+ dictWord{134, 0, 1279},
+ dictWord{9, 11, 513},
+ dictWord{10, 11, 22},
+ dictWord{10, 11, 39},
+ dictWord{12, 11, 122},
+ dictWord{140, 11, 187},
+ dictWord{133, 0, 896},
+ dictWord{146, 0, 178},
+ dictWord{134, 0, 695},
+ dictWord{137, 0, 808},
+ dictWord{
+ 134,
+ 11,
+ 587,
+ },
+ dictWord{7, 11, 107},
+ dictWord{7, 11, 838},
+ dictWord{8, 11, 550},
+ dictWord{138, 11, 401},
+ dictWord{7, 0, 1117},
+ dictWord{136, 0, 539},
+ dictWord{
+ 4,
+ 10,
+ 277,
+ },
+ dictWord{5, 10, 608},
+ dictWord{6, 10, 493},
+ dictWord{7, 10, 457},
+ dictWord{140, 10, 384},
+ dictWord{133, 11, 768},
+ dictWord{12, 0, 257},
+ dictWord{
+ 7,
+ 10,
+ 27,
+ },
+ dictWord{135, 10, 316},
+ dictWord{140, 0, 1003},
+ dictWord{4, 0, 207},
+ dictWord{5, 0, 586},
+ dictWord{5, 0, 676},
+ dictWord{6, 0, 448},
+ dictWord{
+ 8,
+ 0,
+ 244,
+ },
+ dictWord{11, 0, 1},
+ dictWord{13, 0, 3},
+ dictWord{16, 0, 54},
+ dictWord{17, 0, 4},
+ dictWord{18, 0, 13},
+ dictWord{133, 10, 552},
+ dictWord{4, 10, 401},
+ dictWord{
+ 137,
+ 10,
+ 264,
+ },
+ dictWord{5, 0, 516},
+ dictWord{7, 0, 1883},
+ dictWord{135, 11, 1883},
+ dictWord{12, 0, 960},
+ dictWord{132, 11, 894},
+ dictWord{5, 0, 4},
+ dictWord{
+ 5,
+ 0,
+ 810,
+ },
+ dictWord{6, 0, 13},
+ dictWord{6, 0, 538},
+ dictWord{6, 0, 1690},
+ dictWord{6, 0, 1726},
+ dictWord{7, 0, 499},
+ dictWord{7, 0, 1819},
+ dictWord{8, 0, 148},
+ dictWord{
+ 8,
+ 0,
+ 696,
+ },
+ dictWord{8, 0, 791},
+ dictWord{12, 0, 125},
+ dictWord{143, 0, 9},
+ dictWord{135, 0, 1268},
+ dictWord{11, 0, 30},
+ dictWord{14, 0, 315},
+ dictWord{
+ 9,
+ 10,
+ 543,
+ },
+ dictWord{10, 10, 524},
+ dictWord{12, 10, 524},
+ dictWord{16, 10, 18},
+ dictWord{20, 10, 26},
+ dictWord{148, 10, 65},
+ dictWord{6, 0, 748},
+ dictWord{
+ 4,
+ 10,
+ 205,
+ },
+ dictWord{5, 10, 623},
+ dictWord{7, 10, 104},
+ dictWord{136, 10, 519},
+ dictWord{11, 0, 542},
+ dictWord{139, 0, 852},
+ dictWord{140, 0, 6},
+ dictWord{
+ 132,
+ 0,
+ 848,
+ },
+ dictWord{7, 0, 1385},
+ dictWord{11, 0, 582},
+ dictWord{11, 0, 650},
+ dictWord{11, 0, 901},
+ dictWord{11, 0, 949},
+ dictWord{12, 0, 232},
+ dictWord{12, 0, 236},
+ dictWord{13, 0, 413},
+ dictWord{13, 0, 501},
+ dictWord{18, 0, 116},
+ dictWord{7, 10, 579},
+ dictWord{9, 10, 41},
+ dictWord{9, 10, 244},
+ dictWord{9, 10, 669},
+ dictWord{10, 10, 5},
+ dictWord{11, 10, 861},
+ dictWord{11, 10, 951},
+ dictWord{139, 10, 980},
+ dictWord{4, 0, 945},
+ dictWord{6, 0, 1811},
+ dictWord{6, 0, 1845},
+ dictWord{
+ 6,
+ 0,
+ 1853,
+ },
+ dictWord{6, 0, 1858},
+ dictWord{8, 0, 862},
+ dictWord{12, 0, 782},
+ dictWord{12, 0, 788},
+ dictWord{18, 0, 160},
+ dictWord{148, 0, 117},
+ dictWord{
+ 132,
+ 10,
+ 717,
+ },
+ dictWord{4, 0, 925},
+ dictWord{5, 0, 803},
+ dictWord{8, 0, 698},
+ dictWord{138, 0, 828},
+ dictWord{134, 0, 1416},
+ dictWord{132, 0, 610},
+ dictWord{
+ 139,
+ 0,
+ 992,
+ },
+ dictWord{6, 0, 878},
+ dictWord{134, 0, 1477},
+ dictWord{135, 0, 1847},
+ dictWord{138, 11, 531},
+ dictWord{137, 11, 539},
+ dictWord{134, 11, 272},
+ dictWord{133, 0, 383},
+ dictWord{134, 0, 1404},
+ dictWord{132, 10, 489},
+ dictWord{4, 11, 9},
+ dictWord{5, 11, 128},
+ dictWord{7, 11, 368},
+ dictWord{
+ 11,
+ 11,
+ 480,
+ },
+ dictWord{148, 11, 3},
+ dictWord{136, 0, 986},
+ dictWord{9, 0, 660},
+ dictWord{138, 0, 347},
+ dictWord{135, 10, 892},
+ dictWord{136, 11, 682},
+ dictWord{
+ 7,
+ 0,
+ 572,
+ },
+ dictWord{9, 0, 592},
+ dictWord{11, 0, 680},
+ dictWord{12, 0, 356},
+ dictWord{140, 0, 550},
+ dictWord{7, 0, 1411},
+ dictWord{138, 11, 527},
+ dictWord{
+ 4,
+ 11,
+ 2,
+ },
+ dictWord{7, 11, 545},
+ dictWord{135, 11, 894},
+ dictWord{137, 10, 473},
+ dictWord{11, 0, 64},
+ dictWord{7, 11, 481},
+ dictWord{7, 10, 819},
+ dictWord{9, 10, 26},
+ dictWord{9, 10, 392},
+ dictWord{9, 11, 792},
+ dictWord{10, 10, 152},
+ dictWord{10, 10, 226},
+ dictWord{12, 10, 276},
+ dictWord{12, 10, 426},
+ dictWord{
+ 12,
+ 10,
+ 589,
+ },
+ dictWord{13, 10, 460},
+ dictWord{15, 10, 97},
+ dictWord{19, 10, 48},
+ dictWord{148, 10, 104},
+ dictWord{135, 10, 51},
+ dictWord{136, 11, 445},
+ dictWord{136, 11, 646},
+ dictWord{135, 0, 606},
+ dictWord{132, 10, 674},
+ dictWord{6, 0, 1829},
+ dictWord{134, 0, 1830},
+ dictWord{132, 10, 770},
+ dictWord{
+ 5,
+ 10,
+ 79,
+ },
+ dictWord{7, 10, 1027},
+ dictWord{7, 10, 1477},
+ dictWord{139, 10, 52},
+ dictWord{5, 11, 530},
+ dictWord{142, 11, 113},
+ dictWord{134, 10, 1666},
+ dictWord{
+ 7,
+ 0,
+ 748,
+ },
+ dictWord{139, 0, 700},
+ dictWord{134, 10, 195},
+ dictWord{133, 10, 789},
+ dictWord{9, 0, 87},
+ dictWord{10, 0, 365},
+ dictWord{4, 10, 251},
+ dictWord{
+ 4,
+ 10,
+ 688,
+ },
+ dictWord{7, 10, 513},
+ dictWord{135, 10, 1284},
+ dictWord{136, 11, 111},
+ dictWord{133, 0, 127},
+ dictWord{6, 0, 198},
+ dictWord{140, 0, 83},
+ dictWord{133, 11, 556},
+ dictWord{133, 10, 889},
+ dictWord{4, 10, 160},
+ dictWord{5, 10, 330},
+ dictWord{7, 10, 1434},
+ dictWord{136, 10, 174},
+ dictWord{5, 0, 276},
+ dictWord{6, 0, 55},
+ dictWord{7, 0, 1369},
+ dictWord{138, 0, 864},
+ dictWord{8, 11, 16},
+ dictWord{140, 11, 568},
+ dictWord{6, 0, 1752},
+ dictWord{136, 0, 726},
+ dictWord{135, 0, 1066},
+ dictWord{133, 0, 764},
+ dictWord{6, 11, 186},
+ dictWord{137, 11, 426},
+ dictWord{11, 0, 683},
+ dictWord{139, 11, 683},
+ dictWord{
+ 6,
+ 0,
+ 309,
+ },
+ dictWord{7, 0, 331},
+ dictWord{138, 0, 550},
+ dictWord{133, 10, 374},
+ dictWord{6, 0, 1212},
+ dictWord{6, 0, 1852},
+ dictWord{7, 0, 1062},
+ dictWord{
+ 8,
+ 0,
+ 874,
+ },
+ dictWord{8, 0, 882},
+ dictWord{138, 0, 936},
+ dictWord{132, 11, 585},
+ dictWord{134, 0, 1364},
+ dictWord{7, 0, 986},
+ dictWord{133, 10, 731},
+ dictWord{
+ 6,
+ 0,
+ 723,
+ },
+ dictWord{6, 0, 1408},
+ dictWord{138, 0, 381},
+ dictWord{135, 0, 1573},
+ dictWord{134, 0, 1025},
+ dictWord{4, 10, 626},
+ dictWord{5, 10, 642},
+ dictWord{
+ 6,
+ 10,
+ 425,
+ },
+ dictWord{10, 10, 202},
+ dictWord{139, 10, 141},
+ dictWord{4, 11, 93},
+ dictWord{5, 11, 252},
+ dictWord{6, 11, 229},
+ dictWord{7, 11, 291},
+ dictWord{
+ 9,
+ 11,
+ 550,
+ },
+ dictWord{139, 11, 644},
+ dictWord{137, 11, 749},
+ dictWord{137, 11, 162},
+ dictWord{132, 11, 381},
+ dictWord{135, 0, 1559},
+ dictWord{
+ 6,
+ 0,
+ 194,
+ },
+ dictWord{7, 0, 133},
+ dictWord{10, 0, 493},
+ dictWord{10, 0, 570},
+ dictWord{139, 0, 664},
+ dictWord{5, 0, 24},
+ dictWord{5, 0, 569},
+ dictWord{6, 0, 3},
+ dictWord{
+ 6,
+ 0,
+ 119,
+ },
+ dictWord{6, 0, 143},
+ dictWord{6, 0, 440},
+ dictWord{7, 0, 295},
+ dictWord{7, 0, 599},
+ dictWord{7, 0, 1686},
+ dictWord{7, 0, 1854},
+ dictWord{8, 0, 424},
+ dictWord{
+ 9,
+ 0,
+ 43,
+ },
+ dictWord{9, 0, 584},
+ dictWord{9, 0, 760},
+ dictWord{10, 0, 148},
+ dictWord{10, 0, 328},
+ dictWord{11, 0, 159},
+ dictWord{11, 0, 253},
+ dictWord{11, 0, 506},
+ dictWord{12, 0, 487},
+ dictWord{140, 0, 531},
+ dictWord{6, 0, 661},
+ dictWord{134, 0, 1517},
+ dictWord{136, 10, 835},
+ dictWord{151, 10, 17},
+ dictWord{5, 0, 14},
+ dictWord{5, 0, 892},
+ dictWord{6, 0, 283},
+ dictWord{7, 0, 234},
+ dictWord{136, 0, 537},
+ dictWord{139, 0, 541},
+ dictWord{4, 0, 126},
+ dictWord{8, 0, 635},
+ dictWord{
+ 147,
+ 0,
+ 34,
+ },
+ dictWord{4, 0, 316},
+ dictWord{4, 0, 495},
+ dictWord{135, 0, 1561},
+ dictWord{4, 11, 187},
+ dictWord{5, 11, 184},
+ dictWord{5, 11, 690},
+ dictWord{
+ 7,
+ 11,
+ 1869,
+ },
+ dictWord{138, 11, 756},
+ dictWord{139, 11, 783},
+ dictWord{4, 0, 998},
+ dictWord{137, 0, 861},
+ dictWord{136, 0, 1009},
+ dictWord{139, 11, 292},
+ dictWord{5, 11, 21},
+ dictWord{6, 11, 77},
+ dictWord{6, 11, 157},
+ dictWord{7, 11, 974},
+ dictWord{7, 11, 1301},
+ dictWord{7, 11, 1339},
+ dictWord{7, 11, 1490},
+ dictWord{
+ 7,
+ 11,
+ 1873,
+ },
+ dictWord{137, 11, 628},
+ dictWord{7, 11, 1283},
+ dictWord{9, 11, 227},
+ dictWord{9, 11, 499},
+ dictWord{10, 11, 341},
+ dictWord{11, 11, 325},
+ dictWord{11, 11, 408},
+ dictWord{14, 11, 180},
+ dictWord{15, 11, 144},
+ dictWord{18, 11, 47},
+ dictWord{147, 11, 49},
+ dictWord{4, 0, 64},
+ dictWord{5, 0, 352},
+ dictWord{5, 0, 720},
+ dictWord{6, 0, 368},
+ dictWord{139, 0, 359},
+ dictWord{5, 10, 384},
+ dictWord{8, 10, 455},
+ dictWord{140, 10, 48},
+ dictWord{5, 10, 264},
+ dictWord{
+ 134,
+ 10,
+ 184,
+ },
+ dictWord{7, 0, 1577},
+ dictWord{10, 0, 304},
+ dictWord{10, 0, 549},
+ dictWord{12, 0, 365},
+ dictWord{13, 0, 220},
+ dictWord{13, 0, 240},
+ dictWord{
+ 142,
+ 0,
+ 33,
+ },
+ dictWord{134, 0, 1107},
+ dictWord{134, 0, 929},
+ dictWord{135, 0, 1142},
+ dictWord{6, 0, 175},
+ dictWord{137, 0, 289},
+ dictWord{5, 0, 432},
+ dictWord{
+ 133,
+ 0,
+ 913,
+ },
+ dictWord{6, 0, 279},
+ dictWord{7, 0, 219},
+ dictWord{5, 10, 633},
+ dictWord{135, 10, 1323},
+ dictWord{7, 0, 785},
+ dictWord{7, 10, 359},
+ dictWord{
+ 8,
+ 10,
+ 243,
+ },
+ dictWord{140, 10, 175},
+ dictWord{139, 0, 595},
+ dictWord{132, 10, 105},
+ dictWord{8, 11, 398},
+ dictWord{9, 11, 681},
+ dictWord{139, 11, 632},
+ dictWord{140, 0, 80},
+ dictWord{5, 0, 931},
+ dictWord{134, 0, 1698},
+ dictWord{142, 11, 241},
+ dictWord{134, 11, 20},
+ dictWord{134, 0, 1323},
+ dictWord{11, 0, 526},
+ dictWord{11, 0, 939},
+ dictWord{141, 0, 290},
+ dictWord{5, 0, 774},
+ dictWord{6, 0, 780},
+ dictWord{6, 0, 1637},
+ dictWord{6, 0, 1686},
+ dictWord{6, 0, 1751},
+ dictWord{
+ 8,
+ 0,
+ 559,
+ },
+ dictWord{141, 0, 109},
+ dictWord{141, 0, 127},
+ dictWord{7, 0, 1167},
+ dictWord{11, 0, 934},
+ dictWord{13, 0, 391},
+ dictWord{17, 0, 76},
+ dictWord{
+ 135,
+ 11,
+ 709,
+ },
+ dictWord{135, 0, 963},
+ dictWord{6, 0, 260},
+ dictWord{135, 0, 1484},
+ dictWord{134, 0, 573},
+ dictWord{4, 10, 758},
+ dictWord{139, 11, 941},
+ dictWord{135, 10, 1649},
+ dictWord{145, 11, 36},
+ dictWord{4, 0, 292},
+ dictWord{137, 0, 580},
+ dictWord{4, 0, 736},
+ dictWord{5, 0, 871},
+ dictWord{6, 0, 1689},
+ dictWord{135, 0, 1944},
+ dictWord{7, 11, 945},
+ dictWord{11, 11, 713},
+ dictWord{139, 11, 744},
+ dictWord{134, 0, 1164},
+ dictWord{135, 11, 937},
+ dictWord{
+ 6,
+ 0,
+ 1922,
+ },
+ dictWord{9, 0, 982},
+ dictWord{15, 0, 173},
+ dictWord{15, 0, 178},
+ dictWord{15, 0, 200},
+ dictWord{18, 0, 189},
+ dictWord{18, 0, 207},
+ dictWord{21, 0, 47},
+ dictWord{135, 11, 1652},
+ dictWord{7, 0, 1695},
+ dictWord{139, 10, 128},
+ dictWord{6, 0, 63},
+ dictWord{135, 0, 920},
+ dictWord{133, 0, 793},
+ dictWord{
+ 143,
+ 11,
+ 134,
+ },
+ dictWord{133, 10, 918},
+ dictWord{5, 0, 67},
+ dictWord{6, 0, 62},
+ dictWord{6, 0, 374},
+ dictWord{135, 0, 1391},
+ dictWord{9, 0, 790},
+ dictWord{12, 0, 47},
+ dictWord{4, 11, 579},
+ dictWord{5, 11, 226},
+ dictWord{5, 11, 323},
+ dictWord{135, 11, 960},
+ dictWord{10, 11, 784},
+ dictWord{141, 11, 191},
+ dictWord{4, 0, 391},
+ dictWord{135, 0, 1169},
+ dictWord{137, 0, 443},
+ dictWord{13, 11, 232},
+ dictWord{146, 11, 35},
+ dictWord{132, 10, 340},
+ dictWord{132, 0, 271},
+ dictWord{
+ 137,
+ 11,
+ 313,
+ },
+ dictWord{5, 11, 973},
+ dictWord{137, 11, 659},
+ dictWord{134, 0, 1140},
+ dictWord{6, 11, 135},
+ dictWord{135, 11, 1176},
+ dictWord{4, 0, 253},
+ dictWord{5, 0, 544},
+ dictWord{7, 0, 300},
+ dictWord{137, 0, 340},
+ dictWord{7, 0, 897},
+ dictWord{5, 10, 985},
+ dictWord{7, 10, 509},
+ dictWord{145, 10, 96},
+ dictWord{
+ 138,
+ 11,
+ 735,
+ },
+ dictWord{135, 10, 1919},
+ dictWord{138, 0, 890},
+ dictWord{5, 0, 818},
+ dictWord{134, 0, 1122},
+ dictWord{5, 0, 53},
+ dictWord{5, 0, 541},
+ dictWord{
+ 6,
+ 0,
+ 94,
+ },
+ dictWord{6, 0, 499},
+ dictWord{7, 0, 230},
+ dictWord{139, 0, 321},
+ dictWord{4, 0, 920},
+ dictWord{5, 0, 25},
+ dictWord{5, 0, 790},
+ dictWord{6, 0, 457},
+ dictWord{
+ 7,
+ 0,
+ 853,
+ },
+ dictWord{8, 0, 788},
+ dictWord{142, 11, 31},
+ dictWord{132, 10, 247},
+ dictWord{135, 11, 314},
+ dictWord{132, 0, 468},
+ dictWord{7, 0, 243},
+ dictWord{
+ 6,
+ 10,
+ 337,
+ },
+ dictWord{7, 10, 494},
+ dictWord{8, 10, 27},
+ dictWord{8, 10, 599},
+ dictWord{138, 10, 153},
+ dictWord{4, 10, 184},
+ dictWord{5, 10, 390},
+ dictWord{
+ 7,
+ 10,
+ 618,
+ },
+ dictWord{7, 10, 1456},
+ dictWord{139, 10, 710},
+ dictWord{134, 0, 870},
+ dictWord{134, 0, 1238},
+ dictWord{134, 0, 1765},
+ dictWord{10, 0, 853},
+ dictWord{10, 0, 943},
+ dictWord{14, 0, 437},
+ dictWord{14, 0, 439},
+ dictWord{14, 0, 443},
+ dictWord{14, 0, 446},
+ dictWord{14, 0, 452},
+ dictWord{14, 0, 469},
+ dictWord{
+ 14,
+ 0,
+ 471,
+ },
+ dictWord{14, 0, 473},
+ dictWord{16, 0, 93},
+ dictWord{16, 0, 102},
+ dictWord{16, 0, 110},
+ dictWord{148, 0, 121},
+ dictWord{4, 0, 605},
+ dictWord{
+ 7,
+ 0,
+ 518,
+ },
+ dictWord{7, 0, 1282},
+ dictWord{7, 0, 1918},
+ dictWord{10, 0, 180},
+ dictWord{139, 0, 218},
+ dictWord{133, 0, 822},
+ dictWord{4, 0, 634},
+ dictWord{
+ 11,
+ 0,
+ 916,
+ },
+ dictWord{142, 0, 419},
+ dictWord{6, 11, 281},
+ dictWord{7, 11, 6},
+ dictWord{8, 11, 282},
+ dictWord{8, 11, 480},
+ dictWord{8, 11, 499},
+ dictWord{9, 11, 198},
+ dictWord{10, 11, 143},
+ dictWord{10, 11, 169},
+ dictWord{10, 11, 211},
+ dictWord{10, 11, 417},
+ dictWord{10, 11, 574},
+ dictWord{11, 11, 147},
+ dictWord{
+ 11,
+ 11,
+ 395,
+ },
+ dictWord{12, 11, 75},
+ dictWord{12, 11, 407},
+ dictWord{12, 11, 608},
+ dictWord{13, 11, 500},
+ dictWord{142, 11, 251},
+ dictWord{134, 0, 898},
+ dictWord{
+ 6,
+ 0,
+ 36,
+ },
+ dictWord{7, 0, 658},
+ dictWord{8, 0, 454},
+ dictWord{150, 11, 48},
+ dictWord{133, 11, 674},
+ dictWord{135, 11, 1776},
+ dictWord{4, 11, 419},
+ dictWord{
+ 10,
+ 10,
+ 227,
+ },
+ dictWord{11, 10, 497},
+ dictWord{11, 10, 709},
+ dictWord{140, 10, 415},
+ dictWord{6, 10, 360},
+ dictWord{7, 10, 1664},
+ dictWord{136, 10, 478},
+ dictWord{137, 0, 806},
+ dictWord{12, 11, 508},
+ dictWord{14, 11, 102},
+ dictWord{14, 11, 226},
+ dictWord{144, 11, 57},
+ dictWord{135, 11, 1123},
+ dictWord{
+ 4,
+ 11,
+ 138,
+ },
+ dictWord{7, 11, 1012},
+ dictWord{7, 11, 1280},
+ dictWord{137, 11, 76},
+ dictWord{5, 11, 29},
+ dictWord{140, 11, 638},
+ dictWord{136, 10, 699},
+ dictWord{134, 0, 1326},
+ dictWord{132, 0, 104},
+ dictWord{135, 11, 735},
+ dictWord{132, 10, 739},
+ dictWord{134, 0, 1331},
+ dictWord{7, 0, 260},
+ dictWord{
+ 135,
+ 11,
+ 260,
+ },
+ dictWord{135, 11, 1063},
+ dictWord{7, 0, 45},
+ dictWord{9, 0, 542},
+ dictWord{9, 0, 566},
+ dictWord{10, 0, 728},
+ dictWord{137, 10, 869},
+ dictWord{
+ 4,
+ 10,
+ 67,
+ },
+ dictWord{5, 10, 422},
+ dictWord{7, 10, 1037},
+ dictWord{7, 10, 1289},
+ dictWord{7, 10, 1555},
+ dictWord{9, 10, 741},
+ dictWord{145, 10, 108},
+ dictWord{
+ 139,
+ 0,
+ 263,
+ },
+ dictWord{134, 0, 1516},
+ dictWord{14, 0, 146},
+ dictWord{15, 0, 42},
+ dictWord{16, 0, 23},
+ dictWord{17, 0, 86},
+ dictWord{146, 0, 17},
+ dictWord{
+ 138,
+ 0,
+ 468,
+ },
+ dictWord{136, 0, 1005},
+ dictWord{4, 11, 17},
+ dictWord{5, 11, 23},
+ dictWord{7, 11, 995},
+ dictWord{11, 11, 383},
+ dictWord{11, 11, 437},
+ dictWord{
+ 12,
+ 11,
+ 460,
+ },
+ dictWord{140, 11, 532},
+ dictWord{7, 0, 87},
+ dictWord{142, 0, 288},
+ dictWord{138, 10, 96},
+ dictWord{135, 11, 626},
+ dictWord{144, 10, 26},
+ dictWord{
+ 7,
+ 0,
+ 988,
+ },
+ dictWord{7, 0, 1939},
+ dictWord{9, 0, 64},
+ dictWord{9, 0, 502},
+ dictWord{12, 0, 22},
+ dictWord{12, 0, 34},
+ dictWord{13, 0, 12},
+ dictWord{13, 0, 234},
+ dictWord{147, 0, 77},
+ dictWord{13, 0, 133},
+ dictWord{8, 10, 203},
+ dictWord{11, 10, 823},
+ dictWord{11, 10, 846},
+ dictWord{12, 10, 482},
+ dictWord{13, 10, 277},
+ dictWord{13, 10, 302},
+ dictWord{13, 10, 464},
+ dictWord{14, 10, 205},
+ dictWord{142, 10, 221},
+ dictWord{4, 10, 449},
+ dictWord{133, 10, 718},
+ dictWord{
+ 135,
+ 0,
+ 141,
+ },
+ dictWord{6, 0, 1842},
+ dictWord{136, 0, 872},
+ dictWord{8, 11, 70},
+ dictWord{12, 11, 171},
+ dictWord{141, 11, 272},
+ dictWord{4, 10, 355},
+ dictWord{
+ 6,
+ 10,
+ 311,
+ },
+ dictWord{9, 10, 256},
+ dictWord{138, 10, 404},
+ dictWord{132, 0, 619},
+ dictWord{137, 0, 261},
+ dictWord{10, 11, 233},
+ dictWord{10, 10, 758},
+ dictWord{139, 11, 76},
+ dictWord{5, 0, 246},
+ dictWord{8, 0, 189},
+ dictWord{9, 0, 355},
+ dictWord{9, 0, 512},
+ dictWord{10, 0, 124},
+ dictWord{10, 0, 453},
+ dictWord{
+ 11,
+ 0,
+ 143,
+ },
+ dictWord{11, 0, 416},
+ dictWord{11, 0, 859},
+ dictWord{141, 0, 341},
+ dictWord{134, 11, 442},
+ dictWord{133, 10, 827},
+ dictWord{5, 10, 64},
+ dictWord{
+ 140,
+ 10,
+ 581,
+ },
+ dictWord{4, 10, 442},
+ dictWord{7, 10, 1047},
+ dictWord{7, 10, 1352},
+ dictWord{135, 10, 1643},
+ dictWord{134, 11, 1709},
+ dictWord{5, 0, 678},
+ dictWord{6, 0, 305},
+ dictWord{7, 0, 775},
+ dictWord{7, 0, 1065},
+ dictWord{133, 10, 977},
+ dictWord{11, 11, 69},
+ dictWord{12, 11, 105},
+ dictWord{12, 11, 117},
+ dictWord{13, 11, 213},
+ dictWord{14, 11, 13},
+ dictWord{14, 11, 62},
+ dictWord{14, 11, 177},
+ dictWord{14, 11, 421},
+ dictWord{15, 11, 19},
+ dictWord{146, 11, 141},
+ dictWord{137, 11, 309},
+ dictWord{5, 0, 35},
+ dictWord{7, 0, 862},
+ dictWord{7, 0, 1886},
+ dictWord{138, 0, 179},
+ dictWord{136, 0, 285},
+ dictWord{132, 0, 517},
+ dictWord{7, 11, 976},
+ dictWord{9, 11, 146},
+ dictWord{10, 11, 206},
+ dictWord{10, 11, 596},
+ dictWord{13, 11, 218},
+ dictWord{142, 11, 153},
+ dictWord{
+ 132,
+ 10,
+ 254,
+ },
+ dictWord{6, 0, 214},
+ dictWord{12, 0, 540},
+ dictWord{4, 10, 275},
+ dictWord{7, 10, 1219},
+ dictWord{140, 10, 376},
+ dictWord{8, 0, 667},
+ dictWord{
+ 11,
+ 0,
+ 403,
+ },
+ dictWord{146, 0, 83},
+ dictWord{12, 0, 74},
+ dictWord{10, 11, 648},
+ dictWord{11, 11, 671},
+ dictWord{143, 11, 46},
+ dictWord{135, 0, 125},
+ dictWord{
+ 134,
+ 10,
+ 1753,
+ },
+ dictWord{133, 0, 761},
+ dictWord{6, 0, 912},
+ dictWord{4, 11, 518},
+ dictWord{6, 10, 369},
+ dictWord{6, 10, 502},
+ dictWord{7, 10, 1036},
+ dictWord{
+ 7,
+ 11,
+ 1136,
+ },
+ dictWord{8, 10, 348},
+ dictWord{9, 10, 452},
+ dictWord{10, 10, 26},
+ dictWord{11, 10, 224},
+ dictWord{11, 10, 387},
+ dictWord{11, 10, 772},
+ dictWord{12, 10, 95},
+ dictWord{12, 10, 629},
+ dictWord{13, 10, 195},
+ dictWord{13, 10, 207},
+ dictWord{13, 10, 241},
+ dictWord{14, 10, 260},
+ dictWord{14, 10, 270},
+ dictWord{143, 10, 140},
+ dictWord{10, 0, 131},
+ dictWord{140, 0, 72},
+ dictWord{132, 10, 269},
+ dictWord{5, 10, 480},
+ dictWord{7, 10, 532},
+ dictWord{
+ 7,
+ 10,
+ 1197,
+ },
+ dictWord{7, 10, 1358},
+ dictWord{8, 10, 291},
+ dictWord{11, 10, 349},
+ dictWord{142, 10, 396},
+ dictWord{8, 11, 689},
+ dictWord{137, 11, 863},
+ dictWord{
+ 8,
+ 0,
+ 333,
+ },
+ dictWord{138, 0, 182},
+ dictWord{4, 11, 18},
+ dictWord{7, 11, 145},
+ dictWord{7, 11, 444},
+ dictWord{7, 11, 1278},
+ dictWord{8, 11, 49},
+ dictWord{
+ 8,
+ 11,
+ 400,
+ },
+ dictWord{9, 11, 71},
+ dictWord{9, 11, 250},
+ dictWord{10, 11, 459},
+ dictWord{12, 11, 160},
+ dictWord{144, 11, 24},
+ dictWord{14, 11, 35},
+ dictWord{
+ 142,
+ 11,
+ 191,
+ },
+ dictWord{135, 11, 1864},
+ dictWord{135, 0, 1338},
+ dictWord{148, 10, 15},
+ dictWord{14, 0, 94},
+ dictWord{15, 0, 65},
+ dictWord{16, 0, 4},
+ dictWord{
+ 16,
+ 0,
+ 77,
+ },
+ dictWord{16, 0, 80},
+ dictWord{145, 0, 5},
+ dictWord{12, 11, 82},
+ dictWord{143, 11, 36},
+ dictWord{133, 11, 1010},
+ dictWord{133, 0, 449},
+ dictWord{
+ 133,
+ 0,
+ 646,
+ },
+ dictWord{7, 0, 86},
+ dictWord{8, 0, 103},
+ dictWord{135, 10, 657},
+ dictWord{7, 0, 2028},
+ dictWord{138, 0, 641},
+ dictWord{136, 10, 533},
+ dictWord{
+ 134,
+ 0,
+ 1,
+ },
+ dictWord{139, 11, 970},
+ dictWord{5, 11, 87},
+ dictWord{7, 11, 313},
+ dictWord{7, 11, 1103},
+ dictWord{10, 11, 112},
+ dictWord{10, 11, 582},
+ dictWord{
+ 11,
+ 11,
+ 389,
+ },
+ dictWord{11, 11, 813},
+ dictWord{12, 11, 385},
+ dictWord{13, 11, 286},
+ dictWord{14, 11, 124},
+ dictWord{146, 11, 108},
+ dictWord{6, 0, 869},
+ dictWord{
+ 132,
+ 11,
+ 267,
+ },
+ dictWord{6, 0, 277},
+ dictWord{7, 0, 1274},
+ dictWord{7, 0, 1386},
+ dictWord{146, 0, 87},
+ dictWord{6, 0, 187},
+ dictWord{7, 0, 39},
+ dictWord{7, 0, 1203},
+ dictWord{8, 0, 380},
+ dictWord{14, 0, 117},
+ dictWord{149, 0, 28},
+ dictWord{4, 10, 211},
+ dictWord{4, 10, 332},
+ dictWord{5, 10, 335},
+ dictWord{6, 10, 238},
+ dictWord{
+ 7,
+ 10,
+ 269,
+ },
+ dictWord{7, 10, 811},
+ dictWord{7, 10, 1797},
+ dictWord{8, 10, 836},
+ dictWord{9, 10, 507},
+ dictWord{141, 10, 242},
+ dictWord{4, 0, 785},
+ dictWord{
+ 5,
+ 0,
+ 368,
+ },
+ dictWord{6, 0, 297},
+ dictWord{7, 0, 793},
+ dictWord{139, 0, 938},
+ dictWord{7, 0, 464},
+ dictWord{8, 0, 558},
+ dictWord{11, 0, 105},
+ dictWord{12, 0, 231},
+ dictWord{14, 0, 386},
+ dictWord{15, 0, 102},
+ dictWord{148, 0, 75},
+ dictWord{133, 10, 1009},
+ dictWord{8, 0, 877},
+ dictWord{140, 0, 731},
+ dictWord{
+ 139,
+ 11,
+ 289,
+ },
+ dictWord{10, 11, 249},
+ dictWord{139, 11, 209},
+ dictWord{132, 11, 561},
+ dictWord{134, 0, 1608},
+ dictWord{132, 11, 760},
+ dictWord{134, 0, 1429},
+ dictWord{9, 11, 154},
+ dictWord{140, 11, 485},
+ dictWord{5, 10, 228},
+ dictWord{6, 10, 203},
+ dictWord{7, 10, 156},
+ dictWord{8, 10, 347},
+ dictWord{
+ 137,
+ 10,
+ 265,
+ },
+ dictWord{7, 0, 1010},
+ dictWord{11, 0, 733},
+ dictWord{11, 0, 759},
+ dictWord{13, 0, 34},
+ dictWord{14, 0, 427},
+ dictWord{146, 0, 45},
+ dictWord{7, 10, 1131},
+ dictWord{135, 10, 1468},
+ dictWord{136, 11, 255},
+ dictWord{7, 0, 1656},
+ dictWord{9, 0, 369},
+ dictWord{10, 0, 338},
+ dictWord{10, 0, 490},
+ dictWord{
+ 11,
+ 0,
+ 154,
+ },
+ dictWord{11, 0, 545},
+ dictWord{11, 0, 775},
+ dictWord{13, 0, 77},
+ dictWord{141, 0, 274},
+ dictWord{133, 11, 621},
+ dictWord{134, 0, 1038},
+ dictWord{
+ 4,
+ 11,
+ 368,
+ },
+ dictWord{135, 11, 641},
+ dictWord{6, 0, 2010},
+ dictWord{8, 0, 979},
+ dictWord{8, 0, 985},
+ dictWord{10, 0, 951},
+ dictWord{138, 0, 1011},
+ dictWord{
+ 134,
+ 0,
+ 1005,
+ },
+ dictWord{19, 0, 121},
+ dictWord{5, 10, 291},
+ dictWord{5, 10, 318},
+ dictWord{7, 10, 765},
+ dictWord{9, 10, 389},
+ dictWord{140, 10, 548},
+ dictWord{
+ 5,
+ 0,
+ 20,
+ },
+ dictWord{6, 0, 298},
+ dictWord{7, 0, 659},
+ dictWord{137, 0, 219},
+ dictWord{7, 0, 1440},
+ dictWord{11, 0, 854},
+ dictWord{11, 0, 872},
+ dictWord{11, 0, 921},
+ dictWord{12, 0, 551},
+ dictWord{13, 0, 472},
+ dictWord{142, 0, 367},
+ dictWord{5, 0, 490},
+ dictWord{6, 0, 615},
+ dictWord{6, 0, 620},
+ dictWord{135, 0, 683},
+ dictWord{
+ 6,
+ 0,
+ 1070,
+ },
+ dictWord{134, 0, 1597},
+ dictWord{139, 0, 522},
+ dictWord{132, 0, 439},
+ dictWord{136, 0, 669},
+ dictWord{6, 0, 766},
+ dictWord{6, 0, 1143},
+ dictWord{
+ 6,
+ 0,
+ 1245,
+ },
+ dictWord{10, 10, 525},
+ dictWord{139, 10, 82},
+ dictWord{9, 11, 92},
+ dictWord{147, 11, 91},
+ dictWord{6, 0, 668},
+ dictWord{134, 0, 1218},
+ dictWord{
+ 6,
+ 11,
+ 525,
+ },
+ dictWord{9, 11, 876},
+ dictWord{140, 11, 284},
+ dictWord{132, 0, 233},
+ dictWord{136, 0, 547},
+ dictWord{132, 10, 422},
+ dictWord{5, 10, 355},
+ dictWord{145, 10, 0},
+ dictWord{6, 11, 300},
+ dictWord{135, 11, 1515},
+ dictWord{4, 0, 482},
+ dictWord{137, 10, 905},
+ dictWord{4, 0, 886},
+ dictWord{7, 0, 346},
+ dictWord{133, 11, 594},
+ dictWord{133, 10, 865},
+ dictWord{5, 10, 914},
+ dictWord{134, 10, 1625},
+ dictWord{135, 0, 334},
+ dictWord{5, 0, 795},
+ dictWord{
+ 6,
+ 0,
+ 1741,
+ },
+ dictWord{133, 10, 234},
+ dictWord{135, 10, 1383},
+ dictWord{6, 11, 1641},
+ dictWord{136, 11, 820},
+ dictWord{135, 0, 371},
+ dictWord{7, 11, 1313},
+ dictWord{138, 11, 660},
+ dictWord{135, 10, 1312},
+ dictWord{135, 0, 622},
+ dictWord{7, 0, 625},
+ dictWord{135, 0, 1750},
+ dictWord{135, 0, 339},
+ dictWord{
+ 4,
+ 0,
+ 203,
+ },
+ dictWord{135, 0, 1936},
+ dictWord{15, 0, 29},
+ dictWord{16, 0, 38},
+ dictWord{15, 11, 29},
+ dictWord{144, 11, 38},
+ dictWord{5, 0, 338},
+ dictWord{
+ 135,
+ 0,
+ 1256,
+ },
+ dictWord{135, 10, 1493},
+ dictWord{10, 0, 130},
+ dictWord{6, 10, 421},
+ dictWord{7, 10, 61},
+ dictWord{7, 10, 1540},
+ dictWord{138, 10, 501},
+ dictWord{
+ 6,
+ 11,
+ 389,
+ },
+ dictWord{7, 11, 149},
+ dictWord{9, 11, 142},
+ dictWord{138, 11, 94},
+ dictWord{137, 10, 341},
+ dictWord{11, 0, 678},
+ dictWord{12, 0, 307},
+ dictWord{142, 10, 98},
+ dictWord{6, 11, 8},
+ dictWord{7, 11, 1881},
+ dictWord{136, 11, 91},
+ dictWord{135, 0, 2044},
+ dictWord{6, 0, 770},
+ dictWord{6, 0, 802},
+ dictWord{
+ 6,
+ 0,
+ 812,
+ },
+ dictWord{7, 0, 311},
+ dictWord{9, 0, 308},
+ dictWord{12, 0, 255},
+ dictWord{6, 10, 102},
+ dictWord{7, 10, 72},
+ dictWord{15, 10, 142},
+ dictWord{
+ 147,
+ 10,
+ 67,
+ },
+ dictWord{151, 10, 30},
+ dictWord{135, 10, 823},
+ dictWord{135, 0, 1266},
+ dictWord{135, 11, 1746},
+ dictWord{135, 10, 1870},
+ dictWord{4, 0, 400},
+ dictWord{5, 0, 267},
+ dictWord{135, 0, 232},
+ dictWord{7, 11, 24},
+ dictWord{11, 11, 542},
+ dictWord{139, 11, 852},
+ dictWord{135, 11, 1739},
+ dictWord{4, 11, 503},
+ dictWord{135, 11, 1661},
+ dictWord{5, 11, 130},
+ dictWord{7, 11, 1314},
+ dictWord{9, 11, 610},
+ dictWord{10, 11, 718},
+ dictWord{11, 11, 601},
+ dictWord{
+ 11,
+ 11,
+ 819,
+ },
+ dictWord{11, 11, 946},
+ dictWord{140, 11, 536},
+ dictWord{10, 11, 149},
+ dictWord{11, 11, 280},
+ dictWord{142, 11, 336},
+ dictWord{7, 0, 739},
+ dictWord{11, 0, 690},
+ dictWord{7, 11, 1946},
+ dictWord{8, 10, 48},
+ dictWord{8, 10, 88},
+ dictWord{8, 10, 582},
+ dictWord{8, 10, 681},
+ dictWord{9, 10, 373},
+ dictWord{
+ 9,
+ 10,
+ 864,
+ },
+ dictWord{11, 10, 157},
+ dictWord{11, 10, 843},
+ dictWord{148, 10, 27},
+ dictWord{134, 0, 990},
+ dictWord{4, 10, 88},
+ dictWord{5, 10, 137},
+ dictWord{
+ 5,
+ 10,
+ 174,
+ },
+ dictWord{5, 10, 777},
+ dictWord{6, 10, 1664},
+ dictWord{6, 10, 1725},
+ dictWord{7, 10, 77},
+ dictWord{7, 10, 426},
+ dictWord{7, 10, 1317},
+ dictWord{
+ 7,
+ 10,
+ 1355,
+ },
+ dictWord{8, 10, 126},
+ dictWord{8, 10, 563},
+ dictWord{9, 10, 523},
+ dictWord{9, 10, 750},
+ dictWord{10, 10, 310},
+ dictWord{10, 10, 836},
+ dictWord{
+ 11,
+ 10,
+ 42,
+ },
+ dictWord{11, 10, 318},
+ dictWord{11, 10, 731},
+ dictWord{12, 10, 68},
+ dictWord{12, 10, 92},
+ dictWord{12, 10, 507},
+ dictWord{12, 10, 692},
+ dictWord{
+ 13,
+ 10,
+ 81,
+ },
+ dictWord{13, 10, 238},
+ dictWord{13, 10, 374},
+ dictWord{14, 10, 436},
+ dictWord{18, 10, 138},
+ dictWord{19, 10, 78},
+ dictWord{19, 10, 111},
+ dictWord{20, 10, 55},
+ dictWord{20, 10, 77},
+ dictWord{148, 10, 92},
+ dictWord{141, 10, 418},
+ dictWord{7, 0, 1831},
+ dictWord{132, 10, 938},
+ dictWord{6, 0, 776},
+ dictWord{134, 0, 915},
+ dictWord{138, 10, 351},
+ dictWord{5, 11, 348},
+ dictWord{6, 11, 522},
+ dictWord{6, 10, 1668},
+ dictWord{7, 10, 1499},
+ dictWord{8, 10, 117},
+ dictWord{9, 10, 314},
+ dictWord{138, 10, 174},
+ dictWord{135, 10, 707},
+ dictWord{132, 0, 613},
+ dictWord{133, 10, 403},
+ dictWord{132, 11, 392},
+ dictWord{
+ 5,
+ 11,
+ 433,
+ },
+ dictWord{9, 11, 633},
+ dictWord{139, 11, 629},
+ dictWord{133, 0, 763},
+ dictWord{132, 0, 878},
+ dictWord{132, 0, 977},
+ dictWord{132, 0, 100},
+ dictWord{6, 0, 463},
+ dictWord{4, 10, 44},
+ dictWord{5, 10, 311},
+ dictWord{7, 10, 639},
+ dictWord{7, 10, 762},
+ dictWord{7, 10, 1827},
+ dictWord{9, 10, 8},
+ dictWord{
+ 9,
+ 10,
+ 462,
+ },
+ dictWord{148, 10, 83},
+ dictWord{134, 11, 234},
+ dictWord{4, 10, 346},
+ dictWord{7, 10, 115},
+ dictWord{9, 10, 180},
+ dictWord{9, 10, 456},
+ dictWord{
+ 138,
+ 10,
+ 363,
+ },
+ dictWord{5, 0, 362},
+ dictWord{5, 0, 443},
+ dictWord{6, 0, 318},
+ dictWord{7, 0, 1019},
+ dictWord{139, 0, 623},
+ dictWord{5, 0, 463},
+ dictWord{8, 0, 296},
+ dictWord{7, 11, 140},
+ dictWord{7, 11, 1950},
+ dictWord{8, 11, 680},
+ dictWord{11, 11, 817},
+ dictWord{147, 11, 88},
+ dictWord{7, 11, 1222},
+ dictWord{
+ 138,
+ 11,
+ 386,
+ },
+ dictWord{142, 0, 137},
+ dictWord{132, 0, 454},
+ dictWord{7, 0, 1914},
+ dictWord{6, 11, 5},
+ dictWord{7, 10, 1051},
+ dictWord{9, 10, 545},
+ dictWord{
+ 11,
+ 11,
+ 249,
+ },
+ dictWord{12, 11, 313},
+ dictWord{16, 11, 66},
+ dictWord{145, 11, 26},
+ dictWord{135, 0, 1527},
+ dictWord{145, 0, 58},
+ dictWord{148, 11, 59},
+ dictWord{
+ 5,
+ 0,
+ 48,
+ },
+ dictWord{5, 0, 404},
+ dictWord{6, 0, 557},
+ dictWord{7, 0, 458},
+ dictWord{8, 0, 597},
+ dictWord{10, 0, 455},
+ dictWord{10, 0, 606},
+ dictWord{11, 0, 49},
+ dictWord{
+ 11,
+ 0,
+ 548,
+ },
+ dictWord{12, 0, 476},
+ dictWord{13, 0, 18},
+ dictWord{141, 0, 450},
+ dictWord{5, 11, 963},
+ dictWord{134, 11, 1773},
+ dictWord{133, 0, 729},
+ dictWord{138, 11, 586},
+ dictWord{5, 0, 442},
+ dictWord{135, 0, 1984},
+ dictWord{134, 0, 449},
+ dictWord{144, 0, 40},
+ dictWord{4, 0, 853},
+ dictWord{7, 11, 180},
+ dictWord{8, 11, 509},
+ dictWord{136, 11, 792},
+ dictWord{6, 10, 185},
+ dictWord{7, 10, 1899},
+ dictWord{9, 10, 875},
+ dictWord{139, 10, 673},
+ dictWord{
+ 134,
+ 11,
+ 524,
+ },
+ dictWord{12, 0, 227},
+ dictWord{4, 10, 327},
+ dictWord{5, 10, 478},
+ dictWord{7, 10, 1332},
+ dictWord{136, 10, 753},
+ dictWord{6, 0, 1491},
+ dictWord{
+ 5,
+ 10,
+ 1020,
+ },
+ dictWord{133, 10, 1022},
+ dictWord{4, 10, 103},
+ dictWord{133, 10, 401},
+ dictWord{132, 11, 931},
+ dictWord{4, 10, 499},
+ dictWord{135, 10, 1421},
+ dictWord{5, 0, 55},
+ dictWord{7, 0, 376},
+ dictWord{140, 0, 161},
+ dictWord{133, 0, 450},
+ dictWord{6, 0, 1174},
+ dictWord{134, 0, 1562},
+ dictWord{10, 0, 62},
+ dictWord{13, 0, 400},
+ dictWord{135, 11, 1837},
+ dictWord{140, 0, 207},
+ dictWord{135, 0, 869},
+ dictWord{4, 11, 773},
+ dictWord{5, 11, 618},
+ dictWord{
+ 137,
+ 11,
+ 756,
+ },
+ dictWord{132, 10, 96},
+ dictWord{4, 0, 213},
+ dictWord{7, 0, 223},
+ dictWord{8, 0, 80},
+ dictWord{135, 10, 968},
+ dictWord{4, 11, 90},
+ dictWord{5, 11, 337},
+ dictWord{5, 11, 545},
+ dictWord{7, 11, 754},
+ dictWord{9, 11, 186},
+ dictWord{10, 11, 72},
+ dictWord{10, 11, 782},
+ dictWord{11, 11, 513},
+ dictWord{11, 11, 577},
+ dictWord{11, 11, 610},
+ dictWord{11, 11, 889},
+ dictWord{11, 11, 961},
+ dictWord{12, 11, 354},
+ dictWord{12, 11, 362},
+ dictWord{12, 11, 461},
+ dictWord{
+ 12,
+ 11,
+ 595,
+ },
+ dictWord{13, 11, 79},
+ dictWord{143, 11, 121},
+ dictWord{7, 0, 381},
+ dictWord{7, 0, 806},
+ dictWord{7, 0, 820},
+ dictWord{8, 0, 354},
+ dictWord{8, 0, 437},
+ dictWord{8, 0, 787},
+ dictWord{9, 0, 657},
+ dictWord{10, 0, 58},
+ dictWord{10, 0, 339},
+ dictWord{10, 0, 749},
+ dictWord{11, 0, 914},
+ dictWord{12, 0, 162},
+ dictWord{
+ 13,
+ 0,
+ 75,
+ },
+ dictWord{14, 0, 106},
+ dictWord{14, 0, 198},
+ dictWord{14, 0, 320},
+ dictWord{14, 0, 413},
+ dictWord{146, 0, 43},
+ dictWord{136, 0, 747},
+ dictWord{
+ 136,
+ 0,
+ 954,
+ },
+ dictWord{134, 0, 1073},
+ dictWord{135, 0, 556},
+ dictWord{7, 11, 151},
+ dictWord{9, 11, 329},
+ dictWord{139, 11, 254},
+ dictWord{5, 0, 692},
+ dictWord{
+ 134,
+ 0,
+ 1395,
+ },
+ dictWord{6, 10, 563},
+ dictWord{137, 10, 224},
+ dictWord{134, 0, 191},
+ dictWord{132, 0, 804},
+ dictWord{9, 11, 187},
+ dictWord{10, 11, 36},
+ dictWord{17, 11, 44},
+ dictWord{146, 11, 64},
+ dictWord{7, 11, 165},
+ dictWord{7, 11, 919},
+ dictWord{136, 11, 517},
+ dictWord{4, 11, 506},
+ dictWord{5, 11, 295},
+ dictWord{7, 11, 1680},
+ dictWord{15, 11, 14},
+ dictWord{144, 11, 5},
+ dictWord{4, 0, 706},
+ dictWord{6, 0, 162},
+ dictWord{7, 0, 1960},
+ dictWord{136, 0, 831},
+ dictWord{
+ 135,
+ 11,
+ 1376,
+ },
+ dictWord{7, 11, 987},
+ dictWord{9, 11, 688},
+ dictWord{10, 11, 522},
+ dictWord{11, 11, 788},
+ dictWord{140, 11, 566},
+ dictWord{150, 0, 35},
+ dictWord{138, 0, 426},
+ dictWord{135, 0, 1235},
+ dictWord{135, 11, 1741},
+ dictWord{7, 11, 389},
+ dictWord{7, 11, 700},
+ dictWord{7, 11, 940},
+ dictWord{
+ 8,
+ 11,
+ 514,
+ },
+ dictWord{9, 11, 116},
+ dictWord{9, 11, 535},
+ dictWord{10, 11, 118},
+ dictWord{11, 11, 107},
+ dictWord{11, 11, 148},
+ dictWord{11, 11, 922},
+ dictWord{
+ 12,
+ 11,
+ 254,
+ },
+ dictWord{12, 11, 421},
+ dictWord{142, 11, 238},
+ dictWord{134, 0, 1234},
+ dictWord{132, 11, 743},
+ dictWord{4, 10, 910},
+ dictWord{5, 10, 832},
+ dictWord{135, 11, 1335},
+ dictWord{141, 0, 96},
+ dictWord{135, 11, 185},
+ dictWord{146, 0, 149},
+ dictWord{4, 0, 204},
+ dictWord{137, 0, 902},
+ dictWord{
+ 4,
+ 11,
+ 784,
+ },
+ dictWord{133, 11, 745},
+ dictWord{136, 0, 833},
+ dictWord{136, 0, 949},
+ dictWord{7, 0, 366},
+ dictWord{9, 0, 287},
+ dictWord{12, 0, 199},
+ dictWord{
+ 12,
+ 0,
+ 556,
+ },
+ dictWord{12, 0, 577},
+ dictWord{5, 11, 81},
+ dictWord{7, 11, 146},
+ dictWord{7, 11, 1342},
+ dictWord{7, 11, 1446},
+ dictWord{8, 11, 53},
+ dictWord{8, 11, 561},
+ dictWord{8, 11, 694},
+ dictWord{8, 11, 754},
+ dictWord{9, 11, 97},
+ dictWord{9, 11, 115},
+ dictWord{9, 11, 894},
+ dictWord{10, 11, 462},
+ dictWord{10, 11, 813},
+ dictWord{11, 11, 230},
+ dictWord{11, 11, 657},
+ dictWord{11, 11, 699},
+ dictWord{11, 11, 748},
+ dictWord{12, 11, 119},
+ dictWord{12, 11, 200},
+ dictWord{
+ 12,
+ 11,
+ 283,
+ },
+ dictWord{14, 11, 273},
+ dictWord{145, 11, 15},
+ dictWord{5, 11, 408},
+ dictWord{137, 11, 747},
+ dictWord{9, 11, 498},
+ dictWord{140, 11, 181},
+ dictWord{
+ 6,
+ 0,
+ 2020,
+ },
+ dictWord{136, 0, 992},
+ dictWord{5, 0, 356},
+ dictWord{135, 0, 224},
+ dictWord{134, 0, 784},
+ dictWord{7, 0, 630},
+ dictWord{9, 0, 567},
+ dictWord{
+ 11,
+ 0,
+ 150,
+ },
+ dictWord{11, 0, 444},
+ dictWord{13, 0, 119},
+ dictWord{8, 10, 528},
+ dictWord{137, 10, 348},
+ dictWord{134, 0, 539},
+ dictWord{4, 10, 20},
+ dictWord{
+ 133,
+ 10,
+ 616,
+ },
+ dictWord{142, 0, 27},
+ dictWord{7, 11, 30},
+ dictWord{8, 11, 86},
+ dictWord{8, 11, 315},
+ dictWord{8, 11, 700},
+ dictWord{9, 11, 576},
+ dictWord{9, 11, 858},
+ dictWord{11, 11, 310},
+ dictWord{11, 11, 888},
+ dictWord{11, 11, 904},
+ dictWord{12, 11, 361},
+ dictWord{141, 11, 248},
+ dictWord{138, 11, 839},
+ dictWord{
+ 134,
+ 0,
+ 755,
+ },
+ dictWord{134, 0, 1063},
+ dictWord{7, 10, 1091},
+ dictWord{135, 10, 1765},
+ dictWord{134, 11, 428},
+ dictWord{7, 11, 524},
+ dictWord{8, 11, 169},
+ dictWord{8, 11, 234},
+ dictWord{9, 11, 480},
+ dictWord{138, 11, 646},
+ dictWord{139, 0, 814},
+ dictWord{7, 11, 1462},
+ dictWord{139, 11, 659},
+ dictWord{
+ 4,
+ 10,
+ 26,
+ },
+ dictWord{5, 10, 429},
+ dictWord{6, 10, 245},
+ dictWord{7, 10, 704},
+ dictWord{7, 10, 1379},
+ dictWord{135, 10, 1474},
+ dictWord{7, 11, 1205},
+ dictWord{
+ 138,
+ 11,
+ 637,
+ },
+ dictWord{139, 11, 803},
+ dictWord{132, 10, 621},
+ dictWord{136, 0, 987},
+ dictWord{4, 11, 266},
+ dictWord{8, 11, 4},
+ dictWord{9, 11, 39},
+ dictWord{
+ 10,
+ 11,
+ 166,
+ },
+ dictWord{11, 11, 918},
+ dictWord{12, 11, 635},
+ dictWord{20, 11, 10},
+ dictWord{22, 11, 27},
+ dictWord{150, 11, 43},
+ dictWord{4, 0, 235},
+ dictWord{
+ 135,
+ 0,
+ 255,
+ },
+ dictWord{4, 0, 194},
+ dictWord{5, 0, 584},
+ dictWord{6, 0, 384},
+ dictWord{7, 0, 583},
+ dictWord{10, 0, 761},
+ dictWord{11, 0, 760},
+ dictWord{139, 0, 851},
+ dictWord{133, 10, 542},
+ dictWord{134, 0, 1086},
+ dictWord{133, 10, 868},
+ dictWord{8, 0, 1016},
+ dictWord{136, 0, 1018},
+ dictWord{7, 0, 1396},
+ dictWord{
+ 7,
+ 11,
+ 1396,
+ },
+ dictWord{136, 10, 433},
+ dictWord{135, 10, 1495},
+ dictWord{138, 10, 215},
+ dictWord{141, 10, 124},
+ dictWord{7, 11, 157},
+ dictWord{
+ 8,
+ 11,
+ 279,
+ },
+ dictWord{9, 11, 759},
+ dictWord{16, 11, 31},
+ dictWord{16, 11, 39},
+ dictWord{16, 11, 75},
+ dictWord{18, 11, 24},
+ dictWord{20, 11, 42},
+ dictWord{152, 11, 1},
+ dictWord{5, 0, 562},
+ dictWord{134, 11, 604},
+ dictWord{134, 0, 913},
+ dictWord{5, 0, 191},
+ dictWord{137, 0, 271},
+ dictWord{4, 0, 470},
+ dictWord{6, 0, 153},
+ dictWord{7, 0, 1503},
+ dictWord{7, 0, 1923},
+ dictWord{10, 0, 701},
+ dictWord{11, 0, 132},
+ dictWord{11, 0, 227},
+ dictWord{11, 0, 320},
+ dictWord{11, 0, 436},
+ dictWord{
+ 11,
+ 0,
+ 525,
+ },
+ dictWord{11, 0, 855},
+ dictWord{11, 0, 873},
+ dictWord{12, 0, 41},
+ dictWord{12, 0, 286},
+ dictWord{13, 0, 103},
+ dictWord{13, 0, 284},
+ dictWord{
+ 14,
+ 0,
+ 255,
+ },
+ dictWord{14, 0, 262},
+ dictWord{15, 0, 117},
+ dictWord{143, 0, 127},
+ dictWord{7, 0, 475},
+ dictWord{12, 0, 45},
+ dictWord{147, 10, 112},
+ dictWord{
+ 132,
+ 11,
+ 567,
+ },
+ dictWord{137, 11, 859},
+ dictWord{6, 0, 713},
+ dictWord{6, 0, 969},
+ dictWord{6, 0, 1290},
+ dictWord{134, 0, 1551},
+ dictWord{133, 0, 327},
+ dictWord{
+ 6,
+ 0,
+ 552,
+ },
+ dictWord{6, 0, 1292},
+ dictWord{7, 0, 1754},
+ dictWord{137, 0, 604},
+ dictWord{4, 0, 223},
+ dictWord{6, 0, 359},
+ dictWord{11, 0, 3},
+ dictWord{13, 0, 108},
+ dictWord{14, 0, 89},
+ dictWord{16, 0, 22},
+ dictWord{5, 11, 762},
+ dictWord{7, 11, 1880},
+ dictWord{9, 11, 680},
+ dictWord{139, 11, 798},
+ dictWord{5, 0, 80},
+ dictWord{
+ 6,
+ 0,
+ 405,
+ },
+ dictWord{7, 0, 403},
+ dictWord{7, 0, 1502},
+ dictWord{8, 0, 456},
+ dictWord{9, 0, 487},
+ dictWord{9, 0, 853},
+ dictWord{9, 0, 889},
+ dictWord{10, 0, 309},
+ dictWord{
+ 11,
+ 0,
+ 721,
+ },
+ dictWord{11, 0, 994},
+ dictWord{12, 0, 430},
+ dictWord{141, 0, 165},
+ dictWord{133, 11, 298},
+ dictWord{132, 10, 647},
+ dictWord{134, 0, 2016},
+ dictWord{18, 10, 10},
+ dictWord{146, 11, 10},
+ dictWord{4, 0, 453},
+ dictWord{5, 0, 887},
+ dictWord{6, 0, 535},
+ dictWord{8, 0, 6},
+ dictWord{8, 0, 543},
+ dictWord{
+ 136,
+ 0,
+ 826,
+ },
+ dictWord{136, 0, 975},
+ dictWord{10, 0, 961},
+ dictWord{138, 0, 962},
+ dictWord{138, 10, 220},
+ dictWord{6, 0, 1891},
+ dictWord{6, 0, 1893},
+ dictWord{
+ 9,
+ 0,
+ 916,
+ },
+ dictWord{9, 0, 965},
+ dictWord{9, 0, 972},
+ dictWord{12, 0, 801},
+ dictWord{12, 0, 859},
+ dictWord{12, 0, 883},
+ dictWord{15, 0, 226},
+ dictWord{149, 0, 51},
+ dictWord{132, 10, 109},
+ dictWord{135, 11, 267},
+ dictWord{7, 11, 92},
+ dictWord{7, 11, 182},
+ dictWord{8, 11, 453},
+ dictWord{9, 11, 204},
+ dictWord{11, 11, 950},
+ dictWord{12, 11, 94},
+ dictWord{12, 11, 644},
+ dictWord{16, 11, 20},
+ dictWord{16, 11, 70},
+ dictWord{16, 11, 90},
+ dictWord{147, 11, 55},
+ dictWord{
+ 134,
+ 10,
+ 1746,
+ },
+ dictWord{6, 11, 71},
+ dictWord{7, 11, 845},
+ dictWord{7, 11, 1308},
+ dictWord{8, 11, 160},
+ dictWord{137, 11, 318},
+ dictWord{5, 0, 101},
+ dictWord{6, 0, 88},
+ dictWord{7, 0, 263},
+ dictWord{7, 0, 628},
+ dictWord{7, 0, 1677},
+ dictWord{8, 0, 349},
+ dictWord{9, 0, 100},
+ dictWord{10, 0, 677},
+ dictWord{14, 0, 169},
+ dictWord{
+ 14,
+ 0,
+ 302,
+ },
+ dictWord{14, 0, 313},
+ dictWord{15, 0, 48},
+ dictWord{15, 0, 84},
+ dictWord{7, 11, 237},
+ dictWord{8, 11, 664},
+ dictWord{9, 11, 42},
+ dictWord{9, 11, 266},
+ dictWord{9, 11, 380},
+ dictWord{9, 11, 645},
+ dictWord{10, 11, 177},
+ dictWord{138, 11, 276},
+ dictWord{138, 11, 69},
+ dictWord{4, 0, 310},
+ dictWord{7, 0, 708},
+ dictWord{7, 0, 996},
+ dictWord{9, 0, 795},
+ dictWord{10, 0, 390},
+ dictWord{10, 0, 733},
+ dictWord{11, 0, 451},
+ dictWord{12, 0, 249},
+ dictWord{14, 0, 115},
+ dictWord{
+ 14,
+ 0,
+ 286,
+ },
+ dictWord{143, 0, 100},
+ dictWord{5, 0, 587},
+ dictWord{4, 10, 40},
+ dictWord{10, 10, 67},
+ dictWord{11, 10, 117},
+ dictWord{11, 10, 768},
+ dictWord{
+ 139,
+ 10,
+ 935,
+ },
+ dictWord{6, 0, 1942},
+ dictWord{7, 0, 512},
+ dictWord{136, 0, 983},
+ dictWord{7, 10, 992},
+ dictWord{8, 10, 301},
+ dictWord{9, 10, 722},
+ dictWord{12, 10, 63},
+ dictWord{13, 10, 29},
+ dictWord{14, 10, 161},
+ dictWord{143, 10, 18},
+ dictWord{136, 11, 76},
+ dictWord{139, 10, 923},
+ dictWord{134, 0, 645},
+ dictWord{
+ 134,
+ 0,
+ 851,
+ },
+ dictWord{4, 0, 498},
+ dictWord{132, 11, 293},
+ dictWord{7, 0, 217},
+ dictWord{8, 0, 140},
+ dictWord{10, 0, 610},
+ dictWord{14, 11, 352},
+ dictWord{
+ 17,
+ 11,
+ 53,
+ },
+ dictWord{18, 11, 146},
+ dictWord{18, 11, 152},
+ dictWord{19, 11, 11},
+ dictWord{150, 11, 54},
+ dictWord{134, 0, 1448},
+ dictWord{138, 11, 841},
+ dictWord{133, 0, 905},
+ dictWord{4, 11, 605},
+ dictWord{7, 11, 518},
+ dictWord{7, 11, 1282},
+ dictWord{7, 11, 1918},
+ dictWord{10, 11, 180},
+ dictWord{139, 11, 218},
+ dictWord{139, 11, 917},
+ dictWord{135, 10, 825},
+ dictWord{140, 10, 328},
+ dictWord{4, 0, 456},
+ dictWord{7, 0, 105},
+ dictWord{7, 0, 358},
+ dictWord{7, 0, 1637},
+ dictWord{8, 0, 643},
+ dictWord{139, 0, 483},
+ dictWord{134, 0, 792},
+ dictWord{6, 11, 96},
+ dictWord{135, 11, 1426},
+ dictWord{137, 11, 691},
+ dictWord{
+ 4,
+ 11,
+ 651,
+ },
+ dictWord{133, 11, 289},
+ dictWord{7, 11, 688},
+ dictWord{8, 11, 35},
+ dictWord{9, 11, 511},
+ dictWord{10, 11, 767},
+ dictWord{147, 11, 118},
+ dictWord{
+ 150,
+ 0,
+ 56,
+ },
+ dictWord{5, 0, 243},
+ dictWord{5, 0, 535},
+ dictWord{6, 10, 204},
+ dictWord{10, 10, 320},
+ dictWord{10, 10, 583},
+ dictWord{13, 10, 502},
+ dictWord{
+ 14,
+ 10,
+ 72,
+ },
+ dictWord{14, 10, 274},
+ dictWord{14, 10, 312},
+ dictWord{14, 10, 344},
+ dictWord{15, 10, 159},
+ dictWord{16, 10, 62},
+ dictWord{16, 10, 69},
+ dictWord{
+ 17,
+ 10,
+ 30,
+ },
+ dictWord{18, 10, 42},
+ dictWord{18, 10, 53},
+ dictWord{18, 10, 84},
+ dictWord{18, 10, 140},
+ dictWord{19, 10, 68},
+ dictWord{19, 10, 85},
+ dictWord{20, 10, 5},
+ dictWord{20, 10, 45},
+ dictWord{20, 10, 101},
+ dictWord{22, 10, 7},
+ dictWord{150, 10, 20},
+ dictWord{4, 10, 558},
+ dictWord{6, 10, 390},
+ dictWord{7, 10, 162},
+ dictWord{7, 10, 689},
+ dictWord{9, 10, 360},
+ dictWord{138, 10, 653},
+ dictWord{146, 11, 23},
+ dictWord{135, 0, 1748},
+ dictWord{5, 10, 856},
+ dictWord{
+ 6,
+ 10,
+ 1672,
+ },
+ dictWord{6, 10, 1757},
+ dictWord{134, 10, 1781},
+ dictWord{5, 0, 539},
+ dictWord{5, 0, 754},
+ dictWord{6, 0, 876},
+ dictWord{132, 11, 704},
+ dictWord{
+ 135,
+ 11,
+ 1078,
+ },
+ dictWord{5, 10, 92},
+ dictWord{10, 10, 736},
+ dictWord{140, 10, 102},
+ dictWord{17, 0, 91},
+ dictWord{5, 10, 590},
+ dictWord{137, 10, 213},
+ dictWord{134, 0, 1565},
+ dictWord{6, 0, 91},
+ dictWord{135, 0, 435},
+ dictWord{4, 0, 939},
+ dictWord{140, 0, 792},
+ dictWord{134, 0, 1399},
+ dictWord{4, 0, 16},
+ dictWord{
+ 5,
+ 0,
+ 316,
+ },
+ dictWord{5, 0, 842},
+ dictWord{6, 0, 370},
+ dictWord{6, 0, 1778},
+ dictWord{8, 0, 166},
+ dictWord{11, 0, 812},
+ dictWord{12, 0, 206},
+ dictWord{12, 0, 351},
+ dictWord{14, 0, 418},
+ dictWord{16, 0, 15},
+ dictWord{16, 0, 34},
+ dictWord{18, 0, 3},
+ dictWord{19, 0, 3},
+ dictWord{19, 0, 7},
+ dictWord{20, 0, 4},
+ dictWord{21, 0, 21},
+ dictWord{
+ 4,
+ 11,
+ 720,
+ },
+ dictWord{133, 11, 306},
+ dictWord{144, 0, 95},
+ dictWord{133, 11, 431},
+ dictWord{132, 11, 234},
+ dictWord{135, 0, 551},
+ dictWord{4, 0, 999},
+ dictWord{6, 0, 1966},
+ dictWord{134, 0, 2042},
+ dictWord{7, 0, 619},
+ dictWord{10, 0, 547},
+ dictWord{11, 0, 122},
+ dictWord{12, 0, 601},
+ dictWord{15, 0, 7},
+ dictWord{148, 0, 20},
+ dictWord{5, 11, 464},
+ dictWord{6, 11, 236},
+ dictWord{7, 11, 276},
+ dictWord{7, 11, 696},
+ dictWord{7, 11, 914},
+ dictWord{7, 11, 1108},
+ dictWord{
+ 7,
+ 11,
+ 1448,
+ },
+ dictWord{9, 11, 15},
+ dictWord{9, 11, 564},
+ dictWord{10, 11, 14},
+ dictWord{12, 11, 565},
+ dictWord{13, 11, 449},
+ dictWord{14, 11, 53},
+ dictWord{
+ 15,
+ 11,
+ 13,
+ },
+ dictWord{16, 11, 64},
+ dictWord{145, 11, 41},
+ dictWord{6, 0, 884},
+ dictWord{6, 0, 1019},
+ dictWord{134, 0, 1150},
+ dictWord{6, 11, 1767},
+ dictWord{
+ 12,
+ 11,
+ 194,
+ },
+ dictWord{145, 11, 107},
+ dictWord{136, 10, 503},
+ dictWord{133, 11, 840},
+ dictWord{7, 0, 671},
+ dictWord{134, 10, 466},
+ dictWord{132, 0, 888},
+ dictWord{4, 0, 149},
+ dictWord{138, 0, 368},
+ dictWord{4, 0, 154},
+ dictWord{7, 0, 1134},
+ dictWord{136, 0, 105},
+ dictWord{135, 0, 983},
+ dictWord{9, 11, 642},
+ dictWord{11, 11, 236},
+ dictWord{142, 11, 193},
+ dictWord{4, 0, 31},
+ dictWord{6, 0, 429},
+ dictWord{7, 0, 962},
+ dictWord{9, 0, 458},
+ dictWord{139, 0, 691},
+ dictWord{
+ 6,
+ 0,
+ 643,
+ },
+ dictWord{134, 0, 1102},
+ dictWord{132, 0, 312},
+ dictWord{4, 11, 68},
+ dictWord{5, 11, 634},
+ dictWord{6, 11, 386},
+ dictWord{7, 11, 794},
+ dictWord{
+ 8,
+ 11,
+ 273,
+ },
+ dictWord{9, 11, 563},
+ dictWord{10, 11, 105},
+ dictWord{10, 11, 171},
+ dictWord{11, 11, 94},
+ dictWord{139, 11, 354},
+ dictWord{133, 0, 740},
+ dictWord{
+ 135,
+ 0,
+ 1642,
+ },
+ dictWord{4, 11, 95},
+ dictWord{7, 11, 416},
+ dictWord{8, 11, 211},
+ dictWord{139, 11, 830},
+ dictWord{132, 0, 236},
+ dictWord{138, 10, 241},
+ dictWord{7, 11, 731},
+ dictWord{13, 11, 20},
+ dictWord{143, 11, 11},
+ dictWord{5, 0, 836},
+ dictWord{5, 0, 857},
+ dictWord{6, 0, 1680},
+ dictWord{135, 0, 59},
+ dictWord{
+ 10,
+ 0,
+ 68,
+ },
+ dictWord{11, 0, 494},
+ dictWord{152, 11, 6},
+ dictWord{4, 0, 81},
+ dictWord{139, 0, 867},
+ dictWord{135, 0, 795},
+ dictWord{133, 11, 689},
+ dictWord{
+ 4,
+ 0,
+ 1001,
+ },
+ dictWord{5, 0, 282},
+ dictWord{6, 0, 1932},
+ dictWord{6, 0, 1977},
+ dictWord{6, 0, 1987},
+ dictWord{6, 0, 1992},
+ dictWord{8, 0, 650},
+ dictWord{8, 0, 919},
+ dictWord{8, 0, 920},
+ dictWord{8, 0, 923},
+ dictWord{8, 0, 926},
+ dictWord{8, 0, 927},
+ dictWord{8, 0, 931},
+ dictWord{8, 0, 939},
+ dictWord{8, 0, 947},
+ dictWord{8, 0, 956},
+ dictWord{8, 0, 997},
+ dictWord{9, 0, 907},
+ dictWord{10, 0, 950},
+ dictWord{10, 0, 953},
+ dictWord{10, 0, 954},
+ dictWord{10, 0, 956},
+ dictWord{10, 0, 958},
+ dictWord{
+ 10,
+ 0,
+ 959,
+ },
+ dictWord{10, 0, 964},
+ dictWord{10, 0, 970},
+ dictWord{10, 0, 972},
+ dictWord{10, 0, 973},
+ dictWord{10, 0, 975},
+ dictWord{10, 0, 976},
+ dictWord{
+ 10,
+ 0,
+ 980,
+ },
+ dictWord{10, 0, 981},
+ dictWord{10, 0, 984},
+ dictWord{10, 0, 988},
+ dictWord{10, 0, 990},
+ dictWord{10, 0, 995},
+ dictWord{10, 0, 999},
+ dictWord{
+ 10,
+ 0,
+ 1002,
+ },
+ dictWord{10, 0, 1003},
+ dictWord{10, 0, 1005},
+ dictWord{10, 0, 1006},
+ dictWord{10, 0, 1008},
+ dictWord{10, 0, 1009},
+ dictWord{10, 0, 1012},
+ dictWord{10, 0, 1014},
+ dictWord{10, 0, 1015},
+ dictWord{10, 0, 1019},
+ dictWord{10, 0, 1020},
+ dictWord{10, 0, 1022},
+ dictWord{12, 0, 959},
+ dictWord{12, 0, 961},
+ dictWord{12, 0, 962},
+ dictWord{12, 0, 963},
+ dictWord{12, 0, 964},
+ dictWord{12, 0, 965},
+ dictWord{12, 0, 967},
+ dictWord{12, 0, 968},
+ dictWord{12, 0, 969},
+ dictWord{12, 0, 970},
+ dictWord{12, 0, 971},
+ dictWord{12, 0, 972},
+ dictWord{12, 0, 973},
+ dictWord{12, 0, 974},
+ dictWord{12, 0, 975},
+ dictWord{12, 0, 976},
+ dictWord{
+ 12,
+ 0,
+ 977,
+ },
+ dictWord{12, 0, 979},
+ dictWord{12, 0, 981},
+ dictWord{12, 0, 982},
+ dictWord{12, 0, 983},
+ dictWord{12, 0, 984},
+ dictWord{12, 0, 985},
+ dictWord{
+ 12,
+ 0,
+ 986,
+ },
+ dictWord{12, 0, 987},
+ dictWord{12, 0, 989},
+ dictWord{12, 0, 990},
+ dictWord{12, 0, 992},
+ dictWord{12, 0, 993},
+ dictWord{12, 0, 995},
+ dictWord{12, 0, 998},
+ dictWord{12, 0, 999},
+ dictWord{12, 0, 1000},
+ dictWord{12, 0, 1001},
+ dictWord{12, 0, 1002},
+ dictWord{12, 0, 1004},
+ dictWord{12, 0, 1005},
+ dictWord{
+ 12,
+ 0,
+ 1006,
+ },
+ dictWord{12, 0, 1007},
+ dictWord{12, 0, 1008},
+ dictWord{12, 0, 1009},
+ dictWord{12, 0, 1010},
+ dictWord{12, 0, 1011},
+ dictWord{12, 0, 1012},
+ dictWord{12, 0, 1014},
+ dictWord{12, 0, 1015},
+ dictWord{12, 0, 1016},
+ dictWord{12, 0, 1017},
+ dictWord{12, 0, 1018},
+ dictWord{12, 0, 1019},
+ dictWord{
+ 12,
+ 0,
+ 1022,
+ },
+ dictWord{12, 0, 1023},
+ dictWord{14, 0, 475},
+ dictWord{14, 0, 477},
+ dictWord{14, 0, 478},
+ dictWord{14, 0, 479},
+ dictWord{14, 0, 480},
+ dictWord{
+ 14,
+ 0,
+ 482,
+ },
+ dictWord{14, 0, 483},
+ dictWord{14, 0, 484},
+ dictWord{14, 0, 485},
+ dictWord{14, 0, 486},
+ dictWord{14, 0, 487},
+ dictWord{14, 0, 488},
+ dictWord{14, 0, 489},
+ dictWord{14, 0, 490},
+ dictWord{14, 0, 491},
+ dictWord{14, 0, 492},
+ dictWord{14, 0, 493},
+ dictWord{14, 0, 494},
+ dictWord{14, 0, 495},
+ dictWord{14, 0, 496},
+ dictWord{14, 0, 497},
+ dictWord{14, 0, 498},
+ dictWord{14, 0, 499},
+ dictWord{14, 0, 500},
+ dictWord{14, 0, 501},
+ dictWord{14, 0, 502},
+ dictWord{14, 0, 503},
+ dictWord{
+ 14,
+ 0,
+ 504,
+ },
+ dictWord{14, 0, 506},
+ dictWord{14, 0, 507},
+ dictWord{14, 0, 508},
+ dictWord{14, 0, 509},
+ dictWord{14, 0, 510},
+ dictWord{14, 0, 511},
+ dictWord{
+ 16,
+ 0,
+ 113,
+ },
+ dictWord{16, 0, 114},
+ dictWord{16, 0, 115},
+ dictWord{16, 0, 117},
+ dictWord{16, 0, 118},
+ dictWord{16, 0, 119},
+ dictWord{16, 0, 121},
+ dictWord{16, 0, 122},
+ dictWord{16, 0, 123},
+ dictWord{16, 0, 124},
+ dictWord{16, 0, 125},
+ dictWord{16, 0, 126},
+ dictWord{16, 0, 127},
+ dictWord{18, 0, 242},
+ dictWord{18, 0, 243},
+ dictWord{18, 0, 244},
+ dictWord{18, 0, 245},
+ dictWord{18, 0, 248},
+ dictWord{18, 0, 249},
+ dictWord{18, 0, 250},
+ dictWord{18, 0, 251},
+ dictWord{18, 0, 252},
+ dictWord{
+ 18,
+ 0,
+ 253,
+ },
+ dictWord{18, 0, 254},
+ dictWord{18, 0, 255},
+ dictWord{20, 0, 125},
+ dictWord{20, 0, 126},
+ dictWord{148, 0, 127},
+ dictWord{7, 11, 1717},
+ dictWord{
+ 7,
+ 11,
+ 1769,
+ },
+ dictWord{138, 11, 546},
+ dictWord{7, 11, 1127},
+ dictWord{7, 11, 1572},
+ dictWord{10, 11, 297},
+ dictWord{10, 11, 422},
+ dictWord{11, 11, 764},
+ dictWord{11, 11, 810},
+ dictWord{12, 11, 264},
+ dictWord{13, 11, 102},
+ dictWord{13, 11, 300},
+ dictWord{13, 11, 484},
+ dictWord{14, 11, 147},
+ dictWord{
+ 14,
+ 11,
+ 229,
+ },
+ dictWord{17, 11, 71},
+ dictWord{18, 11, 118},
+ dictWord{147, 11, 120},
+ dictWord{6, 0, 1148},
+ dictWord{134, 0, 1586},
+ dictWord{132, 0, 775},
+ dictWord{135, 10, 954},
+ dictWord{133, 11, 864},
+ dictWord{133, 11, 928},
+ dictWord{138, 11, 189},
+ dictWord{135, 10, 1958},
+ dictWord{6, 10, 549},
+ dictWord{
+ 8,
+ 10,
+ 34,
+ },
+ dictWord{8, 10, 283},
+ dictWord{9, 10, 165},
+ dictWord{138, 10, 475},
+ dictWord{5, 10, 652},
+ dictWord{5, 10, 701},
+ dictWord{135, 10, 449},
+ dictWord{135, 11, 695},
+ dictWord{4, 10, 655},
+ dictWord{7, 10, 850},
+ dictWord{17, 10, 75},
+ dictWord{146, 10, 137},
+ dictWord{140, 11, 682},
+ dictWord{
+ 133,
+ 11,
+ 523,
+ },
+ dictWord{8, 0, 970},
+ dictWord{136, 10, 670},
+ dictWord{136, 11, 555},
+ dictWord{7, 11, 76},
+ dictWord{8, 11, 44},
+ dictWord{9, 11, 884},
+ dictWord{
+ 10,
+ 11,
+ 580,
+ },
+ dictWord{11, 11, 399},
+ dictWord{11, 11, 894},
+ dictWord{15, 11, 122},
+ dictWord{18, 11, 144},
+ dictWord{147, 11, 61},
+ dictWord{6, 10, 159},
+ dictWord{
+ 6,
+ 10,
+ 364,
+ },
+ dictWord{7, 10, 516},
+ dictWord{7, 10, 1439},
+ dictWord{137, 10, 518},
+ dictWord{4, 0, 71},
+ dictWord{5, 0, 376},
+ dictWord{7, 0, 119},
+ dictWord{
+ 138,
+ 0,
+ 665,
+ },
+ dictWord{141, 10, 151},
+ dictWord{11, 0, 827},
+ dictWord{14, 0, 34},
+ dictWord{143, 0, 148},
+ dictWord{133, 11, 518},
+ dictWord{4, 0, 479},
+ dictWord{
+ 135,
+ 11,
+ 1787,
+ },
+ dictWord{135, 11, 1852},
+ dictWord{135, 10, 993},
+ dictWord{7, 0, 607},
+ dictWord{136, 0, 99},
+ dictWord{134, 0, 1960},
+ dictWord{132, 0, 793},
+ dictWord{4, 0, 41},
+ dictWord{5, 0, 74},
+ dictWord{7, 0, 1627},
+ dictWord{11, 0, 871},
+ dictWord{140, 0, 619},
+ dictWord{7, 0, 94},
+ dictWord{11, 0, 329},
+ dictWord{
+ 11,
+ 0,
+ 965,
+ },
+ dictWord{12, 0, 241},
+ dictWord{14, 0, 354},
+ dictWord{15, 0, 22},
+ dictWord{148, 0, 63},
+ dictWord{7, 10, 501},
+ dictWord{9, 10, 111},
+ dictWord{10, 10, 141},
+ dictWord{11, 10, 332},
+ dictWord{13, 10, 43},
+ dictWord{13, 10, 429},
+ dictWord{14, 10, 130},
+ dictWord{14, 10, 415},
+ dictWord{145, 10, 102},
+ dictWord{
+ 9,
+ 0,
+ 209,
+ },
+ dictWord{137, 0, 300},
+ dictWord{134, 0, 1497},
+ dictWord{138, 11, 255},
+ dictWord{4, 11, 934},
+ dictWord{5, 11, 138},
+ dictWord{136, 11, 610},
+ dictWord{133, 0, 98},
+ dictWord{6, 0, 1316},
+ dictWord{10, 11, 804},
+ dictWord{138, 11, 832},
+ dictWord{8, 11, 96},
+ dictWord{9, 11, 36},
+ dictWord{10, 11, 607},
+ dictWord{11, 11, 423},
+ dictWord{11, 11, 442},
+ dictWord{12, 11, 309},
+ dictWord{14, 11, 199},
+ dictWord{15, 11, 90},
+ dictWord{145, 11, 110},
+ dictWord{
+ 132,
+ 0,
+ 463,
+ },
+ dictWord{5, 10, 149},
+ dictWord{136, 10, 233},
+ dictWord{133, 10, 935},
+ dictWord{4, 11, 652},
+ dictWord{8, 11, 320},
+ dictWord{9, 11, 13},
+ dictWord{
+ 9,
+ 11,
+ 398,
+ },
+ dictWord{9, 11, 727},
+ dictWord{10, 11, 75},
+ dictWord{10, 11, 184},
+ dictWord{10, 11, 230},
+ dictWord{10, 11, 564},
+ dictWord{10, 11, 569},
+ dictWord{
+ 11,
+ 11,
+ 973,
+ },
+ dictWord{12, 11, 70},
+ dictWord{12, 11, 189},
+ dictWord{13, 11, 57},
+ dictWord{13, 11, 257},
+ dictWord{22, 11, 6},
+ dictWord{150, 11, 16},
+ dictWord{
+ 142,
+ 0,
+ 291,
+ },
+ dictWord{12, 10, 582},
+ dictWord{146, 10, 131},
+ dictWord{136, 10, 801},
+ dictWord{133, 0, 984},
+ dictWord{145, 11, 116},
+ dictWord{4, 11, 692},
+ dictWord{133, 11, 321},
+ dictWord{4, 0, 182},
+ dictWord{6, 0, 205},
+ dictWord{135, 0, 220},
+ dictWord{4, 0, 42},
+ dictWord{9, 0, 205},
+ dictWord{9, 0, 786},
+ dictWord{
+ 138,
+ 0,
+ 659,
+ },
+ dictWord{6, 0, 801},
+ dictWord{11, 11, 130},
+ dictWord{140, 11, 609},
+ dictWord{132, 0, 635},
+ dictWord{5, 11, 345},
+ dictWord{135, 11, 1016},
+ dictWord{139, 0, 533},
+ dictWord{132, 0, 371},
+ dictWord{4, 0, 272},
+ dictWord{135, 0, 836},
+ dictWord{6, 0, 1282},
+ dictWord{135, 11, 1100},
+ dictWord{5, 0, 825},
+ dictWord{134, 0, 1640},
+ dictWord{135, 11, 1325},
+ dictWord{133, 11, 673},
+ dictWord{4, 11, 287},
+ dictWord{133, 11, 1018},
+ dictWord{135, 0, 357},
+ dictWord{
+ 6,
+ 0,
+ 467,
+ },
+ dictWord{137, 0, 879},
+ dictWord{7, 0, 317},
+ dictWord{135, 0, 569},
+ dictWord{6, 0, 924},
+ dictWord{134, 0, 1588},
+ dictWord{5, 11, 34},
+ dictWord{
+ 5,
+ 10,
+ 406,
+ },
+ dictWord{10, 11, 724},
+ dictWord{12, 11, 444},
+ dictWord{13, 11, 354},
+ dictWord{18, 11, 32},
+ dictWord{23, 11, 24},
+ dictWord{23, 11, 31},
+ dictWord{
+ 152,
+ 11,
+ 5,
+ },
+ dictWord{6, 0, 1795},
+ dictWord{6, 0, 1835},
+ dictWord{6, 0, 1836},
+ dictWord{6, 0, 1856},
+ dictWord{8, 0, 844},
+ dictWord{8, 0, 849},
+ dictWord{8, 0, 854},
+ dictWord{8, 0, 870},
+ dictWord{8, 0, 887},
+ dictWord{10, 0, 852},
+ dictWord{138, 0, 942},
+ dictWord{6, 10, 69},
+ dictWord{135, 10, 117},
+ dictWord{137, 0, 307},
+ dictWord{
+ 4,
+ 0,
+ 944,
+ },
+ dictWord{6, 0, 1799},
+ dictWord{6, 0, 1825},
+ dictWord{10, 0, 848},
+ dictWord{10, 0, 875},
+ dictWord{10, 0, 895},
+ dictWord{10, 0, 899},
+ dictWord{
+ 10,
+ 0,
+ 902,
+ },
+ dictWord{140, 0, 773},
+ dictWord{11, 0, 43},
+ dictWord{13, 0, 72},
+ dictWord{141, 0, 142},
+ dictWord{135, 10, 1830},
+ dictWord{134, 11, 382},
+ dictWord{
+ 4,
+ 10,
+ 432,
+ },
+ dictWord{135, 10, 824},
+ dictWord{132, 11, 329},
+ dictWord{7, 0, 1820},
+ dictWord{139, 11, 124},
+ dictWord{133, 10, 826},
+ dictWord{
+ 133,
+ 0,
+ 525,
+ },
+ dictWord{132, 11, 906},
+ dictWord{7, 11, 1940},
+ dictWord{136, 11, 366},
+ dictWord{138, 11, 10},
+ dictWord{4, 11, 123},
+ dictWord{4, 11, 649},
+ dictWord{
+ 5,
+ 11,
+ 605,
+ },
+ dictWord{7, 11, 1509},
+ dictWord{136, 11, 36},
+ dictWord{6, 0, 110},
+ dictWord{135, 0, 1681},
+ dictWord{133, 0, 493},
+ dictWord{133, 11, 767},
+ dictWord{4, 0, 174},
+ dictWord{135, 0, 911},
+ dictWord{138, 11, 786},
+ dictWord{8, 0, 417},
+ dictWord{137, 0, 782},
+ dictWord{133, 10, 1000},
+ dictWord{7, 0, 733},
+ dictWord{137, 0, 583},
+ dictWord{4, 10, 297},
+ dictWord{6, 10, 529},
+ dictWord{7, 10, 152},
+ dictWord{7, 10, 713},
+ dictWord{7, 10, 1845},
+ dictWord{8, 10, 710},
+ dictWord{8, 10, 717},
+ dictWord{12, 10, 639},
+ dictWord{140, 10, 685},
+ dictWord{4, 0, 32},
+ dictWord{5, 0, 215},
+ dictWord{6, 0, 269},
+ dictWord{7, 0, 1782},
+ dictWord{
+ 7,
+ 0,
+ 1892,
+ },
+ dictWord{10, 0, 16},
+ dictWord{11, 0, 822},
+ dictWord{11, 0, 954},
+ dictWord{141, 0, 481},
+ dictWord{4, 11, 273},
+ dictWord{5, 11, 658},
+ dictWord{
+ 133,
+ 11,
+ 995,
+ },
+ dictWord{136, 0, 477},
+ dictWord{134, 11, 72},
+ dictWord{135, 11, 1345},
+ dictWord{5, 0, 308},
+ dictWord{7, 0, 1088},
+ dictWord{4, 10, 520},
+ dictWord{
+ 135,
+ 10,
+ 575,
+ },
+ dictWord{133, 11, 589},
+ dictWord{5, 0, 126},
+ dictWord{8, 0, 297},
+ dictWord{9, 0, 366},
+ dictWord{140, 0, 374},
+ dictWord{7, 0, 1551},
+ dictWord{
+ 139,
+ 0,
+ 361,
+ },
+ dictWord{5, 11, 117},
+ dictWord{6, 11, 514},
+ dictWord{6, 11, 541},
+ dictWord{7, 11, 1164},
+ dictWord{7, 11, 1436},
+ dictWord{8, 11, 220},
+ dictWord{
+ 8,
+ 11,
+ 648,
+ },
+ dictWord{10, 11, 688},
+ dictWord{139, 11, 560},
+ dictWord{133, 11, 686},
+ dictWord{4, 0, 946},
+ dictWord{6, 0, 1807},
+ dictWord{8, 0, 871},
+ dictWord{
+ 10,
+ 0,
+ 854,
+ },
+ dictWord{10, 0, 870},
+ dictWord{10, 0, 888},
+ dictWord{10, 0, 897},
+ dictWord{10, 0, 920},
+ dictWord{12, 0, 722},
+ dictWord{12, 0, 761},
+ dictWord{
+ 12,
+ 0,
+ 763,
+ },
+ dictWord{12, 0, 764},
+ dictWord{14, 0, 454},
+ dictWord{14, 0, 465},
+ dictWord{16, 0, 107},
+ dictWord{18, 0, 167},
+ dictWord{18, 0, 168},
+ dictWord{
+ 146,
+ 0,
+ 172,
+ },
+ dictWord{132, 0, 175},
+ dictWord{135, 0, 1307},
+ dictWord{132, 0, 685},
+ dictWord{135, 11, 1834},
+ dictWord{133, 0, 797},
+ dictWord{6, 0, 745},
+ dictWord{
+ 6,
+ 0,
+ 858,
+ },
+ dictWord{134, 0, 963},
+ dictWord{133, 0, 565},
+ dictWord{5, 10, 397},
+ dictWord{6, 10, 154},
+ dictWord{7, 11, 196},
+ dictWord{7, 10, 676},
+ dictWord{
+ 8,
+ 10,
+ 443,
+ },
+ dictWord{8, 10, 609},
+ dictWord{9, 10, 24},
+ dictWord{9, 10, 325},
+ dictWord{10, 10, 35},
+ dictWord{10, 11, 765},
+ dictWord{11, 11, 347},
+ dictWord{
+ 11,
+ 10,
+ 535,
+ },
+ dictWord{11, 11, 552},
+ dictWord{11, 11, 576},
+ dictWord{11, 10, 672},
+ dictWord{11, 11, 790},
+ dictWord{11, 10, 1018},
+ dictWord{12, 11, 263},
+ dictWord{12, 10, 637},
+ dictWord{13, 11, 246},
+ dictWord{13, 11, 270},
+ dictWord{13, 11, 395},
+ dictWord{14, 11, 74},
+ dictWord{14, 11, 176},
+ dictWord{
+ 14,
+ 11,
+ 190,
+ },
+ dictWord{14, 11, 398},
+ dictWord{14, 11, 412},
+ dictWord{15, 11, 32},
+ dictWord{15, 11, 63},
+ dictWord{16, 10, 30},
+ dictWord{16, 11, 88},
+ dictWord{
+ 147,
+ 11,
+ 105,
+ },
+ dictWord{13, 11, 84},
+ dictWord{141, 11, 122},
+ dictWord{4, 0, 252},
+ dictWord{7, 0, 1068},
+ dictWord{10, 0, 434},
+ dictWord{11, 0, 228},
+ dictWord{
+ 11,
+ 0,
+ 426,
+ },
+ dictWord{13, 0, 231},
+ dictWord{18, 0, 106},
+ dictWord{148, 0, 87},
+ dictWord{137, 0, 826},
+ dictWord{4, 11, 589},
+ dictWord{139, 11, 282},
+ dictWord{
+ 5,
+ 11,
+ 381,
+ },
+ dictWord{135, 11, 1792},
+ dictWord{132, 0, 791},
+ dictWord{5, 0, 231},
+ dictWord{10, 0, 509},
+ dictWord{133, 10, 981},
+ dictWord{7, 0, 601},
+ dictWord{
+ 9,
+ 0,
+ 277,
+ },
+ dictWord{9, 0, 674},
+ dictWord{10, 0, 178},
+ dictWord{10, 0, 418},
+ dictWord{10, 0, 571},
+ dictWord{11, 0, 531},
+ dictWord{12, 0, 113},
+ dictWord{12, 0, 475},
+ dictWord{13, 0, 99},
+ dictWord{142, 0, 428},
+ dictWord{4, 10, 56},
+ dictWord{7, 11, 616},
+ dictWord{7, 10, 1791},
+ dictWord{8, 10, 607},
+ dictWord{8, 10, 651},
+ dictWord{10, 11, 413},
+ dictWord{11, 10, 465},
+ dictWord{11, 10, 835},
+ dictWord{12, 10, 337},
+ dictWord{141, 10, 480},
+ dictWord{7, 0, 1591},
+ dictWord{144, 0, 43},
+ dictWord{9, 10, 158},
+ dictWord{138, 10, 411},
+ dictWord{135, 0, 1683},
+ dictWord{8, 0, 289},
+ dictWord{11, 0, 45},
+ dictWord{12, 0, 278},
+ dictWord{140, 0, 537},
+ dictWord{6, 11, 120},
+ dictWord{7, 11, 1188},
+ dictWord{7, 11, 1710},
+ dictWord{8, 11, 286},
+ dictWord{9, 11, 667},
+ dictWord{11, 11, 592},
+ dictWord{
+ 139,
+ 11,
+ 730,
+ },
+ dictWord{136, 10, 617},
+ dictWord{135, 0, 1120},
+ dictWord{135, 11, 1146},
+ dictWord{139, 10, 563},
+ dictWord{4, 11, 352},
+ dictWord{4, 10, 369},
+ dictWord{135, 11, 687},
+ dictWord{143, 11, 38},
+ dictWord{4, 0, 399},
+ dictWord{5, 0, 119},
+ dictWord{5, 0, 494},
+ dictWord{7, 0, 751},
+ dictWord{9, 0, 556},
+ dictWord{
+ 14,
+ 11,
+ 179,
+ },
+ dictWord{15, 11, 151},
+ dictWord{150, 11, 11},
+ dictWord{4, 11, 192},
+ dictWord{5, 11, 49},
+ dictWord{6, 11, 200},
+ dictWord{6, 11, 293},
+ dictWord{
+ 6,
+ 11,
+ 1696,
+ },
+ dictWord{135, 11, 488},
+ dictWord{4, 0, 398},
+ dictWord{133, 0, 660},
+ dictWord{7, 0, 1030},
+ dictWord{134, 10, 622},
+ dictWord{135, 11, 595},
+ dictWord{141, 0, 168},
+ dictWord{132, 11, 147},
+ dictWord{7, 0, 973},
+ dictWord{10, 10, 624},
+ dictWord{142, 10, 279},
+ dictWord{132, 10, 363},
+ dictWord{
+ 132,
+ 0,
+ 642,
+ },
+ dictWord{133, 11, 934},
+ dictWord{134, 0, 1615},
+ dictWord{7, 11, 505},
+ dictWord{135, 11, 523},
+ dictWord{7, 0, 594},
+ dictWord{7, 0, 851},
+ dictWord{
+ 7,
+ 0,
+ 1858,
+ },
+ dictWord{9, 0, 411},
+ dictWord{9, 0, 574},
+ dictWord{9, 0, 666},
+ dictWord{9, 0, 737},
+ dictWord{10, 0, 346},
+ dictWord{10, 0, 712},
+ dictWord{11, 0, 246},
+ dictWord{11, 0, 432},
+ dictWord{11, 0, 517},
+ dictWord{11, 0, 647},
+ dictWord{11, 0, 679},
+ dictWord{11, 0, 727},
+ dictWord{12, 0, 304},
+ dictWord{12, 0, 305},
+ dictWord{
+ 12,
+ 0,
+ 323,
+ },
+ dictWord{12, 0, 483},
+ dictWord{12, 0, 572},
+ dictWord{12, 0, 593},
+ dictWord{12, 0, 602},
+ dictWord{13, 0, 95},
+ dictWord{13, 0, 101},
+ dictWord{
+ 13,
+ 0,
+ 171,
+ },
+ dictWord{13, 0, 315},
+ dictWord{13, 0, 378},
+ dictWord{13, 0, 425},
+ dictWord{13, 0, 475},
+ dictWord{14, 0, 63},
+ dictWord{14, 0, 380},
+ dictWord{14, 0, 384},
+ dictWord{15, 0, 133},
+ dictWord{18, 0, 112},
+ dictWord{148, 0, 72},
+ dictWord{135, 0, 1093},
+ dictWord{132, 0, 679},
+ dictWord{8, 0, 913},
+ dictWord{10, 0, 903},
+ dictWord{10, 0, 915},
+ dictWord{12, 0, 648},
+ dictWord{12, 0, 649},
+ dictWord{14, 0, 455},
+ dictWord{16, 0, 112},
+ dictWord{138, 11, 438},
+ dictWord{137, 0, 203},
+ dictWord{134, 10, 292},
+ dictWord{134, 0, 1492},
+ dictWord{7, 0, 1374},
+ dictWord{8, 0, 540},
+ dictWord{5, 10, 177},
+ dictWord{6, 10, 616},
+ dictWord{7, 10, 827},
+ dictWord{9, 10, 525},
+ dictWord{138, 10, 656},
+ dictWord{135, 0, 1486},
+ dictWord{9, 0, 714},
+ dictWord{138, 10, 31},
+ dictWord{136, 0, 825},
+ dictWord{
+ 134,
+ 0,
+ 1511,
+ },
+ dictWord{132, 11, 637},
+ dictWord{134, 0, 952},
+ dictWord{4, 10, 161},
+ dictWord{133, 10, 631},
+ dictWord{5, 0, 143},
+ dictWord{5, 0, 769},
+ dictWord{
+ 6,
+ 0,
+ 1760,
+ },
+ dictWord{7, 0, 682},
+ dictWord{7, 0, 1992},
+ dictWord{136, 0, 736},
+ dictWord{132, 0, 700},
+ dictWord{134, 0, 1540},
+ dictWord{132, 11, 777},
+ dictWord{
+ 9,
+ 11,
+ 867,
+ },
+ dictWord{138, 11, 837},
+ dictWord{7, 0, 1557},
+ dictWord{135, 10, 1684},
+ dictWord{133, 0, 860},
+ dictWord{6, 0, 422},
+ dictWord{7, 0, 0},
+ dictWord{
+ 7,
+ 0,
+ 1544,
+ },
+ dictWord{9, 0, 605},
+ dictWord{11, 0, 990},
+ dictWord{12, 0, 235},
+ dictWord{12, 0, 453},
+ dictWord{13, 0, 47},
+ dictWord{13, 0, 266},
+ dictWord{9, 10, 469},
+ dictWord{9, 10, 709},
+ dictWord{12, 10, 512},
+ dictWord{14, 10, 65},
+ dictWord{145, 10, 12},
+ dictWord{11, 0, 807},
+ dictWord{10, 10, 229},
+ dictWord{11, 10, 73},
+ dictWord{139, 10, 376},
+ dictWord{6, 11, 170},
+ dictWord{7, 11, 1080},
+ dictWord{8, 11, 395},
+ dictWord{8, 11, 487},
+ dictWord{11, 11, 125},
+ dictWord{
+ 141,
+ 11,
+ 147,
+ },
+ dictWord{5, 0, 515},
+ dictWord{137, 0, 131},
+ dictWord{7, 0, 1605},
+ dictWord{11, 0, 962},
+ dictWord{146, 0, 139},
+ dictWord{132, 0, 646},
+ dictWord{
+ 4,
+ 0,
+ 396,
+ },
+ dictWord{7, 0, 728},
+ dictWord{9, 0, 117},
+ dictWord{13, 0, 202},
+ dictWord{148, 0, 51},
+ dictWord{6, 0, 121},
+ dictWord{6, 0, 124},
+ dictWord{6, 0, 357},
+ dictWord{
+ 7,
+ 0,
+ 1138,
+ },
+ dictWord{7, 0, 1295},
+ dictWord{8, 0, 162},
+ dictWord{8, 0, 508},
+ dictWord{11, 0, 655},
+ dictWord{4, 11, 535},
+ dictWord{6, 10, 558},
+ dictWord{
+ 7,
+ 10,
+ 651,
+ },
+ dictWord{8, 11, 618},
+ dictWord{9, 10, 0},
+ dictWord{10, 10, 34},
+ dictWord{139, 10, 1008},
+ dictWord{135, 11, 1245},
+ dictWord{138, 0, 357},
+ dictWord{
+ 150,
+ 11,
+ 23,
+ },
+ dictWord{133, 0, 237},
+ dictWord{135, 0, 1784},
+ dictWord{7, 10, 1832},
+ dictWord{138, 10, 374},
+ dictWord{132, 0, 713},
+ dictWord{132, 11, 46},
+ dictWord{6, 0, 1536},
+ dictWord{10, 0, 348},
+ dictWord{5, 11, 811},
+ dictWord{6, 11, 1679},
+ dictWord{6, 11, 1714},
+ dictWord{135, 11, 2032},
+ dictWord{
+ 11,
+ 11,
+ 182,
+ },
+ dictWord{142, 11, 195},
+ dictWord{6, 0, 523},
+ dictWord{7, 0, 738},
+ dictWord{7, 10, 771},
+ dictWord{7, 10, 1731},
+ dictWord{9, 10, 405},
+ dictWord{
+ 138,
+ 10,
+ 421,
+ },
+ dictWord{7, 11, 1458},
+ dictWord{9, 11, 407},
+ dictWord{139, 11, 15},
+ dictWord{6, 11, 34},
+ dictWord{7, 11, 69},
+ dictWord{7, 11, 640},
+ dictWord{
+ 7,
+ 11,
+ 1089,
+ },
+ dictWord{8, 11, 708},
+ dictWord{8, 11, 721},
+ dictWord{9, 11, 363},
+ dictWord{9, 11, 643},
+ dictWord{10, 11, 628},
+ dictWord{148, 11, 98},
+ dictWord{
+ 133,
+ 0,
+ 434,
+ },
+ dictWord{135, 0, 1877},
+ dictWord{7, 0, 571},
+ dictWord{138, 0, 366},
+ dictWord{5, 10, 881},
+ dictWord{133, 10, 885},
+ dictWord{9, 0, 513},
+ dictWord{
+ 10,
+ 0,
+ 25,
+ },
+ dictWord{10, 0, 39},
+ dictWord{12, 0, 122},
+ dictWord{140, 0, 187},
+ dictWord{132, 0, 580},
+ dictWord{5, 10, 142},
+ dictWord{134, 10, 546},
+ dictWord{
+ 132,
+ 11,
+ 462,
+ },
+ dictWord{137, 0, 873},
+ dictWord{5, 10, 466},
+ dictWord{11, 10, 571},
+ dictWord{12, 10, 198},
+ dictWord{13, 10, 283},
+ dictWord{14, 10, 186},
+ dictWord{15, 10, 21},
+ dictWord{143, 10, 103},
+ dictWord{7, 0, 171},
+ dictWord{4, 10, 185},
+ dictWord{5, 10, 257},
+ dictWord{5, 10, 839},
+ dictWord{5, 10, 936},
+ dictWord{
+ 9,
+ 10,
+ 399,
+ },
+ dictWord{10, 10, 258},
+ dictWord{10, 10, 395},
+ dictWord{10, 10, 734},
+ dictWord{11, 10, 1014},
+ dictWord{12, 10, 23},
+ dictWord{13, 10, 350},
+ dictWord{14, 10, 150},
+ dictWord{147, 10, 6},
+ dictWord{134, 0, 625},
+ dictWord{7, 0, 107},
+ dictWord{7, 0, 838},
+ dictWord{8, 0, 550},
+ dictWord{138, 0, 401},
+ dictWord{
+ 5,
+ 11,
+ 73,
+ },
+ dictWord{6, 11, 23},
+ dictWord{134, 11, 338},
+ dictWord{4, 0, 943},
+ dictWord{6, 0, 1850},
+ dictWord{12, 0, 713},
+ dictWord{142, 0, 434},
+ dictWord{
+ 11,
+ 0,
+ 588,
+ },
+ dictWord{11, 0, 864},
+ dictWord{11, 0, 936},
+ dictWord{11, 0, 968},
+ dictWord{12, 0, 73},
+ dictWord{12, 0, 343},
+ dictWord{12, 0, 394},
+ dictWord{13, 0, 275},
+ dictWord{14, 0, 257},
+ dictWord{15, 0, 160},
+ dictWord{7, 10, 404},
+ dictWord{7, 10, 1377},
+ dictWord{7, 10, 1430},
+ dictWord{7, 10, 2017},
+ dictWord{8, 10, 149},
+ dictWord{8, 10, 239},
+ dictWord{8, 10, 512},
+ dictWord{8, 10, 793},
+ dictWord{8, 10, 818},
+ dictWord{9, 10, 474},
+ dictWord{9, 10, 595},
+ dictWord{10, 10, 122},
+ dictWord{10, 10, 565},
+ dictWord{10, 10, 649},
+ dictWord{10, 10, 783},
+ dictWord{11, 10, 239},
+ dictWord{11, 10, 295},
+ dictWord{11, 10, 447},
+ dictWord{
+ 11,
+ 10,
+ 528,
+ },
+ dictWord{11, 10, 639},
+ dictWord{11, 10, 800},
+ dictWord{12, 10, 25},
+ dictWord{12, 10, 157},
+ dictWord{12, 10, 316},
+ dictWord{12, 10, 390},
+ dictWord{
+ 12,
+ 10,
+ 391,
+ },
+ dictWord{12, 10, 395},
+ dictWord{12, 10, 478},
+ dictWord{12, 10, 503},
+ dictWord{12, 10, 592},
+ dictWord{12, 10, 680},
+ dictWord{13, 10, 50},
+ dictWord{13, 10, 53},
+ dictWord{13, 10, 132},
+ dictWord{13, 10, 198},
+ dictWord{13, 10, 322},
+ dictWord{13, 10, 415},
+ dictWord{13, 10, 511},
+ dictWord{14, 10, 71},
+ dictWord{14, 10, 395},
+ dictWord{15, 10, 71},
+ dictWord{15, 10, 136},
+ dictWord{17, 10, 123},
+ dictWord{18, 10, 93},
+ dictWord{147, 10, 58},
+ dictWord{
+ 133,
+ 0,
+ 768,
+ },
+ dictWord{11, 0, 103},
+ dictWord{142, 0, 0},
+ dictWord{136, 10, 712},
+ dictWord{132, 0, 799},
+ dictWord{132, 0, 894},
+ dictWord{7, 11, 725},
+ dictWord{
+ 8,
+ 11,
+ 498,
+ },
+ dictWord{139, 11, 268},
+ dictWord{135, 11, 1798},
+ dictWord{135, 11, 773},
+ dictWord{141, 11, 360},
+ dictWord{4, 10, 377},
+ dictWord{152, 10, 13},
+ dictWord{135, 0, 1673},
+ dictWord{132, 11, 583},
+ dictWord{134, 0, 1052},
+ dictWord{133, 11, 220},
+ dictWord{140, 11, 69},
+ dictWord{132, 11, 544},
+ dictWord{
+ 4,
+ 10,
+ 180,
+ },
+ dictWord{135, 10, 1906},
+ dictWord{134, 0, 272},
+ dictWord{4, 0, 441},
+ dictWord{134, 0, 1421},
+ dictWord{4, 0, 9},
+ dictWord{5, 0, 128},
+ dictWord{
+ 7,
+ 0,
+ 368,
+ },
+ dictWord{11, 0, 480},
+ dictWord{148, 0, 3},
+ dictWord{5, 11, 176},
+ dictWord{6, 11, 437},
+ dictWord{6, 11, 564},
+ dictWord{11, 11, 181},
+ dictWord{
+ 141,
+ 11,
+ 183,
+ },
+ dictWord{132, 10, 491},
+ dictWord{7, 0, 1182},
+ dictWord{141, 11, 67},
+ dictWord{6, 0, 1346},
+ dictWord{4, 10, 171},
+ dictWord{138, 10, 234},
+ dictWord{
+ 4,
+ 10,
+ 586,
+ },
+ dictWord{7, 10, 1186},
+ dictWord{138, 10, 631},
+ dictWord{136, 0, 682},
+ dictWord{134, 0, 1004},
+ dictWord{15, 0, 24},
+ dictWord{143, 11, 24},
+ dictWord{134, 0, 968},
+ dictWord{4, 0, 2},
+ dictWord{6, 0, 742},
+ dictWord{6, 0, 793},
+ dictWord{7, 0, 545},
+ dictWord{7, 0, 894},
+ dictWord{9, 10, 931},
+ dictWord{
+ 10,
+ 10,
+ 334,
+ },
+ dictWord{148, 10, 71},
+ dictWord{136, 11, 600},
+ dictWord{133, 10, 765},
+ dictWord{9, 0, 769},
+ dictWord{140, 0, 185},
+ dictWord{4, 11, 790},
+ dictWord{
+ 5,
+ 11,
+ 273,
+ },
+ dictWord{134, 11, 394},
+ dictWord{7, 0, 474},
+ dictWord{137, 0, 578},
+ dictWord{4, 11, 135},
+ dictWord{6, 11, 127},
+ dictWord{7, 11, 1185},
+ dictWord{
+ 7,
+ 11,
+ 1511,
+ },
+ dictWord{8, 11, 613},
+ dictWord{11, 11, 5},
+ dictWord{12, 11, 133},
+ dictWord{12, 11, 495},
+ dictWord{12, 11, 586},
+ dictWord{14, 11, 385},
+ dictWord{15, 11, 118},
+ dictWord{17, 11, 20},
+ dictWord{146, 11, 98},
+ dictWord{133, 10, 424},
+ dictWord{5, 0, 530},
+ dictWord{142, 0, 113},
+ dictWord{6, 11, 230},
+ dictWord{7, 11, 961},
+ dictWord{7, 11, 1085},
+ dictWord{136, 11, 462},
+ dictWord{7, 11, 1954},
+ dictWord{137, 11, 636},
+ dictWord{136, 10, 714},
+ dictWord{
+ 149,
+ 11,
+ 6,
+ },
+ dictWord{135, 10, 685},
+ dictWord{9, 10, 420},
+ dictWord{10, 10, 269},
+ dictWord{10, 10, 285},
+ dictWord{10, 10, 576},
+ dictWord{11, 10, 397},
+ dictWord{13, 10, 175},
+ dictWord{145, 10, 90},
+ dictWord{132, 10, 429},
+ dictWord{5, 0, 556},
+ dictWord{5, 11, 162},
+ dictWord{136, 11, 68},
+ dictWord{132, 11, 654},
+ dictWord{4, 11, 156},
+ dictWord{7, 11, 998},
+ dictWord{7, 11, 1045},
+ dictWord{7, 11, 1860},
+ dictWord{9, 11, 48},
+ dictWord{9, 11, 692},
+ dictWord{11, 11, 419},
+ dictWord{139, 11, 602},
+ dictWord{6, 0, 1317},
+ dictWord{8, 0, 16},
+ dictWord{9, 0, 825},
+ dictWord{12, 0, 568},
+ dictWord{7, 11, 1276},
+ dictWord{8, 11, 474},
+ dictWord{137, 11, 652},
+ dictWord{18, 0, 97},
+ dictWord{7, 10, 18},
+ dictWord{7, 10, 699},
+ dictWord{7, 10, 1966},
+ dictWord{8, 10, 752},
+ dictWord{9, 10, 273},
+ dictWord{
+ 9,
+ 10,
+ 412,
+ },
+ dictWord{9, 10, 703},
+ dictWord{10, 10, 71},
+ dictWord{10, 10, 427},
+ dictWord{138, 10, 508},
+ dictWord{10, 0, 703},
+ dictWord{7, 11, 1454},
+ dictWord{138, 11, 703},
+ dictWord{4, 10, 53},
+ dictWord{5, 10, 186},
+ dictWord{135, 10, 752},
+ dictWord{134, 0, 892},
+ dictWord{134, 0, 1571},
+ dictWord{8, 10, 575},
+ dictWord{10, 10, 289},
+ dictWord{139, 10, 319},
+ dictWord{6, 0, 186},
+ dictWord{137, 0, 426},
+ dictWord{134, 0, 1101},
+ dictWord{132, 10, 675},
+ dictWord{
+ 132,
+ 0,
+ 585,
+ },
+ dictWord{6, 0, 1870},
+ dictWord{137, 0, 937},
+ dictWord{152, 11, 10},
+ dictWord{9, 11, 197},
+ dictWord{10, 11, 300},
+ dictWord{12, 11, 473},
+ dictWord{
+ 13,
+ 11,
+ 90,
+ },
+ dictWord{141, 11, 405},
+ dictWord{4, 0, 93},
+ dictWord{5, 0, 252},
+ dictWord{6, 0, 229},
+ dictWord{7, 0, 291},
+ dictWord{9, 0, 550},
+ dictWord{139, 0, 644},
+ dictWord{137, 0, 749},
+ dictWord{9, 0, 162},
+ dictWord{6, 10, 209},
+ dictWord{8, 10, 468},
+ dictWord{9, 10, 210},
+ dictWord{11, 10, 36},
+ dictWord{12, 10, 28},
+ dictWord{12, 10, 630},
+ dictWord{13, 10, 21},
+ dictWord{13, 10, 349},
+ dictWord{14, 10, 7},
+ dictWord{145, 10, 13},
+ dictWord{132, 0, 381},
+ dictWord{132, 11, 606},
+ dictWord{4, 10, 342},
+ dictWord{135, 10, 1179},
+ dictWord{7, 11, 1587},
+ dictWord{7, 11, 1707},
+ dictWord{10, 11, 528},
+ dictWord{139, 11, 504},
+ dictWord{
+ 12,
+ 11,
+ 39,
+ },
+ dictWord{13, 11, 265},
+ dictWord{141, 11, 439},
+ dictWord{4, 10, 928},
+ dictWord{133, 10, 910},
+ dictWord{7, 10, 1838},
+ dictWord{7, 11, 1978},
+ dictWord{136, 11, 676},
+ dictWord{6, 0, 762},
+ dictWord{6, 0, 796},
+ dictWord{134, 0, 956},
+ dictWord{4, 10, 318},
+ dictWord{4, 10, 496},
+ dictWord{7, 10, 856},
+ dictWord{139, 10, 654},
+ dictWord{137, 11, 242},
+ dictWord{4, 11, 361},
+ dictWord{133, 11, 315},
+ dictWord{132, 11, 461},
+ dictWord{132, 11, 472},
+ dictWord{
+ 132,
+ 0,
+ 857,
+ },
+ dictWord{5, 0, 21},
+ dictWord{6, 0, 77},
+ dictWord{6, 0, 157},
+ dictWord{7, 0, 974},
+ dictWord{7, 0, 1301},
+ dictWord{7, 0, 1339},
+ dictWord{7, 0, 1490},
+ dictWord{
+ 7,
+ 0,
+ 1873,
+ },
+ dictWord{9, 0, 628},
+ dictWord{7, 10, 915},
+ dictWord{8, 10, 247},
+ dictWord{147, 10, 0},
+ dictWord{4, 10, 202},
+ dictWord{5, 10, 382},
+ dictWord{
+ 6,
+ 10,
+ 454,
+ },
+ dictWord{7, 10, 936},
+ dictWord{7, 10, 1803},
+ dictWord{8, 10, 758},
+ dictWord{9, 10, 375},
+ dictWord{9, 10, 895},
+ dictWord{10, 10, 743},
+ dictWord{
+ 10,
+ 10,
+ 792,
+ },
+ dictWord{11, 10, 978},
+ dictWord{11, 10, 1012},
+ dictWord{142, 10, 109},
+ dictWord{7, 11, 617},
+ dictWord{10, 11, 498},
+ dictWord{11, 11, 501},
+ dictWord{12, 11, 16},
+ dictWord{140, 11, 150},
+ dictWord{7, 10, 1150},
+ dictWord{7, 10, 1425},
+ dictWord{7, 10, 1453},
+ dictWord{10, 11, 747},
+ dictWord{
+ 140,
+ 10,
+ 513,
+ },
+ dictWord{133, 11, 155},
+ dictWord{11, 0, 919},
+ dictWord{141, 0, 409},
+ dictWord{138, 10, 791},
+ dictWord{10, 0, 633},
+ dictWord{139, 11, 729},
+ dictWord{
+ 7,
+ 11,
+ 163,
+ },
+ dictWord{8, 11, 319},
+ dictWord{9, 11, 402},
+ dictWord{10, 11, 24},
+ dictWord{10, 11, 681},
+ dictWord{11, 11, 200},
+ dictWord{11, 11, 567},
+ dictWord{12, 11, 253},
+ dictWord{12, 11, 410},
+ dictWord{142, 11, 219},
+ dictWord{5, 11, 475},
+ dictWord{7, 11, 1780},
+ dictWord{9, 11, 230},
+ dictWord{11, 11, 297},
+ dictWord{11, 11, 558},
+ dictWord{14, 11, 322},
+ dictWord{147, 11, 76},
+ dictWord{7, 0, 332},
+ dictWord{6, 10, 445},
+ dictWord{137, 10, 909},
+ dictWord{
+ 135,
+ 11,
+ 1956,
+ },
+ dictWord{136, 11, 274},
+ dictWord{134, 10, 578},
+ dictWord{135, 0, 1489},
+ dictWord{135, 11, 1848},
+ dictWord{5, 11, 944},
+ dictWord{
+ 134,
+ 11,
+ 1769,
+ },
+ dictWord{132, 11, 144},
+ dictWord{136, 10, 766},
+ dictWord{4, 0, 832},
+ dictWord{135, 10, 541},
+ dictWord{8, 0, 398},
+ dictWord{9, 0, 681},
+ dictWord{
+ 139,
+ 0,
+ 632,
+ },
+ dictWord{136, 0, 645},
+ dictWord{9, 0, 791},
+ dictWord{10, 0, 93},
+ dictWord{16, 0, 13},
+ dictWord{17, 0, 23},
+ dictWord{18, 0, 135},
+ dictWord{19, 0, 12},
+ dictWord{20, 0, 1},
+ dictWord{20, 0, 12},
+ dictWord{148, 0, 14},
+ dictWord{6, 11, 247},
+ dictWord{137, 11, 555},
+ dictWord{134, 0, 20},
+ dictWord{132, 0, 800},
+ dictWord{135, 0, 1841},
+ dictWord{139, 10, 983},
+ dictWord{137, 10, 768},
+ dictWord{132, 10, 584},
+ dictWord{141, 11, 51},
+ dictWord{6, 0, 1993},
+ dictWord{
+ 4,
+ 11,
+ 620,
+ },
+ dictWord{138, 11, 280},
+ dictWord{136, 0, 769},
+ dictWord{11, 0, 290},
+ dictWord{11, 0, 665},
+ dictWord{7, 11, 1810},
+ dictWord{11, 11, 866},
+ dictWord{
+ 12,
+ 11,
+ 103,
+ },
+ dictWord{13, 11, 495},
+ dictWord{17, 11, 67},
+ dictWord{147, 11, 74},
+ dictWord{134, 0, 1426},
+ dictWord{139, 0, 60},
+ dictWord{4, 10, 326},
+ dictWord{135, 10, 1770},
+ dictWord{7, 0, 1874},
+ dictWord{9, 0, 641},
+ dictWord{132, 10, 226},
+ dictWord{6, 0, 644},
+ dictWord{5, 10, 426},
+ dictWord{8, 10, 30},
+ dictWord{
+ 9,
+ 10,
+ 2,
+ },
+ dictWord{11, 10, 549},
+ dictWord{147, 10, 122},
+ dictWord{5, 11, 428},
+ dictWord{138, 11, 442},
+ dictWord{135, 11, 1871},
+ dictWord{
+ 135,
+ 0,
+ 1757,
+ },
+ dictWord{147, 10, 117},
+ dictWord{135, 0, 937},
+ dictWord{135, 0, 1652},
+ dictWord{6, 0, 654},
+ dictWord{134, 0, 1476},
+ dictWord{133, 11, 99},
+ dictWord{135, 0, 527},
+ dictWord{132, 10, 345},
+ dictWord{4, 10, 385},
+ dictWord{4, 11, 397},
+ dictWord{7, 10, 265},
+ dictWord{135, 10, 587},
+ dictWord{4, 0, 579},
+ dictWord{5, 0, 226},
+ dictWord{5, 0, 323},
+ dictWord{135, 0, 960},
+ dictWord{134, 0, 1486},
+ dictWord{8, 11, 502},
+ dictWord{144, 11, 9},
+ dictWord{4, 10, 347},
+ dictWord{
+ 5,
+ 10,
+ 423,
+ },
+ dictWord{5, 10, 996},
+ dictWord{135, 10, 1329},
+ dictWord{7, 11, 727},
+ dictWord{146, 11, 73},
+ dictWord{4, 11, 485},
+ dictWord{7, 11, 353},
+ dictWord{7, 10, 1259},
+ dictWord{7, 11, 1523},
+ dictWord{9, 10, 125},
+ dictWord{139, 10, 65},
+ dictWord{6, 0, 325},
+ dictWord{5, 10, 136},
+ dictWord{6, 11, 366},
+ dictWord{
+ 7,
+ 11,
+ 1384,
+ },
+ dictWord{7, 11, 1601},
+ dictWord{136, 10, 644},
+ dictWord{138, 11, 160},
+ dictWord{6, 0, 1345},
+ dictWord{137, 11, 282},
+ dictWord{18, 0, 91},
+ dictWord{147, 0, 70},
+ dictWord{136, 0, 404},
+ dictWord{4, 11, 157},
+ dictWord{133, 11, 471},
+ dictWord{133, 0, 973},
+ dictWord{6, 0, 135},
+ dictWord{
+ 135,
+ 0,
+ 1176,
+ },
+ dictWord{8, 11, 116},
+ dictWord{11, 11, 551},
+ dictWord{142, 11, 159},
+ dictWord{4, 0, 549},
+ dictWord{4, 10, 433},
+ dictWord{133, 10, 719},
+ dictWord{
+ 136,
+ 0,
+ 976,
+ },
+ dictWord{5, 11, 160},
+ dictWord{7, 11, 363},
+ dictWord{7, 11, 589},
+ dictWord{10, 11, 170},
+ dictWord{141, 11, 55},
+ dictWord{144, 0, 21},
+ dictWord{
+ 144,
+ 0,
+ 51,
+ },
+ dictWord{135, 0, 314},
+ dictWord{135, 10, 1363},
+ dictWord{4, 11, 108},
+ dictWord{7, 11, 405},
+ dictWord{10, 11, 491},
+ dictWord{139, 11, 498},
+ dictWord{146, 0, 4},
+ dictWord{4, 10, 555},
+ dictWord{8, 10, 536},
+ dictWord{10, 10, 288},
+ dictWord{139, 10, 1005},
+ dictWord{135, 11, 1005},
+ dictWord{6, 0, 281},
+ dictWord{7, 0, 6},
+ dictWord{8, 0, 282},
+ dictWord{8, 0, 480},
+ dictWord{8, 0, 499},
+ dictWord{9, 0, 198},
+ dictWord{10, 0, 143},
+ dictWord{10, 0, 169},
+ dictWord{
+ 10,
+ 0,
+ 211,
+ },
+ dictWord{10, 0, 417},
+ dictWord{10, 0, 574},
+ dictWord{11, 0, 147},
+ dictWord{11, 0, 395},
+ dictWord{12, 0, 75},
+ dictWord{12, 0, 407},
+ dictWord{12, 0, 608},
+ dictWord{13, 0, 500},
+ dictWord{142, 0, 251},
+ dictWord{6, 0, 1093},
+ dictWord{6, 0, 1405},
+ dictWord{9, 10, 370},
+ dictWord{138, 10, 90},
+ dictWord{4, 11, 926},
+ dictWord{133, 11, 983},
+ dictWord{135, 0, 1776},
+ dictWord{134, 0, 1528},
+ dictWord{132, 0, 419},
+ dictWord{132, 11, 538},
+ dictWord{6, 11, 294},
+ dictWord{
+ 7,
+ 11,
+ 1267,
+ },
+ dictWord{136, 11, 624},
+ dictWord{135, 11, 1772},
+ dictWord{138, 11, 301},
+ dictWord{4, 10, 257},
+ dictWord{135, 10, 2031},
+ dictWord{4, 0, 138},
+ dictWord{7, 0, 1012},
+ dictWord{7, 0, 1280},
+ dictWord{9, 0, 76},
+ dictWord{135, 10, 1768},
+ dictWord{132, 11, 757},
+ dictWord{5, 0, 29},
+ dictWord{140, 0, 638},
+ dictWord{7, 11, 655},
+ dictWord{135, 11, 1844},
+ dictWord{7, 0, 1418},
+ dictWord{6, 11, 257},
+ dictWord{135, 11, 1522},
+ dictWord{8, 11, 469},
+ dictWord{
+ 138,
+ 11,
+ 47,
+ },
+ dictWord{142, 11, 278},
+ dictWord{6, 10, 83},
+ dictWord{6, 10, 1733},
+ dictWord{135, 10, 1389},
+ dictWord{11, 11, 204},
+ dictWord{11, 11, 243},
+ dictWord{140, 11, 293},
+ dictWord{135, 11, 1875},
+ dictWord{6, 0, 1710},
+ dictWord{135, 0, 2038},
+ dictWord{137, 11, 299},
+ dictWord{4, 0, 17},
+ dictWord{5, 0, 23},
+ dictWord{7, 0, 995},
+ dictWord{11, 0, 383},
+ dictWord{11, 0, 437},
+ dictWord{12, 0, 460},
+ dictWord{140, 0, 532},
+ dictWord{133, 0, 862},
+ dictWord{137, 10, 696},
+ dictWord{6, 0, 592},
+ dictWord{138, 0, 946},
+ dictWord{138, 11, 599},
+ dictWord{7, 10, 1718},
+ dictWord{9, 10, 95},
+ dictWord{9, 10, 274},
+ dictWord{10, 10, 279},
+ dictWord{10, 10, 317},
+ dictWord{10, 10, 420},
+ dictWord{11, 10, 303},
+ dictWord{11, 10, 808},
+ dictWord{12, 10, 134},
+ dictWord{12, 10, 367},
+ dictWord{
+ 13,
+ 10,
+ 149,
+ },
+ dictWord{13, 10, 347},
+ dictWord{14, 10, 349},
+ dictWord{14, 10, 406},
+ dictWord{18, 10, 22},
+ dictWord{18, 10, 89},
+ dictWord{18, 10, 122},
+ dictWord{
+ 147,
+ 10,
+ 47,
+ },
+ dictWord{8, 0, 70},
+ dictWord{12, 0, 171},
+ dictWord{141, 0, 272},
+ dictWord{133, 10, 26},
+ dictWord{132, 10, 550},
+ dictWord{137, 0, 812},
+ dictWord{
+ 10,
+ 0,
+ 233,
+ },
+ dictWord{139, 0, 76},
+ dictWord{134, 0, 988},
+ dictWord{134, 0, 442},
+ dictWord{136, 10, 822},
+ dictWord{7, 0, 896},
+ dictWord{4, 10, 902},
+ dictWord{
+ 5,
+ 10,
+ 809,
+ },
+ dictWord{134, 10, 122},
+ dictWord{5, 11, 150},
+ dictWord{7, 11, 106},
+ dictWord{8, 11, 603},
+ dictWord{9, 11, 593},
+ dictWord{9, 11, 634},
+ dictWord{
+ 10,
+ 11,
+ 44,
+ },
+ dictWord{10, 11, 173},
+ dictWord{11, 11, 462},
+ dictWord{11, 11, 515},
+ dictWord{13, 11, 216},
+ dictWord{13, 11, 288},
+ dictWord{142, 11, 400},
+ dictWord{136, 0, 483},
+ dictWord{135, 10, 262},
+ dictWord{6, 0, 1709},
+ dictWord{133, 10, 620},
+ dictWord{4, 10, 34},
+ dictWord{5, 10, 574},
+ dictWord{7, 10, 279},
+ dictWord{7, 10, 1624},
+ dictWord{136, 10, 601},
+ dictWord{137, 10, 170},
+ dictWord{147, 0, 119},
+ dictWord{12, 11, 108},
+ dictWord{141, 11, 291},
+ dictWord{
+ 11,
+ 0,
+ 69,
+ },
+ dictWord{12, 0, 105},
+ dictWord{12, 0, 117},
+ dictWord{13, 0, 213},
+ dictWord{14, 0, 13},
+ dictWord{14, 0, 62},
+ dictWord{14, 0, 177},
+ dictWord{14, 0, 421},
+ dictWord{15, 0, 19},
+ dictWord{146, 0, 141},
+ dictWord{137, 0, 309},
+ dictWord{11, 11, 278},
+ dictWord{142, 11, 73},
+ dictWord{7, 0, 608},
+ dictWord{7, 0, 976},
+ dictWord{9, 0, 146},
+ dictWord{10, 0, 206},
+ dictWord{10, 0, 596},
+ dictWord{13, 0, 218},
+ dictWord{142, 0, 153},
+ dictWord{133, 10, 332},
+ dictWord{6, 10, 261},
+ dictWord{
+ 8,
+ 10,
+ 182,
+ },
+ dictWord{139, 10, 943},
+ dictWord{4, 11, 493},
+ dictWord{144, 11, 55},
+ dictWord{134, 10, 1721},
+ dictWord{132, 0, 768},
+ dictWord{4, 10, 933},
+ dictWord{133, 10, 880},
+ dictWord{7, 11, 555},
+ dictWord{7, 11, 1316},
+ dictWord{7, 11, 1412},
+ dictWord{7, 11, 1839},
+ dictWord{9, 11, 192},
+ dictWord{
+ 9,
+ 11,
+ 589,
+ },
+ dictWord{11, 11, 241},
+ dictWord{11, 11, 676},
+ dictWord{11, 11, 811},
+ dictWord{11, 11, 891},
+ dictWord{12, 11, 140},
+ dictWord{12, 11, 346},
+ dictWord{
+ 12,
+ 11,
+ 479,
+ },
+ dictWord{13, 11, 30},
+ dictWord{13, 11, 49},
+ dictWord{13, 11, 381},
+ dictWord{14, 11, 188},
+ dictWord{15, 11, 150},
+ dictWord{16, 11, 76},
+ dictWord{18, 11, 30},
+ dictWord{148, 11, 52},
+ dictWord{4, 0, 518},
+ dictWord{135, 0, 1136},
+ dictWord{6, 11, 568},
+ dictWord{7, 11, 112},
+ dictWord{7, 11, 1804},
+ dictWord{8, 11, 362},
+ dictWord{8, 11, 410},
+ dictWord{8, 11, 830},
+ dictWord{9, 11, 514},
+ dictWord{11, 11, 649},
+ dictWord{142, 11, 157},
+ dictWord{135, 11, 673},
+ dictWord{8, 0, 689},
+ dictWord{137, 0, 863},
+ dictWord{4, 0, 18},
+ dictWord{7, 0, 145},
+ dictWord{7, 0, 444},
+ dictWord{7, 0, 1278},
+ dictWord{8, 0, 49},
+ dictWord{8, 0, 400},
+ dictWord{9, 0, 71},
+ dictWord{9, 0, 250},
+ dictWord{10, 0, 459},
+ dictWord{12, 0, 160},
+ dictWord{16, 0, 24},
+ dictWord{132, 11, 625},
+ dictWord{140, 0, 1020},
+ dictWord{4, 0, 997},
+ dictWord{6, 0, 1946},
+ dictWord{6, 0, 1984},
+ dictWord{134, 0, 1998},
+ dictWord{6, 11, 16},
+ dictWord{6, 11, 158},
+ dictWord{7, 11, 43},
+ dictWord{
+ 7,
+ 11,
+ 129,
+ },
+ dictWord{7, 11, 181},
+ dictWord{8, 11, 276},
+ dictWord{8, 11, 377},
+ dictWord{10, 11, 523},
+ dictWord{11, 11, 816},
+ dictWord{12, 11, 455},
+ dictWord{
+ 13,
+ 11,
+ 303,
+ },
+ dictWord{142, 11, 135},
+ dictWord{133, 10, 812},
+ dictWord{134, 0, 658},
+ dictWord{4, 11, 1},
+ dictWord{7, 11, 1143},
+ dictWord{7, 11, 1463},
+ dictWord{8, 11, 61},
+ dictWord{9, 11, 207},
+ dictWord{9, 11, 390},
+ dictWord{9, 11, 467},
+ dictWord{139, 11, 836},
+ dictWord{150, 11, 26},
+ dictWord{140, 0, 106},
+ dictWord{6, 0, 1827},
+ dictWord{10, 0, 931},
+ dictWord{18, 0, 166},
+ dictWord{20, 0, 114},
+ dictWord{4, 10, 137},
+ dictWord{7, 10, 1178},
+ dictWord{7, 11, 1319},
+ dictWord{135, 10, 1520},
+ dictWord{133, 0, 1010},
+ dictWord{4, 11, 723},
+ dictWord{5, 11, 895},
+ dictWord{7, 11, 1031},
+ dictWord{8, 11, 199},
+ dictWord{8, 11, 340},
+ dictWord{9, 11, 153},
+ dictWord{9, 11, 215},
+ dictWord{10, 11, 21},
+ dictWord{10, 11, 59},
+ dictWord{10, 11, 80},
+ dictWord{10, 11, 224},
+ dictWord{11, 11, 229},
+ dictWord{11, 11, 652},
+ dictWord{12, 11, 192},
+ dictWord{13, 11, 146},
+ dictWord{142, 11, 91},
+ dictWord{132, 11, 295},
+ dictWord{6, 11, 619},
+ dictWord{
+ 7,
+ 11,
+ 898,
+ },
+ dictWord{7, 11, 1092},
+ dictWord{8, 11, 485},
+ dictWord{18, 11, 28},
+ dictWord{147, 11, 116},
+ dictWord{137, 11, 51},
+ dictWord{6, 10, 1661},
+ dictWord{
+ 7,
+ 10,
+ 1975,
+ },
+ dictWord{7, 10, 2009},
+ dictWord{135, 10, 2011},
+ dictWord{5, 11, 309},
+ dictWord{140, 11, 211},
+ dictWord{5, 0, 87},
+ dictWord{7, 0, 313},
+ dictWord{
+ 7,
+ 0,
+ 1103,
+ },
+ dictWord{10, 0, 208},
+ dictWord{10, 0, 582},
+ dictWord{11, 0, 389},
+ dictWord{11, 0, 813},
+ dictWord{12, 0, 385},
+ dictWord{13, 0, 286},
+ dictWord{
+ 14,
+ 0,
+ 124,
+ },
+ dictWord{146, 0, 108},
+ dictWord{5, 11, 125},
+ dictWord{8, 11, 77},
+ dictWord{138, 11, 15},
+ dictWord{132, 0, 267},
+ dictWord{133, 0, 703},
+ dictWord{
+ 137,
+ 11,
+ 155,
+ },
+ dictWord{133, 11, 439},
+ dictWord{11, 11, 164},
+ dictWord{140, 11, 76},
+ dictWord{9, 0, 496},
+ dictWord{5, 10, 89},
+ dictWord{7, 10, 1915},
+ dictWord{
+ 9,
+ 10,
+ 185,
+ },
+ dictWord{9, 10, 235},
+ dictWord{10, 10, 64},
+ dictWord{10, 10, 270},
+ dictWord{10, 10, 403},
+ dictWord{10, 10, 469},
+ dictWord{10, 10, 529},
+ dictWord{10, 10, 590},
+ dictWord{11, 10, 140},
+ dictWord{11, 10, 860},
+ dictWord{13, 10, 1},
+ dictWord{13, 10, 422},
+ dictWord{14, 10, 341},
+ dictWord{14, 10, 364},
+ dictWord{17, 10, 93},
+ dictWord{18, 10, 113},
+ dictWord{19, 10, 97},
+ dictWord{147, 10, 113},
+ dictWord{133, 10, 695},
+ dictWord{135, 0, 1121},
+ dictWord{
+ 5,
+ 10,
+ 6,
+ },
+ dictWord{6, 10, 183},
+ dictWord{7, 10, 680},
+ dictWord{7, 10, 978},
+ dictWord{7, 10, 1013},
+ dictWord{7, 10, 1055},
+ dictWord{12, 10, 230},
+ dictWord{
+ 13,
+ 10,
+ 172,
+ },
+ dictWord{146, 10, 29},
+ dictWord{4, 11, 8},
+ dictWord{7, 11, 1152},
+ dictWord{7, 11, 1153},
+ dictWord{7, 11, 1715},
+ dictWord{9, 11, 374},
+ dictWord{
+ 10,
+ 11,
+ 478,
+ },
+ dictWord{139, 11, 648},
+ dictWord{135, 11, 1099},
+ dictWord{6, 10, 29},
+ dictWord{139, 10, 63},
+ dictWord{4, 0, 561},
+ dictWord{10, 0, 249},
+ dictWord{
+ 139,
+ 0,
+ 209,
+ },
+ dictWord{132, 0, 760},
+ dictWord{7, 11, 799},
+ dictWord{138, 11, 511},
+ dictWord{136, 11, 87},
+ dictWord{9, 0, 154},
+ dictWord{140, 0, 485},
+ dictWord{136, 0, 255},
+ dictWord{132, 0, 323},
+ dictWord{140, 0, 419},
+ dictWord{132, 10, 311},
+ dictWord{134, 10, 1740},
+ dictWord{4, 0, 368},
+ dictWord{
+ 135,
+ 0,
+ 641,
+ },
+ dictWord{7, 10, 170},
+ dictWord{8, 10, 90},
+ dictWord{8, 10, 177},
+ dictWord{8, 10, 415},
+ dictWord{11, 10, 714},
+ dictWord{142, 10, 281},
+ dictWord{
+ 4,
+ 11,
+ 69,
+ },
+ dictWord{5, 11, 122},
+ dictWord{9, 11, 656},
+ dictWord{138, 11, 464},
+ dictWord{5, 11, 849},
+ dictWord{134, 11, 1633},
+ dictWord{8, 0, 522},
+ dictWord{
+ 142,
+ 0,
+ 328,
+ },
+ dictWord{11, 10, 91},
+ dictWord{13, 10, 129},
+ dictWord{15, 10, 101},
+ dictWord{145, 10, 125},
+ dictWord{7, 0, 562},
+ dictWord{8, 0, 551},
+ dictWord{
+ 4,
+ 10,
+ 494,
+ },
+ dictWord{6, 10, 74},
+ dictWord{7, 10, 44},
+ dictWord{11, 11, 499},
+ dictWord{12, 10, 17},
+ dictWord{15, 10, 5},
+ dictWord{148, 10, 11},
+ dictWord{4, 10, 276},
+ dictWord{133, 10, 296},
+ dictWord{9, 0, 92},
+ dictWord{147, 0, 91},
+ dictWord{4, 10, 7},
+ dictWord{5, 10, 90},
+ dictWord{5, 10, 158},
+ dictWord{6, 10, 542},
+ dictWord{
+ 7,
+ 10,
+ 221,
+ },
+ dictWord{7, 10, 1574},
+ dictWord{9, 10, 490},
+ dictWord{10, 10, 540},
+ dictWord{11, 10, 443},
+ dictWord{139, 10, 757},
+ dictWord{6, 0, 525},
+ dictWord{
+ 6,
+ 0,
+ 1976,
+ },
+ dictWord{8, 0, 806},
+ dictWord{9, 0, 876},
+ dictWord{140, 0, 284},
+ dictWord{5, 11, 859},
+ dictWord{7, 10, 588},
+ dictWord{7, 11, 1160},
+ dictWord{
+ 8,
+ 11,
+ 107,
+ },
+ dictWord{9, 10, 175},
+ dictWord{9, 11, 291},
+ dictWord{9, 11, 439},
+ dictWord{10, 10, 530},
+ dictWord{10, 11, 663},
+ dictWord{11, 11, 609},
+ dictWord{
+ 140,
+ 11,
+ 197,
+ },
+ dictWord{7, 11, 168},
+ dictWord{13, 11, 196},
+ dictWord{141, 11, 237},
+ dictWord{139, 0, 958},
+ dictWord{133, 0, 594},
+ dictWord{135, 10, 580},
+ dictWord{7, 10, 88},
+ dictWord{136, 10, 627},
+ dictWord{6, 0, 479},
+ dictWord{6, 0, 562},
+ dictWord{7, 0, 1060},
+ dictWord{13, 0, 6},
+ dictWord{5, 10, 872},
+ dictWord{
+ 6,
+ 10,
+ 57,
+ },
+ dictWord{7, 10, 471},
+ dictWord{9, 10, 447},
+ dictWord{137, 10, 454},
+ dictWord{136, 11, 413},
+ dictWord{145, 11, 19},
+ dictWord{4, 11, 117},
+ dictWord{
+ 6,
+ 11,
+ 372,
+ },
+ dictWord{7, 11, 1905},
+ dictWord{142, 11, 323},
+ dictWord{4, 11, 722},
+ dictWord{139, 11, 471},
+ dictWord{17, 0, 61},
+ dictWord{5, 10, 31},
+ dictWord{134, 10, 614},
+ dictWord{8, 10, 330},
+ dictWord{140, 10, 477},
+ dictWord{7, 10, 1200},
+ dictWord{138, 10, 460},
+ dictWord{6, 10, 424},
+ dictWord{
+ 135,
+ 10,
+ 1866,
+ },
+ dictWord{6, 0, 1641},
+ dictWord{136, 0, 820},
+ dictWord{6, 0, 1556},
+ dictWord{134, 0, 1618},
+ dictWord{9, 11, 5},
+ dictWord{12, 11, 216},
+ dictWord{
+ 12,
+ 11,
+ 294,
+ },
+ dictWord{12, 11, 298},
+ dictWord{12, 11, 400},
+ dictWord{12, 11, 518},
+ dictWord{13, 11, 229},
+ dictWord{143, 11, 139},
+ dictWord{15, 11, 155},
+ dictWord{144, 11, 79},
+ dictWord{4, 0, 302},
+ dictWord{135, 0, 1766},
+ dictWord{5, 10, 13},
+ dictWord{134, 10, 142},
+ dictWord{6, 0, 148},
+ dictWord{7, 0, 1313},
+ dictWord{
+ 7,
+ 10,
+ 116,
+ },
+ dictWord{8, 10, 322},
+ dictWord{8, 10, 755},
+ dictWord{9, 10, 548},
+ dictWord{10, 10, 714},
+ dictWord{11, 10, 884},
+ dictWord{141, 10, 324},
+ dictWord{137, 0, 676},
+ dictWord{9, 11, 88},
+ dictWord{139, 11, 270},
+ dictWord{5, 11, 12},
+ dictWord{7, 11, 375},
+ dictWord{137, 11, 438},
+ dictWord{134, 0, 1674},
+ dictWord{7, 10, 1472},
+ dictWord{135, 10, 1554},
+ dictWord{11, 0, 178},
+ dictWord{7, 10, 1071},
+ dictWord{7, 10, 1541},
+ dictWord{7, 10, 1767},
+ dictWord{
+ 7,
+ 10,
+ 1806,
+ },
+ dictWord{11, 10, 162},
+ dictWord{11, 10, 242},
+ dictWord{12, 10, 605},
+ dictWord{15, 10, 26},
+ dictWord{144, 10, 44},
+ dictWord{6, 0, 389},
+ dictWord{
+ 7,
+ 0,
+ 149,
+ },
+ dictWord{9, 0, 142},
+ dictWord{138, 0, 94},
+ dictWord{140, 11, 71},
+ dictWord{145, 10, 115},
+ dictWord{6, 0, 8},
+ dictWord{7, 0, 1881},
+ dictWord{8, 0, 91},
+ dictWord{11, 11, 966},
+ dictWord{12, 11, 287},
+ dictWord{13, 11, 342},
+ dictWord{13, 11, 402},
+ dictWord{15, 11, 110},
+ dictWord{143, 11, 163},
+ dictWord{
+ 4,
+ 11,
+ 258,
+ },
+ dictWord{136, 11, 639},
+ dictWord{6, 11, 22},
+ dictWord{7, 11, 903},
+ dictWord{138, 11, 577},
+ dictWord{133, 11, 681},
+ dictWord{135, 10, 1111},
+ dictWord{135, 11, 1286},
+ dictWord{9, 0, 112},
+ dictWord{8, 10, 1},
+ dictWord{138, 10, 326},
+ dictWord{5, 10, 488},
+ dictWord{6, 10, 527},
+ dictWord{7, 10, 489},
+ dictWord{
+ 7,
+ 10,
+ 1636,
+ },
+ dictWord{8, 10, 121},
+ dictWord{8, 10, 144},
+ dictWord{8, 10, 359},
+ dictWord{9, 10, 193},
+ dictWord{9, 10, 241},
+ dictWord{9, 10, 336},
+ dictWord{
+ 9,
+ 10,
+ 882,
+ },
+ dictWord{11, 10, 266},
+ dictWord{11, 10, 372},
+ dictWord{11, 10, 944},
+ dictWord{12, 10, 401},
+ dictWord{140, 10, 641},
+ dictWord{4, 11, 664},
+ dictWord{133, 11, 804},
+ dictWord{6, 0, 747},
+ dictWord{134, 0, 1015},
+ dictWord{135, 0, 1746},
+ dictWord{9, 10, 31},
+ dictWord{10, 10, 244},
+ dictWord{
+ 10,
+ 10,
+ 699,
+ },
+ dictWord{12, 10, 149},
+ dictWord{141, 10, 497},
+ dictWord{133, 10, 377},
+ dictWord{135, 0, 24},
+ dictWord{6, 0, 1352},
+ dictWord{5, 11, 32},
+ dictWord{
+ 145,
+ 10,
+ 101,
+ },
+ dictWord{7, 0, 1530},
+ dictWord{10, 0, 158},
+ dictWord{13, 0, 13},
+ dictWord{13, 0, 137},
+ dictWord{13, 0, 258},
+ dictWord{14, 0, 111},
+ dictWord{
+ 14,
+ 0,
+ 225,
+ },
+ dictWord{14, 0, 253},
+ dictWord{14, 0, 304},
+ dictWord{14, 0, 339},
+ dictWord{14, 0, 417},
+ dictWord{146, 0, 33},
+ dictWord{4, 0, 503},
+ dictWord{
+ 135,
+ 0,
+ 1661,
+ },
+ dictWord{5, 0, 130},
+ dictWord{6, 0, 845},
+ dictWord{7, 0, 1314},
+ dictWord{9, 0, 610},
+ dictWord{10, 0, 718},
+ dictWord{11, 0, 601},
+ dictWord{11, 0, 819},
+ dictWord{11, 0, 946},
+ dictWord{140, 0, 536},
+ dictWord{10, 0, 149},
+ dictWord{11, 0, 280},
+ dictWord{142, 0, 336},
+ dictWord{134, 0, 1401},
+ dictWord{
+ 135,
+ 0,
+ 1946,
+ },
+ dictWord{8, 0, 663},
+ dictWord{144, 0, 8},
+ dictWord{134, 0, 1607},
+ dictWord{135, 10, 2023},
+ dictWord{4, 11, 289},
+ dictWord{7, 11, 629},
+ dictWord{
+ 7,
+ 11,
+ 1698,
+ },
+ dictWord{7, 11, 1711},
+ dictWord{140, 11, 215},
+ dictWord{6, 11, 450},
+ dictWord{136, 11, 109},
+ dictWord{10, 0, 882},
+ dictWord{10, 0, 883},
+ dictWord{10, 0, 914},
+ dictWord{138, 0, 928},
+ dictWord{133, 10, 843},
+ dictWord{136, 11, 705},
+ dictWord{132, 10, 554},
+ dictWord{133, 10, 536},
+ dictWord{
+ 5,
+ 0,
+ 417,
+ },
+ dictWord{9, 10, 79},
+ dictWord{11, 10, 625},
+ dictWord{145, 10, 7},
+ dictWord{7, 11, 1238},
+ dictWord{142, 11, 37},
+ dictWord{4, 0, 392},
+ dictWord{
+ 135,
+ 0,
+ 1597,
+ },
+ dictWord{5, 0, 433},
+ dictWord{9, 0, 633},
+ dictWord{11, 0, 629},
+ dictWord{132, 10, 424},
+ dictWord{7, 10, 336},
+ dictWord{136, 10, 785},
+ dictWord{
+ 134,
+ 11,
+ 355,
+ },
+ dictWord{6, 0, 234},
+ dictWord{7, 0, 769},
+ dictWord{9, 0, 18},
+ dictWord{138, 0, 358},
+ dictWord{4, 10, 896},
+ dictWord{134, 10, 1777},
+ dictWord{
+ 138,
+ 11,
+ 323,
+ },
+ dictWord{7, 0, 140},
+ dictWord{7, 0, 1950},
+ dictWord{8, 0, 680},
+ dictWord{11, 0, 817},
+ dictWord{147, 0, 88},
+ dictWord{7, 0, 1222},
+ dictWord{
+ 138,
+ 0,
+ 386,
+ },
+ dictWord{139, 11, 908},
+ dictWord{11, 0, 249},
+ dictWord{12, 0, 313},
+ dictWord{16, 0, 66},
+ dictWord{145, 0, 26},
+ dictWord{134, 0, 5},
+ dictWord{7, 10, 750},
+ dictWord{9, 10, 223},
+ dictWord{11, 10, 27},
+ dictWord{11, 10, 466},
+ dictWord{12, 10, 624},
+ dictWord{14, 10, 265},
+ dictWord{146, 10, 61},
+ dictWord{
+ 134,
+ 11,
+ 26,
+ },
+ dictWord{134, 0, 1216},
+ dictWord{5, 0, 963},
+ dictWord{134, 0, 1773},
+ dictWord{4, 11, 414},
+ dictWord{5, 11, 467},
+ dictWord{9, 11, 654},
+ dictWord{
+ 10,
+ 11,
+ 451,
+ },
+ dictWord{12, 11, 59},
+ dictWord{141, 11, 375},
+ dictWord{135, 11, 17},
+ dictWord{4, 10, 603},
+ dictWord{133, 10, 661},
+ dictWord{4, 10, 11},
+ dictWord{
+ 6,
+ 10,
+ 128,
+ },
+ dictWord{7, 10, 231},
+ dictWord{7, 10, 1533},
+ dictWord{138, 10, 725},
+ dictWord{135, 11, 955},
+ dictWord{7, 0, 180},
+ dictWord{8, 0, 509},
+ dictWord{
+ 136,
+ 0,
+ 792,
+ },
+ dictWord{132, 10, 476},
+ dictWord{132, 0, 1002},
+ dictWord{133, 11, 538},
+ dictWord{135, 10, 1807},
+ dictWord{132, 0, 931},
+ dictWord{7, 0, 943},
+ dictWord{11, 0, 614},
+ dictWord{140, 0, 747},
+ dictWord{135, 0, 1837},
+ dictWord{9, 10, 20},
+ dictWord{10, 10, 324},
+ dictWord{10, 10, 807},
+ dictWord{
+ 139,
+ 10,
+ 488,
+ },
+ dictWord{134, 0, 641},
+ dictWord{6, 11, 280},
+ dictWord{10, 11, 502},
+ dictWord{11, 11, 344},
+ dictWord{140, 11, 38},
+ dictWord{5, 11, 45},
+ dictWord{
+ 7,
+ 11,
+ 1161,
+ },
+ dictWord{11, 11, 448},
+ dictWord{11, 11, 880},
+ dictWord{13, 11, 139},
+ dictWord{13, 11, 407},
+ dictWord{15, 11, 16},
+ dictWord{17, 11, 95},
+ dictWord{
+ 18,
+ 11,
+ 66,
+ },
+ dictWord{18, 11, 88},
+ dictWord{18, 11, 123},
+ dictWord{149, 11, 7},
+ dictWord{9, 0, 280},
+ dictWord{138, 0, 134},
+ dictWord{22, 0, 22},
+ dictWord{23, 0, 5},
+ dictWord{151, 0, 29},
+ dictWord{136, 11, 777},
+ dictWord{4, 0, 90},
+ dictWord{5, 0, 545},
+ dictWord{7, 0, 754},
+ dictWord{9, 0, 186},
+ dictWord{10, 0, 72},
+ dictWord{
+ 10,
+ 0,
+ 782,
+ },
+ dictWord{11, 0, 577},
+ dictWord{11, 0, 610},
+ dictWord{11, 0, 960},
+ dictWord{12, 0, 354},
+ dictWord{12, 0, 362},
+ dictWord{12, 0, 595},
+ dictWord{
+ 4,
+ 11,
+ 410,
+ },
+ dictWord{135, 11, 521},
+ dictWord{135, 11, 1778},
+ dictWord{5, 10, 112},
+ dictWord{6, 10, 103},
+ dictWord{134, 10, 150},
+ dictWord{138, 10, 356},
+ dictWord{132, 0, 742},
+ dictWord{7, 0, 151},
+ dictWord{9, 0, 329},
+ dictWord{139, 0, 254},
+ dictWord{8, 0, 853},
+ dictWord{8, 0, 881},
+ dictWord{8, 0, 911},
+ dictWord{
+ 8,
+ 0,
+ 912,
+ },
+ dictWord{10, 0, 872},
+ dictWord{12, 0, 741},
+ dictWord{12, 0, 742},
+ dictWord{152, 0, 18},
+ dictWord{4, 11, 573},
+ dictWord{136, 11, 655},
+ dictWord{
+ 6,
+ 0,
+ 921,
+ },
+ dictWord{134, 0, 934},
+ dictWord{9, 0, 187},
+ dictWord{10, 0, 36},
+ dictWord{11, 0, 1016},
+ dictWord{17, 0, 44},
+ dictWord{146, 0, 64},
+ dictWord{7, 0, 833},
+ dictWord{136, 0, 517},
+ dictWord{4, 0, 506},
+ dictWord{5, 0, 295},
+ dictWord{135, 0, 1680},
+ dictWord{4, 10, 708},
+ dictWord{8, 10, 15},
+ dictWord{9, 10, 50},
+ dictWord{
+ 9,
+ 10,
+ 386,
+ },
+ dictWord{11, 10, 18},
+ dictWord{11, 10, 529},
+ dictWord{140, 10, 228},
+ dictWord{7, 0, 251},
+ dictWord{7, 0, 1701},
+ dictWord{8, 0, 436},
+ dictWord{
+ 4,
+ 10,
+ 563,
+ },
+ dictWord{7, 10, 592},
+ dictWord{7, 10, 637},
+ dictWord{7, 10, 770},
+ dictWord{8, 10, 463},
+ dictWord{9, 10, 60},
+ dictWord{9, 10, 335},
+ dictWord{9, 10, 904},
+ dictWord{10, 10, 73},
+ dictWord{11, 10, 434},
+ dictWord{12, 10, 585},
+ dictWord{13, 10, 331},
+ dictWord{18, 10, 110},
+ dictWord{148, 10, 60},
+ dictWord{
+ 132,
+ 10,
+ 502,
+ },
+ dictWord{136, 0, 584},
+ dictWord{6, 10, 347},
+ dictWord{138, 10, 161},
+ dictWord{7, 0, 987},
+ dictWord{9, 0, 688},
+ dictWord{10, 0, 522},
+ dictWord{
+ 11,
+ 0,
+ 788,
+ },
+ dictWord{12, 0, 137},
+ dictWord{12, 0, 566},
+ dictWord{14, 0, 9},
+ dictWord{14, 0, 24},
+ dictWord{14, 0, 64},
+ dictWord{7, 11, 899},
+ dictWord{142, 11, 325},
+ dictWord{4, 0, 214},
+ dictWord{5, 0, 500},
+ dictWord{5, 10, 102},
+ dictWord{6, 10, 284},
+ dictWord{7, 10, 1079},
+ dictWord{7, 10, 1423},
+ dictWord{7, 10, 1702},
+ dictWord{
+ 8,
+ 10,
+ 470,
+ },
+ dictWord{9, 10, 554},
+ dictWord{9, 10, 723},
+ dictWord{139, 10, 333},
+ dictWord{7, 10, 246},
+ dictWord{135, 10, 840},
+ dictWord{6, 10, 10},
+ dictWord{
+ 8,
+ 10,
+ 571,
+ },
+ dictWord{9, 10, 739},
+ dictWord{143, 10, 91},
+ dictWord{133, 10, 626},
+ dictWord{146, 0, 195},
+ dictWord{134, 0, 1775},
+ dictWord{7, 0, 389},
+ dictWord{7, 0, 700},
+ dictWord{7, 0, 940},
+ dictWord{8, 0, 514},
+ dictWord{9, 0, 116},
+ dictWord{9, 0, 535},
+ dictWord{10, 0, 118},
+ dictWord{11, 0, 107},
+ dictWord{
+ 11,
+ 0,
+ 148,
+ },
+ dictWord{11, 0, 922},
+ dictWord{12, 0, 254},
+ dictWord{12, 0, 421},
+ dictWord{142, 0, 238},
+ dictWord{5, 10, 18},
+ dictWord{6, 10, 526},
+ dictWord{13, 10, 24},
+ dictWord{13, 10, 110},
+ dictWord{19, 10, 5},
+ dictWord{147, 10, 44},
+ dictWord{132, 0, 743},
+ dictWord{11, 0, 292},
+ dictWord{4, 10, 309},
+ dictWord{5, 10, 462},
+ dictWord{7, 10, 970},
+ dictWord{135, 10, 1097},
+ dictWord{22, 10, 30},
+ dictWord{150, 10, 33},
+ dictWord{139, 11, 338},
+ dictWord{135, 11, 1598},
+ dictWord{
+ 7,
+ 0,
+ 1283,
+ },
+ dictWord{9, 0, 227},
+ dictWord{11, 0, 325},
+ dictWord{11, 0, 408},
+ dictWord{14, 0, 180},
+ dictWord{146, 0, 47},
+ dictWord{4, 0, 953},
+ dictWord{6, 0, 1805},
+ dictWord{6, 0, 1814},
+ dictWord{6, 0, 1862},
+ dictWord{140, 0, 774},
+ dictWord{6, 11, 611},
+ dictWord{135, 11, 1733},
+ dictWord{135, 11, 1464},
+ dictWord{
+ 5,
+ 0,
+ 81,
+ },
+ dictWord{7, 0, 146},
+ dictWord{7, 0, 1342},
+ dictWord{8, 0, 53},
+ dictWord{8, 0, 561},
+ dictWord{8, 0, 694},
+ dictWord{8, 0, 754},
+ dictWord{9, 0, 115},
+ dictWord{
+ 9,
+ 0,
+ 179,
+ },
+ dictWord{9, 0, 894},
+ dictWord{10, 0, 462},
+ dictWord{10, 0, 813},
+ dictWord{11, 0, 230},
+ dictWord{11, 0, 657},
+ dictWord{11, 0, 699},
+ dictWord{11, 0, 748},
+ dictWord{12, 0, 119},
+ dictWord{12, 0, 200},
+ dictWord{12, 0, 283},
+ dictWord{142, 0, 273},
+ dictWord{5, 0, 408},
+ dictWord{6, 0, 789},
+ dictWord{6, 0, 877},
+ dictWord{
+ 6,
+ 0,
+ 1253,
+ },
+ dictWord{6, 0, 1413},
+ dictWord{137, 0, 747},
+ dictWord{134, 10, 1704},
+ dictWord{135, 11, 663},
+ dictWord{6, 0, 1910},
+ dictWord{6, 0, 1915},
+ dictWord{6, 0, 1923},
+ dictWord{9, 0, 913},
+ dictWord{9, 0, 928},
+ dictWord{9, 0, 950},
+ dictWord{9, 0, 954},
+ dictWord{9, 0, 978},
+ dictWord{9, 0, 993},
+ dictWord{12, 0, 812},
+ dictWord{12, 0, 819},
+ dictWord{12, 0, 831},
+ dictWord{12, 0, 833},
+ dictWord{12, 0, 838},
+ dictWord{12, 0, 909},
+ dictWord{12, 0, 928},
+ dictWord{12, 0, 931},
+ dictWord{12, 0, 950},
+ dictWord{15, 0, 186},
+ dictWord{15, 0, 187},
+ dictWord{15, 0, 195},
+ dictWord{15, 0, 196},
+ dictWord{15, 0, 209},
+ dictWord{15, 0, 215},
+ dictWord{
+ 15,
+ 0,
+ 236,
+ },
+ dictWord{15, 0, 241},
+ dictWord{15, 0, 249},
+ dictWord{15, 0, 253},
+ dictWord{18, 0, 180},
+ dictWord{18, 0, 221},
+ dictWord{18, 0, 224},
+ dictWord{
+ 18,
+ 0,
+ 227,
+ },
+ dictWord{18, 0, 229},
+ dictWord{149, 0, 60},
+ dictWord{7, 0, 1826},
+ dictWord{135, 0, 1938},
+ dictWord{11, 0, 490},
+ dictWord{18, 0, 143},
+ dictWord{
+ 5,
+ 10,
+ 86,
+ },
+ dictWord{7, 10, 743},
+ dictWord{9, 10, 85},
+ dictWord{10, 10, 281},
+ dictWord{10, 10, 432},
+ dictWord{12, 10, 251},
+ dictWord{13, 10, 118},
+ dictWord{
+ 142,
+ 10,
+ 378,
+ },
+ dictWord{5, 10, 524},
+ dictWord{133, 10, 744},
+ dictWord{141, 11, 442},
+ dictWord{10, 10, 107},
+ dictWord{140, 10, 436},
+ dictWord{135, 11, 503},
+ dictWord{134, 0, 1162},
+ dictWord{132, 10, 927},
+ dictWord{7, 0, 30},
+ dictWord{8, 0, 86},
+ dictWord{8, 0, 315},
+ dictWord{8, 0, 700},
+ dictWord{9, 0, 576},
+ dictWord{
+ 9,
+ 0,
+ 858,
+ },
+ dictWord{10, 0, 414},
+ dictWord{11, 0, 310},
+ dictWord{11, 0, 888},
+ dictWord{11, 0, 904},
+ dictWord{12, 0, 361},
+ dictWord{13, 0, 248},
+ dictWord{13, 0, 371},
+ dictWord{14, 0, 142},
+ dictWord{12, 10, 670},
+ dictWord{146, 10, 94},
+ dictWord{134, 0, 721},
+ dictWord{4, 11, 113},
+ dictWord{5, 11, 163},
+ dictWord{5, 11, 735},
+ dictWord{7, 11, 1009},
+ dictWord{7, 10, 1149},
+ dictWord{9, 11, 9},
+ dictWord{9, 10, 156},
+ dictWord{9, 11, 771},
+ dictWord{12, 11, 90},
+ dictWord{13, 11, 138},
+ dictWord{13, 11, 410},
+ dictWord{143, 11, 128},
+ dictWord{138, 0, 839},
+ dictWord{133, 10, 778},
+ dictWord{137, 0, 617},
+ dictWord{133, 10, 502},
+ dictWord{
+ 8,
+ 10,
+ 196,
+ },
+ dictWord{10, 10, 283},
+ dictWord{139, 10, 406},
+ dictWord{6, 0, 428},
+ dictWord{7, 0, 524},
+ dictWord{8, 0, 169},
+ dictWord{8, 0, 234},
+ dictWord{9, 0, 480},
+ dictWord{138, 0, 646},
+ dictWord{133, 10, 855},
+ dictWord{134, 0, 1648},
+ dictWord{7, 0, 1205},
+ dictWord{138, 0, 637},
+ dictWord{7, 0, 1596},
+ dictWord{
+ 4,
+ 11,
+ 935,
+ },
+ dictWord{133, 11, 823},
+ dictWord{5, 11, 269},
+ dictWord{7, 11, 434},
+ dictWord{7, 11, 891},
+ dictWord{8, 11, 339},
+ dictWord{9, 11, 702},
+ dictWord{
+ 11,
+ 11,
+ 594,
+ },
+ dictWord{11, 11, 718},
+ dictWord{145, 11, 100},
+ dictWord{7, 11, 878},
+ dictWord{9, 11, 485},
+ dictWord{141, 11, 264},
+ dictWord{4, 0, 266},
+ dictWord{
+ 8,
+ 0,
+ 4,
+ },
+ dictWord{9, 0, 39},
+ dictWord{10, 0, 166},
+ dictWord{11, 0, 918},
+ dictWord{12, 0, 635},
+ dictWord{20, 0, 10},
+ dictWord{22, 0, 27},
+ dictWord{22, 0, 43},
+ dictWord{
+ 22,
+ 0,
+ 52,
+ },
+ dictWord{134, 11, 1713},
+ dictWord{7, 10, 1400},
+ dictWord{9, 10, 446},
+ dictWord{138, 10, 45},
+ dictWord{135, 11, 900},
+ dictWord{132, 0, 862},
+ dictWord{134, 0, 1554},
+ dictWord{135, 11, 1033},
+ dictWord{19, 0, 16},
+ dictWord{147, 11, 16},
+ dictWord{135, 11, 1208},
+ dictWord{7, 0, 157},
+ dictWord{
+ 136,
+ 0,
+ 279,
+ },
+ dictWord{6, 0, 604},
+ dictWord{136, 0, 391},
+ dictWord{13, 10, 455},
+ dictWord{15, 10, 99},
+ dictWord{15, 10, 129},
+ dictWord{144, 10, 68},
+ dictWord{
+ 135,
+ 10,
+ 172,
+ },
+ dictWord{7, 0, 945},
+ dictWord{11, 0, 713},
+ dictWord{139, 0, 744},
+ dictWord{4, 0, 973},
+ dictWord{10, 0, 877},
+ dictWord{10, 0, 937},
+ dictWord{
+ 10,
+ 0,
+ 938,
+ },
+ dictWord{140, 0, 711},
+ dictWord{139, 0, 1022},
+ dictWord{132, 10, 568},
+ dictWord{142, 11, 143},
+ dictWord{4, 0, 567},
+ dictWord{9, 0, 859},
+ dictWord{
+ 132,
+ 10,
+ 732,
+ },
+ dictWord{7, 0, 1846},
+ dictWord{136, 0, 628},
+ dictWord{136, 10, 733},
+ dictWord{133, 0, 762},
+ dictWord{4, 10, 428},
+ dictWord{135, 10, 1789},
+ dictWord{10, 0, 784},
+ dictWord{13, 0, 191},
+ dictWord{7, 10, 2015},
+ dictWord{140, 10, 665},
+ dictWord{133, 0, 298},
+ dictWord{7, 0, 633},
+ dictWord{7, 0, 905},
+ dictWord{7, 0, 909},
+ dictWord{7, 0, 1538},
+ dictWord{9, 0, 767},
+ dictWord{140, 0, 636},
+ dictWord{138, 10, 806},
+ dictWord{132, 0, 795},
+ dictWord{139, 0, 301},
+ dictWord{135, 0, 1970},
+ dictWord{5, 11, 625},
+ dictWord{135, 11, 1617},
+ dictWord{135, 11, 275},
+ dictWord{7, 11, 37},
+ dictWord{8, 11, 425},
+ dictWord{
+ 8,
+ 11,
+ 693,
+ },
+ dictWord{9, 11, 720},
+ dictWord{10, 11, 380},
+ dictWord{10, 11, 638},
+ dictWord{11, 11, 273},
+ dictWord{11, 11, 307},
+ dictWord{11, 11, 473},
+ dictWord{
+ 12,
+ 11,
+ 61,
+ },
+ dictWord{143, 11, 43},
+ dictWord{135, 11, 198},
+ dictWord{134, 0, 1236},
+ dictWord{7, 0, 369},
+ dictWord{12, 0, 644},
+ dictWord{12, 0, 645},
+ dictWord{144, 0, 90},
+ dictWord{19, 0, 15},
+ dictWord{149, 0, 27},
+ dictWord{6, 0, 71},
+ dictWord{7, 0, 845},
+ dictWord{8, 0, 160},
+ dictWord{9, 0, 318},
+ dictWord{6, 10, 1623},
+ dictWord{134, 10, 1681},
+ dictWord{134, 0, 1447},
+ dictWord{134, 0, 1255},
+ dictWord{138, 0, 735},
+ dictWord{8, 0, 76},
+ dictWord{132, 11, 168},
+ dictWord{
+ 6,
+ 10,
+ 1748,
+ },
+ dictWord{8, 10, 715},
+ dictWord{9, 10, 802},
+ dictWord{10, 10, 46},
+ dictWord{10, 10, 819},
+ dictWord{13, 10, 308},
+ dictWord{14, 10, 351},
+ dictWord{14, 10, 363},
+ dictWord{146, 10, 67},
+ dictWord{135, 11, 91},
+ dictWord{6, 0, 474},
+ dictWord{4, 10, 63},
+ dictWord{133, 10, 347},
+ dictWord{133, 10, 749},
+ dictWord{138, 0, 841},
+ dictWord{133, 10, 366},
+ dictWord{6, 0, 836},
+ dictWord{132, 11, 225},
+ dictWord{135, 0, 1622},
+ dictWord{135, 10, 89},
+ dictWord{
+ 140,
+ 0,
+ 735,
+ },
+ dictWord{134, 0, 1601},
+ dictWord{138, 11, 145},
+ dictWord{6, 0, 1390},
+ dictWord{137, 0, 804},
+ dictWord{142, 0, 394},
+ dictWord{6, 11, 15},
+ dictWord{
+ 7,
+ 11,
+ 70,
+ },
+ dictWord{10, 11, 240},
+ dictWord{147, 11, 93},
+ dictWord{6, 0, 96},
+ dictWord{135, 0, 1426},
+ dictWord{4, 0, 651},
+ dictWord{133, 0, 289},
+ dictWord{
+ 7,
+ 11,
+ 956,
+ },
+ dictWord{7, 10, 977},
+ dictWord{7, 11, 1157},
+ dictWord{7, 11, 1506},
+ dictWord{7, 11, 1606},
+ dictWord{7, 11, 1615},
+ dictWord{7, 11, 1619},
+ dictWord{
+ 7,
+ 11,
+ 1736,
+ },
+ dictWord{7, 11, 1775},
+ dictWord{8, 11, 590},
+ dictWord{9, 11, 324},
+ dictWord{9, 11, 736},
+ dictWord{9, 11, 774},
+ dictWord{9, 11, 776},
+ dictWord{
+ 9,
+ 11,
+ 784,
+ },
+ dictWord{10, 11, 567},
+ dictWord{10, 11, 708},
+ dictWord{11, 11, 518},
+ dictWord{11, 11, 613},
+ dictWord{11, 11, 695},
+ dictWord{11, 11, 716},
+ dictWord{11, 11, 739},
+ dictWord{11, 11, 770},
+ dictWord{11, 11, 771},
+ dictWord{11, 11, 848},
+ dictWord{11, 11, 857},
+ dictWord{11, 11, 931},
+ dictWord{
+ 11,
+ 11,
+ 947,
+ },
+ dictWord{12, 11, 326},
+ dictWord{12, 11, 387},
+ dictWord{12, 11, 484},
+ dictWord{12, 11, 528},
+ dictWord{12, 11, 552},
+ dictWord{12, 11, 613},
+ dictWord{
+ 13,
+ 11,
+ 189,
+ },
+ dictWord{13, 11, 256},
+ dictWord{13, 11, 340},
+ dictWord{13, 11, 432},
+ dictWord{13, 11, 436},
+ dictWord{13, 11, 440},
+ dictWord{13, 11, 454},
+ dictWord{14, 11, 174},
+ dictWord{14, 11, 220},
+ dictWord{14, 11, 284},
+ dictWord{14, 11, 390},
+ dictWord{145, 11, 121},
+ dictWord{7, 0, 688},
+ dictWord{8, 0, 35},
+ dictWord{9, 0, 511},
+ dictWord{10, 0, 767},
+ dictWord{147, 0, 118},
+ dictWord{134, 0, 667},
+ dictWord{4, 0, 513},
+ dictWord{5, 10, 824},
+ dictWord{133, 10, 941},
+ dictWord{7, 10, 440},
+ dictWord{8, 10, 230},
+ dictWord{139, 10, 106},
+ dictWord{134, 0, 2034},
+ dictWord{135, 11, 1399},
+ dictWord{143, 11, 66},
+ dictWord{
+ 135,
+ 11,
+ 1529,
+ },
+ dictWord{4, 11, 145},
+ dictWord{6, 11, 176},
+ dictWord{7, 11, 395},
+ dictWord{9, 11, 562},
+ dictWord{144, 11, 28},
+ dictWord{132, 11, 501},
+ dictWord{132, 0, 704},
+ dictWord{134, 0, 1524},
+ dictWord{7, 0, 1078},
+ dictWord{134, 11, 464},
+ dictWord{6, 11, 509},
+ dictWord{10, 11, 82},
+ dictWord{20, 11, 91},
+ dictWord{151, 11, 13},
+ dictWord{4, 0, 720},
+ dictWord{133, 0, 306},
+ dictWord{133, 0, 431},
+ dictWord{7, 0, 1196},
+ dictWord{4, 10, 914},
+ dictWord{5, 10, 800},
+ dictWord{133, 10, 852},
+ dictWord{135, 11, 1189},
+ dictWord{10, 0, 54},
+ dictWord{141, 10, 115},
+ dictWord{7, 10, 564},
+ dictWord{142, 10, 168},
+ dictWord{
+ 5,
+ 0,
+ 464,
+ },
+ dictWord{6, 0, 236},
+ dictWord{7, 0, 696},
+ dictWord{7, 0, 914},
+ dictWord{7, 0, 1108},
+ dictWord{7, 0, 1448},
+ dictWord{9, 0, 15},
+ dictWord{9, 0, 564},
+ dictWord{
+ 10,
+ 0,
+ 14,
+ },
+ dictWord{12, 0, 565},
+ dictWord{13, 0, 449},
+ dictWord{14, 0, 53},
+ dictWord{15, 0, 13},
+ dictWord{16, 0, 64},
+ dictWord{17, 0, 41},
+ dictWord{4, 10, 918},
+ dictWord{133, 10, 876},
+ dictWord{6, 0, 1418},
+ dictWord{134, 10, 1764},
+ dictWord{4, 10, 92},
+ dictWord{133, 10, 274},
+ dictWord{134, 0, 907},
+ dictWord{
+ 4,
+ 11,
+ 114,
+ },
+ dictWord{8, 10, 501},
+ dictWord{9, 11, 492},
+ dictWord{13, 11, 462},
+ dictWord{142, 11, 215},
+ dictWord{4, 11, 77},
+ dictWord{5, 11, 361},
+ dictWord{
+ 6,
+ 11,
+ 139,
+ },
+ dictWord{6, 11, 401},
+ dictWord{6, 11, 404},
+ dictWord{7, 11, 413},
+ dictWord{7, 11, 715},
+ dictWord{7, 11, 1716},
+ dictWord{11, 11, 279},
+ dictWord{
+ 12,
+ 11,
+ 179,
+ },
+ dictWord{12, 11, 258},
+ dictWord{13, 11, 244},
+ dictWord{142, 11, 358},
+ dictWord{6, 0, 1767},
+ dictWord{12, 0, 194},
+ dictWord{145, 0, 107},
+ dictWord{
+ 134,
+ 11,
+ 1717,
+ },
+ dictWord{5, 10, 743},
+ dictWord{142, 11, 329},
+ dictWord{4, 10, 49},
+ dictWord{7, 10, 280},
+ dictWord{135, 10, 1633},
+ dictWord{5, 0, 840},
+ dictWord{7, 11, 1061},
+ dictWord{8, 11, 82},
+ dictWord{11, 11, 250},
+ dictWord{12, 11, 420},
+ dictWord{141, 11, 184},
+ dictWord{135, 11, 724},
+ dictWord{
+ 134,
+ 0,
+ 900,
+ },
+ dictWord{136, 10, 47},
+ dictWord{134, 0, 1436},
+ dictWord{144, 11, 0},
+ dictWord{6, 0, 675},
+ dictWord{7, 0, 1008},
+ dictWord{7, 0, 1560},
+ dictWord{
+ 9,
+ 0,
+ 642,
+ },
+ dictWord{11, 0, 236},
+ dictWord{14, 0, 193},
+ dictWord{5, 10, 272},
+ dictWord{5, 10, 908},
+ dictWord{5, 10, 942},
+ dictWord{8, 10, 197},
+ dictWord{9, 10, 47},
+ dictWord{11, 10, 538},
+ dictWord{139, 10, 742},
+ dictWord{4, 0, 68},
+ dictWord{5, 0, 628},
+ dictWord{5, 0, 634},
+ dictWord{6, 0, 386},
+ dictWord{7, 0, 794},
+ dictWord{
+ 8,
+ 0,
+ 273,
+ },
+ dictWord{9, 0, 563},
+ dictWord{10, 0, 105},
+ dictWord{10, 0, 171},
+ dictWord{11, 0, 94},
+ dictWord{139, 0, 354},
+ dictWord{135, 10, 1911},
+ dictWord{
+ 137,
+ 10,
+ 891,
+ },
+ dictWord{4, 0, 95},
+ dictWord{6, 0, 1297},
+ dictWord{6, 0, 1604},
+ dictWord{7, 0, 416},
+ dictWord{139, 0, 830},
+ dictWord{6, 11, 513},
+ dictWord{
+ 135,
+ 11,
+ 1052,
+ },
+ dictWord{7, 0, 731},
+ dictWord{13, 0, 20},
+ dictWord{143, 0, 11},
+ dictWord{137, 11, 899},
+ dictWord{10, 0, 850},
+ dictWord{140, 0, 697},
+ dictWord{
+ 4,
+ 0,
+ 662,
+ },
+ dictWord{7, 11, 1417},
+ dictWord{12, 11, 382},
+ dictWord{17, 11, 48},
+ dictWord{152, 11, 12},
+ dictWord{133, 0, 736},
+ dictWord{132, 0, 861},
+ dictWord{
+ 4,
+ 10,
+ 407,
+ },
+ dictWord{132, 10, 560},
+ dictWord{141, 10, 490},
+ dictWord{6, 11, 545},
+ dictWord{7, 11, 565},
+ dictWord{7, 11, 1669},
+ dictWord{10, 11, 114},
+ dictWord{11, 11, 642},
+ dictWord{140, 11, 618},
+ dictWord{6, 0, 871},
+ dictWord{134, 0, 1000},
+ dictWord{5, 0, 864},
+ dictWord{10, 0, 648},
+ dictWord{11, 0, 671},
+ dictWord{15, 0, 46},
+ dictWord{133, 11, 5},
+ dictWord{133, 0, 928},
+ dictWord{11, 0, 90},
+ dictWord{13, 0, 7},
+ dictWord{4, 10, 475},
+ dictWord{11, 10, 35},
+ dictWord{
+ 13,
+ 10,
+ 71,
+ },
+ dictWord{13, 10, 177},
+ dictWord{142, 10, 422},
+ dictWord{136, 0, 332},
+ dictWord{135, 11, 192},
+ dictWord{134, 0, 1055},
+ dictWord{136, 11, 763},
+ dictWord{11, 0, 986},
+ dictWord{140, 0, 682},
+ dictWord{7, 0, 76},
+ dictWord{8, 0, 44},
+ dictWord{9, 0, 884},
+ dictWord{10, 0, 580},
+ dictWord{11, 0, 399},
+ dictWord{
+ 11,
+ 0,
+ 894,
+ },
+ dictWord{143, 0, 122},
+ dictWord{135, 11, 1237},
+ dictWord{135, 10, 636},
+ dictWord{11, 0, 300},
+ dictWord{6, 10, 222},
+ dictWord{7, 10, 1620},
+ dictWord{
+ 8,
+ 10,
+ 409,
+ },
+ dictWord{137, 10, 693},
+ dictWord{4, 11, 87},
+ dictWord{5, 11, 250},
+ dictWord{10, 11, 601},
+ dictWord{13, 11, 298},
+ dictWord{13, 11, 353},
+ dictWord{141, 11, 376},
+ dictWord{5, 0, 518},
+ dictWord{10, 0, 340},
+ dictWord{11, 0, 175},
+ dictWord{149, 0, 16},
+ dictWord{140, 0, 771},
+ dictWord{6, 0, 1108},
+ dictWord{137, 0, 831},
+ dictWord{132, 0, 836},
+ dictWord{135, 0, 1852},
+ dictWord{4, 0, 957},
+ dictWord{6, 0, 1804},
+ dictWord{8, 0, 842},
+ dictWord{8, 0, 843},
+ dictWord{
+ 8,
+ 0,
+ 851,
+ },
+ dictWord{8, 0, 855},
+ dictWord{140, 0, 767},
+ dictWord{135, 11, 814},
+ dictWord{4, 11, 57},
+ dictWord{7, 11, 1195},
+ dictWord{7, 11, 1438},
+ dictWord{
+ 7,
+ 11,
+ 1548,
+ },
+ dictWord{7, 11, 1835},
+ dictWord{7, 11, 1904},
+ dictWord{9, 11, 757},
+ dictWord{10, 11, 604},
+ dictWord{139, 11, 519},
+ dictWord{133, 10, 882},
+ dictWord{138, 0, 246},
+ dictWord{4, 0, 934},
+ dictWord{5, 0, 202},
+ dictWord{8, 0, 610},
+ dictWord{7, 11, 1897},
+ dictWord{12, 11, 290},
+ dictWord{13, 11, 80},
+ dictWord{13, 11, 437},
+ dictWord{145, 11, 74},
+ dictWord{8, 0, 96},
+ dictWord{9, 0, 36},
+ dictWord{10, 0, 607},
+ dictWord{10, 0, 804},
+ dictWord{10, 0, 832},
+ dictWord{
+ 11,
+ 0,
+ 423,
+ },
+ dictWord{11, 0, 442},
+ dictWord{12, 0, 309},
+ dictWord{14, 0, 199},
+ dictWord{15, 0, 90},
+ dictWord{145, 0, 110},
+ dictWord{132, 10, 426},
+ dictWord{
+ 7,
+ 0,
+ 654,
+ },
+ dictWord{8, 0, 240},
+ dictWord{6, 10, 58},
+ dictWord{7, 10, 745},
+ dictWord{7, 10, 1969},
+ dictWord{8, 10, 675},
+ dictWord{9, 10, 479},
+ dictWord{9, 10, 731},
+ dictWord{10, 10, 330},
+ dictWord{10, 10, 593},
+ dictWord{10, 10, 817},
+ dictWord{11, 10, 32},
+ dictWord{11, 10, 133},
+ dictWord{11, 10, 221},
+ dictWord{
+ 145,
+ 10,
+ 68,
+ },
+ dictWord{9, 0, 13},
+ dictWord{9, 0, 398},
+ dictWord{9, 0, 727},
+ dictWord{10, 0, 75},
+ dictWord{10, 0, 184},
+ dictWord{10, 0, 230},
+ dictWord{10, 0, 564},
+ dictWord{
+ 10,
+ 0,
+ 569,
+ },
+ dictWord{11, 0, 973},
+ dictWord{12, 0, 70},
+ dictWord{12, 0, 189},
+ dictWord{13, 0, 57},
+ dictWord{141, 0, 257},
+ dictWord{4, 11, 209},
+ dictWord{
+ 135,
+ 11,
+ 902,
+ },
+ dictWord{7, 0, 391},
+ dictWord{137, 10, 538},
+ dictWord{134, 0, 403},
+ dictWord{6, 11, 303},
+ dictWord{7, 11, 335},
+ dictWord{7, 11, 1437},
+ dictWord{
+ 7,
+ 11,
+ 1668,
+ },
+ dictWord{8, 11, 553},
+ dictWord{8, 11, 652},
+ dictWord{8, 11, 656},
+ dictWord{9, 11, 558},
+ dictWord{11, 11, 743},
+ dictWord{149, 11, 18},
+ dictWord{
+ 132,
+ 11,
+ 559,
+ },
+ dictWord{11, 0, 75},
+ dictWord{142, 0, 267},
+ dictWord{6, 0, 815},
+ dictWord{141, 11, 2},
+ dictWord{141, 0, 366},
+ dictWord{137, 0, 631},
+ dictWord{
+ 133,
+ 11,
+ 1017,
+ },
+ dictWord{5, 0, 345},
+ dictWord{135, 0, 1016},
+ dictWord{133, 11, 709},
+ dictWord{134, 11, 1745},
+ dictWord{133, 10, 566},
+ dictWord{7, 0, 952},
+ dictWord{6, 10, 48},
+ dictWord{9, 10, 139},
+ dictWord{10, 10, 399},
+ dictWord{11, 10, 469},
+ dictWord{12, 10, 634},
+ dictWord{141, 10, 223},
+ dictWord{
+ 133,
+ 0,
+ 673,
+ },
+ dictWord{9, 0, 850},
+ dictWord{7, 11, 8},
+ dictWord{136, 11, 206},
+ dictWord{6, 0, 662},
+ dictWord{149, 0, 35},
+ dictWord{4, 0, 287},
+ dictWord{133, 0, 1018},
+ dictWord{6, 10, 114},
+ dictWord{7, 10, 1224},
+ dictWord{7, 10, 1556},
+ dictWord{136, 10, 3},
+ dictWord{8, 10, 576},
+ dictWord{137, 10, 267},
+ dictWord{4, 0, 884},
+ dictWord{5, 0, 34},
+ dictWord{10, 0, 724},
+ dictWord{12, 0, 444},
+ dictWord{13, 0, 354},
+ dictWord{18, 0, 32},
+ dictWord{23, 0, 24},
+ dictWord{23, 0, 31},
+ dictWord{
+ 152,
+ 0,
+ 5,
+ },
+ dictWord{133, 10, 933},
+ dictWord{132, 11, 776},
+ dictWord{138, 0, 151},
+ dictWord{136, 0, 427},
+ dictWord{134, 0, 382},
+ dictWord{132, 0, 329},
+ dictWord{
+ 9,
+ 0,
+ 846,
+ },
+ dictWord{10, 0, 827},
+ dictWord{138, 11, 33},
+ dictWord{9, 0, 279},
+ dictWord{10, 0, 407},
+ dictWord{14, 0, 84},
+ dictWord{22, 0, 18},
+ dictWord{
+ 135,
+ 11,
+ 1297,
+ },
+ dictWord{136, 11, 406},
+ dictWord{132, 0, 906},
+ dictWord{136, 0, 366},
+ dictWord{134, 0, 843},
+ dictWord{134, 0, 1443},
+ dictWord{135, 0, 1372},
+ dictWord{138, 0, 992},
+ dictWord{4, 0, 123},
+ dictWord{5, 0, 605},
+ dictWord{7, 0, 1509},
+ dictWord{136, 0, 36},
+ dictWord{132, 0, 649},
+ dictWord{8, 11, 175},
+ dictWord{10, 11, 168},
+ dictWord{138, 11, 573},
+ dictWord{133, 0, 767},
+ dictWord{134, 0, 1018},
+ dictWord{135, 11, 1305},
+ dictWord{12, 10, 30},
+ dictWord{
+ 13,
+ 10,
+ 148,
+ },
+ dictWord{14, 10, 87},
+ dictWord{14, 10, 182},
+ dictWord{16, 10, 42},
+ dictWord{148, 10, 70},
+ dictWord{134, 11, 607},
+ dictWord{4, 0, 273},
+ dictWord{
+ 5,
+ 0,
+ 658,
+ },
+ dictWord{133, 0, 995},
+ dictWord{6, 0, 72},
+ dictWord{139, 11, 174},
+ dictWord{10, 0, 483},
+ dictWord{12, 0, 368},
+ dictWord{7, 10, 56},
+ dictWord{
+ 7,
+ 10,
+ 1989,
+ },
+ dictWord{8, 10, 337},
+ dictWord{8, 10, 738},
+ dictWord{9, 10, 600},
+ dictWord{13, 10, 447},
+ dictWord{142, 10, 92},
+ dictWord{5, 11, 784},
+ dictWord{
+ 138,
+ 10,
+ 666,
+ },
+ dictWord{135, 0, 1345},
+ dictWord{139, 11, 882},
+ dictWord{134, 0, 1293},
+ dictWord{133, 0, 589},
+ dictWord{134, 0, 1988},
+ dictWord{5, 0, 117},
+ dictWord{6, 0, 514},
+ dictWord{6, 0, 541},
+ dictWord{7, 0, 1164},
+ dictWord{7, 0, 1436},
+ dictWord{8, 0, 220},
+ dictWord{8, 0, 648},
+ dictWord{10, 0, 688},
+ dictWord{
+ 139,
+ 0,
+ 560,
+ },
+ dictWord{136, 0, 379},
+ dictWord{5, 0, 686},
+ dictWord{7, 10, 866},
+ dictWord{135, 10, 1163},
+ dictWord{132, 10, 328},
+ dictWord{9, 11, 14},
+ dictWord{
+ 9,
+ 11,
+ 441,
+ },
+ dictWord{10, 11, 306},
+ dictWord{139, 11, 9},
+ dictWord{4, 10, 101},
+ dictWord{135, 10, 1171},
+ dictWord{5, 10, 833},
+ dictWord{136, 10, 744},
+ dictWord{5, 11, 161},
+ dictWord{7, 11, 839},
+ dictWord{135, 11, 887},
+ dictWord{7, 0, 196},
+ dictWord{10, 0, 765},
+ dictWord{11, 0, 347},
+ dictWord{11, 0, 552},
+ dictWord{11, 0, 790},
+ dictWord{12, 0, 263},
+ dictWord{13, 0, 246},
+ dictWord{13, 0, 270},
+ dictWord{13, 0, 395},
+ dictWord{14, 0, 176},
+ dictWord{14, 0, 190},
+ dictWord{
+ 14,
+ 0,
+ 398,
+ },
+ dictWord{14, 0, 412},
+ dictWord{15, 0, 32},
+ dictWord{15, 0, 63},
+ dictWord{16, 0, 88},
+ dictWord{147, 0, 105},
+ dictWord{6, 10, 9},
+ dictWord{6, 10, 397},
+ dictWord{7, 10, 53},
+ dictWord{7, 10, 1742},
+ dictWord{10, 10, 632},
+ dictWord{11, 10, 828},
+ dictWord{140, 10, 146},
+ dictWord{5, 0, 381},
+ dictWord{135, 0, 1792},
+ dictWord{134, 0, 1452},
+ dictWord{135, 11, 429},
+ dictWord{8, 0, 367},
+ dictWord{10, 0, 760},
+ dictWord{14, 0, 79},
+ dictWord{20, 0, 17},
+ dictWord{152, 0, 0},
+ dictWord{7, 0, 616},
+ dictWord{138, 0, 413},
+ dictWord{11, 10, 417},
+ dictWord{12, 10, 223},
+ dictWord{140, 10, 265},
+ dictWord{7, 11, 1611},
+ dictWord{13, 11, 14},
+ dictWord{15, 11, 44},
+ dictWord{19, 11, 13},
+ dictWord{148, 11, 76},
+ dictWord{135, 0, 1229},
+ dictWord{6, 0, 120},
+ dictWord{7, 0, 1188},
+ dictWord{7, 0, 1710},
+ dictWord{8, 0, 286},
+ dictWord{9, 0, 667},
+ dictWord{11, 0, 592},
+ dictWord{139, 0, 730},
+ dictWord{135, 11, 1814},
+ dictWord{135, 0, 1146},
+ dictWord{4, 10, 186},
+ dictWord{5, 10, 157},
+ dictWord{8, 10, 168},
+ dictWord{138, 10, 6},
+ dictWord{4, 0, 352},
+ dictWord{135, 0, 687},
+ dictWord{4, 0, 192},
+ dictWord{5, 0, 49},
+ dictWord{
+ 6,
+ 0,
+ 200,
+ },
+ dictWord{6, 0, 293},
+ dictWord{6, 0, 1696},
+ dictWord{135, 0, 1151},
+ dictWord{133, 10, 875},
+ dictWord{5, 10, 773},
+ dictWord{5, 10, 991},
+ dictWord{
+ 6,
+ 10,
+ 1635,
+ },
+ dictWord{134, 10, 1788},
+ dictWord{7, 10, 111},
+ dictWord{136, 10, 581},
+ dictWord{6, 0, 935},
+ dictWord{134, 0, 1151},
+ dictWord{134, 0, 1050},
+ dictWord{132, 0, 650},
+ dictWord{132, 0, 147},
+ dictWord{11, 0, 194},
+ dictWord{12, 0, 62},
+ dictWord{12, 0, 88},
+ dictWord{11, 11, 194},
+ dictWord{12, 11, 62},
+ dictWord{140, 11, 88},
+ dictWord{6, 0, 339},
+ dictWord{135, 0, 923},
+ dictWord{134, 10, 1747},
+ dictWord{7, 11, 643},
+ dictWord{136, 11, 236},
+ dictWord{
+ 133,
+ 0,
+ 934,
+ },
+ dictWord{7, 10, 1364},
+ dictWord{7, 10, 1907},
+ dictWord{141, 10, 158},
+ dictWord{132, 10, 659},
+ dictWord{4, 10, 404},
+ dictWord{135, 10, 675},
+ dictWord{7, 11, 581},
+ dictWord{9, 11, 644},
+ dictWord{137, 11, 699},
+ dictWord{13, 0, 211},
+ dictWord{14, 0, 133},
+ dictWord{14, 0, 204},
+ dictWord{15, 0, 64},
+ dictWord{
+ 15,
+ 0,
+ 69,
+ },
+ dictWord{15, 0, 114},
+ dictWord{16, 0, 10},
+ dictWord{19, 0, 23},
+ dictWord{19, 0, 35},
+ dictWord{19, 0, 39},
+ dictWord{19, 0, 51},
+ dictWord{19, 0, 71},
+ dictWord{19, 0, 75},
+ dictWord{152, 0, 15},
+ dictWord{133, 10, 391},
+ dictWord{5, 11, 54},
+ dictWord{135, 11, 1513},
+ dictWord{7, 0, 222},
+ dictWord{8, 0, 341},
+ dictWord{
+ 5,
+ 10,
+ 540,
+ },
+ dictWord{134, 10, 1697},
+ dictWord{134, 10, 78},
+ dictWord{132, 11, 744},
+ dictWord{136, 0, 293},
+ dictWord{137, 11, 701},
+ dictWord{
+ 7,
+ 11,
+ 930,
+ },
+ dictWord{10, 11, 402},
+ dictWord{10, 11, 476},
+ dictWord{13, 11, 452},
+ dictWord{18, 11, 55},
+ dictWord{147, 11, 104},
+ dictWord{132, 0, 637},
+ dictWord{133, 10, 460},
+ dictWord{8, 11, 50},
+ dictWord{137, 11, 624},
+ dictWord{132, 11, 572},
+ dictWord{134, 0, 1159},
+ dictWord{4, 10, 199},
+ dictWord{
+ 139,
+ 10,
+ 34,
+ },
+ dictWord{134, 0, 847},
+ dictWord{134, 10, 388},
+ dictWord{6, 11, 43},
+ dictWord{7, 11, 38},
+ dictWord{8, 11, 248},
+ dictWord{9, 11, 504},
+ dictWord{
+ 138,
+ 11,
+ 513,
+ },
+ dictWord{9, 0, 683},
+ dictWord{4, 10, 511},
+ dictWord{6, 10, 608},
+ dictWord{9, 10, 333},
+ dictWord{10, 10, 602},
+ dictWord{11, 10, 441},
+ dictWord{
+ 11,
+ 10,
+ 723,
+ },
+ dictWord{11, 10, 976},
+ dictWord{140, 10, 357},
+ dictWord{9, 0, 867},
+ dictWord{138, 0, 837},
+ dictWord{6, 0, 944},
+ dictWord{135, 11, 326},
+ dictWord{
+ 135,
+ 0,
+ 1809,
+ },
+ dictWord{5, 10, 938},
+ dictWord{7, 11, 783},
+ dictWord{136, 10, 707},
+ dictWord{133, 11, 766},
+ dictWord{133, 11, 363},
+ dictWord{6, 0, 170},
+ dictWord{7, 0, 1080},
+ dictWord{8, 0, 395},
+ dictWord{8, 0, 487},
+ dictWord{141, 0, 147},
+ dictWord{6, 11, 258},
+ dictWord{140, 11, 409},
+ dictWord{4, 0, 535},
+ dictWord{
+ 8,
+ 0,
+ 618,
+ },
+ dictWord{5, 11, 249},
+ dictWord{148, 11, 82},
+ dictWord{6, 0, 1379},
+ dictWord{149, 11, 15},
+ dictWord{135, 0, 1625},
+ dictWord{150, 0, 23},
+ dictWord{
+ 5,
+ 11,
+ 393,
+ },
+ dictWord{6, 11, 378},
+ dictWord{7, 11, 1981},
+ dictWord{9, 11, 32},
+ dictWord{9, 11, 591},
+ dictWord{10, 11, 685},
+ dictWord{10, 11, 741},
+ dictWord{
+ 142,
+ 11,
+ 382,
+ },
+ dictWord{133, 11, 788},
+ dictWord{7, 11, 1968},
+ dictWord{10, 11, 19},
+ dictWord{139, 11, 911},
+ dictWord{7, 11, 1401},
+ dictWord{
+ 135,
+ 11,
+ 1476,
+ },
+ dictWord{4, 11, 61},
+ dictWord{5, 11, 58},
+ dictWord{5, 11, 171},
+ dictWord{5, 11, 635},
+ dictWord{5, 11, 683},
+ dictWord{5, 11, 700},
+ dictWord{6, 11, 291},
+ dictWord{6, 11, 566},
+ dictWord{7, 11, 1650},
+ dictWord{11, 11, 523},
+ dictWord{12, 11, 273},
+ dictWord{12, 11, 303},
+ dictWord{15, 11, 39},
+ dictWord{
+ 143,
+ 11,
+ 111,
+ },
+ dictWord{6, 10, 469},
+ dictWord{7, 10, 1709},
+ dictWord{138, 10, 515},
+ dictWord{4, 0, 778},
+ dictWord{134, 11, 589},
+ dictWord{132, 0, 46},
+ dictWord{
+ 5,
+ 0,
+ 811,
+ },
+ dictWord{6, 0, 1679},
+ dictWord{6, 0, 1714},
+ dictWord{135, 0, 2032},
+ dictWord{7, 0, 1458},
+ dictWord{9, 0, 407},
+ dictWord{11, 0, 15},
+ dictWord{12, 0, 651},
+ dictWord{149, 0, 37},
+ dictWord{7, 0, 938},
+ dictWord{132, 10, 500},
+ dictWord{6, 0, 34},
+ dictWord{7, 0, 69},
+ dictWord{7, 0, 1089},
+ dictWord{7, 0, 1281},
+ dictWord{
+ 8,
+ 0,
+ 708,
+ },
+ dictWord{8, 0, 721},
+ dictWord{9, 0, 363},
+ dictWord{148, 0, 98},
+ dictWord{10, 11, 231},
+ dictWord{147, 11, 124},
+ dictWord{7, 11, 726},
+ dictWord{
+ 152,
+ 11,
+ 9,
+ },
+ dictWord{5, 10, 68},
+ dictWord{134, 10, 383},
+ dictWord{136, 11, 583},
+ dictWord{4, 11, 917},
+ dictWord{133, 11, 1005},
+ dictWord{11, 10, 216},
+ dictWord{139, 10, 340},
+ dictWord{135, 11, 1675},
+ dictWord{8, 0, 441},
+ dictWord{10, 0, 314},
+ dictWord{143, 0, 3},
+ dictWord{132, 11, 919},
+ dictWord{4, 10, 337},
+ dictWord{6, 10, 353},
+ dictWord{7, 10, 1934},
+ dictWord{8, 10, 488},
+ dictWord{137, 10, 429},
+ dictWord{7, 0, 889},
+ dictWord{7, 10, 1795},
+ dictWord{8, 10, 259},
+ dictWord{9, 10, 135},
+ dictWord{9, 10, 177},
+ dictWord{9, 10, 860},
+ dictWord{10, 10, 825},
+ dictWord{11, 10, 115},
+ dictWord{11, 10, 370},
+ dictWord{11, 10, 405},
+ dictWord{11, 10, 604},
+ dictWord{12, 10, 10},
+ dictWord{12, 10, 667},
+ dictWord{12, 10, 669},
+ dictWord{13, 10, 76},
+ dictWord{14, 10, 310},
+ dictWord{
+ 15,
+ 10,
+ 76,
+ },
+ dictWord{15, 10, 147},
+ dictWord{148, 10, 23},
+ dictWord{4, 10, 15},
+ dictWord{4, 11, 255},
+ dictWord{5, 10, 22},
+ dictWord{5, 11, 302},
+ dictWord{6, 11, 132},
+ dictWord{6, 10, 244},
+ dictWord{7, 10, 40},
+ dictWord{7, 11, 128},
+ dictWord{7, 10, 200},
+ dictWord{7, 11, 283},
+ dictWord{7, 10, 906},
+ dictWord{7, 10, 1199},
+ dictWord{
+ 7,
+ 11,
+ 1299,
+ },
+ dictWord{9, 10, 616},
+ dictWord{10, 11, 52},
+ dictWord{10, 11, 514},
+ dictWord{10, 10, 716},
+ dictWord{11, 10, 635},
+ dictWord{11, 10, 801},
+ dictWord{11, 11, 925},
+ dictWord{12, 10, 458},
+ dictWord{13, 11, 92},
+ dictWord{142, 11, 309},
+ dictWord{132, 0, 462},
+ dictWord{137, 11, 173},
+ dictWord{
+ 135,
+ 10,
+ 1735,
+ },
+ dictWord{8, 0, 525},
+ dictWord{5, 10, 598},
+ dictWord{7, 10, 791},
+ dictWord{8, 10, 108},
+ dictWord{137, 10, 123},
+ dictWord{5, 0, 73},
+ dictWord{6, 0, 23},
+ dictWord{134, 0, 338},
+ dictWord{132, 0, 676},
+ dictWord{132, 10, 683},
+ dictWord{7, 0, 725},
+ dictWord{8, 0, 498},
+ dictWord{139, 0, 268},
+ dictWord{12, 0, 21},
+ dictWord{151, 0, 7},
+ dictWord{135, 0, 773},
+ dictWord{4, 10, 155},
+ dictWord{135, 10, 1689},
+ dictWord{4, 0, 164},
+ dictWord{5, 0, 730},
+ dictWord{5, 10, 151},
+ dictWord{
+ 5,
+ 10,
+ 741,
+ },
+ dictWord{6, 11, 210},
+ dictWord{7, 10, 498},
+ dictWord{7, 10, 870},
+ dictWord{7, 10, 1542},
+ dictWord{12, 10, 213},
+ dictWord{14, 10, 36},
+ dictWord{
+ 14,
+ 10,
+ 391,
+ },
+ dictWord{17, 10, 111},
+ dictWord{18, 10, 6},
+ dictWord{18, 10, 46},
+ dictWord{18, 10, 151},
+ dictWord{19, 10, 36},
+ dictWord{20, 10, 32},
+ dictWord{
+ 20,
+ 10,
+ 56,
+ },
+ dictWord{20, 10, 69},
+ dictWord{20, 10, 102},
+ dictWord{21, 10, 4},
+ dictWord{22, 10, 8},
+ dictWord{22, 10, 10},
+ dictWord{22, 10, 14},
+ dictWord{
+ 150,
+ 10,
+ 31,
+ },
+ dictWord{4, 10, 624},
+ dictWord{135, 10, 1752},
+ dictWord{4, 0, 583},
+ dictWord{9, 0, 936},
+ dictWord{15, 0, 214},
+ dictWord{18, 0, 199},
+ dictWord{24, 0, 26},
+ dictWord{134, 11, 588},
+ dictWord{7, 0, 1462},
+ dictWord{11, 0, 659},
+ dictWord{4, 11, 284},
+ dictWord{134, 11, 223},
+ dictWord{133, 0, 220},
+ dictWord{
+ 139,
+ 0,
+ 803,
+ },
+ dictWord{132, 0, 544},
+ dictWord{4, 10, 492},
+ dictWord{133, 10, 451},
+ dictWord{16, 0, 98},
+ dictWord{148, 0, 119},
+ dictWord{4, 11, 218},
+ dictWord{
+ 7,
+ 11,
+ 526,
+ },
+ dictWord{143, 11, 137},
+ dictWord{135, 10, 835},
+ dictWord{4, 11, 270},
+ dictWord{5, 11, 192},
+ dictWord{6, 11, 332},
+ dictWord{7, 11, 1322},
+ dictWord{
+ 13,
+ 11,
+ 9,
+ },
+ dictWord{13, 10, 70},
+ dictWord{14, 11, 104},
+ dictWord{142, 11, 311},
+ dictWord{132, 10, 539},
+ dictWord{140, 11, 661},
+ dictWord{5, 0, 176},
+ dictWord{
+ 6,
+ 0,
+ 437,
+ },
+ dictWord{6, 0, 564},
+ dictWord{11, 0, 181},
+ dictWord{141, 0, 183},
+ dictWord{135, 0, 1192},
+ dictWord{6, 10, 113},
+ dictWord{135, 10, 436},
+ dictWord{136, 10, 718},
+ dictWord{135, 10, 520},
+ dictWord{135, 0, 1878},
+ dictWord{140, 11, 196},
+ dictWord{7, 11, 379},
+ dictWord{8, 11, 481},
+ dictWord{
+ 137,
+ 11,
+ 377,
+ },
+ dictWord{5, 11, 1003},
+ dictWord{6, 11, 149},
+ dictWord{137, 11, 746},
+ dictWord{8, 11, 262},
+ dictWord{9, 11, 627},
+ dictWord{10, 11, 18},
+ dictWord{
+ 11,
+ 11,
+ 214,
+ },
+ dictWord{11, 11, 404},
+ dictWord{11, 11, 457},
+ dictWord{11, 11, 780},
+ dictWord{11, 11, 849},
+ dictWord{11, 11, 913},
+ dictWord{13, 11, 330},
+ dictWord{13, 11, 401},
+ dictWord{142, 11, 200},
+ dictWord{149, 0, 26},
+ dictWord{136, 11, 304},
+ dictWord{132, 11, 142},
+ dictWord{135, 0, 944},
+ dictWord{
+ 4,
+ 0,
+ 790,
+ },
+ dictWord{5, 0, 273},
+ dictWord{134, 0, 394},
+ dictWord{134, 0, 855},
+ dictWord{4, 0, 135},
+ dictWord{6, 0, 127},
+ dictWord{7, 0, 1185},
+ dictWord{7, 0, 1511},
+ dictWord{8, 0, 613},
+ dictWord{11, 0, 5},
+ dictWord{12, 0, 336},
+ dictWord{12, 0, 495},
+ dictWord{12, 0, 586},
+ dictWord{12, 0, 660},
+ dictWord{12, 0, 668},
+ dictWord{
+ 14,
+ 0,
+ 385,
+ },
+ dictWord{15, 0, 118},
+ dictWord{17, 0, 20},
+ dictWord{146, 0, 98},
+ dictWord{6, 0, 230},
+ dictWord{9, 0, 752},
+ dictWord{18, 0, 109},
+ dictWord{12, 10, 610},
+ dictWord{13, 10, 431},
+ dictWord{144, 10, 59},
+ dictWord{7, 0, 1954},
+ dictWord{135, 11, 925},
+ dictWord{4, 11, 471},
+ dictWord{5, 11, 51},
+ dictWord{6, 11, 602},
+ dictWord{8, 11, 484},
+ dictWord{10, 11, 195},
+ dictWord{140, 11, 159},
+ dictWord{132, 10, 307},
+ dictWord{136, 11, 688},
+ dictWord{132, 11, 697},
+ dictWord{
+ 7,
+ 11,
+ 812,
+ },
+ dictWord{7, 11, 1261},
+ dictWord{7, 11, 1360},
+ dictWord{9, 11, 632},
+ dictWord{140, 11, 352},
+ dictWord{5, 0, 162},
+ dictWord{8, 0, 68},
+ dictWord{
+ 133,
+ 10,
+ 964,
+ },
+ dictWord{4, 0, 654},
+ dictWord{136, 11, 212},
+ dictWord{4, 0, 156},
+ dictWord{7, 0, 998},
+ dictWord{7, 0, 1045},
+ dictWord{7, 0, 1860},
+ dictWord{9, 0, 48},
+ dictWord{9, 0, 692},
+ dictWord{11, 0, 419},
+ dictWord{139, 0, 602},
+ dictWord{133, 11, 221},
+ dictWord{4, 11, 373},
+ dictWord{5, 11, 283},
+ dictWord{6, 11, 480},
+ dictWord{135, 11, 609},
+ dictWord{142, 11, 216},
+ dictWord{132, 0, 240},
+ dictWord{6, 11, 192},
+ dictWord{9, 11, 793},
+ dictWord{145, 11, 55},
+ dictWord{
+ 4,
+ 10,
+ 75,
+ },
+ dictWord{5, 10, 180},
+ dictWord{6, 10, 500},
+ dictWord{7, 10, 58},
+ dictWord{7, 10, 710},
+ dictWord{138, 10, 645},
+ dictWord{4, 11, 132},
+ dictWord{5, 11, 69},
+ dictWord{5, 10, 649},
+ dictWord{135, 11, 1242},
+ dictWord{6, 10, 276},
+ dictWord{7, 10, 282},
+ dictWord{7, 10, 879},
+ dictWord{7, 10, 924},
+ dictWord{8, 10, 459},
+ dictWord{9, 10, 599},
+ dictWord{9, 10, 754},
+ dictWord{11, 10, 574},
+ dictWord{12, 10, 128},
+ dictWord{12, 10, 494},
+ dictWord{13, 10, 52},
+ dictWord{13, 10, 301},
+ dictWord{15, 10, 30},
+ dictWord{143, 10, 132},
+ dictWord{132, 10, 200},
+ dictWord{4, 11, 111},
+ dictWord{135, 11, 302},
+ dictWord{9, 0, 197},
+ dictWord{
+ 10,
+ 0,
+ 300,
+ },
+ dictWord{12, 0, 473},
+ dictWord{13, 0, 90},
+ dictWord{141, 0, 405},
+ dictWord{132, 11, 767},
+ dictWord{6, 11, 42},
+ dictWord{7, 11, 1416},
+ dictWord{
+ 7,
+ 11,
+ 1590,
+ },
+ dictWord{7, 11, 2005},
+ dictWord{8, 11, 131},
+ dictWord{8, 11, 466},
+ dictWord{9, 11, 672},
+ dictWord{13, 11, 252},
+ dictWord{148, 11, 103},
+ dictWord{
+ 8,
+ 0,
+ 958,
+ },
+ dictWord{8, 0, 999},
+ dictWord{10, 0, 963},
+ dictWord{138, 0, 1001},
+ dictWord{135, 10, 1621},
+ dictWord{135, 0, 858},
+ dictWord{4, 0, 606},
+ dictWord{
+ 137,
+ 11,
+ 444,
+ },
+ dictWord{6, 11, 44},
+ dictWord{136, 11, 368},
+ dictWord{139, 11, 172},
+ dictWord{4, 11, 570},
+ dictWord{133, 11, 120},
+ dictWord{139, 11, 624},
+ dictWord{7, 0, 1978},
+ dictWord{8, 0, 676},
+ dictWord{6, 10, 225},
+ dictWord{137, 10, 211},
+ dictWord{7, 0, 972},
+ dictWord{11, 0, 102},
+ dictWord{136, 10, 687},
+ dictWord{6, 11, 227},
+ dictWord{135, 11, 1589},
+ dictWord{8, 10, 58},
+ dictWord{9, 10, 724},
+ dictWord{11, 10, 809},
+ dictWord{13, 10, 113},
+ dictWord{
+ 145,
+ 10,
+ 72,
+ },
+ dictWord{4, 0, 361},
+ dictWord{133, 0, 315},
+ dictWord{132, 0, 461},
+ dictWord{6, 10, 345},
+ dictWord{135, 10, 1247},
+ dictWord{132, 0, 472},
+ dictWord{
+ 8,
+ 10,
+ 767,
+ },
+ dictWord{8, 10, 803},
+ dictWord{9, 10, 301},
+ dictWord{137, 10, 903},
+ dictWord{135, 11, 1333},
+ dictWord{135, 11, 477},
+ dictWord{7, 10, 1949},
+ dictWord{136, 10, 674},
+ dictWord{6, 0, 905},
+ dictWord{138, 0, 747},
+ dictWord{133, 0, 155},
+ dictWord{134, 10, 259},
+ dictWord{7, 0, 163},
+ dictWord{8, 0, 319},
+ dictWord{9, 0, 402},
+ dictWord{10, 0, 24},
+ dictWord{10, 0, 681},
+ dictWord{11, 0, 200},
+ dictWord{12, 0, 253},
+ dictWord{12, 0, 410},
+ dictWord{142, 0, 219},
+ dictWord{
+ 5,
+ 0,
+ 475,
+ },
+ dictWord{7, 0, 1780},
+ dictWord{9, 0, 230},
+ dictWord{11, 0, 297},
+ dictWord{11, 0, 558},
+ dictWord{14, 0, 322},
+ dictWord{19, 0, 76},
+ dictWord{6, 11, 1667},
+ dictWord{7, 11, 2036},
+ dictWord{138, 11, 600},
+ dictWord{136, 10, 254},
+ dictWord{6, 0, 848},
+ dictWord{135, 0, 1956},
+ dictWord{6, 11, 511},
+ dictWord{
+ 140,
+ 11,
+ 132,
+ },
+ dictWord{5, 11, 568},
+ dictWord{6, 11, 138},
+ dictWord{135, 11, 1293},
+ dictWord{6, 0, 631},
+ dictWord{137, 0, 838},
+ dictWord{149, 0, 36},
+ dictWord{
+ 4,
+ 11,
+ 565,
+ },
+ dictWord{8, 11, 23},
+ dictWord{136, 11, 827},
+ dictWord{5, 0, 944},
+ dictWord{134, 0, 1769},
+ dictWord{4, 0, 144},
+ dictWord{6, 0, 842},
+ dictWord{
+ 6,
+ 0,
+ 1400,
+ },
+ dictWord{4, 11, 922},
+ dictWord{133, 11, 1023},
+ dictWord{133, 10, 248},
+ dictWord{9, 10, 800},
+ dictWord{10, 10, 693},
+ dictWord{11, 10, 482},
+ dictWord{11, 10, 734},
+ dictWord{139, 10, 789},
+ dictWord{7, 11, 1002},
+ dictWord{139, 11, 145},
+ dictWord{4, 10, 116},
+ dictWord{5, 10, 95},
+ dictWord{5, 10, 445},
+ dictWord{7, 10, 1688},
+ dictWord{8, 10, 29},
+ dictWord{9, 10, 272},
+ dictWord{11, 10, 509},
+ dictWord{139, 10, 915},
+ dictWord{14, 0, 369},
+ dictWord{146, 0, 72},
+ dictWord{135, 10, 1641},
+ dictWord{132, 11, 740},
+ dictWord{133, 10, 543},
+ dictWord{140, 11, 116},
+ dictWord{6, 0, 247},
+ dictWord{9, 0, 555},
+ dictWord{
+ 5,
+ 10,
+ 181,
+ },
+ dictWord{136, 10, 41},
+ dictWord{133, 10, 657},
+ dictWord{136, 0, 996},
+ dictWord{138, 10, 709},
+ dictWord{7, 0, 189},
+ dictWord{8, 10, 202},
+ dictWord{
+ 138,
+ 10,
+ 536,
+ },
+ dictWord{136, 11, 402},
+ dictWord{4, 11, 716},
+ dictWord{141, 11, 31},
+ dictWord{10, 0, 280},
+ dictWord{138, 0, 797},
+ dictWord{9, 10, 423},
+ dictWord{140, 10, 89},
+ dictWord{8, 10, 113},
+ dictWord{9, 10, 877},
+ dictWord{10, 10, 554},
+ dictWord{11, 10, 83},
+ dictWord{12, 10, 136},
+ dictWord{147, 10, 109},
+ dictWord{133, 10, 976},
+ dictWord{7, 0, 746},
+ dictWord{132, 10, 206},
+ dictWord{136, 0, 526},
+ dictWord{139, 0, 345},
+ dictWord{136, 0, 1017},
+ dictWord{
+ 8,
+ 11,
+ 152,
+ },
+ dictWord{9, 11, 53},
+ dictWord{9, 11, 268},
+ dictWord{9, 11, 901},
+ dictWord{10, 11, 518},
+ dictWord{10, 11, 829},
+ dictWord{11, 11, 188},
+ dictWord{
+ 13,
+ 11,
+ 74,
+ },
+ dictWord{14, 11, 46},
+ dictWord{15, 11, 17},
+ dictWord{15, 11, 33},
+ dictWord{17, 11, 40},
+ dictWord{18, 11, 36},
+ dictWord{19, 11, 20},
+ dictWord{22, 11, 1},
+ dictWord{152, 11, 2},
+ dictWord{133, 11, 736},
+ dictWord{136, 11, 532},
+ dictWord{5, 0, 428},
+ dictWord{138, 0, 651},
+ dictWord{135, 11, 681},
+ dictWord{
+ 135,
+ 0,
+ 1162,
+ },
+ dictWord{7, 0, 327},
+ dictWord{13, 0, 230},
+ dictWord{17, 0, 113},
+ dictWord{8, 10, 226},
+ dictWord{10, 10, 537},
+ dictWord{11, 10, 570},
+ dictWord{
+ 11,
+ 10,
+ 605,
+ },
+ dictWord{11, 10, 799},
+ dictWord{11, 10, 804},
+ dictWord{12, 10, 85},
+ dictWord{12, 10, 516},
+ dictWord{12, 10, 623},
+ dictWord{12, 11, 677},
+ dictWord{
+ 13,
+ 10,
+ 361,
+ },
+ dictWord{14, 10, 77},
+ dictWord{14, 10, 78},
+ dictWord{147, 10, 110},
+ dictWord{4, 0, 792},
+ dictWord{7, 0, 1717},
+ dictWord{10, 0, 546},
+ dictWord{
+ 132,
+ 10,
+ 769,
+ },
+ dictWord{4, 11, 684},
+ dictWord{136, 11, 384},
+ dictWord{132, 10, 551},
+ dictWord{134, 0, 1203},
+ dictWord{9, 10, 57},
+ dictWord{9, 10, 459},
+ dictWord{10, 10, 425},
+ dictWord{11, 10, 119},
+ dictWord{12, 10, 184},
+ dictWord{12, 10, 371},
+ dictWord{13, 10, 358},
+ dictWord{145, 10, 51},
+ dictWord{5, 0, 672},
+ dictWord{5, 10, 814},
+ dictWord{8, 10, 10},
+ dictWord{9, 10, 421},
+ dictWord{9, 10, 729},
+ dictWord{10, 10, 609},
+ dictWord{139, 10, 689},
+ dictWord{138, 0, 189},
+ dictWord{134, 10, 624},
+ dictWord{7, 11, 110},
+ dictWord{7, 11, 188},
+ dictWord{8, 11, 290},
+ dictWord{8, 11, 591},
+ dictWord{9, 11, 382},
+ dictWord{9, 11, 649},
+ dictWord{11, 11, 71},
+ dictWord{11, 11, 155},
+ dictWord{11, 11, 313},
+ dictWord{12, 11, 5},
+ dictWord{13, 11, 325},
+ dictWord{142, 11, 287},
+ dictWord{133, 0, 99},
+ dictWord{6, 0, 1053},
+ dictWord{135, 0, 298},
+ dictWord{7, 11, 360},
+ dictWord{7, 11, 425},
+ dictWord{9, 11, 66},
+ dictWord{9, 11, 278},
+ dictWord{138, 11, 644},
+ dictWord{4, 0, 397},
+ dictWord{136, 0, 555},
+ dictWord{137, 10, 269},
+ dictWord{132, 10, 528},
+ dictWord{4, 11, 900},
+ dictWord{133, 11, 861},
+ dictWord{
+ 6,
+ 0,
+ 1157,
+ },
+ dictWord{5, 11, 254},
+ dictWord{7, 11, 985},
+ dictWord{136, 11, 73},
+ dictWord{7, 11, 1959},
+ dictWord{136, 11, 683},
+ dictWord{12, 0, 398},
+ dictWord{
+ 20,
+ 0,
+ 39,
+ },
+ dictWord{21, 0, 11},
+ dictWord{150, 0, 41},
+ dictWord{4, 0, 485},
+ dictWord{7, 0, 353},
+ dictWord{135, 0, 1523},
+ dictWord{6, 0, 366},
+ dictWord{7, 0, 1384},
+ dictWord{135, 0, 1601},
+ dictWord{138, 0, 787},
+ dictWord{137, 0, 282},
+ dictWord{5, 10, 104},
+ dictWord{6, 10, 173},
+ dictWord{135, 10, 1631},
+ dictWord{
+ 139,
+ 11,
+ 146,
+ },
+ dictWord{4, 0, 157},
+ dictWord{133, 0, 471},
+ dictWord{134, 0, 941},
+ dictWord{132, 11, 725},
+ dictWord{7, 0, 1336},
+ dictWord{8, 10, 138},
+ dictWord{
+ 8,
+ 10,
+ 342,
+ },
+ dictWord{9, 10, 84},
+ dictWord{10, 10, 193},
+ dictWord{11, 10, 883},
+ dictWord{140, 10, 359},
+ dictWord{134, 11, 196},
+ dictWord{136, 0, 116},
+ dictWord{133, 11, 831},
+ dictWord{134, 0, 787},
+ dictWord{134, 10, 95},
+ dictWord{6, 10, 406},
+ dictWord{10, 10, 409},
+ dictWord{10, 10, 447},
+ dictWord{
+ 11,
+ 10,
+ 44,
+ },
+ dictWord{140, 10, 100},
+ dictWord{5, 0, 160},
+ dictWord{7, 0, 363},
+ dictWord{7, 0, 589},
+ dictWord{10, 0, 170},
+ dictWord{141, 0, 55},
+ dictWord{134, 0, 1815},
+ dictWord{132, 0, 866},
+ dictWord{6, 0, 889},
+ dictWord{6, 0, 1067},
+ dictWord{6, 0, 1183},
+ dictWord{4, 11, 321},
+ dictWord{134, 11, 569},
+ dictWord{5, 11, 848},
+ dictWord{134, 11, 66},
+ dictWord{4, 11, 36},
+ dictWord{6, 10, 1636},
+ dictWord{7, 11, 1387},
+ dictWord{10, 11, 205},
+ dictWord{11, 11, 755},
+ dictWord{
+ 141,
+ 11,
+ 271,
+ },
+ dictWord{132, 0, 689},
+ dictWord{9, 0, 820},
+ dictWord{4, 10, 282},
+ dictWord{7, 10, 1034},
+ dictWord{11, 10, 398},
+ dictWord{11, 10, 634},
+ dictWord{
+ 12,
+ 10,
+ 1,
+ },
+ dictWord{12, 10, 79},
+ dictWord{12, 10, 544},
+ dictWord{14, 10, 237},
+ dictWord{17, 10, 10},
+ dictWord{146, 10, 20},
+ dictWord{4, 0, 108},
+ dictWord{7, 0, 804},
+ dictWord{139, 0, 498},
+ dictWord{132, 11, 887},
+ dictWord{6, 0, 1119},
+ dictWord{135, 11, 620},
+ dictWord{6, 11, 165},
+ dictWord{138, 11, 388},
+ dictWord{
+ 5,
+ 0,
+ 244,
+ },
+ dictWord{5, 10, 499},
+ dictWord{6, 10, 476},
+ dictWord{7, 10, 600},
+ dictWord{7, 10, 888},
+ dictWord{135, 10, 1096},
+ dictWord{140, 0, 609},
+ dictWord{
+ 135,
+ 0,
+ 1005,
+ },
+ dictWord{4, 0, 412},
+ dictWord{133, 0, 581},
+ dictWord{4, 11, 719},
+ dictWord{135, 11, 155},
+ dictWord{7, 10, 296},
+ dictWord{7, 10, 596},
+ dictWord{
+ 8,
+ 10,
+ 560,
+ },
+ dictWord{8, 10, 586},
+ dictWord{9, 10, 612},
+ dictWord{11, 10, 304},
+ dictWord{12, 10, 46},
+ dictWord{13, 10, 89},
+ dictWord{14, 10, 112},
+ dictWord{
+ 145,
+ 10,
+ 122,
+ },
+ dictWord{4, 0, 895},
+ dictWord{133, 0, 772},
+ dictWord{142, 11, 307},
+ dictWord{135, 0, 1898},
+ dictWord{4, 0, 926},
+ dictWord{133, 0, 983},
+ dictWord{4, 11, 353},
+ dictWord{6, 11, 146},
+ dictWord{6, 11, 1789},
+ dictWord{7, 11, 288},
+ dictWord{7, 11, 990},
+ dictWord{7, 11, 1348},
+ dictWord{9, 11, 665},
+ dictWord{
+ 9,
+ 11,
+ 898,
+ },
+ dictWord{11, 11, 893},
+ dictWord{142, 11, 212},
+ dictWord{132, 0, 538},
+ dictWord{133, 11, 532},
+ dictWord{6, 0, 294},
+ dictWord{7, 0, 1267},
+ dictWord{8, 0, 624},
+ dictWord{141, 0, 496},
+ dictWord{7, 0, 1325},
+ dictWord{4, 11, 45},
+ dictWord{135, 11, 1257},
+ dictWord{138, 0, 301},
+ dictWord{9, 0, 298},
+ dictWord{12, 0, 291},
+ dictWord{13, 0, 276},
+ dictWord{14, 0, 6},
+ dictWord{17, 0, 18},
+ dictWord{21, 0, 32},
+ dictWord{7, 10, 1599},
+ dictWord{7, 10, 1723},
+ dictWord{
+ 8,
+ 10,
+ 79,
+ },
+ dictWord{8, 10, 106},
+ dictWord{8, 10, 190},
+ dictWord{8, 10, 302},
+ dictWord{8, 10, 383},
+ dictWord{8, 10, 713},
+ dictWord{9, 10, 119},
+ dictWord{9, 10, 233},
+ dictWord{9, 10, 419},
+ dictWord{9, 10, 471},
+ dictWord{10, 10, 181},
+ dictWord{10, 10, 406},
+ dictWord{11, 10, 57},
+ dictWord{11, 10, 85},
+ dictWord{11, 10, 120},
+ dictWord{11, 10, 177},
+ dictWord{11, 10, 296},
+ dictWord{11, 10, 382},
+ dictWord{11, 10, 454},
+ dictWord{11, 10, 758},
+ dictWord{11, 10, 999},
+ dictWord{
+ 12,
+ 10,
+ 27,
+ },
+ dictWord{12, 10, 131},
+ dictWord{12, 10, 245},
+ dictWord{12, 10, 312},
+ dictWord{12, 10, 446},
+ dictWord{12, 10, 454},
+ dictWord{13, 10, 98},
+ dictWord{
+ 13,
+ 10,
+ 426,
+ },
+ dictWord{13, 10, 508},
+ dictWord{14, 10, 163},
+ dictWord{14, 10, 272},
+ dictWord{14, 10, 277},
+ dictWord{14, 10, 370},
+ dictWord{15, 10, 95},
+ dictWord{15, 10, 138},
+ dictWord{15, 10, 167},
+ dictWord{17, 10, 38},
+ dictWord{148, 10, 96},
+ dictWord{132, 0, 757},
+ dictWord{134, 0, 1263},
+ dictWord{4, 0, 820},
+ dictWord{134, 10, 1759},
+ dictWord{133, 0, 722},
+ dictWord{136, 11, 816},
+ dictWord{138, 10, 372},
+ dictWord{145, 10, 16},
+ dictWord{134, 0, 1039},
+ dictWord{
+ 4,
+ 0,
+ 991,
+ },
+ dictWord{134, 0, 2028},
+ dictWord{133, 10, 258},
+ dictWord{7, 0, 1875},
+ dictWord{139, 0, 124},
+ dictWord{6, 11, 559},
+ dictWord{6, 11, 1691},
+ dictWord{135, 11, 586},
+ dictWord{5, 0, 324},
+ dictWord{7, 0, 881},
+ dictWord{8, 10, 134},
+ dictWord{9, 10, 788},
+ dictWord{140, 10, 438},
+ dictWord{7, 11, 1823},
+ dictWord{139, 11, 693},
+ dictWord{6, 0, 1348},
+ dictWord{134, 0, 1545},
+ dictWord{134, 0, 911},
+ dictWord{132, 0, 954},
+ dictWord{8, 0, 329},
+ dictWord{8, 0, 414},
+ dictWord{7, 10, 1948},
+ dictWord{135, 10, 2004},
+ dictWord{5, 0, 517},
+ dictWord{6, 10, 439},
+ dictWord{7, 10, 780},
+ dictWord{135, 10, 1040},
+ dictWord{
+ 132,
+ 0,
+ 816,
+ },
+ dictWord{5, 10, 1},
+ dictWord{6, 10, 81},
+ dictWord{138, 10, 520},
+ dictWord{9, 0, 713},
+ dictWord{10, 0, 222},
+ dictWord{5, 10, 482},
+ dictWord{8, 10, 98},
+ dictWord{10, 10, 700},
+ dictWord{10, 10, 822},
+ dictWord{11, 10, 302},
+ dictWord{11, 10, 778},
+ dictWord{12, 10, 50},
+ dictWord{12, 10, 127},
+ dictWord{12, 10, 396},
+ dictWord{13, 10, 62},
+ dictWord{13, 10, 328},
+ dictWord{14, 10, 122},
+ dictWord{147, 10, 72},
+ dictWord{137, 0, 33},
+ dictWord{5, 10, 2},
+ dictWord{7, 10, 1494},
+ dictWord{136, 10, 589},
+ dictWord{6, 10, 512},
+ dictWord{7, 10, 797},
+ dictWord{8, 10, 253},
+ dictWord{9, 10, 77},
+ dictWord{10, 10, 1},
+ dictWord{10, 11, 108},
+ dictWord{10, 10, 129},
+ dictWord{10, 10, 225},
+ dictWord{11, 11, 116},
+ dictWord{11, 10, 118},
+ dictWord{11, 10, 226},
+ dictWord{11, 10, 251},
+ dictWord{
+ 11,
+ 10,
+ 430,
+ },
+ dictWord{11, 10, 701},
+ dictWord{11, 10, 974},
+ dictWord{11, 10, 982},
+ dictWord{12, 10, 64},
+ dictWord{12, 10, 260},
+ dictWord{12, 10, 488},
+ dictWord{
+ 140,
+ 10,
+ 690,
+ },
+ dictWord{134, 11, 456},
+ dictWord{133, 11, 925},
+ dictWord{5, 0, 150},
+ dictWord{7, 0, 106},
+ dictWord{7, 0, 774},
+ dictWord{8, 0, 603},
+ dictWord{
+ 9,
+ 0,
+ 593,
+ },
+ dictWord{9, 0, 634},
+ dictWord{10, 0, 44},
+ dictWord{10, 0, 173},
+ dictWord{11, 0, 462},
+ dictWord{11, 0, 515},
+ dictWord{13, 0, 216},
+ dictWord{13, 0, 288},
+ dictWord{142, 0, 400},
+ dictWord{137, 10, 347},
+ dictWord{5, 0, 748},
+ dictWord{134, 0, 553},
+ dictWord{12, 0, 108},
+ dictWord{141, 0, 291},
+ dictWord{7, 0, 420},
+ dictWord{4, 10, 12},
+ dictWord{7, 10, 522},
+ dictWord{7, 10, 809},
+ dictWord{8, 10, 797},
+ dictWord{141, 10, 88},
+ dictWord{6, 11, 193},
+ dictWord{7, 11, 240},
+ dictWord{
+ 7,
+ 11,
+ 1682,
+ },
+ dictWord{10, 11, 51},
+ dictWord{10, 11, 640},
+ dictWord{11, 11, 410},
+ dictWord{13, 11, 82},
+ dictWord{14, 11, 247},
+ dictWord{14, 11, 331},
+ dictWord{142, 11, 377},
+ dictWord{133, 10, 528},
+ dictWord{135, 0, 1777},
+ dictWord{4, 0, 493},
+ dictWord{144, 0, 55},
+ dictWord{136, 11, 633},
+ dictWord{
+ 139,
+ 0,
+ 81,
+ },
+ dictWord{6, 0, 980},
+ dictWord{136, 0, 321},
+ dictWord{148, 10, 109},
+ dictWord{5, 10, 266},
+ dictWord{9, 10, 290},
+ dictWord{9, 10, 364},
+ dictWord{
+ 10,
+ 10,
+ 293,
+ },
+ dictWord{11, 10, 606},
+ dictWord{142, 10, 45},
+ dictWord{6, 0, 568},
+ dictWord{7, 0, 112},
+ dictWord{7, 0, 1804},
+ dictWord{8, 0, 362},
+ dictWord{8, 0, 410},
+ dictWord{8, 0, 830},
+ dictWord{9, 0, 514},
+ dictWord{11, 0, 649},
+ dictWord{142, 0, 157},
+ dictWord{4, 0, 74},
+ dictWord{6, 0, 510},
+ dictWord{6, 10, 594},
+ dictWord{
+ 9,
+ 10,
+ 121,
+ },
+ dictWord{10, 10, 49},
+ dictWord{10, 10, 412},
+ dictWord{139, 10, 834},
+ dictWord{134, 0, 838},
+ dictWord{136, 10, 748},
+ dictWord{132, 10, 466},
+ dictWord{132, 0, 625},
+ dictWord{135, 11, 1443},
+ dictWord{4, 11, 237},
+ dictWord{135, 11, 514},
+ dictWord{9, 10, 378},
+ dictWord{141, 10, 162},
+ dictWord{6, 0, 16},
+ dictWord{6, 0, 158},
+ dictWord{7, 0, 43},
+ dictWord{7, 0, 129},
+ dictWord{7, 0, 181},
+ dictWord{8, 0, 276},
+ dictWord{8, 0, 377},
+ dictWord{10, 0, 523},
+ dictWord{
+ 11,
+ 0,
+ 816,
+ },
+ dictWord{12, 0, 455},
+ dictWord{13, 0, 303},
+ dictWord{142, 0, 135},
+ dictWord{135, 0, 281},
+ dictWord{4, 0, 1},
+ dictWord{7, 0, 1143},
+ dictWord{7, 0, 1463},
+ dictWord{8, 0, 61},
+ dictWord{9, 0, 207},
+ dictWord{9, 0, 390},
+ dictWord{9, 0, 467},
+ dictWord{139, 0, 836},
+ dictWord{6, 11, 392},
+ dictWord{7, 11, 65},
+ dictWord{
+ 135,
+ 11,
+ 2019,
+ },
+ dictWord{132, 10, 667},
+ dictWord{4, 0, 723},
+ dictWord{5, 0, 895},
+ dictWord{7, 0, 1031},
+ dictWord{8, 0, 199},
+ dictWord{8, 0, 340},
+ dictWord{9, 0, 153},
+ dictWord{9, 0, 215},
+ dictWord{10, 0, 21},
+ dictWord{10, 0, 59},
+ dictWord{10, 0, 80},
+ dictWord{10, 0, 224},
+ dictWord{10, 0, 838},
+ dictWord{11, 0, 229},
+ dictWord{
+ 11,
+ 0,
+ 652,
+ },
+ dictWord{12, 0, 192},
+ dictWord{13, 0, 146},
+ dictWord{142, 0, 91},
+ dictWord{132, 0, 295},
+ dictWord{137, 0, 51},
+ dictWord{9, 11, 222},
+ dictWord{
+ 10,
+ 11,
+ 43,
+ },
+ dictWord{139, 11, 900},
+ dictWord{5, 0, 309},
+ dictWord{140, 0, 211},
+ dictWord{5, 0, 125},
+ dictWord{8, 0, 77},
+ dictWord{138, 0, 15},
+ dictWord{136, 11, 604},
+ dictWord{138, 0, 789},
+ dictWord{5, 0, 173},
+ dictWord{4, 10, 39},
+ dictWord{7, 10, 1843},
+ dictWord{8, 10, 407},
+ dictWord{11, 10, 144},
+ dictWord{140, 10, 523},
+ dictWord{138, 11, 265},
+ dictWord{133, 0, 439},
+ dictWord{132, 10, 510},
+ dictWord{7, 0, 648},
+ dictWord{7, 0, 874},
+ dictWord{11, 0, 164},
+ dictWord{12, 0, 76},
+ dictWord{18, 0, 9},
+ dictWord{7, 10, 1980},
+ dictWord{10, 10, 487},
+ dictWord{138, 10, 809},
+ dictWord{12, 0, 111},
+ dictWord{14, 0, 294},
+ dictWord{19, 0, 45},
+ dictWord{13, 10, 260},
+ dictWord{146, 10, 63},
+ dictWord{133, 11, 549},
+ dictWord{134, 10, 570},
+ dictWord{4, 0, 8},
+ dictWord{7, 0, 1152},
+ dictWord{7, 0, 1153},
+ dictWord{7, 0, 1715},
+ dictWord{9, 0, 374},
+ dictWord{10, 0, 478},
+ dictWord{139, 0, 648},
+ dictWord{135, 0, 1099},
+ dictWord{5, 0, 575},
+ dictWord{6, 0, 354},
+ dictWord{
+ 135,
+ 0,
+ 701,
+ },
+ dictWord{7, 11, 36},
+ dictWord{8, 11, 201},
+ dictWord{136, 11, 605},
+ dictWord{4, 10, 787},
+ dictWord{136, 11, 156},
+ dictWord{6, 0, 518},
+ dictWord{
+ 149,
+ 11,
+ 13,
+ },
+ dictWord{140, 11, 224},
+ dictWord{134, 0, 702},
+ dictWord{132, 10, 516},
+ dictWord{5, 11, 724},
+ dictWord{10, 11, 305},
+ dictWord{11, 11, 151},
+ dictWord{12, 11, 33},
+ dictWord{12, 11, 121},
+ dictWord{12, 11, 381},
+ dictWord{17, 11, 3},
+ dictWord{17, 11, 27},
+ dictWord{17, 11, 78},
+ dictWord{18, 11, 18},
+ dictWord{19, 11, 54},
+ dictWord{149, 11, 5},
+ dictWord{8, 0, 87},
+ dictWord{4, 11, 523},
+ dictWord{5, 11, 638},
+ dictWord{11, 10, 887},
+ dictWord{14, 10, 365},
+ dictWord{
+ 142,
+ 10,
+ 375,
+ },
+ dictWord{138, 0, 438},
+ dictWord{136, 10, 821},
+ dictWord{135, 11, 1908},
+ dictWord{6, 11, 242},
+ dictWord{7, 11, 227},
+ dictWord{7, 11, 1581},
+ dictWord{8, 11, 104},
+ dictWord{9, 11, 113},
+ dictWord{9, 11, 220},
+ dictWord{9, 11, 427},
+ dictWord{10, 11, 74},
+ dictWord{10, 11, 239},
+ dictWord{11, 11, 579},
+ dictWord{11, 11, 1023},
+ dictWord{13, 11, 4},
+ dictWord{13, 11, 204},
+ dictWord{13, 11, 316},
+ dictWord{18, 11, 95},
+ dictWord{148, 11, 86},
+ dictWord{4, 0, 69},
+ dictWord{5, 0, 122},
+ dictWord{5, 0, 849},
+ dictWord{6, 0, 1633},
+ dictWord{9, 0, 656},
+ dictWord{138, 0, 464},
+ dictWord{7, 0, 1802},
+ dictWord{4, 10, 10},
+ dictWord{
+ 139,
+ 10,
+ 786,
+ },
+ dictWord{135, 11, 861},
+ dictWord{139, 0, 499},
+ dictWord{7, 0, 476},
+ dictWord{7, 0, 1592},
+ dictWord{138, 0, 87},
+ dictWord{133, 10, 684},
+ dictWord{
+ 4,
+ 0,
+ 840,
+ },
+ dictWord{134, 10, 27},
+ dictWord{142, 0, 283},
+ dictWord{6, 0, 1620},
+ dictWord{7, 11, 1328},
+ dictWord{136, 11, 494},
+ dictWord{5, 0, 859},
+ dictWord{
+ 7,
+ 0,
+ 1160,
+ },
+ dictWord{8, 0, 107},
+ dictWord{9, 0, 291},
+ dictWord{9, 0, 439},
+ dictWord{10, 0, 663},
+ dictWord{11, 0, 609},
+ dictWord{140, 0, 197},
+ dictWord{
+ 7,
+ 11,
+ 1306,
+ },
+ dictWord{8, 11, 505},
+ dictWord{9, 11, 482},
+ dictWord{10, 11, 126},
+ dictWord{11, 11, 225},
+ dictWord{12, 11, 347},
+ dictWord{12, 11, 449},
+ dictWord{
+ 13,
+ 11,
+ 19,
+ },
+ dictWord{142, 11, 218},
+ dictWord{5, 11, 268},
+ dictWord{10, 11, 764},
+ dictWord{12, 11, 120},
+ dictWord{13, 11, 39},
+ dictWord{145, 11, 127},
+ dictWord{145, 10, 56},
+ dictWord{7, 11, 1672},
+ dictWord{10, 11, 472},
+ dictWord{11, 11, 189},
+ dictWord{143, 11, 51},
+ dictWord{6, 10, 342},
+ dictWord{6, 10, 496},
+ dictWord{8, 10, 275},
+ dictWord{137, 10, 206},
+ dictWord{133, 0, 600},
+ dictWord{4, 0, 117},
+ dictWord{6, 0, 372},
+ dictWord{7, 0, 1905},
+ dictWord{142, 0, 323},
+ dictWord{4, 10, 909},
+ dictWord{5, 10, 940},
+ dictWord{135, 11, 1471},
+ dictWord{132, 10, 891},
+ dictWord{4, 0, 722},
+ dictWord{139, 0, 471},
+ dictWord{4, 11, 384},
+ dictWord{135, 11, 1022},
+ dictWord{132, 10, 687},
+ dictWord{9, 0, 5},
+ dictWord{12, 0, 216},
+ dictWord{12, 0, 294},
+ dictWord{12, 0, 298},
+ dictWord{12, 0, 400},
+ dictWord{12, 0, 518},
+ dictWord{13, 0, 229},
+ dictWord{143, 0, 139},
+ dictWord{135, 11, 1703},
+ dictWord{7, 11, 1602},
+ dictWord{10, 11, 698},
+ dictWord{
+ 12,
+ 11,
+ 212,
+ },
+ dictWord{141, 11, 307},
+ dictWord{6, 10, 41},
+ dictWord{141, 10, 160},
+ dictWord{135, 11, 1077},
+ dictWord{9, 11, 159},
+ dictWord{11, 11, 28},
+ dictWord{140, 11, 603},
+ dictWord{4, 0, 514},
+ dictWord{7, 0, 1304},
+ dictWord{138, 0, 477},
+ dictWord{134, 0, 1774},
+ dictWord{9, 0, 88},
+ dictWord{139, 0, 270},
+ dictWord{5, 0, 12},
+ dictWord{7, 0, 375},
+ dictWord{9, 0, 438},
+ dictWord{134, 10, 1718},
+ dictWord{132, 11, 515},
+ dictWord{136, 10, 778},
+ dictWord{8, 11, 632},
+ dictWord{8, 11, 697},
+ dictWord{137, 11, 854},
+ dictWord{6, 0, 362},
+ dictWord{6, 0, 997},
+ dictWord{146, 0, 51},
+ dictWord{7, 0, 816},
+ dictWord{7, 0, 1241},
+ dictWord{
+ 9,
+ 0,
+ 283,
+ },
+ dictWord{9, 0, 520},
+ dictWord{10, 0, 213},
+ dictWord{10, 0, 307},
+ dictWord{10, 0, 463},
+ dictWord{10, 0, 671},
+ dictWord{10, 0, 746},
+ dictWord{11, 0, 401},
+ dictWord{11, 0, 794},
+ dictWord{12, 0, 517},
+ dictWord{18, 0, 107},
+ dictWord{147, 0, 115},
+ dictWord{133, 10, 115},
+ dictWord{150, 11, 28},
+ dictWord{4, 11, 136},
+ dictWord{133, 11, 551},
+ dictWord{142, 10, 314},
+ dictWord{132, 0, 258},
+ dictWord{6, 0, 22},
+ dictWord{7, 0, 903},
+ dictWord{7, 0, 1963},
+ dictWord{8, 0, 639},
+ dictWord{138, 0, 577},
+ dictWord{5, 0, 681},
+ dictWord{8, 0, 782},
+ dictWord{13, 0, 130},
+ dictWord{17, 0, 84},
+ dictWord{5, 10, 193},
+ dictWord{140, 10, 178},
+ dictWord{
+ 9,
+ 11,
+ 17,
+ },
+ dictWord{138, 11, 291},
+ dictWord{7, 11, 1287},
+ dictWord{9, 11, 44},
+ dictWord{10, 11, 552},
+ dictWord{10, 11, 642},
+ dictWord{11, 11, 839},
+ dictWord{12, 11, 274},
+ dictWord{12, 11, 275},
+ dictWord{12, 11, 372},
+ dictWord{13, 11, 91},
+ dictWord{142, 11, 125},
+ dictWord{135, 10, 174},
+ dictWord{4, 0, 664},
+ dictWord{5, 0, 804},
+ dictWord{139, 0, 1013},
+ dictWord{134, 0, 942},
+ dictWord{6, 0, 1349},
+ dictWord{6, 0, 1353},
+ dictWord{6, 0, 1450},
+ dictWord{7, 11, 1518},
+ dictWord{139, 11, 694},
+ dictWord{11, 0, 356},
+ dictWord{4, 10, 122},
+ dictWord{5, 10, 796},
+ dictWord{5, 10, 952},
+ dictWord{6, 10, 1660},
+ dictWord{
+ 6,
+ 10,
+ 1671,
+ },
+ dictWord{8, 10, 567},
+ dictWord{9, 10, 687},
+ dictWord{9, 10, 742},
+ dictWord{10, 10, 686},
+ dictWord{11, 10, 682},
+ dictWord{140, 10, 281},
+ dictWord{
+ 5,
+ 0,
+ 32,
+ },
+ dictWord{6, 11, 147},
+ dictWord{7, 11, 886},
+ dictWord{9, 11, 753},
+ dictWord{138, 11, 268},
+ dictWord{5, 10, 179},
+ dictWord{7, 10, 1095},
+ dictWord{
+ 135,
+ 10,
+ 1213,
+ },
+ dictWord{4, 10, 66},
+ dictWord{7, 10, 722},
+ dictWord{135, 10, 904},
+ dictWord{135, 10, 352},
+ dictWord{9, 11, 245},
+ dictWord{138, 11, 137},
+ dictWord{4, 0, 289},
+ dictWord{7, 0, 629},
+ dictWord{7, 0, 1698},
+ dictWord{7, 0, 1711},
+ dictWord{12, 0, 215},
+ dictWord{133, 11, 414},
+ dictWord{6, 0, 1975},
+ dictWord{135, 11, 1762},
+ dictWord{6, 0, 450},
+ dictWord{136, 0, 109},
+ dictWord{141, 10, 35},
+ dictWord{134, 11, 599},
+ dictWord{136, 0, 705},
+ dictWord{
+ 133,
+ 0,
+ 664,
+ },
+ dictWord{134, 11, 1749},
+ dictWord{11, 11, 402},
+ dictWord{12, 11, 109},
+ dictWord{12, 11, 431},
+ dictWord{13, 11, 179},
+ dictWord{13, 11, 206},
+ dictWord{14, 11, 175},
+ dictWord{14, 11, 217},
+ dictWord{16, 11, 3},
+ dictWord{148, 11, 53},
+ dictWord{135, 0, 1238},
+ dictWord{134, 11, 1627},
+ dictWord{
+ 132,
+ 11,
+ 488,
+ },
+ dictWord{13, 0, 318},
+ dictWord{10, 10, 592},
+ dictWord{10, 10, 753},
+ dictWord{12, 10, 317},
+ dictWord{12, 10, 355},
+ dictWord{12, 10, 465},
+ dictWord{
+ 12,
+ 10,
+ 469,
+ },
+ dictWord{12, 10, 560},
+ dictWord{140, 10, 578},
+ dictWord{133, 10, 564},
+ dictWord{132, 11, 83},
+ dictWord{140, 11, 676},
+ dictWord{6, 0, 1872},
+ dictWord{6, 0, 1906},
+ dictWord{6, 0, 1907},
+ dictWord{9, 0, 934},
+ dictWord{9, 0, 956},
+ dictWord{9, 0, 960},
+ dictWord{9, 0, 996},
+ dictWord{12, 0, 794},
+ dictWord{
+ 12,
+ 0,
+ 876,
+ },
+ dictWord{12, 0, 880},
+ dictWord{12, 0, 918},
+ dictWord{15, 0, 230},
+ dictWord{18, 0, 234},
+ dictWord{18, 0, 238},
+ dictWord{21, 0, 38},
+ dictWord{149, 0, 62},
+ dictWord{134, 10, 556},
+ dictWord{134, 11, 278},
+ dictWord{137, 0, 103},
+ dictWord{7, 10, 544},
+ dictWord{8, 10, 719},
+ dictWord{138, 10, 61},
+ dictWord{
+ 4,
+ 10,
+ 5,
+ },
+ dictWord{5, 10, 498},
+ dictWord{8, 10, 637},
+ dictWord{137, 10, 521},
+ dictWord{7, 0, 777},
+ dictWord{12, 0, 229},
+ dictWord{12, 0, 239},
+ dictWord{15, 0, 12},
+ dictWord{12, 11, 229},
+ dictWord{12, 11, 239},
+ dictWord{143, 11, 12},
+ dictWord{6, 0, 26},
+ dictWord{7, 11, 388},
+ dictWord{7, 11, 644},
+ dictWord{139, 11, 781},
+ dictWord{7, 11, 229},
+ dictWord{8, 11, 59},
+ dictWord{9, 11, 190},
+ dictWord{9, 11, 257},
+ dictWord{10, 11, 378},
+ dictWord{140, 11, 191},
+ dictWord{133, 10, 927},
+ dictWord{135, 10, 1441},
+ dictWord{4, 10, 893},
+ dictWord{5, 10, 780},
+ dictWord{133, 10, 893},
+ dictWord{4, 0, 414},
+ dictWord{5, 0, 467},
+ dictWord{9, 0, 654},
+ dictWord{10, 0, 451},
+ dictWord{12, 0, 59},
+ dictWord{141, 0, 375},
+ dictWord{142, 0, 173},
+ dictWord{135, 0, 17},
+ dictWord{7, 0, 1350},
+ dictWord{133, 10, 238},
+ dictWord{135, 0, 955},
+ dictWord{4, 0, 960},
+ dictWord{10, 0, 887},
+ dictWord{12, 0, 753},
+ dictWord{18, 0, 161},
+ dictWord{18, 0, 162},
+ dictWord{152, 0, 19},
+ dictWord{136, 11, 344},
+ dictWord{6, 10, 1729},
+ dictWord{137, 11, 288},
+ dictWord{132, 11, 660},
+ dictWord{4, 0, 217},
+ dictWord{5, 0, 710},
+ dictWord{7, 0, 760},
+ dictWord{7, 0, 1926},
+ dictWord{9, 0, 428},
+ dictWord{9, 0, 708},
+ dictWord{10, 0, 254},
+ dictWord{10, 0, 296},
+ dictWord{10, 0, 720},
+ dictWord{11, 0, 109},
+ dictWord{
+ 11,
+ 0,
+ 255,
+ },
+ dictWord{12, 0, 165},
+ dictWord{12, 0, 315},
+ dictWord{13, 0, 107},
+ dictWord{13, 0, 203},
+ dictWord{14, 0, 54},
+ dictWord{14, 0, 99},
+ dictWord{14, 0, 114},
+ dictWord{14, 0, 388},
+ dictWord{16, 0, 85},
+ dictWord{17, 0, 9},
+ dictWord{17, 0, 33},
+ dictWord{20, 0, 25},
+ dictWord{20, 0, 28},
+ dictWord{20, 0, 29},
+ dictWord{21, 0, 9},
+ dictWord{21, 0, 10},
+ dictWord{21, 0, 34},
+ dictWord{22, 0, 17},
+ dictWord{4, 10, 60},
+ dictWord{7, 10, 1800},
+ dictWord{8, 10, 314},
+ dictWord{9, 10, 700},
+ dictWord{
+ 139,
+ 10,
+ 487,
+ },
+ dictWord{7, 11, 1035},
+ dictWord{138, 11, 737},
+ dictWord{7, 11, 690},
+ dictWord{9, 11, 217},
+ dictWord{9, 11, 587},
+ dictWord{140, 11, 521},
+ dictWord{6, 0, 919},
+ dictWord{7, 11, 706},
+ dictWord{7, 11, 1058},
+ dictWord{138, 11, 538},
+ dictWord{7, 10, 1853},
+ dictWord{138, 10, 437},
+ dictWord{
+ 136,
+ 10,
+ 419,
+ },
+ dictWord{6, 0, 280},
+ dictWord{10, 0, 502},
+ dictWord{11, 0, 344},
+ dictWord{140, 0, 38},
+ dictWord{5, 0, 45},
+ dictWord{7, 0, 1161},
+ dictWord{11, 0, 448},
+ dictWord{11, 0, 880},
+ dictWord{13, 0, 139},
+ dictWord{13, 0, 407},
+ dictWord{15, 0, 16},
+ dictWord{17, 0, 95},
+ dictWord{18, 0, 66},
+ dictWord{18, 0, 88},
+ dictWord{
+ 18,
+ 0,
+ 123,
+ },
+ dictWord{149, 0, 7},
+ dictWord{11, 11, 92},
+ dictWord{11, 11, 196},
+ dictWord{11, 11, 409},
+ dictWord{11, 11, 450},
+ dictWord{11, 11, 666},
+ dictWord{
+ 11,
+ 11,
+ 777,
+ },
+ dictWord{12, 11, 262},
+ dictWord{13, 11, 385},
+ dictWord{13, 11, 393},
+ dictWord{15, 11, 115},
+ dictWord{16, 11, 45},
+ dictWord{145, 11, 82},
+ dictWord{136, 0, 777},
+ dictWord{134, 11, 1744},
+ dictWord{4, 0, 410},
+ dictWord{7, 0, 521},
+ dictWord{133, 10, 828},
+ dictWord{134, 0, 673},
+ dictWord{7, 0, 1110},
+ dictWord{7, 0, 1778},
+ dictWord{7, 10, 176},
+ dictWord{135, 10, 178},
+ dictWord{5, 10, 806},
+ dictWord{7, 11, 268},
+ dictWord{7, 10, 1976},
+ dictWord{
+ 136,
+ 11,
+ 569,
+ },
+ dictWord{4, 11, 733},
+ dictWord{9, 11, 194},
+ dictWord{10, 11, 92},
+ dictWord{11, 11, 198},
+ dictWord{12, 11, 84},
+ dictWord{12, 11, 87},
+ dictWord{
+ 13,
+ 11,
+ 128,
+ },
+ dictWord{144, 11, 74},
+ dictWord{5, 0, 341},
+ dictWord{7, 0, 1129},
+ dictWord{11, 0, 414},
+ dictWord{4, 10, 51},
+ dictWord{6, 10, 4},
+ dictWord{7, 10, 591},
+ dictWord{7, 10, 849},
+ dictWord{7, 10, 951},
+ dictWord{7, 10, 1613},
+ dictWord{7, 10, 1760},
+ dictWord{7, 10, 1988},
+ dictWord{9, 10, 434},
+ dictWord{10, 10, 754},
+ dictWord{11, 10, 25},
+ dictWord{139, 10, 37},
+ dictWord{133, 10, 902},
+ dictWord{135, 10, 928},
+ dictWord{135, 0, 787},
+ dictWord{132, 0, 436},
+ dictWord{
+ 134,
+ 10,
+ 270,
+ },
+ dictWord{7, 0, 1587},
+ dictWord{135, 0, 1707},
+ dictWord{6, 0, 377},
+ dictWord{7, 0, 1025},
+ dictWord{9, 0, 613},
+ dictWord{145, 0, 104},
+ dictWord{
+ 7,
+ 11,
+ 982,
+ },
+ dictWord{7, 11, 1361},
+ dictWord{10, 11, 32},
+ dictWord{143, 11, 56},
+ dictWord{139, 0, 96},
+ dictWord{132, 0, 451},
+ dictWord{132, 10, 416},
+ dictWord{
+ 142,
+ 10,
+ 372,
+ },
+ dictWord{5, 10, 152},
+ dictWord{5, 10, 197},
+ dictWord{7, 11, 306},
+ dictWord{7, 10, 340},
+ dictWord{7, 10, 867},
+ dictWord{10, 10, 548},
+ dictWord{
+ 10,
+ 10,
+ 581,
+ },
+ dictWord{11, 10, 6},
+ dictWord{12, 10, 3},
+ dictWord{12, 10, 19},
+ dictWord{14, 10, 110},
+ dictWord{142, 10, 289},
+ dictWord{134, 0, 680},
+ dictWord{
+ 134,
+ 11,
+ 609,
+ },
+ dictWord{7, 0, 483},
+ dictWord{7, 10, 190},
+ dictWord{8, 10, 28},
+ dictWord{8, 10, 141},
+ dictWord{8, 10, 444},
+ dictWord{8, 10, 811},
+ dictWord{
+ 9,
+ 10,
+ 468,
+ },
+ dictWord{11, 10, 334},
+ dictWord{12, 10, 24},
+ dictWord{12, 10, 386},
+ dictWord{140, 10, 576},
+ dictWord{10, 0, 916},
+ dictWord{133, 10, 757},
+ dictWord{
+ 5,
+ 10,
+ 721,
+ },
+ dictWord{135, 10, 1553},
+ dictWord{133, 11, 178},
+ dictWord{134, 0, 937},
+ dictWord{132, 10, 898},
+ dictWord{133, 0, 739},
+ dictWord{
+ 147,
+ 0,
+ 82,
+ },
+ dictWord{135, 0, 663},
+ dictWord{146, 0, 128},
+ dictWord{5, 10, 277},
+ dictWord{141, 10, 247},
+ dictWord{134, 0, 1087},
+ dictWord{132, 10, 435},
+ dictWord{
+ 6,
+ 11,
+ 381,
+ },
+ dictWord{7, 11, 645},
+ dictWord{7, 11, 694},
+ dictWord{136, 11, 546},
+ dictWord{7, 0, 503},
+ dictWord{135, 0, 1885},
+ dictWord{6, 0, 1965},
+ dictWord{
+ 8,
+ 0,
+ 925,
+ },
+ dictWord{138, 0, 955},
+ dictWord{4, 0, 113},
+ dictWord{5, 0, 163},
+ dictWord{5, 0, 735},
+ dictWord{7, 0, 1009},
+ dictWord{9, 0, 9},
+ dictWord{9, 0, 771},
+ dictWord{12, 0, 90},
+ dictWord{13, 0, 138},
+ dictWord{13, 0, 410},
+ dictWord{143, 0, 128},
+ dictWord{4, 0, 324},
+ dictWord{138, 0, 104},
+ dictWord{7, 0, 460},
+ dictWord{
+ 5,
+ 10,
+ 265,
+ },
+ dictWord{134, 10, 212},
+ dictWord{133, 11, 105},
+ dictWord{7, 11, 261},
+ dictWord{7, 11, 1107},
+ dictWord{7, 11, 1115},
+ dictWord{7, 11, 1354},
+ dictWord{7, 11, 1588},
+ dictWord{7, 11, 1705},
+ dictWord{7, 11, 1902},
+ dictWord{9, 11, 465},
+ dictWord{10, 11, 248},
+ dictWord{10, 11, 349},
+ dictWord{10, 11, 647},
+ dictWord{11, 11, 527},
+ dictWord{11, 11, 660},
+ dictWord{11, 11, 669},
+ dictWord{12, 11, 529},
+ dictWord{141, 11, 305},
+ dictWord{5, 11, 438},
+ dictWord{
+ 9,
+ 11,
+ 694,
+ },
+ dictWord{12, 11, 627},
+ dictWord{141, 11, 210},
+ dictWord{152, 11, 11},
+ dictWord{4, 0, 935},
+ dictWord{133, 0, 823},
+ dictWord{132, 10, 702},
+ dictWord{
+ 5,
+ 0,
+ 269,
+ },
+ dictWord{7, 0, 434},
+ dictWord{7, 0, 891},
+ dictWord{8, 0, 339},
+ dictWord{9, 0, 702},
+ dictWord{11, 0, 594},
+ dictWord{11, 0, 718},
+ dictWord{17, 0, 100},
+ dictWord{5, 10, 808},
+ dictWord{135, 10, 2045},
+ dictWord{7, 0, 1014},
+ dictWord{9, 0, 485},
+ dictWord{141, 0, 264},
+ dictWord{134, 0, 1713},
+ dictWord{7, 0, 1810},
+ dictWord{11, 0, 866},
+ dictWord{12, 0, 103},
+ dictWord{13, 0, 495},
+ dictWord{140, 11, 233},
+ dictWord{4, 0, 423},
+ dictWord{10, 0, 949},
+ dictWord{138, 0, 1013},
+ dictWord{135, 0, 900},
+ dictWord{8, 11, 25},
+ dictWord{138, 11, 826},
+ dictWord{5, 10, 166},
+ dictWord{8, 10, 739},
+ dictWord{140, 10, 511},
+ dictWord{
+ 134,
+ 0,
+ 2018,
+ },
+ dictWord{7, 11, 1270},
+ dictWord{139, 11, 612},
+ dictWord{4, 10, 119},
+ dictWord{5, 10, 170},
+ dictWord{5, 10, 447},
+ dictWord{7, 10, 1708},
+ dictWord{
+ 7,
+ 10,
+ 1889,
+ },
+ dictWord{9, 10, 357},
+ dictWord{9, 10, 719},
+ dictWord{12, 10, 486},
+ dictWord{140, 10, 596},
+ dictWord{12, 0, 574},
+ dictWord{140, 11, 574},
+ dictWord{132, 11, 308},
+ dictWord{6, 0, 964},
+ dictWord{6, 0, 1206},
+ dictWord{134, 0, 1302},
+ dictWord{4, 10, 450},
+ dictWord{135, 10, 1158},
+ dictWord{
+ 135,
+ 11,
+ 150,
+ },
+ dictWord{136, 11, 649},
+ dictWord{14, 0, 213},
+ dictWord{148, 0, 38},
+ dictWord{9, 11, 45},
+ dictWord{9, 11, 311},
+ dictWord{141, 11, 42},
+ dictWord{
+ 134,
+ 11,
+ 521,
+ },
+ dictWord{7, 10, 1375},
+ dictWord{7, 10, 1466},
+ dictWord{138, 10, 331},
+ dictWord{132, 10, 754},
+ dictWord{5, 11, 339},
+ dictWord{7, 11, 1442},
+ dictWord{14, 11, 3},
+ dictWord{15, 11, 41},
+ dictWord{147, 11, 66},
+ dictWord{136, 11, 378},
+ dictWord{134, 0, 1022},
+ dictWord{5, 10, 850},
+ dictWord{136, 10, 799},
+ dictWord{142, 0, 143},
+ dictWord{135, 0, 2029},
+ dictWord{134, 11, 1628},
+ dictWord{8, 0, 523},
+ dictWord{150, 0, 34},
+ dictWord{5, 0, 625},
+ dictWord{
+ 135,
+ 0,
+ 1617,
+ },
+ dictWord{7, 0, 275},
+ dictWord{7, 10, 238},
+ dictWord{7, 10, 2033},
+ dictWord{8, 10, 120},
+ dictWord{8, 10, 188},
+ dictWord{8, 10, 659},
+ dictWord{
+ 9,
+ 10,
+ 598,
+ },
+ dictWord{10, 10, 466},
+ dictWord{12, 10, 342},
+ dictWord{12, 10, 588},
+ dictWord{13, 10, 503},
+ dictWord{14, 10, 246},
+ dictWord{143, 10, 92},
+ dictWord{
+ 7,
+ 0,
+ 37,
+ },
+ dictWord{8, 0, 425},
+ dictWord{8, 0, 693},
+ dictWord{9, 0, 720},
+ dictWord{10, 0, 380},
+ dictWord{10, 0, 638},
+ dictWord{11, 0, 273},
+ dictWord{11, 0, 473},
+ dictWord{12, 0, 61},
+ dictWord{143, 0, 43},
+ dictWord{135, 11, 829},
+ dictWord{135, 0, 1943},
+ dictWord{132, 0, 765},
+ dictWord{5, 11, 486},
+ dictWord{
+ 135,
+ 11,
+ 1349,
+ },
+ dictWord{7, 11, 1635},
+ dictWord{8, 11, 17},
+ dictWord{10, 11, 217},
+ dictWord{138, 11, 295},
+ dictWord{4, 10, 201},
+ dictWord{7, 10, 1744},
+ dictWord{
+ 8,
+ 10,
+ 602,
+ },
+ dictWord{11, 10, 247},
+ dictWord{11, 10, 826},
+ dictWord{145, 10, 65},
+ dictWord{138, 11, 558},
+ dictWord{11, 0, 551},
+ dictWord{142, 0, 159},
+ dictWord{8, 10, 164},
+ dictWord{146, 10, 62},
+ dictWord{139, 11, 176},
+ dictWord{132, 0, 168},
+ dictWord{136, 0, 1010},
+ dictWord{134, 0, 1994},
+ dictWord{
+ 135,
+ 0,
+ 91,
+ },
+ dictWord{138, 0, 532},
+ dictWord{135, 10, 1243},
+ dictWord{135, 0, 1884},
+ dictWord{132, 10, 907},
+ dictWord{5, 10, 100},
+ dictWord{10, 10, 329},
+ dictWord{12, 10, 416},
+ dictWord{149, 10, 29},
+ dictWord{134, 11, 447},
+ dictWord{132, 10, 176},
+ dictWord{5, 10, 636},
+ dictWord{5, 10, 998},
+ dictWord{7, 10, 9},
+ dictWord{7, 10, 1508},
+ dictWord{8, 10, 26},
+ dictWord{9, 10, 317},
+ dictWord{9, 10, 358},
+ dictWord{10, 10, 210},
+ dictWord{10, 10, 292},
+ dictWord{10, 10, 533},
+ dictWord{11, 10, 555},
+ dictWord{12, 10, 526},
+ dictWord{12, 10, 607},
+ dictWord{13, 10, 263},
+ dictWord{13, 10, 459},
+ dictWord{142, 10, 271},
+ dictWord{
+ 4,
+ 11,
+ 609,
+ },
+ dictWord{135, 11, 756},
+ dictWord{6, 0, 15},
+ dictWord{7, 0, 70},
+ dictWord{10, 0, 240},
+ dictWord{147, 0, 93},
+ dictWord{4, 11, 930},
+ dictWord{133, 11, 947},
+ dictWord{134, 0, 1227},
+ dictWord{134, 0, 1534},
+ dictWord{133, 11, 939},
+ dictWord{133, 11, 962},
+ dictWord{5, 11, 651},
+ dictWord{8, 11, 170},
+ dictWord{
+ 9,
+ 11,
+ 61,
+ },
+ dictWord{9, 11, 63},
+ dictWord{10, 11, 23},
+ dictWord{10, 11, 37},
+ dictWord{10, 11, 834},
+ dictWord{11, 11, 4},
+ dictWord{11, 11, 187},
+ dictWord{
+ 11,
+ 11,
+ 281,
+ },
+ dictWord{11, 11, 503},
+ dictWord{11, 11, 677},
+ dictWord{12, 11, 96},
+ dictWord{12, 11, 130},
+ dictWord{12, 11, 244},
+ dictWord{14, 11, 5},
+ dictWord{
+ 14,
+ 11,
+ 40,
+ },
+ dictWord{14, 11, 162},
+ dictWord{14, 11, 202},
+ dictWord{146, 11, 133},
+ dictWord{4, 11, 406},
+ dictWord{5, 11, 579},
+ dictWord{12, 11, 492},
+ dictWord{
+ 150,
+ 11,
+ 15,
+ },
+ dictWord{139, 0, 392},
+ dictWord{6, 10, 610},
+ dictWord{10, 10, 127},
+ dictWord{141, 10, 27},
+ dictWord{7, 0, 655},
+ dictWord{7, 0, 1844},
+ dictWord{
+ 136,
+ 10,
+ 119,
+ },
+ dictWord{4, 0, 145},
+ dictWord{6, 0, 176},
+ dictWord{7, 0, 395},
+ dictWord{137, 0, 562},
+ dictWord{132, 0, 501},
+ dictWord{140, 11, 145},
+ dictWord{
+ 136,
+ 0,
+ 1019,
+ },
+ dictWord{134, 0, 509},
+ dictWord{139, 0, 267},
+ dictWord{6, 11, 17},
+ dictWord{7, 11, 16},
+ dictWord{7, 11, 1001},
+ dictWord{7, 11, 1982},
+ dictWord{
+ 9,
+ 11,
+ 886,
+ },
+ dictWord{10, 11, 489},
+ dictWord{10, 11, 800},
+ dictWord{11, 11, 782},
+ dictWord{12, 11, 320},
+ dictWord{13, 11, 467},
+ dictWord{14, 11, 145},
+ dictWord{14, 11, 387},
+ dictWord{143, 11, 119},
+ dictWord{145, 11, 17},
+ dictWord{6, 0, 1099},
+ dictWord{133, 11, 458},
+ dictWord{7, 11, 1983},
+ dictWord{8, 11, 0},
+ dictWord{8, 11, 171},
+ dictWord{9, 11, 120},
+ dictWord{9, 11, 732},
+ dictWord{10, 11, 473},
+ dictWord{11, 11, 656},
+ dictWord{11, 11, 998},
+ dictWord{18, 11, 0},
+ dictWord{18, 11, 2},
+ dictWord{147, 11, 21},
+ dictWord{12, 11, 427},
+ dictWord{146, 11, 38},
+ dictWord{10, 0, 948},
+ dictWord{138, 0, 968},
+ dictWord{7, 10, 126},
+ dictWord{136, 10, 84},
+ dictWord{136, 10, 790},
+ dictWord{4, 0, 114},
+ dictWord{9, 0, 492},
+ dictWord{13, 0, 462},
+ dictWord{142, 0, 215},
+ dictWord{6, 10, 64},
+ dictWord{12, 10, 377},
+ dictWord{141, 10, 309},
+ dictWord{4, 0, 77},
+ dictWord{5, 0, 361},
+ dictWord{6, 0, 139},
+ dictWord{6, 0, 401},
+ dictWord{6, 0, 404},
+ dictWord{
+ 7,
+ 0,
+ 413,
+ },
+ dictWord{7, 0, 715},
+ dictWord{7, 0, 1716},
+ dictWord{11, 0, 279},
+ dictWord{12, 0, 179},
+ dictWord{12, 0, 258},
+ dictWord{13, 0, 244},
+ dictWord{142, 0, 358},
+ dictWord{134, 0, 1717},
+ dictWord{7, 0, 772},
+ dictWord{7, 0, 1061},
+ dictWord{7, 0, 1647},
+ dictWord{8, 0, 82},
+ dictWord{11, 0, 250},
+ dictWord{11, 0, 607},
+ dictWord{12, 0, 311},
+ dictWord{12, 0, 420},
+ dictWord{13, 0, 184},
+ dictWord{13, 0, 367},
+ dictWord{7, 10, 1104},
+ dictWord{11, 10, 269},
+ dictWord{11, 10, 539},
+ dictWord{11, 10, 627},
+ dictWord{11, 10, 706},
+ dictWord{11, 10, 975},
+ dictWord{12, 10, 248},
+ dictWord{12, 10, 434},
+ dictWord{12, 10, 600},
+ dictWord{
+ 12,
+ 10,
+ 622,
+ },
+ dictWord{13, 10, 297},
+ dictWord{13, 10, 485},
+ dictWord{14, 10, 69},
+ dictWord{14, 10, 409},
+ dictWord{143, 10, 108},
+ dictWord{135, 0, 724},
+ dictWord{
+ 4,
+ 11,
+ 512,
+ },
+ dictWord{4, 11, 519},
+ dictWord{133, 11, 342},
+ dictWord{134, 0, 1133},
+ dictWord{145, 11, 29},
+ dictWord{11, 10, 977},
+ dictWord{141, 10, 507},
+ dictWord{6, 0, 841},
+ dictWord{6, 0, 1042},
+ dictWord{6, 0, 1194},
+ dictWord{10, 0, 993},
+ dictWord{140, 0, 1021},
+ dictWord{6, 11, 31},
+ dictWord{7, 11, 491},
+ dictWord{7, 11, 530},
+ dictWord{8, 11, 592},
+ dictWord{9, 10, 34},
+ dictWord{11, 11, 53},
+ dictWord{11, 10, 484},
+ dictWord{11, 11, 779},
+ dictWord{12, 11, 167},
+ dictWord{12, 11, 411},
+ dictWord{14, 11, 14},
+ dictWord{14, 11, 136},
+ dictWord{15, 11, 72},
+ dictWord{16, 11, 17},
+ dictWord{144, 11, 72},
+ dictWord{4, 0, 1021},
+ dictWord{6, 0, 2037},
+ dictWord{133, 11, 907},
+ dictWord{7, 0, 373},
+ dictWord{8, 0, 335},
+ dictWord{8, 0, 596},
+ dictWord{9, 0, 488},
+ dictWord{6, 10, 1700},
+ dictWord{
+ 7,
+ 10,
+ 293,
+ },
+ dictWord{7, 10, 382},
+ dictWord{7, 10, 1026},
+ dictWord{7, 10, 1087},
+ dictWord{7, 10, 2027},
+ dictWord{8, 10, 252},
+ dictWord{8, 10, 727},
+ dictWord{
+ 8,
+ 10,
+ 729,
+ },
+ dictWord{9, 10, 30},
+ dictWord{9, 10, 199},
+ dictWord{9, 10, 231},
+ dictWord{9, 10, 251},
+ dictWord{9, 10, 334},
+ dictWord{9, 10, 361},
+ dictWord{9, 10, 712},
+ dictWord{10, 10, 55},
+ dictWord{10, 10, 60},
+ dictWord{10, 10, 232},
+ dictWord{10, 10, 332},
+ dictWord{10, 10, 384},
+ dictWord{10, 10, 396},
+ dictWord{
+ 10,
+ 10,
+ 504,
+ },
+ dictWord{10, 10, 542},
+ dictWord{10, 10, 652},
+ dictWord{11, 10, 20},
+ dictWord{11, 10, 48},
+ dictWord{11, 10, 207},
+ dictWord{11, 10, 291},
+ dictWord{
+ 11,
+ 10,
+ 298,
+ },
+ dictWord{11, 10, 342},
+ dictWord{11, 10, 365},
+ dictWord{11, 10, 394},
+ dictWord{11, 10, 620},
+ dictWord{11, 10, 705},
+ dictWord{11, 10, 1017},
+ dictWord{12, 10, 123},
+ dictWord{12, 10, 340},
+ dictWord{12, 10, 406},
+ dictWord{12, 10, 643},
+ dictWord{13, 10, 61},
+ dictWord{13, 10, 269},
+ dictWord{
+ 13,
+ 10,
+ 311,
+ },
+ dictWord{13, 10, 319},
+ dictWord{13, 10, 486},
+ dictWord{14, 10, 234},
+ dictWord{15, 10, 62},
+ dictWord{15, 10, 85},
+ dictWord{16, 10, 71},
+ dictWord{
+ 18,
+ 10,
+ 119,
+ },
+ dictWord{148, 10, 105},
+ dictWord{150, 0, 37},
+ dictWord{4, 11, 208},
+ dictWord{5, 11, 106},
+ dictWord{6, 11, 531},
+ dictWord{8, 11, 408},
+ dictWord{
+ 9,
+ 11,
+ 188,
+ },
+ dictWord{138, 11, 572},
+ dictWord{132, 0, 564},
+ dictWord{6, 0, 513},
+ dictWord{135, 0, 1052},
+ dictWord{132, 0, 825},
+ dictWord{9, 0, 899},
+ dictWord{
+ 140,
+ 11,
+ 441,
+ },
+ dictWord{134, 0, 778},
+ dictWord{133, 11, 379},
+ dictWord{7, 0, 1417},
+ dictWord{12, 0, 382},
+ dictWord{17, 0, 48},
+ dictWord{152, 0, 12},
+ dictWord{
+ 132,
+ 11,
+ 241,
+ },
+ dictWord{7, 0, 1116},
+ dictWord{6, 10, 379},
+ dictWord{7, 10, 270},
+ dictWord{8, 10, 176},
+ dictWord{8, 10, 183},
+ dictWord{9, 10, 432},
+ dictWord{
+ 9,
+ 10,
+ 661,
+ },
+ dictWord{12, 10, 247},
+ dictWord{12, 10, 617},
+ dictWord{146, 10, 125},
+ dictWord{5, 10, 792},
+ dictWord{133, 10, 900},
+ dictWord{6, 0, 545},
+ dictWord{
+ 7,
+ 0,
+ 565,
+ },
+ dictWord{7, 0, 1669},
+ dictWord{10, 0, 114},
+ dictWord{11, 0, 642},
+ dictWord{140, 0, 618},
+ dictWord{133, 0, 5},
+ dictWord{138, 11, 7},
+ dictWord{
+ 132,
+ 11,
+ 259,
+ },
+ dictWord{135, 0, 192},
+ dictWord{134, 0, 701},
+ dictWord{136, 0, 763},
+ dictWord{135, 10, 1979},
+ dictWord{4, 10, 901},
+ dictWord{133, 10, 776},
+ dictWord{10, 0, 755},
+ dictWord{147, 0, 29},
+ dictWord{133, 0, 759},
+ dictWord{4, 11, 173},
+ dictWord{5, 11, 312},
+ dictWord{5, 11, 512},
+ dictWord{135, 11, 1285},
+ dictWord{7, 11, 1603},
+ dictWord{7, 11, 1691},
+ dictWord{9, 11, 464},
+ dictWord{11, 11, 195},
+ dictWord{12, 11, 279},
+ dictWord{12, 11, 448},
+ dictWord{
+ 14,
+ 11,
+ 11,
+ },
+ dictWord{147, 11, 102},
+ dictWord{7, 0, 370},
+ dictWord{7, 0, 1007},
+ dictWord{7, 0, 1177},
+ dictWord{135, 0, 1565},
+ dictWord{135, 0, 1237},
+ dictWord{
+ 4,
+ 0,
+ 87,
+ },
+ dictWord{5, 0, 250},
+ dictWord{141, 0, 298},
+ dictWord{4, 11, 452},
+ dictWord{5, 11, 583},
+ dictWord{5, 11, 817},
+ dictWord{6, 11, 433},
+ dictWord{7, 11, 593},
+ dictWord{7, 11, 720},
+ dictWord{7, 11, 1378},
+ dictWord{8, 11, 161},
+ dictWord{9, 11, 284},
+ dictWord{10, 11, 313},
+ dictWord{139, 11, 886},
+ dictWord{4, 11, 547},
+ dictWord{135, 11, 1409},
+ dictWord{136, 11, 722},
+ dictWord{4, 10, 37},
+ dictWord{5, 10, 334},
+ dictWord{135, 10, 1253},
+ dictWord{132, 10, 508},
+ dictWord{
+ 12,
+ 0,
+ 107,
+ },
+ dictWord{146, 0, 31},
+ dictWord{8, 11, 420},
+ dictWord{139, 11, 193},
+ dictWord{135, 0, 814},
+ dictWord{135, 11, 409},
+ dictWord{140, 0, 991},
+ dictWord{4, 0, 57},
+ dictWord{7, 0, 1195},
+ dictWord{7, 0, 1438},
+ dictWord{7, 0, 1548},
+ dictWord{7, 0, 1835},
+ dictWord{7, 0, 1904},
+ dictWord{9, 0, 757},
+ dictWord{
+ 10,
+ 0,
+ 604,
+ },
+ dictWord{139, 0, 519},
+ dictWord{132, 0, 540},
+ dictWord{138, 11, 308},
+ dictWord{132, 10, 533},
+ dictWord{136, 0, 608},
+ dictWord{144, 11, 65},
+ dictWord{4, 0, 1014},
+ dictWord{134, 0, 2029},
+ dictWord{4, 0, 209},
+ dictWord{7, 0, 902},
+ dictWord{5, 11, 1002},
+ dictWord{136, 11, 745},
+ dictWord{134, 0, 2030},
+ dictWord{6, 0, 303},
+ dictWord{7, 0, 335},
+ dictWord{7, 0, 1437},
+ dictWord{7, 0, 1668},
+ dictWord{8, 0, 553},
+ dictWord{8, 0, 652},
+ dictWord{8, 0, 656},
+ dictWord{
+ 9,
+ 0,
+ 558,
+ },
+ dictWord{11, 0, 743},
+ dictWord{149, 0, 18},
+ dictWord{5, 11, 575},
+ dictWord{6, 11, 354},
+ dictWord{135, 11, 701},
+ dictWord{4, 11, 239},
+ dictWord{
+ 6,
+ 11,
+ 477,
+ },
+ dictWord{7, 11, 1607},
+ dictWord{11, 11, 68},
+ dictWord{139, 11, 617},
+ dictWord{132, 0, 559},
+ dictWord{8, 0, 527},
+ dictWord{18, 0, 60},
+ dictWord{
+ 147,
+ 0,
+ 24,
+ },
+ dictWord{133, 10, 920},
+ dictWord{138, 0, 511},
+ dictWord{133, 0, 1017},
+ dictWord{133, 0, 675},
+ dictWord{138, 10, 391},
+ dictWord{11, 0, 156},
+ dictWord{135, 10, 1952},
+ dictWord{138, 11, 369},
+ dictWord{132, 11, 367},
+ dictWord{133, 0, 709},
+ dictWord{6, 0, 698},
+ dictWord{134, 0, 887},
+ dictWord{
+ 142,
+ 10,
+ 126,
+ },
+ dictWord{134, 0, 1745},
+ dictWord{132, 10, 483},
+ dictWord{13, 11, 299},
+ dictWord{142, 11, 75},
+ dictWord{133, 0, 714},
+ dictWord{7, 0, 8},
+ dictWord{
+ 136,
+ 0,
+ 206,
+ },
+ dictWord{138, 10, 480},
+ dictWord{4, 11, 694},
+ dictWord{9, 10, 495},
+ dictWord{146, 10, 104},
+ dictWord{7, 11, 1248},
+ dictWord{11, 11, 621},
+ dictWord{139, 11, 702},
+ dictWord{140, 11, 687},
+ dictWord{132, 0, 776},
+ dictWord{139, 10, 1009},
+ dictWord{135, 0, 1272},
+ dictWord{134, 0, 1059},
+ dictWord{
+ 8,
+ 10,
+ 653,
+ },
+ dictWord{13, 10, 93},
+ dictWord{147, 10, 14},
+ dictWord{135, 11, 213},
+ dictWord{136, 0, 406},
+ dictWord{133, 10, 172},
+ dictWord{132, 0, 947},
+ dictWord{8, 0, 175},
+ dictWord{10, 0, 168},
+ dictWord{138, 0, 573},
+ dictWord{132, 0, 870},
+ dictWord{6, 0, 1567},
+ dictWord{151, 11, 28},
+ dictWord{
+ 134,
+ 11,
+ 472,
+ },
+ dictWord{5, 10, 260},
+ dictWord{136, 11, 132},
+ dictWord{4, 11, 751},
+ dictWord{11, 11, 390},
+ dictWord{140, 11, 32},
+ dictWord{4, 11, 409},
+ dictWord{
+ 133,
+ 11,
+ 78,
+ },
+ dictWord{12, 0, 554},
+ dictWord{6, 11, 473},
+ dictWord{145, 11, 105},
+ dictWord{133, 0, 784},
+ dictWord{8, 0, 908},
+ dictWord{136, 11, 306},
+ dictWord{139, 0, 882},
+ dictWord{6, 0, 358},
+ dictWord{7, 0, 1393},
+ dictWord{8, 0, 396},
+ dictWord{10, 0, 263},
+ dictWord{14, 0, 154},
+ dictWord{16, 0, 48},
+ dictWord{
+ 17,
+ 0,
+ 8,
+ },
+ dictWord{7, 11, 1759},
+ dictWord{8, 11, 396},
+ dictWord{10, 11, 263},
+ dictWord{14, 11, 154},
+ dictWord{16, 11, 48},
+ dictWord{145, 11, 8},
+ dictWord{
+ 13,
+ 11,
+ 163,
+ },
+ dictWord{13, 11, 180},
+ dictWord{18, 11, 78},
+ dictWord{148, 11, 35},
+ dictWord{14, 0, 32},
+ dictWord{18, 0, 85},
+ dictWord{20, 0, 2},
+ dictWord{152, 0, 16},
+ dictWord{7, 0, 228},
+ dictWord{10, 0, 770},
+ dictWord{8, 10, 167},
+ dictWord{8, 10, 375},
+ dictWord{9, 10, 82},
+ dictWord{9, 10, 561},
+ dictWord{138, 10, 620},
+ dictWord{132, 0, 845},
+ dictWord{9, 0, 14},
+ dictWord{9, 0, 441},
+ dictWord{10, 0, 306},
+ dictWord{139, 0, 9},
+ dictWord{11, 0, 966},
+ dictWord{12, 0, 287},
+ dictWord{
+ 13,
+ 0,
+ 342,
+ },
+ dictWord{13, 0, 402},
+ dictWord{15, 0, 110},
+ dictWord{15, 0, 163},
+ dictWord{8, 10, 194},
+ dictWord{136, 10, 756},
+ dictWord{134, 0, 1578},
+ dictWord{
+ 4,
+ 0,
+ 967,
+ },
+ dictWord{6, 0, 1820},
+ dictWord{6, 0, 1847},
+ dictWord{140, 0, 716},
+ dictWord{136, 0, 594},
+ dictWord{7, 0, 1428},
+ dictWord{7, 0, 1640},
+ dictWord{
+ 7,
+ 0,
+ 1867,
+ },
+ dictWord{9, 0, 169},
+ dictWord{9, 0, 182},
+ dictWord{9, 0, 367},
+ dictWord{9, 0, 478},
+ dictWord{9, 0, 506},
+ dictWord{9, 0, 551},
+ dictWord{9, 0, 557},
+ dictWord{
+ 9,
+ 0,
+ 648,
+ },
+ dictWord{9, 0, 697},
+ dictWord{9, 0, 705},
+ dictWord{9, 0, 725},
+ dictWord{9, 0, 787},
+ dictWord{9, 0, 794},
+ dictWord{10, 0, 198},
+ dictWord{10, 0, 214},
+ dictWord{10, 0, 267},
+ dictWord{10, 0, 275},
+ dictWord{10, 0, 456},
+ dictWord{10, 0, 551},
+ dictWord{10, 0, 561},
+ dictWord{10, 0, 613},
+ dictWord{10, 0, 627},
+ dictWord{
+ 10,
+ 0,
+ 668,
+ },
+ dictWord{10, 0, 675},
+ dictWord{10, 0, 691},
+ dictWord{10, 0, 695},
+ dictWord{10, 0, 707},
+ dictWord{10, 0, 715},
+ dictWord{11, 0, 183},
+ dictWord{
+ 11,
+ 0,
+ 201,
+ },
+ dictWord{11, 0, 244},
+ dictWord{11, 0, 262},
+ dictWord{11, 0, 352},
+ dictWord{11, 0, 439},
+ dictWord{11, 0, 493},
+ dictWord{11, 0, 572},
+ dictWord{11, 0, 591},
+ dictWord{11, 0, 608},
+ dictWord{11, 0, 611},
+ dictWord{11, 0, 646},
+ dictWord{11, 0, 674},
+ dictWord{11, 0, 711},
+ dictWord{11, 0, 751},
+ dictWord{11, 0, 761},
+ dictWord{11, 0, 776},
+ dictWord{11, 0, 785},
+ dictWord{11, 0, 850},
+ dictWord{11, 0, 853},
+ dictWord{11, 0, 862},
+ dictWord{11, 0, 865},
+ dictWord{11, 0, 868},
+ dictWord{
+ 11,
+ 0,
+ 875,
+ },
+ dictWord{11, 0, 898},
+ dictWord{11, 0, 902},
+ dictWord{11, 0, 903},
+ dictWord{11, 0, 910},
+ dictWord{11, 0, 932},
+ dictWord{11, 0, 942},
+ dictWord{
+ 11,
+ 0,
+ 957,
+ },
+ dictWord{11, 0, 967},
+ dictWord{11, 0, 972},
+ dictWord{12, 0, 148},
+ dictWord{12, 0, 195},
+ dictWord{12, 0, 220},
+ dictWord{12, 0, 237},
+ dictWord{12, 0, 318},
+ dictWord{12, 0, 339},
+ dictWord{12, 0, 393},
+ dictWord{12, 0, 445},
+ dictWord{12, 0, 450},
+ dictWord{12, 0, 474},
+ dictWord{12, 0, 505},
+ dictWord{12, 0, 509},
+ dictWord{12, 0, 533},
+ dictWord{12, 0, 591},
+ dictWord{12, 0, 594},
+ dictWord{12, 0, 597},
+ dictWord{12, 0, 621},
+ dictWord{12, 0, 633},
+ dictWord{12, 0, 642},
+ dictWord{
+ 13,
+ 0,
+ 59,
+ },
+ dictWord{13, 0, 60},
+ dictWord{13, 0, 145},
+ dictWord{13, 0, 239},
+ dictWord{13, 0, 250},
+ dictWord{13, 0, 329},
+ dictWord{13, 0, 344},
+ dictWord{13, 0, 365},
+ dictWord{13, 0, 372},
+ dictWord{13, 0, 387},
+ dictWord{13, 0, 403},
+ dictWord{13, 0, 414},
+ dictWord{13, 0, 456},
+ dictWord{13, 0, 470},
+ dictWord{13, 0, 478},
+ dictWord{13, 0, 483},
+ dictWord{13, 0, 489},
+ dictWord{14, 0, 55},
+ dictWord{14, 0, 57},
+ dictWord{14, 0, 81},
+ dictWord{14, 0, 90},
+ dictWord{14, 0, 148},
+ dictWord{
+ 14,
+ 0,
+ 239,
+ },
+ dictWord{14, 0, 266},
+ dictWord{14, 0, 321},
+ dictWord{14, 0, 326},
+ dictWord{14, 0, 327},
+ dictWord{14, 0, 330},
+ dictWord{14, 0, 347},
+ dictWord{14, 0, 355},
+ dictWord{14, 0, 401},
+ dictWord{14, 0, 404},
+ dictWord{14, 0, 411},
+ dictWord{14, 0, 414},
+ dictWord{14, 0, 416},
+ dictWord{14, 0, 420},
+ dictWord{15, 0, 61},
+ dictWord{15, 0, 74},
+ dictWord{15, 0, 87},
+ dictWord{15, 0, 88},
+ dictWord{15, 0, 94},
+ dictWord{15, 0, 96},
+ dictWord{15, 0, 116},
+ dictWord{15, 0, 149},
+ dictWord{15, 0, 154},
+ dictWord{16, 0, 50},
+ dictWord{16, 0, 63},
+ dictWord{16, 0, 73},
+ dictWord{17, 0, 2},
+ dictWord{17, 0, 66},
+ dictWord{17, 0, 92},
+ dictWord{17, 0, 103},
+ dictWord{
+ 17,
+ 0,
+ 112,
+ },
+ dictWord{17, 0, 120},
+ dictWord{18, 0, 50},
+ dictWord{18, 0, 54},
+ dictWord{18, 0, 82},
+ dictWord{18, 0, 86},
+ dictWord{18, 0, 90},
+ dictWord{18, 0, 111},
+ dictWord{
+ 18,
+ 0,
+ 115,
+ },
+ dictWord{18, 0, 156},
+ dictWord{19, 0, 40},
+ dictWord{19, 0, 79},
+ dictWord{20, 0, 78},
+ dictWord{21, 0, 22},
+ dictWord{135, 11, 883},
+ dictWord{5, 0, 161},
+ dictWord{135, 0, 839},
+ dictWord{4, 0, 782},
+ dictWord{13, 11, 293},
+ dictWord{142, 11, 56},
+ dictWord{133, 11, 617},
+ dictWord{139, 11, 50},
+ dictWord{
+ 135,
+ 10,
+ 22,
+ },
+ dictWord{145, 0, 64},
+ dictWord{5, 10, 639},
+ dictWord{7, 10, 1249},
+ dictWord{139, 10, 896},
+ dictWord{138, 0, 998},
+ dictWord{135, 11, 2042},
+ dictWord{
+ 4,
+ 11,
+ 546,
+ },
+ dictWord{142, 11, 233},
+ dictWord{6, 0, 1043},
+ dictWord{134, 0, 1574},
+ dictWord{134, 0, 1496},
+ dictWord{4, 10, 102},
+ dictWord{7, 10, 815},
+ dictWord{7, 10, 1699},
+ dictWord{139, 10, 964},
+ dictWord{12, 0, 781},
+ dictWord{142, 0, 461},
+ dictWord{4, 11, 313},
+ dictWord{133, 11, 577},
+ dictWord{
+ 6,
+ 0,
+ 639,
+ },
+ dictWord{6, 0, 1114},
+ dictWord{137, 0, 817},
+ dictWord{8, 11, 184},
+ dictWord{141, 11, 433},
+ dictWord{7, 0, 1814},
+ dictWord{135, 11, 935},
+ dictWord{
+ 10,
+ 0,
+ 997,
+ },
+ dictWord{140, 0, 958},
+ dictWord{4, 0, 812},
+ dictWord{137, 11, 625},
+ dictWord{132, 10, 899},
+ dictWord{136, 10, 795},
+ dictWord{5, 11, 886},
+ dictWord{6, 11, 46},
+ dictWord{6, 11, 1790},
+ dictWord{7, 11, 14},
+ dictWord{7, 11, 732},
+ dictWord{7, 11, 1654},
+ dictWord{8, 11, 95},
+ dictWord{8, 11, 327},
+ dictWord{
+ 8,
+ 11,
+ 616,
+ },
+ dictWord{10, 11, 598},
+ dictWord{10, 11, 769},
+ dictWord{11, 11, 134},
+ dictWord{11, 11, 747},
+ dictWord{12, 11, 378},
+ dictWord{142, 11, 97},
+ dictWord{136, 0, 139},
+ dictWord{6, 10, 52},
+ dictWord{9, 10, 104},
+ dictWord{9, 10, 559},
+ dictWord{12, 10, 308},
+ dictWord{147, 10, 87},
+ dictWord{133, 11, 1021},
+ dictWord{132, 10, 604},
+ dictWord{132, 10, 301},
+ dictWord{136, 10, 779},
+ dictWord{7, 0, 643},
+ dictWord{136, 0, 236},
+ dictWord{132, 11, 153},
+ dictWord{
+ 134,
+ 0,
+ 1172,
+ },
+ dictWord{147, 10, 32},
+ dictWord{133, 11, 798},
+ dictWord{6, 0, 1338},
+ dictWord{132, 11, 587},
+ dictWord{6, 11, 598},
+ dictWord{7, 11, 42},
+ dictWord{
+ 8,
+ 11,
+ 695,
+ },
+ dictWord{10, 11, 212},
+ dictWord{11, 11, 158},
+ dictWord{14, 11, 196},
+ dictWord{145, 11, 85},
+ dictWord{135, 10, 508},
+ dictWord{5, 11, 957},
+ dictWord{5, 11, 1008},
+ dictWord{135, 11, 249},
+ dictWord{4, 11, 129},
+ dictWord{135, 11, 465},
+ dictWord{5, 0, 54},
+ dictWord{7, 11, 470},
+ dictWord{7, 11, 1057},
+ dictWord{7, 11, 1201},
+ dictWord{9, 11, 755},
+ dictWord{11, 11, 906},
+ dictWord{140, 11, 527},
+ dictWord{7, 11, 908},
+ dictWord{146, 11, 7},
+ dictWord{
+ 5,
+ 11,
+ 148,
+ },
+ dictWord{136, 11, 450},
+ dictWord{144, 11, 1},
+ dictWord{4, 0, 256},
+ dictWord{135, 0, 1488},
+ dictWord{9, 0, 351},
+ dictWord{6, 10, 310},
+ dictWord{
+ 7,
+ 10,
+ 1849,
+ },
+ dictWord{8, 10, 72},
+ dictWord{8, 10, 272},
+ dictWord{8, 10, 431},
+ dictWord{9, 10, 12},
+ dictWord{10, 10, 563},
+ dictWord{10, 10, 630},
+ dictWord{
+ 10,
+ 10,
+ 796,
+ },
+ dictWord{10, 10, 810},
+ dictWord{11, 10, 367},
+ dictWord{11, 10, 599},
+ dictWord{11, 10, 686},
+ dictWord{140, 10, 672},
+ dictWord{6, 0, 1885},
+ dictWord{
+ 6,
+ 0,
+ 1898,
+ },
+ dictWord{6, 0, 1899},
+ dictWord{140, 0, 955},
+ dictWord{4, 0, 714},
+ dictWord{133, 0, 469},
+ dictWord{6, 0, 1270},
+ dictWord{134, 0, 1456},
+ dictWord{132, 0, 744},
+ dictWord{6, 0, 313},
+ dictWord{7, 10, 537},
+ dictWord{8, 10, 64},
+ dictWord{9, 10, 127},
+ dictWord{10, 10, 496},
+ dictWord{12, 10, 510},
+ dictWord{141, 10, 384},
+ dictWord{4, 11, 217},
+ dictWord{4, 10, 244},
+ dictWord{5, 11, 710},
+ dictWord{7, 10, 233},
+ dictWord{7, 11, 1926},
+ dictWord{9, 11, 428},
+ dictWord{9, 11, 708},
+ dictWord{10, 11, 254},
+ dictWord{10, 11, 296},
+ dictWord{10, 11, 720},
+ dictWord{11, 11, 109},
+ dictWord{11, 11, 255},
+ dictWord{12, 11, 165},
+ dictWord{12, 11, 315},
+ dictWord{13, 11, 107},
+ dictWord{13, 11, 203},
+ dictWord{14, 11, 54},
+ dictWord{14, 11, 99},
+ dictWord{14, 11, 114},
+ dictWord{
+ 14,
+ 11,
+ 388,
+ },
+ dictWord{16, 11, 85},
+ dictWord{17, 11, 9},
+ dictWord{17, 11, 33},
+ dictWord{20, 11, 25},
+ dictWord{20, 11, 28},
+ dictWord{20, 11, 29},
+ dictWord{21, 11, 9},
+ dictWord{21, 11, 10},
+ dictWord{21, 11, 34},
+ dictWord{150, 11, 17},
+ dictWord{138, 0, 402},
+ dictWord{7, 0, 969},
+ dictWord{146, 0, 55},
+ dictWord{8, 0, 50},
+ dictWord{
+ 137,
+ 0,
+ 624,
+ },
+ dictWord{134, 0, 1355},
+ dictWord{132, 0, 572},
+ dictWord{134, 10, 1650},
+ dictWord{10, 10, 702},
+ dictWord{139, 10, 245},
+ dictWord{
+ 10,
+ 0,
+ 847,
+ },
+ dictWord{142, 0, 445},
+ dictWord{6, 0, 43},
+ dictWord{7, 0, 38},
+ dictWord{8, 0, 248},
+ dictWord{138, 0, 513},
+ dictWord{133, 0, 369},
+ dictWord{137, 10, 338},
+ dictWord{133, 0, 766},
+ dictWord{133, 0, 363},
+ dictWord{133, 10, 896},
+ dictWord{8, 11, 392},
+ dictWord{11, 11, 54},
+ dictWord{13, 11, 173},
+ dictWord{
+ 13,
+ 11,
+ 294,
+ },
+ dictWord{148, 11, 7},
+ dictWord{134, 0, 678},
+ dictWord{7, 11, 1230},
+ dictWord{136, 11, 531},
+ dictWord{6, 0, 258},
+ dictWord{140, 0, 409},
+ dictWord{
+ 5,
+ 0,
+ 249,
+ },
+ dictWord{148, 0, 82},
+ dictWord{7, 10, 1117},
+ dictWord{136, 10, 539},
+ dictWord{5, 0, 393},
+ dictWord{6, 0, 378},
+ dictWord{7, 0, 1981},
+ dictWord{9, 0, 32},
+ dictWord{9, 0, 591},
+ dictWord{10, 0, 685},
+ dictWord{10, 0, 741},
+ dictWord{142, 0, 382},
+ dictWord{133, 0, 788},
+ dictWord{134, 0, 1281},
+ dictWord{
+ 134,
+ 0,
+ 1295,
+ },
+ dictWord{7, 0, 1968},
+ dictWord{141, 0, 509},
+ dictWord{4, 0, 61},
+ dictWord{5, 0, 58},
+ dictWord{5, 0, 171},
+ dictWord{5, 0, 683},
+ dictWord{6, 0, 291},
+ dictWord{
+ 6,
+ 0,
+ 566,
+ },
+ dictWord{7, 0, 1650},
+ dictWord{11, 0, 523},
+ dictWord{12, 0, 273},
+ dictWord{12, 0, 303},
+ dictWord{15, 0, 39},
+ dictWord{143, 0, 111},
+ dictWord{
+ 6,
+ 0,
+ 706,
+ },
+ dictWord{134, 0, 1283},
+ dictWord{134, 0, 589},
+ dictWord{135, 11, 1433},
+ dictWord{133, 11, 435},
+ dictWord{7, 0, 1059},
+ dictWord{13, 0, 54},
+ dictWord{
+ 5,
+ 10,
+ 4,
+ },
+ dictWord{5, 10, 810},
+ dictWord{6, 10, 13},
+ dictWord{6, 10, 538},
+ dictWord{6, 10, 1690},
+ dictWord{6, 10, 1726},
+ dictWord{7, 10, 1819},
+ dictWord{
+ 8,
+ 10,
+ 148,
+ },
+ dictWord{8, 10, 696},
+ dictWord{8, 10, 791},
+ dictWord{12, 10, 125},
+ dictWord{143, 10, 9},
+ dictWord{135, 10, 1268},
+ dictWord{5, 11, 85},
+ dictWord{
+ 6,
+ 11,
+ 419,
+ },
+ dictWord{7, 11, 134},
+ dictWord{7, 11, 305},
+ dictWord{7, 11, 361},
+ dictWord{7, 11, 1337},
+ dictWord{8, 11, 71},
+ dictWord{140, 11, 519},
+ dictWord{
+ 137,
+ 0,
+ 824,
+ },
+ dictWord{140, 11, 688},
+ dictWord{5, 11, 691},
+ dictWord{7, 11, 345},
+ dictWord{7, 10, 1385},
+ dictWord{9, 11, 94},
+ dictWord{11, 10, 582},
+ dictWord{
+ 11,
+ 10,
+ 650,
+ },
+ dictWord{11, 10, 901},
+ dictWord{11, 10, 949},
+ dictWord{12, 11, 169},
+ dictWord{12, 10, 232},
+ dictWord{12, 10, 236},
+ dictWord{13, 10, 413},
+ dictWord{13, 10, 501},
+ dictWord{146, 10, 116},
+ dictWord{4, 0, 917},
+ dictWord{133, 0, 1005},
+ dictWord{7, 0, 1598},
+ dictWord{5, 11, 183},
+ dictWord{6, 11, 582},
+ dictWord{9, 11, 344},
+ dictWord{10, 11, 679},
+ dictWord{140, 11, 435},
+ dictWord{4, 10, 925},
+ dictWord{5, 10, 803},
+ dictWord{8, 10, 698},
+ dictWord{
+ 138,
+ 10,
+ 828,
+ },
+ dictWord{132, 0, 919},
+ dictWord{135, 11, 511},
+ dictWord{139, 10, 992},
+ dictWord{4, 0, 255},
+ dictWord{5, 0, 302},
+ dictWord{6, 0, 132},
+ dictWord{
+ 7,
+ 0,
+ 128,
+ },
+ dictWord{7, 0, 283},
+ dictWord{7, 0, 1299},
+ dictWord{10, 0, 52},
+ dictWord{10, 0, 514},
+ dictWord{11, 0, 925},
+ dictWord{13, 0, 92},
+ dictWord{142, 0, 309},
+ dictWord{134, 0, 1369},
+ dictWord{135, 10, 1847},
+ dictWord{134, 0, 328},
+ dictWord{7, 11, 1993},
+ dictWord{136, 11, 684},
+ dictWord{133, 10, 383},
+ dictWord{137, 0, 173},
+ dictWord{134, 11, 583},
+ dictWord{134, 0, 1411},
+ dictWord{19, 0, 65},
+ dictWord{5, 11, 704},
+ dictWord{8, 11, 357},
+ dictWord{10, 11, 745},
+ dictWord{14, 11, 426},
+ dictWord{17, 11, 94},
+ dictWord{147, 11, 57},
+ dictWord{9, 10, 660},
+ dictWord{138, 10, 347},
+ dictWord{4, 11, 179},
+ dictWord{5, 11, 198},
+ dictWord{133, 11, 697},
+ dictWord{7, 11, 347},
+ dictWord{7, 11, 971},
+ dictWord{8, 11, 181},
+ dictWord{138, 11, 711},
+ dictWord{141, 0, 442},
+ dictWord{
+ 11,
+ 0,
+ 842,
+ },
+ dictWord{11, 0, 924},
+ dictWord{13, 0, 317},
+ dictWord{13, 0, 370},
+ dictWord{13, 0, 469},
+ dictWord{13, 0, 471},
+ dictWord{14, 0, 397},
+ dictWord{18, 0, 69},
+ dictWord{18, 0, 145},
+ dictWord{7, 10, 572},
+ dictWord{9, 10, 592},
+ dictWord{11, 10, 680},
+ dictWord{12, 10, 356},
+ dictWord{140, 10, 550},
+ dictWord{14, 11, 19},
+ dictWord{14, 11, 28},
+ dictWord{144, 11, 29},
+ dictWord{136, 0, 534},
+ dictWord{4, 11, 243},
+ dictWord{5, 11, 203},
+ dictWord{7, 11, 19},
+ dictWord{7, 11, 71},
+ dictWord{7, 11, 113},
+ dictWord{10, 11, 405},
+ dictWord{11, 11, 357},
+ dictWord{142, 11, 240},
+ dictWord{6, 0, 210},
+ dictWord{10, 0, 845},
+ dictWord{138, 0, 862},
+ dictWord{7, 11, 1351},
+ dictWord{9, 11, 581},
+ dictWord{10, 11, 639},
+ dictWord{11, 11, 453},
+ dictWord{140, 11, 584},
+ dictWord{7, 11, 1450},
+ dictWord{
+ 139,
+ 11,
+ 99,
+ },
+ dictWord{10, 0, 892},
+ dictWord{12, 0, 719},
+ dictWord{144, 0, 105},
+ dictWord{4, 0, 284},
+ dictWord{6, 0, 223},
+ dictWord{134, 11, 492},
+ dictWord{5, 11, 134},
+ dictWord{6, 11, 408},
+ dictWord{6, 11, 495},
+ dictWord{135, 11, 1593},
+ dictWord{136, 0, 529},
+ dictWord{137, 0, 807},
+ dictWord{4, 0, 218},
+ dictWord{7, 0, 526},
+ dictWord{143, 0, 137},
+ dictWord{6, 0, 1444},
+ dictWord{142, 11, 4},
+ dictWord{132, 11, 665},
+ dictWord{4, 0, 270},
+ dictWord{5, 0, 192},
+ dictWord{6, 0, 332},
+ dictWord{7, 0, 1322},
+ dictWord{4, 11, 248},
+ dictWord{7, 11, 137},
+ dictWord{137, 11, 349},
+ dictWord{140, 0, 661},
+ dictWord{7, 0, 1517},
+ dictWord{11, 0, 597},
+ dictWord{14, 0, 76},
+ dictWord{14, 0, 335},
+ dictWord{20, 0, 33},
+ dictWord{7, 10, 748},
+ dictWord{139, 10, 700},
+ dictWord{5, 11, 371},
+ dictWord{135, 11, 563},
+ dictWord{146, 11, 57},
+ dictWord{133, 10, 127},
+ dictWord{133, 0, 418},
+ dictWord{4, 11, 374},
+ dictWord{7, 11, 547},
+ dictWord{7, 11, 1700},
+ dictWord{7, 11, 1833},
+ dictWord{139, 11, 858},
+ dictWord{6, 10, 198},
+ dictWord{140, 10, 83},
+ dictWord{7, 11, 1812},
+ dictWord{13, 11, 259},
+ dictWord{13, 11, 356},
+ dictWord{
+ 14,
+ 11,
+ 242,
+ },
+ dictWord{147, 11, 114},
+ dictWord{7, 0, 379},
+ dictWord{8, 0, 481},
+ dictWord{9, 0, 377},
+ dictWord{5, 10, 276},
+ dictWord{6, 10, 55},
+ dictWord{
+ 135,
+ 10,
+ 1369,
+ },
+ dictWord{138, 11, 286},
+ dictWord{5, 0, 1003},
+ dictWord{6, 0, 149},
+ dictWord{6, 10, 1752},
+ dictWord{136, 10, 726},
+ dictWord{8, 0, 262},
+ dictWord{
+ 9,
+ 0,
+ 627,
+ },
+ dictWord{10, 0, 18},
+ dictWord{11, 0, 214},
+ dictWord{11, 0, 404},
+ dictWord{11, 0, 457},
+ dictWord{11, 0, 780},
+ dictWord{11, 0, 913},
+ dictWord{13, 0, 401},
+ dictWord{14, 0, 200},
+ dictWord{6, 11, 1647},
+ dictWord{7, 11, 1552},
+ dictWord{7, 11, 2010},
+ dictWord{9, 11, 494},
+ dictWord{137, 11, 509},
+ dictWord{
+ 135,
+ 0,
+ 742,
+ },
+ dictWord{136, 0, 304},
+ dictWord{132, 0, 142},
+ dictWord{133, 10, 764},
+ dictWord{6, 10, 309},
+ dictWord{7, 10, 331},
+ dictWord{138, 10, 550},
+ dictWord{135, 10, 1062},
+ dictWord{6, 11, 123},
+ dictWord{7, 11, 214},
+ dictWord{7, 10, 986},
+ dictWord{9, 11, 728},
+ dictWord{10, 11, 157},
+ dictWord{11, 11, 346},
+ dictWord{11, 11, 662},
+ dictWord{143, 11, 106},
+ dictWord{135, 10, 1573},
+ dictWord{7, 0, 925},
+ dictWord{137, 0, 799},
+ dictWord{4, 0, 471},
+ dictWord{5, 0, 51},
+ dictWord{6, 0, 602},
+ dictWord{8, 0, 484},
+ dictWord{138, 0, 195},
+ dictWord{136, 0, 688},
+ dictWord{132, 0, 697},
+ dictWord{6, 0, 1169},
+ dictWord{6, 0, 1241},
+ dictWord{6, 10, 194},
+ dictWord{7, 10, 133},
+ dictWord{10, 10, 493},
+ dictWord{10, 10, 570},
+ dictWord{139, 10, 664},
+ dictWord{140, 0, 751},
+ dictWord{7, 0, 929},
+ dictWord{10, 0, 452},
+ dictWord{11, 0, 878},
+ dictWord{16, 0, 33},
+ dictWord{5, 10, 24},
+ dictWord{5, 10, 569},
+ dictWord{6, 10, 3},
+ dictWord{6, 10, 119},
+ dictWord{
+ 6,
+ 10,
+ 143,
+ },
+ dictWord{6, 10, 440},
+ dictWord{7, 10, 599},
+ dictWord{7, 10, 1686},
+ dictWord{7, 10, 1854},
+ dictWord{8, 10, 424},
+ dictWord{9, 10, 43},
+ dictWord{
+ 9,
+ 10,
+ 584,
+ },
+ dictWord{9, 10, 760},
+ dictWord{10, 10, 328},
+ dictWord{11, 10, 159},
+ dictWord{11, 10, 253},
+ dictWord{12, 10, 487},
+ dictWord{140, 10, 531},
+ dictWord{
+ 4,
+ 11,
+ 707,
+ },
+ dictWord{13, 11, 106},
+ dictWord{18, 11, 49},
+ dictWord{147, 11, 41},
+ dictWord{5, 0, 221},
+ dictWord{5, 11, 588},
+ dictWord{134, 11, 393},
+ dictWord{134, 0, 1437},
+ dictWord{6, 11, 211},
+ dictWord{7, 11, 1690},
+ dictWord{11, 11, 486},
+ dictWord{140, 11, 369},
+ dictWord{5, 10, 14},
+ dictWord{5, 10, 892},
+ dictWord{6, 10, 283},
+ dictWord{7, 10, 234},
+ dictWord{136, 10, 537},
+ dictWord{4, 0, 988},
+ dictWord{136, 0, 955},
+ dictWord{135, 0, 1251},
+ dictWord{4, 10, 126},
+ dictWord{8, 10, 635},
+ dictWord{147, 10, 34},
+ dictWord{4, 10, 316},
+ dictWord{135, 10, 1561},
+ dictWord{137, 10, 861},
+ dictWord{4, 10, 64},
+ dictWord{
+ 5,
+ 10,
+ 352,
+ },
+ dictWord{5, 10, 720},
+ dictWord{6, 10, 368},
+ dictWord{139, 10, 359},
+ dictWord{134, 0, 192},
+ dictWord{4, 0, 132},
+ dictWord{5, 0, 69},
+ dictWord{
+ 135,
+ 0,
+ 1242,
+ },
+ dictWord{7, 10, 1577},
+ dictWord{10, 10, 304},
+ dictWord{10, 10, 549},
+ dictWord{12, 10, 365},
+ dictWord{13, 10, 220},
+ dictWord{13, 10, 240},
+ dictWord{142, 10, 33},
+ dictWord{4, 0, 111},
+ dictWord{7, 0, 865},
+ dictWord{134, 11, 219},
+ dictWord{5, 11, 582},
+ dictWord{6, 11, 1646},
+ dictWord{7, 11, 99},
+ dictWord{
+ 7,
+ 11,
+ 1962,
+ },
+ dictWord{7, 11, 1986},
+ dictWord{8, 11, 515},
+ dictWord{8, 11, 773},
+ dictWord{9, 11, 23},
+ dictWord{9, 11, 491},
+ dictWord{12, 11, 620},
+ dictWord{
+ 14,
+ 11,
+ 52,
+ },
+ dictWord{145, 11, 50},
+ dictWord{132, 0, 767},
+ dictWord{7, 11, 568},
+ dictWord{148, 11, 21},
+ dictWord{6, 0, 42},
+ dictWord{7, 0, 1416},
+ dictWord{
+ 7,
+ 0,
+ 2005,
+ },
+ dictWord{8, 0, 131},
+ dictWord{8, 0, 466},
+ dictWord{9, 0, 672},
+ dictWord{13, 0, 252},
+ dictWord{20, 0, 103},
+ dictWord{133, 11, 851},
+ dictWord{
+ 135,
+ 0,
+ 1050,
+ },
+ dictWord{6, 10, 175},
+ dictWord{137, 10, 289},
+ dictWord{5, 10, 432},
+ dictWord{133, 10, 913},
+ dictWord{6, 0, 44},
+ dictWord{136, 0, 368},
+ dictWord{
+ 135,
+ 11,
+ 784,
+ },
+ dictWord{132, 0, 570},
+ dictWord{133, 0, 120},
+ dictWord{139, 10, 595},
+ dictWord{140, 0, 29},
+ dictWord{6, 0, 227},
+ dictWord{135, 0, 1589},
+ dictWord{4, 11, 98},
+ dictWord{7, 11, 1365},
+ dictWord{9, 11, 422},
+ dictWord{9, 11, 670},
+ dictWord{10, 11, 775},
+ dictWord{11, 11, 210},
+ dictWord{13, 11, 26},
+ dictWord{13, 11, 457},
+ dictWord{141, 11, 476},
+ dictWord{140, 10, 80},
+ dictWord{5, 10, 931},
+ dictWord{134, 10, 1698},
+ dictWord{133, 0, 522},
+ dictWord{
+ 134,
+ 0,
+ 1120,
+ },
+ dictWord{135, 0, 1529},
+ dictWord{12, 0, 739},
+ dictWord{14, 0, 448},
+ dictWord{142, 0, 467},
+ dictWord{11, 10, 526},
+ dictWord{11, 10, 939},
+ dictWord{141, 10, 290},
+ dictWord{5, 10, 774},
+ dictWord{6, 10, 1637},
+ dictWord{6, 10, 1686},
+ dictWord{134, 10, 1751},
+ dictWord{6, 0, 1667},
+ dictWord{
+ 135,
+ 0,
+ 2036,
+ },
+ dictWord{7, 10, 1167},
+ dictWord{11, 10, 934},
+ dictWord{13, 10, 391},
+ dictWord{145, 10, 76},
+ dictWord{137, 11, 147},
+ dictWord{6, 10, 260},
+ dictWord{
+ 7,
+ 10,
+ 1484,
+ },
+ dictWord{11, 11, 821},
+ dictWord{12, 11, 110},
+ dictWord{12, 11, 153},
+ dictWord{18, 11, 41},
+ dictWord{150, 11, 19},
+ dictWord{6, 0, 511},
+ dictWord{12, 0, 132},
+ dictWord{134, 10, 573},
+ dictWord{5, 0, 568},
+ dictWord{6, 0, 138},
+ dictWord{135, 0, 1293},
+ dictWord{132, 0, 1020},
+ dictWord{8, 0, 258},
+ dictWord{9, 0, 208},
+ dictWord{137, 0, 359},
+ dictWord{4, 0, 565},
+ dictWord{8, 0, 23},
+ dictWord{136, 0, 827},
+ dictWord{134, 0, 344},
+ dictWord{4, 0, 922},
+ dictWord{
+ 5,
+ 0,
+ 1023,
+ },
+ dictWord{13, 11, 477},
+ dictWord{14, 11, 120},
+ dictWord{148, 11, 61},
+ dictWord{134, 0, 240},
+ dictWord{5, 11, 209},
+ dictWord{6, 11, 30},
+ dictWord{
+ 11,
+ 11,
+ 56,
+ },
+ dictWord{139, 11, 305},
+ dictWord{6, 0, 171},
+ dictWord{7, 0, 1002},
+ dictWord{7, 0, 1324},
+ dictWord{9, 0, 415},
+ dictWord{14, 0, 230},
+ dictWord{
+ 18,
+ 0,
+ 68,
+ },
+ dictWord{4, 10, 292},
+ dictWord{4, 10, 736},
+ dictWord{5, 10, 871},
+ dictWord{6, 10, 1689},
+ dictWord{7, 10, 1944},
+ dictWord{137, 10, 580},
+ dictWord{
+ 9,
+ 11,
+ 635,
+ },
+ dictWord{139, 11, 559},
+ dictWord{4, 11, 150},
+ dictWord{5, 11, 303},
+ dictWord{134, 11, 327},
+ dictWord{6, 10, 63},
+ dictWord{135, 10, 920},
+ dictWord{
+ 133,
+ 10,
+ 793,
+ },
+ dictWord{8, 11, 192},
+ dictWord{10, 11, 78},
+ dictWord{10, 11, 555},
+ dictWord{11, 11, 308},
+ dictWord{13, 11, 359},
+ dictWord{147, 11, 95},
+ dictWord{135, 11, 786},
+ dictWord{135, 11, 1712},
+ dictWord{136, 0, 402},
+ dictWord{6, 0, 754},
+ dictWord{6, 11, 1638},
+ dictWord{7, 11, 79},
+ dictWord{7, 11, 496},
+ dictWord{9, 11, 138},
+ dictWord{10, 11, 336},
+ dictWord{11, 11, 12},
+ dictWord{12, 11, 412},
+ dictWord{12, 11, 440},
+ dictWord{142, 11, 305},
+ dictWord{4, 0, 716},
+ dictWord{141, 0, 31},
+ dictWord{133, 0, 982},
+ dictWord{8, 0, 691},
+ dictWord{8, 0, 731},
+ dictWord{5, 10, 67},
+ dictWord{6, 10, 62},
+ dictWord{6, 10, 374},
+ dictWord{
+ 135,
+ 10,
+ 1391,
+ },
+ dictWord{9, 10, 790},
+ dictWord{140, 10, 47},
+ dictWord{139, 11, 556},
+ dictWord{151, 11, 1},
+ dictWord{7, 11, 204},
+ dictWord{7, 11, 415},
+ dictWord{8, 11, 42},
+ dictWord{10, 11, 85},
+ dictWord{11, 11, 33},
+ dictWord{11, 11, 564},
+ dictWord{12, 11, 571},
+ dictWord{149, 11, 1},
+ dictWord{8, 0, 888},
+ dictWord{
+ 7,
+ 11,
+ 610,
+ },
+ dictWord{135, 11, 1501},
+ dictWord{4, 10, 391},
+ dictWord{135, 10, 1169},
+ dictWord{5, 0, 847},
+ dictWord{9, 0, 840},
+ dictWord{138, 0, 803},
+ dictWord{137, 0, 823},
+ dictWord{134, 0, 785},
+ dictWord{8, 0, 152},
+ dictWord{9, 0, 53},
+ dictWord{9, 0, 268},
+ dictWord{9, 0, 901},
+ dictWord{10, 0, 518},
+ dictWord{
+ 10,
+ 0,
+ 829,
+ },
+ dictWord{11, 0, 188},
+ dictWord{13, 0, 74},
+ dictWord{14, 0, 46},
+ dictWord{15, 0, 17},
+ dictWord{15, 0, 33},
+ dictWord{17, 0, 40},
+ dictWord{18, 0, 36},
+ dictWord{
+ 19,
+ 0,
+ 20,
+ },
+ dictWord{22, 0, 1},
+ dictWord{152, 0, 2},
+ dictWord{4, 11, 3},
+ dictWord{5, 11, 247},
+ dictWord{5, 11, 644},
+ dictWord{7, 11, 744},
+ dictWord{7, 11, 1207},
+ dictWord{7, 11, 1225},
+ dictWord{7, 11, 1909},
+ dictWord{146, 11, 147},
+ dictWord{136, 0, 532},
+ dictWord{135, 0, 681},
+ dictWord{132, 10, 271},
+ dictWord{
+ 140,
+ 0,
+ 314,
+ },
+ dictWord{140, 0, 677},
+ dictWord{4, 0, 684},
+ dictWord{136, 0, 384},
+ dictWord{5, 11, 285},
+ dictWord{9, 11, 67},
+ dictWord{13, 11, 473},
+ dictWord{
+ 143,
+ 11,
+ 82,
+ },
+ dictWord{4, 10, 253},
+ dictWord{5, 10, 544},
+ dictWord{7, 10, 300},
+ dictWord{137, 10, 340},
+ dictWord{7, 0, 110},
+ dictWord{7, 0, 447},
+ dictWord{8, 0, 290},
+ dictWord{8, 0, 591},
+ dictWord{9, 0, 382},
+ dictWord{9, 0, 649},
+ dictWord{11, 0, 71},
+ dictWord{11, 0, 155},
+ dictWord{11, 0, 313},
+ dictWord{12, 0, 5},
+ dictWord{13, 0, 325},
+ dictWord{142, 0, 287},
+ dictWord{134, 0, 1818},
+ dictWord{136, 0, 1007},
+ dictWord{138, 0, 321},
+ dictWord{7, 0, 360},
+ dictWord{7, 0, 425},
+ dictWord{9, 0, 66},
+ dictWord{9, 0, 278},
+ dictWord{138, 0, 644},
+ dictWord{133, 10, 818},
+ dictWord{5, 0, 385},
+ dictWord{5, 10, 541},
+ dictWord{6, 10, 94},
+ dictWord{6, 10, 499},
+ dictWord{
+ 7,
+ 10,
+ 230,
+ },
+ dictWord{139, 10, 321},
+ dictWord{4, 10, 920},
+ dictWord{5, 10, 25},
+ dictWord{5, 10, 790},
+ dictWord{6, 10, 457},
+ dictWord{7, 10, 853},
+ dictWord{
+ 136,
+ 10,
+ 788,
+ },
+ dictWord{4, 0, 900},
+ dictWord{133, 0, 861},
+ dictWord{5, 0, 254},
+ dictWord{7, 0, 985},
+ dictWord{136, 0, 73},
+ dictWord{7, 0, 1959},
+ dictWord{
+ 136,
+ 0,
+ 683,
+ },
+ dictWord{134, 10, 1765},
+ dictWord{133, 10, 822},
+ dictWord{132, 10, 634},
+ dictWord{4, 11, 29},
+ dictWord{6, 11, 532},
+ dictWord{7, 11, 1628},
+ dictWord{
+ 7,
+ 11,
+ 1648,
+ },
+ dictWord{9, 11, 303},
+ dictWord{9, 11, 350},
+ dictWord{10, 11, 433},
+ dictWord{11, 11, 97},
+ dictWord{11, 11, 557},
+ dictWord{11, 11, 745},
+ dictWord{12, 11, 289},
+ dictWord{12, 11, 335},
+ dictWord{12, 11, 348},
+ dictWord{12, 11, 606},
+ dictWord{13, 11, 116},
+ dictWord{13, 11, 233},
+ dictWord{
+ 13,
+ 11,
+ 466,
+ },
+ dictWord{14, 11, 181},
+ dictWord{14, 11, 209},
+ dictWord{14, 11, 232},
+ dictWord{14, 11, 236},
+ dictWord{14, 11, 300},
+ dictWord{16, 11, 41},
+ dictWord{
+ 148,
+ 11,
+ 97,
+ },
+ dictWord{19, 0, 86},
+ dictWord{6, 10, 36},
+ dictWord{7, 10, 658},
+ dictWord{136, 10, 454},
+ dictWord{135, 11, 1692},
+ dictWord{132, 0, 725},
+ dictWord{
+ 5,
+ 11,
+ 501,
+ },
+ dictWord{7, 11, 1704},
+ dictWord{9, 11, 553},
+ dictWord{11, 11, 520},
+ dictWord{12, 11, 557},
+ dictWord{141, 11, 249},
+ dictWord{134, 0, 196},
+ dictWord{133, 0, 831},
+ dictWord{136, 0, 723},
+ dictWord{7, 0, 1897},
+ dictWord{13, 0, 80},
+ dictWord{13, 0, 437},
+ dictWord{145, 0, 74},
+ dictWord{4, 0, 992},
+ dictWord{
+ 6,
+ 0,
+ 627,
+ },
+ dictWord{136, 0, 994},
+ dictWord{135, 11, 1294},
+ dictWord{132, 10, 104},
+ dictWord{5, 0, 848},
+ dictWord{6, 0, 66},
+ dictWord{136, 0, 764},
+ dictWord{
+ 4,
+ 0,
+ 36,
+ },
+ dictWord{7, 0, 1387},
+ dictWord{10, 0, 205},
+ dictWord{139, 0, 755},
+ dictWord{6, 0, 1046},
+ dictWord{134, 0, 1485},
+ dictWord{134, 0, 950},
+ dictWord{132, 0, 887},
+ dictWord{14, 0, 450},
+ dictWord{148, 0, 111},
+ dictWord{7, 0, 620},
+ dictWord{7, 0, 831},
+ dictWord{9, 10, 542},
+ dictWord{9, 10, 566},
+ dictWord{
+ 138,
+ 10,
+ 728,
+ },
+ dictWord{6, 0, 165},
+ dictWord{138, 0, 388},
+ dictWord{139, 10, 263},
+ dictWord{4, 0, 719},
+ dictWord{135, 0, 155},
+ dictWord{138, 10, 468},
+ dictWord{6, 11, 453},
+ dictWord{144, 11, 36},
+ dictWord{134, 11, 129},
+ dictWord{5, 0, 533},
+ dictWord{7, 0, 755},
+ dictWord{138, 0, 780},
+ dictWord{134, 0, 1465},
+ dictWord{4, 0, 353},
+ dictWord{6, 0, 146},
+ dictWord{6, 0, 1789},
+ dictWord{7, 0, 427},
+ dictWord{7, 0, 990},
+ dictWord{7, 0, 1348},
+ dictWord{9, 0, 665},
+ dictWord{9, 0, 898},
+ dictWord{11, 0, 893},
+ dictWord{142, 0, 212},
+ dictWord{7, 10, 87},
+ dictWord{142, 10, 288},
+ dictWord{4, 0, 45},
+ dictWord{135, 0, 1257},
+ dictWord{12, 0, 7},
+ dictWord{7, 10, 988},
+ dictWord{7, 10, 1939},
+ dictWord{9, 10, 64},
+ dictWord{9, 10, 502},
+ dictWord{12, 10, 34},
+ dictWord{13, 10, 12},
+ dictWord{13, 10, 234},
+ dictWord{147, 10, 77},
+ dictWord{4, 0, 607},
+ dictWord{5, 11, 60},
+ dictWord{6, 11, 504},
+ dictWord{7, 11, 614},
+ dictWord{7, 11, 1155},
+ dictWord{140, 11, 0},
+ dictWord{
+ 135,
+ 10,
+ 141,
+ },
+ dictWord{8, 11, 198},
+ dictWord{11, 11, 29},
+ dictWord{140, 11, 534},
+ dictWord{140, 0, 65},
+ dictWord{136, 0, 816},
+ dictWord{132, 10, 619},
+ dictWord{139, 0, 88},
+ dictWord{5, 10, 246},
+ dictWord{8, 10, 189},
+ dictWord{9, 10, 355},
+ dictWord{9, 10, 512},
+ dictWord{10, 10, 124},
+ dictWord{10, 10, 453},
+ dictWord{11, 10, 143},
+ dictWord{11, 10, 416},
+ dictWord{11, 10, 859},
+ dictWord{141, 10, 341},
+ dictWord{4, 11, 379},
+ dictWord{135, 11, 1397},
+ dictWord{
+ 4,
+ 0,
+ 600,
+ },
+ dictWord{137, 0, 621},
+ dictWord{133, 0, 367},
+ dictWord{134, 0, 561},
+ dictWord{6, 0, 559},
+ dictWord{134, 0, 1691},
+ dictWord{6, 0, 585},
+ dictWord{
+ 134,
+ 11,
+ 585,
+ },
+ dictWord{135, 11, 1228},
+ dictWord{4, 11, 118},
+ dictWord{5, 10, 678},
+ dictWord{6, 11, 274},
+ dictWord{6, 11, 361},
+ dictWord{7, 11, 75},
+ dictWord{
+ 141,
+ 11,
+ 441,
+ },
+ dictWord{135, 11, 1818},
+ dictWord{137, 11, 841},
+ dictWord{5, 0, 573},
+ dictWord{6, 0, 287},
+ dictWord{7, 10, 862},
+ dictWord{7, 10, 1886},
+ dictWord{138, 10, 179},
+ dictWord{132, 10, 517},
+ dictWord{140, 11, 693},
+ dictWord{5, 11, 314},
+ dictWord{6, 11, 221},
+ dictWord{7, 11, 419},
+ dictWord{
+ 10,
+ 11,
+ 650,
+ },
+ dictWord{11, 11, 396},
+ dictWord{12, 11, 156},
+ dictWord{13, 11, 369},
+ dictWord{14, 11, 333},
+ dictWord{145, 11, 47},
+ dictWord{140, 10, 540},
+ dictWord{136, 10, 667},
+ dictWord{11, 10, 403},
+ dictWord{146, 10, 83},
+ dictWord{6, 0, 672},
+ dictWord{133, 10, 761},
+ dictWord{9, 0, 157},
+ dictWord{10, 10, 131},
+ dictWord{140, 10, 72},
+ dictWord{7, 0, 714},
+ dictWord{134, 11, 460},
+ dictWord{134, 0, 456},
+ dictWord{133, 0, 925},
+ dictWord{5, 11, 682},
+ dictWord{
+ 135,
+ 11,
+ 1887,
+ },
+ dictWord{136, 11, 510},
+ dictWord{136, 11, 475},
+ dictWord{133, 11, 1016},
+ dictWord{9, 0, 19},
+ dictWord{7, 11, 602},
+ dictWord{8, 11, 179},
+ dictWord{
+ 10,
+ 11,
+ 781,
+ },
+ dictWord{140, 11, 126},
+ dictWord{6, 11, 329},
+ dictWord{138, 11, 111},
+ dictWord{6, 0, 822},
+ dictWord{134, 0, 1473},
+ dictWord{144, 11, 86},
+ dictWord{11, 0, 113},
+ dictWord{139, 11, 113},
+ dictWord{5, 11, 821},
+ dictWord{134, 11, 1687},
+ dictWord{133, 10, 449},
+ dictWord{7, 0, 463},
+ dictWord{
+ 17,
+ 0,
+ 69,
+ },
+ dictWord{136, 10, 103},
+ dictWord{7, 10, 2028},
+ dictWord{138, 10, 641},
+ dictWord{6, 0, 193},
+ dictWord{7, 0, 240},
+ dictWord{7, 0, 1682},
+ dictWord{
+ 10,
+ 0,
+ 51,
+ },
+ dictWord{10, 0, 640},
+ dictWord{11, 0, 410},
+ dictWord{13, 0, 82},
+ dictWord{14, 0, 247},
+ dictWord{14, 0, 331},
+ dictWord{142, 0, 377},
+ dictWord{6, 0, 471},
+ dictWord{11, 0, 411},
+ dictWord{142, 0, 2},
+ dictWord{5, 11, 71},
+ dictWord{7, 11, 1407},
+ dictWord{9, 11, 388},
+ dictWord{9, 11, 704},
+ dictWord{10, 11, 261},
+ dictWord{
+ 10,
+ 11,
+ 619,
+ },
+ dictWord{11, 11, 547},
+ dictWord{11, 11, 619},
+ dictWord{143, 11, 157},
+ dictWord{136, 0, 633},
+ dictWord{135, 0, 1148},
+ dictWord{6, 0, 554},
+ dictWord{7, 0, 1392},
+ dictWord{12, 0, 129},
+ dictWord{7, 10, 1274},
+ dictWord{7, 10, 1386},
+ dictWord{7, 11, 2008},
+ dictWord{9, 11, 337},
+ dictWord{10, 11, 517},
+ dictWord{146, 10, 87},
+ dictWord{7, 0, 803},
+ dictWord{8, 0, 542},
+ dictWord{6, 10, 187},
+ dictWord{7, 10, 1203},
+ dictWord{8, 10, 380},
+ dictWord{14, 10, 117},
+ dictWord{149, 10, 28},
+ dictWord{6, 10, 297},
+ dictWord{7, 10, 793},
+ dictWord{139, 10, 938},
+ dictWord{8, 0, 438},
+ dictWord{11, 0, 363},
+ dictWord{7, 10, 464},
+ dictWord{11, 10, 105},
+ dictWord{12, 10, 231},
+ dictWord{14, 10, 386},
+ dictWord{15, 10, 102},
+ dictWord{148, 10, 75},
+ dictWord{5, 11, 16},
+ dictWord{6, 11, 86},
+ dictWord{6, 11, 603},
+ dictWord{7, 11, 292},
+ dictWord{7, 11, 561},
+ dictWord{8, 11, 257},
+ dictWord{8, 11, 382},
+ dictWord{9, 11, 721},
+ dictWord{9, 11, 778},
+ dictWord{
+ 11,
+ 11,
+ 581,
+ },
+ dictWord{140, 11, 466},
+ dictWord{6, 0, 717},
+ dictWord{4, 11, 486},
+ dictWord{133, 11, 491},
+ dictWord{132, 0, 875},
+ dictWord{132, 11, 72},
+ dictWord{6, 11, 265},
+ dictWord{135, 11, 847},
+ dictWord{4, 0, 237},
+ dictWord{135, 0, 514},
+ dictWord{6, 0, 392},
+ dictWord{7, 0, 65},
+ dictWord{135, 0, 2019},
+ dictWord{140, 11, 261},
+ dictWord{135, 11, 922},
+ dictWord{137, 11, 404},
+ dictWord{12, 0, 563},
+ dictWord{14, 0, 101},
+ dictWord{18, 0, 129},
+ dictWord{
+ 7,
+ 10,
+ 1010,
+ },
+ dictWord{11, 10, 733},
+ dictWord{11, 10, 759},
+ dictWord{13, 10, 34},
+ dictWord{146, 10, 45},
+ dictWord{7, 10, 1656},
+ dictWord{9, 10, 369},
+ dictWord{
+ 10,
+ 10,
+ 338,
+ },
+ dictWord{10, 10, 490},
+ dictWord{11, 10, 154},
+ dictWord{11, 10, 545},
+ dictWord{11, 10, 775},
+ dictWord{13, 10, 77},
+ dictWord{141, 10, 274},
+ dictWord{4, 0, 444},
+ dictWord{10, 0, 146},
+ dictWord{140, 0, 9},
+ dictWord{139, 11, 163},
+ dictWord{7, 0, 1260},
+ dictWord{135, 0, 1790},
+ dictWord{9, 0, 222},
+ dictWord{10, 0, 43},
+ dictWord{139, 0, 900},
+ dictWord{137, 11, 234},
+ dictWord{138, 0, 971},
+ dictWord{137, 0, 761},
+ dictWord{134, 0, 699},
+ dictWord{
+ 136,
+ 11,
+ 434,
+ },
+ dictWord{6, 0, 1116},
+ dictWord{7, 0, 1366},
+ dictWord{5, 10, 20},
+ dictWord{6, 11, 197},
+ dictWord{6, 10, 298},
+ dictWord{7, 10, 659},
+ dictWord{8, 11, 205},
+ dictWord{137, 10, 219},
+ dictWord{132, 11, 490},
+ dictWord{11, 11, 820},
+ dictWord{150, 11, 51},
+ dictWord{7, 10, 1440},
+ dictWord{11, 10, 854},
+ dictWord{
+ 11,
+ 10,
+ 872,
+ },
+ dictWord{11, 10, 921},
+ dictWord{12, 10, 551},
+ dictWord{13, 10, 472},
+ dictWord{142, 10, 367},
+ dictWord{140, 11, 13},
+ dictWord{132, 0, 829},
+ dictWord{12, 0, 242},
+ dictWord{132, 10, 439},
+ dictWord{136, 10, 669},
+ dictWord{6, 0, 593},
+ dictWord{6, 11, 452},
+ dictWord{7, 11, 312},
+ dictWord{
+ 138,
+ 11,
+ 219,
+ },
+ dictWord{4, 11, 333},
+ dictWord{9, 11, 176},
+ dictWord{12, 11, 353},
+ dictWord{141, 11, 187},
+ dictWord{7, 0, 36},
+ dictWord{8, 0, 201},
+ dictWord{
+ 136,
+ 0,
+ 605,
+ },
+ dictWord{140, 0, 224},
+ dictWord{132, 10, 233},
+ dictWord{134, 0, 1430},
+ dictWord{134, 0, 1806},
+ dictWord{4, 0, 523},
+ dictWord{133, 0, 638},
+ dictWord{
+ 6,
+ 0,
+ 1889,
+ },
+ dictWord{9, 0, 958},
+ dictWord{9, 0, 971},
+ dictWord{9, 0, 976},
+ dictWord{12, 0, 796},
+ dictWord{12, 0, 799},
+ dictWord{12, 0, 808},
+ dictWord{
+ 12,
+ 0,
+ 835,
+ },
+ dictWord{12, 0, 836},
+ dictWord{12, 0, 914},
+ dictWord{12, 0, 946},
+ dictWord{15, 0, 216},
+ dictWord{15, 0, 232},
+ dictWord{18, 0, 183},
+ dictWord{18, 0, 187},
+ dictWord{18, 0, 194},
+ dictWord{18, 0, 212},
+ dictWord{18, 0, 232},
+ dictWord{149, 0, 49},
+ dictWord{132, 10, 482},
+ dictWord{6, 0, 827},
+ dictWord{134, 0, 1434},
+ dictWord{135, 10, 346},
+ dictWord{134, 0, 2043},
+ dictWord{6, 0, 242},
+ dictWord{7, 0, 227},
+ dictWord{7, 0, 1581},
+ dictWord{8, 0, 104},
+ dictWord{9, 0, 113},
+ dictWord{9, 0, 220},
+ dictWord{9, 0, 427},
+ dictWord{10, 0, 136},
+ dictWord{10, 0, 239},
+ dictWord{11, 0, 579},
+ dictWord{11, 0, 1023},
+ dictWord{13, 0, 4},
+ dictWord{
+ 13,
+ 0,
+ 204,
+ },
+ dictWord{13, 0, 316},
+ dictWord{148, 0, 86},
+ dictWord{134, 11, 1685},
+ dictWord{7, 0, 148},
+ dictWord{8, 0, 284},
+ dictWord{141, 0, 63},
+ dictWord{
+ 142,
+ 0,
+ 10,
+ },
+ dictWord{135, 11, 584},
+ dictWord{134, 0, 1249},
+ dictWord{7, 0, 861},
+ dictWord{135, 10, 334},
+ dictWord{5, 10, 795},
+ dictWord{6, 10, 1741},
+ dictWord{
+ 137,
+ 11,
+ 70,
+ },
+ dictWord{132, 0, 807},
+ dictWord{7, 11, 135},
+ dictWord{8, 11, 7},
+ dictWord{8, 11, 62},
+ dictWord{9, 11, 243},
+ dictWord{10, 11, 658},
+ dictWord{
+ 10,
+ 11,
+ 697,
+ },
+ dictWord{11, 11, 456},
+ dictWord{139, 11, 756},
+ dictWord{9, 11, 395},
+ dictWord{138, 11, 79},
+ dictWord{137, 11, 108},
+ dictWord{147, 0, 94},
+ dictWord{136, 0, 494},
+ dictWord{135, 11, 631},
+ dictWord{135, 10, 622},
+ dictWord{7, 0, 1510},
+ dictWord{135, 10, 1750},
+ dictWord{4, 10, 203},
+ dictWord{
+ 135,
+ 10,
+ 1936,
+ },
+ dictWord{7, 11, 406},
+ dictWord{7, 11, 459},
+ dictWord{8, 11, 606},
+ dictWord{139, 11, 726},
+ dictWord{7, 0, 1306},
+ dictWord{8, 0, 505},
+ dictWord{
+ 9,
+ 0,
+ 482,
+ },
+ dictWord{10, 0, 126},
+ dictWord{11, 0, 225},
+ dictWord{12, 0, 347},
+ dictWord{12, 0, 449},
+ dictWord{13, 0, 19},
+ dictWord{14, 0, 218},
+ dictWord{142, 0, 435},
+ dictWord{5, 0, 268},
+ dictWord{10, 0, 764},
+ dictWord{12, 0, 120},
+ dictWord{13, 0, 39},
+ dictWord{145, 0, 127},
+ dictWord{142, 11, 68},
+ dictWord{11, 10, 678},
+ dictWord{140, 10, 307},
+ dictWord{12, 11, 268},
+ dictWord{12, 11, 640},
+ dictWord{142, 11, 119},
+ dictWord{135, 10, 2044},
+ dictWord{133, 11, 612},
+ dictWord{
+ 4,
+ 11,
+ 372,
+ },
+ dictWord{7, 11, 482},
+ dictWord{8, 11, 158},
+ dictWord{9, 11, 602},
+ dictWord{9, 11, 615},
+ dictWord{10, 11, 245},
+ dictWord{10, 11, 678},
+ dictWord{
+ 10,
+ 11,
+ 744,
+ },
+ dictWord{11, 11, 248},
+ dictWord{139, 11, 806},
+ dictWord{7, 10, 311},
+ dictWord{9, 10, 308},
+ dictWord{140, 10, 255},
+ dictWord{4, 0, 384},
+ dictWord{135, 0, 1022},
+ dictWord{5, 11, 854},
+ dictWord{135, 11, 1991},
+ dictWord{135, 10, 1266},
+ dictWord{4, 10, 400},
+ dictWord{5, 10, 267},
+ dictWord{
+ 135,
+ 10,
+ 232,
+ },
+ dictWord{135, 0, 1703},
+ dictWord{9, 0, 159},
+ dictWord{11, 0, 661},
+ dictWord{140, 0, 603},
+ dictWord{4, 0, 964},
+ dictWord{14, 0, 438},
+ dictWord{
+ 14,
+ 0,
+ 444,
+ },
+ dictWord{14, 0, 456},
+ dictWord{22, 0, 60},
+ dictWord{22, 0, 63},
+ dictWord{9, 11, 106},
+ dictWord{9, 11, 163},
+ dictWord{9, 11, 296},
+ dictWord{10, 11, 167},
+ dictWord{10, 11, 172},
+ dictWord{10, 11, 777},
+ dictWord{139, 11, 16},
+ dictWord{136, 0, 583},
+ dictWord{132, 0, 515},
+ dictWord{8, 0, 632},
+ dictWord{8, 0, 697},
+ dictWord{137, 0, 854},
+ dictWord{5, 11, 195},
+ dictWord{135, 11, 1685},
+ dictWord{6, 0, 1123},
+ dictWord{134, 0, 1365},
+ dictWord{134, 11, 328},
+ dictWord{
+ 7,
+ 11,
+ 1997,
+ },
+ dictWord{8, 11, 730},
+ dictWord{139, 11, 1006},
+ dictWord{4, 0, 136},
+ dictWord{133, 0, 551},
+ dictWord{134, 0, 1782},
+ dictWord{7, 0, 1287},
+ dictWord{
+ 9,
+ 0,
+ 44,
+ },
+ dictWord{10, 0, 552},
+ dictWord{10, 0, 642},
+ dictWord{11, 0, 839},
+ dictWord{12, 0, 274},
+ dictWord{12, 0, 275},
+ dictWord{12, 0, 372},
+ dictWord{
+ 13,
+ 0,
+ 91,
+ },
+ dictWord{142, 0, 125},
+ dictWord{5, 11, 751},
+ dictWord{11, 11, 797},
+ dictWord{140, 11, 203},
+ dictWord{133, 0, 732},
+ dictWord{7, 0, 679},
+ dictWord{
+ 8,
+ 0,
+ 313,
+ },
+ dictWord{4, 10, 100},
+ dictWord{135, 11, 821},
+ dictWord{10, 0, 361},
+ dictWord{142, 0, 316},
+ dictWord{134, 0, 595},
+ dictWord{6, 0, 147},
+ dictWord{
+ 7,
+ 0,
+ 886,
+ },
+ dictWord{9, 0, 753},
+ dictWord{138, 0, 268},
+ dictWord{5, 10, 362},
+ dictWord{5, 10, 443},
+ dictWord{6, 10, 318},
+ dictWord{7, 10, 1019},
+ dictWord{
+ 139,
+ 10,
+ 623,
+ },
+ dictWord{5, 10, 463},
+ dictWord{136, 10, 296},
+ dictWord{4, 10, 454},
+ dictWord{5, 11, 950},
+ dictWord{5, 11, 994},
+ dictWord{134, 11, 351},
+ dictWord{
+ 138,
+ 0,
+ 137,
+ },
+ dictWord{5, 10, 48},
+ dictWord{5, 10, 404},
+ dictWord{6, 10, 557},
+ dictWord{7, 10, 458},
+ dictWord{8, 10, 597},
+ dictWord{10, 10, 455},
+ dictWord{
+ 10,
+ 10,
+ 606,
+ },
+ dictWord{11, 10, 49},
+ dictWord{11, 10, 548},
+ dictWord{12, 10, 476},
+ dictWord{13, 10, 18},
+ dictWord{141, 10, 450},
+ dictWord{133, 0, 414},
+ dictWord{
+ 135,
+ 0,
+ 1762,
+ },
+ dictWord{5, 11, 421},
+ dictWord{135, 11, 47},
+ dictWord{5, 10, 442},
+ dictWord{135, 10, 1984},
+ dictWord{134, 0, 599},
+ dictWord{134, 0, 1749},
+ dictWord{134, 0, 1627},
+ dictWord{4, 0, 488},
+ dictWord{132, 11, 350},
+ dictWord{137, 11, 751},
+ dictWord{132, 0, 83},
+ dictWord{140, 0, 676},
+ dictWord{
+ 133,
+ 11,
+ 967,
+ },
+ dictWord{7, 0, 1639},
+ dictWord{5, 10, 55},
+ dictWord{140, 10, 161},
+ dictWord{4, 11, 473},
+ dictWord{7, 11, 623},
+ dictWord{8, 11, 808},
+ dictWord{
+ 9,
+ 11,
+ 871,
+ },
+ dictWord{9, 11, 893},
+ dictWord{11, 11, 38},
+ dictWord{11, 11, 431},
+ dictWord{12, 11, 112},
+ dictWord{12, 11, 217},
+ dictWord{12, 11, 243},
+ dictWord{
+ 12,
+ 11,
+ 562,
+ },
+ dictWord{12, 11, 683},
+ dictWord{13, 11, 141},
+ dictWord{13, 11, 197},
+ dictWord{13, 11, 227},
+ dictWord{13, 11, 406},
+ dictWord{13, 11, 487},
+ dictWord{14, 11, 156},
+ dictWord{14, 11, 203},
+ dictWord{14, 11, 224},
+ dictWord{14, 11, 256},
+ dictWord{18, 11, 58},
+ dictWord{150, 11, 0},
+ dictWord{
+ 133,
+ 10,
+ 450,
+ },
+ dictWord{7, 11, 736},
+ dictWord{139, 11, 264},
+ dictWord{134, 0, 278},
+ dictWord{4, 11, 222},
+ dictWord{7, 11, 286},
+ dictWord{136, 11, 629},
+ dictWord{
+ 135,
+ 10,
+ 869,
+ },
+ dictWord{140, 0, 97},
+ dictWord{144, 0, 14},
+ dictWord{134, 0, 1085},
+ dictWord{4, 10, 213},
+ dictWord{7, 10, 223},
+ dictWord{136, 10, 80},
+ dictWord{
+ 7,
+ 0,
+ 388,
+ },
+ dictWord{7, 0, 644},
+ dictWord{139, 0, 781},
+ dictWord{132, 0, 849},
+ dictWord{7, 0, 229},
+ dictWord{8, 0, 59},
+ dictWord{9, 0, 190},
+ dictWord{10, 0, 378},
+ dictWord{140, 0, 191},
+ dictWord{7, 10, 381},
+ dictWord{7, 10, 806},
+ dictWord{7, 10, 820},
+ dictWord{8, 10, 354},
+ dictWord{8, 10, 437},
+ dictWord{8, 10, 787},
+ dictWord{9, 10, 657},
+ dictWord{10, 10, 58},
+ dictWord{10, 10, 339},
+ dictWord{10, 10, 749},
+ dictWord{11, 10, 914},
+ dictWord{12, 10, 162},
+ dictWord{13, 10, 75},
+ dictWord{14, 10, 106},
+ dictWord{14, 10, 198},
+ dictWord{14, 10, 320},
+ dictWord{14, 10, 413},
+ dictWord{146, 10, 43},
+ dictWord{141, 11, 306},
+ dictWord{
+ 136,
+ 10,
+ 747,
+ },
+ dictWord{134, 0, 1115},
+ dictWord{16, 0, 94},
+ dictWord{16, 0, 108},
+ dictWord{136, 11, 146},
+ dictWord{6, 0, 700},
+ dictWord{6, 0, 817},
+ dictWord{
+ 134,
+ 0,
+ 1002,
+ },
+ dictWord{133, 10, 692},
+ dictWord{4, 11, 465},
+ dictWord{135, 11, 1663},
+ dictWord{134, 10, 191},
+ dictWord{6, 0, 1414},
+ dictWord{
+ 135,
+ 11,
+ 913,
+ },
+ dictWord{132, 0, 660},
+ dictWord{7, 0, 1035},
+ dictWord{138, 0, 737},
+ dictWord{6, 10, 162},
+ dictWord{7, 10, 1960},
+ dictWord{136, 10, 831},
+ dictWord{
+ 132,
+ 10,
+ 706,
+ },
+ dictWord{7, 0, 690},
+ dictWord{9, 0, 217},
+ dictWord{9, 0, 587},
+ dictWord{140, 0, 521},
+ dictWord{138, 10, 426},
+ dictWord{135, 10, 1235},
+ dictWord{
+ 6,
+ 11,
+ 82,
+ },
+ dictWord{7, 11, 138},
+ dictWord{7, 11, 517},
+ dictWord{9, 11, 673},
+ dictWord{139, 11, 238},
+ dictWord{138, 0, 272},
+ dictWord{5, 11, 495},
+ dictWord{
+ 7,
+ 11,
+ 834,
+ },
+ dictWord{9, 11, 733},
+ dictWord{139, 11, 378},
+ dictWord{134, 0, 1744},
+ dictWord{132, 0, 1011},
+ dictWord{7, 11, 828},
+ dictWord{142, 11, 116},
+ dictWord{4, 0, 733},
+ dictWord{9, 0, 194},
+ dictWord{10, 0, 92},
+ dictWord{11, 0, 198},
+ dictWord{12, 0, 84},
+ dictWord{13, 0, 128},
+ dictWord{133, 11, 559},
+ dictWord{
+ 10,
+ 0,
+ 57,
+ },
+ dictWord{10, 0, 277},
+ dictWord{6, 11, 21},
+ dictWord{6, 11, 1737},
+ dictWord{7, 11, 1444},
+ dictWord{136, 11, 224},
+ dictWord{4, 10, 204},
+ dictWord{
+ 137,
+ 10,
+ 902,
+ },
+ dictWord{136, 10, 833},
+ dictWord{11, 0, 348},
+ dictWord{12, 0, 99},
+ dictWord{18, 0, 1},
+ dictWord{18, 0, 11},
+ dictWord{19, 0, 4},
+ dictWord{7, 10, 366},
+ dictWord{9, 10, 287},
+ dictWord{12, 10, 199},
+ dictWord{12, 10, 556},
+ dictWord{140, 10, 577},
+ dictWord{6, 0, 1981},
+ dictWord{136, 0, 936},
+ dictWord{
+ 21,
+ 0,
+ 33,
+ },
+ dictWord{150, 0, 40},
+ dictWord{5, 11, 519},
+ dictWord{138, 11, 204},
+ dictWord{5, 10, 356},
+ dictWord{135, 10, 224},
+ dictWord{134, 0, 775},
+ dictWord{
+ 135,
+ 0,
+ 306,
+ },
+ dictWord{7, 10, 630},
+ dictWord{9, 10, 567},
+ dictWord{11, 10, 150},
+ dictWord{11, 10, 444},
+ dictWord{141, 10, 119},
+ dictWord{5, 0, 979},
+ dictWord{
+ 134,
+ 10,
+ 539,
+ },
+ dictWord{133, 0, 611},
+ dictWord{4, 11, 402},
+ dictWord{135, 11, 1679},
+ dictWord{5, 0, 178},
+ dictWord{7, 11, 2},
+ dictWord{8, 11, 323},
+ dictWord{
+ 136,
+ 11,
+ 479,
+ },
+ dictWord{5, 11, 59},
+ dictWord{135, 11, 672},
+ dictWord{4, 0, 1010},
+ dictWord{6, 0, 1969},
+ dictWord{138, 11, 237},
+ dictWord{133, 11, 412},
+ dictWord{146, 11, 34},
+ dictWord{7, 11, 1740},
+ dictWord{146, 11, 48},
+ dictWord{134, 0, 664},
+ dictWord{139, 10, 814},
+ dictWord{4, 11, 85},
+ dictWord{
+ 135,
+ 11,
+ 549,
+ },
+ dictWord{133, 11, 94},
+ dictWord{133, 11, 457},
+ dictWord{132, 0, 390},
+ dictWord{134, 0, 1510},
+ dictWord{4, 10, 235},
+ dictWord{135, 10, 255},
+ dictWord{4, 10, 194},
+ dictWord{5, 10, 584},
+ dictWord{6, 11, 11},
+ dictWord{6, 10, 384},
+ dictWord{7, 11, 187},
+ dictWord{7, 10, 583},
+ dictWord{10, 10, 761},
+ dictWord{
+ 11,
+ 10,
+ 760,
+ },
+ dictWord{139, 10, 851},
+ dictWord{4, 11, 522},
+ dictWord{139, 11, 802},
+ dictWord{135, 0, 493},
+ dictWord{10, 11, 776},
+ dictWord{13, 11, 345},
+ dictWord{142, 11, 425},
+ dictWord{146, 0, 37},
+ dictWord{4, 11, 52},
+ dictWord{135, 11, 661},
+ dictWord{134, 0, 724},
+ dictWord{134, 0, 829},
+ dictWord{
+ 133,
+ 11,
+ 520,
+ },
+ dictWord{133, 10, 562},
+ dictWord{4, 11, 281},
+ dictWord{5, 11, 38},
+ dictWord{7, 11, 194},
+ dictWord{7, 11, 668},
+ dictWord{7, 11, 1893},
+ dictWord{
+ 137,
+ 11,
+ 397,
+ },
+ dictWord{5, 10, 191},
+ dictWord{137, 10, 271},
+ dictWord{7, 0, 1537},
+ dictWord{14, 0, 96},
+ dictWord{143, 0, 73},
+ dictWord{5, 0, 473},
+ dictWord{
+ 11,
+ 0,
+ 168,
+ },
+ dictWord{4, 10, 470},
+ dictWord{6, 10, 153},
+ dictWord{7, 10, 1503},
+ dictWord{7, 10, 1923},
+ dictWord{10, 10, 701},
+ dictWord{11, 10, 132},
+ dictWord{
+ 11,
+ 10,
+ 227,
+ },
+ dictWord{11, 10, 320},
+ dictWord{11, 10, 436},
+ dictWord{11, 10, 525},
+ dictWord{11, 10, 855},
+ dictWord{12, 10, 41},
+ dictWord{12, 10, 286},
+ dictWord{13, 10, 103},
+ dictWord{13, 10, 284},
+ dictWord{14, 10, 255},
+ dictWord{14, 10, 262},
+ dictWord{15, 10, 117},
+ dictWord{143, 10, 127},
+ dictWord{
+ 133,
+ 0,
+ 105,
+ },
+ dictWord{5, 0, 438},
+ dictWord{9, 0, 694},
+ dictWord{12, 0, 627},
+ dictWord{141, 0, 210},
+ dictWord{133, 10, 327},
+ dictWord{6, 10, 552},
+ dictWord{
+ 7,
+ 10,
+ 1754,
+ },
+ dictWord{137, 10, 604},
+ dictWord{134, 0, 1256},
+ dictWord{152, 0, 11},
+ dictWord{5, 11, 448},
+ dictWord{11, 11, 98},
+ dictWord{139, 11, 524},
+ dictWord{
+ 7,
+ 0,
+ 1626,
+ },
+ dictWord{5, 10, 80},
+ dictWord{6, 10, 405},
+ dictWord{7, 10, 403},
+ dictWord{7, 10, 1502},
+ dictWord{8, 10, 456},
+ dictWord{9, 10, 487},
+ dictWord{
+ 9,
+ 10,
+ 853,
+ },
+ dictWord{9, 10, 889},
+ dictWord{10, 10, 309},
+ dictWord{11, 10, 721},
+ dictWord{11, 10, 994},
+ dictWord{12, 10, 430},
+ dictWord{13, 10, 165},
+ dictWord{
+ 14,
+ 11,
+ 16,
+ },
+ dictWord{146, 11, 44},
+ dictWord{132, 0, 779},
+ dictWord{8, 0, 25},
+ dictWord{138, 0, 826},
+ dictWord{4, 10, 453},
+ dictWord{5, 10, 887},
+ dictWord{
+ 6,
+ 10,
+ 535,
+ },
+ dictWord{8, 10, 6},
+ dictWord{8, 10, 543},
+ dictWord{136, 10, 826},
+ dictWord{137, 11, 461},
+ dictWord{140, 11, 632},
+ dictWord{132, 0, 308},
+ dictWord{135, 0, 741},
+ dictWord{132, 0, 671},
+ dictWord{7, 0, 150},
+ dictWord{8, 0, 649},
+ dictWord{136, 0, 1020},
+ dictWord{9, 0, 99},
+ dictWord{6, 11, 336},
+ dictWord{
+ 8,
+ 11,
+ 552,
+ },
+ dictWord{9, 11, 285},
+ dictWord{10, 11, 99},
+ dictWord{139, 11, 568},
+ dictWord{134, 0, 521},
+ dictWord{5, 0, 339},
+ dictWord{14, 0, 3},
+ dictWord{
+ 15,
+ 0,
+ 41,
+ },
+ dictWord{15, 0, 166},
+ dictWord{147, 0, 66},
+ dictWord{6, 11, 423},
+ dictWord{7, 11, 665},
+ dictWord{7, 11, 1210},
+ dictWord{9, 11, 218},
+ dictWord{
+ 141,
+ 11,
+ 222,
+ },
+ dictWord{6, 0, 543},
+ dictWord{5, 10, 101},
+ dictWord{5, 11, 256},
+ dictWord{6, 10, 88},
+ dictWord{7, 10, 1677},
+ dictWord{9, 10, 100},
+ dictWord{10, 10, 677},
+ dictWord{14, 10, 169},
+ dictWord{14, 10, 302},
+ dictWord{14, 10, 313},
+ dictWord{15, 10, 48},
+ dictWord{143, 10, 84},
+ dictWord{4, 10, 310},
+ dictWord{
+ 7,
+ 10,
+ 708,
+ },
+ dictWord{7, 10, 996},
+ dictWord{9, 10, 795},
+ dictWord{10, 10, 390},
+ dictWord{10, 10, 733},
+ dictWord{11, 10, 451},
+ dictWord{12, 10, 249},
+ dictWord{
+ 14,
+ 10,
+ 115,
+ },
+ dictWord{14, 10, 286},
+ dictWord{143, 10, 100},
+ dictWord{133, 10, 587},
+ dictWord{13, 11, 417},
+ dictWord{14, 11, 129},
+ dictWord{143, 11, 15},
+ dictWord{134, 0, 1358},
+ dictWord{136, 11, 554},
+ dictWord{132, 10, 498},
+ dictWord{7, 10, 217},
+ dictWord{8, 10, 140},
+ dictWord{138, 10, 610},
+ dictWord{
+ 135,
+ 11,
+ 989,
+ },
+ dictWord{135, 11, 634},
+ dictWord{6, 0, 155},
+ dictWord{140, 0, 234},
+ dictWord{135, 11, 462},
+ dictWord{132, 11, 618},
+ dictWord{
+ 134,
+ 0,
+ 1628,
+ },
+ dictWord{132, 0, 766},
+ dictWord{4, 11, 339},
+ dictWord{5, 10, 905},
+ dictWord{135, 11, 259},
+ dictWord{135, 0, 829},
+ dictWord{4, 11, 759},
+ dictWord{
+ 141,
+ 11,
+ 169,
+ },
+ dictWord{7, 0, 1445},
+ dictWord{4, 10, 456},
+ dictWord{7, 10, 358},
+ dictWord{7, 10, 1637},
+ dictWord{8, 10, 643},
+ dictWord{139, 10, 483},
+ dictWord{
+ 5,
+ 0,
+ 486,
+ },
+ dictWord{135, 0, 1349},
+ dictWord{5, 11, 688},
+ dictWord{135, 11, 712},
+ dictWord{7, 0, 1635},
+ dictWord{8, 0, 17},
+ dictWord{10, 0, 217},
+ dictWord{
+ 10,
+ 0,
+ 295,
+ },
+ dictWord{12, 0, 2},
+ dictWord{140, 11, 2},
+ dictWord{138, 0, 558},
+ dictWord{150, 10, 56},
+ dictWord{4, 11, 278},
+ dictWord{5, 11, 465},
+ dictWord{
+ 135,
+ 11,
+ 1367,
+ },
+ dictWord{136, 11, 482},
+ dictWord{133, 10, 535},
+ dictWord{6, 0, 1362},
+ dictWord{6, 0, 1461},
+ dictWord{10, 11, 274},
+ dictWord{10, 11, 625},
+ dictWord{139, 11, 530},
+ dictWord{5, 0, 599},
+ dictWord{5, 11, 336},
+ dictWord{6, 11, 341},
+ dictWord{6, 11, 478},
+ dictWord{6, 11, 1763},
+ dictWord{136, 11, 386},
+ dictWord{7, 10, 1748},
+ dictWord{137, 11, 151},
+ dictWord{134, 0, 1376},
+ dictWord{133, 10, 539},
+ dictWord{135, 11, 73},
+ dictWord{135, 11, 1971},
+ dictWord{139, 11, 283},
+ dictWord{9, 0, 93},
+ dictWord{139, 0, 474},
+ dictWord{6, 10, 91},
+ dictWord{135, 10, 435},
+ dictWord{6, 0, 447},
+ dictWord{5, 11, 396},
+ dictWord{134, 11, 501},
+ dictWord{4, 10, 16},
+ dictWord{5, 10, 316},
+ dictWord{5, 10, 842},
+ dictWord{6, 10, 370},
+ dictWord{6, 10, 1778},
+ dictWord{8, 10, 166},
+ dictWord{11, 10, 812},
+ dictWord{12, 10, 206},
+ dictWord{12, 10, 351},
+ dictWord{14, 10, 418},
+ dictWord{16, 10, 15},
+ dictWord{16, 10, 34},
+ dictWord{18, 10, 3},
+ dictWord{19, 10, 3},
+ dictWord{19, 10, 7},
+ dictWord{20, 10, 4},
+ dictWord{149, 10, 21},
+ dictWord{7, 0, 577},
+ dictWord{7, 0, 1432},
+ dictWord{9, 0, 475},
+ dictWord{9, 0, 505},
+ dictWord{9, 0, 526},
+ dictWord{9, 0, 609},
+ dictWord{9, 0, 689},
+ dictWord{9, 0, 726},
+ dictWord{9, 0, 735},
+ dictWord{9, 0, 738},
+ dictWord{10, 0, 556},
+ dictWord{
+ 10,
+ 0,
+ 674,
+ },
+ dictWord{10, 0, 684},
+ dictWord{11, 0, 89},
+ dictWord{11, 0, 202},
+ dictWord{11, 0, 272},
+ dictWord{11, 0, 380},
+ dictWord{11, 0, 415},
+ dictWord{11, 0, 505},
+ dictWord{11, 0, 537},
+ dictWord{11, 0, 550},
+ dictWord{11, 0, 562},
+ dictWord{11, 0, 640},
+ dictWord{11, 0, 667},
+ dictWord{11, 0, 688},
+ dictWord{11, 0, 847},
+ dictWord{11, 0, 927},
+ dictWord{11, 0, 930},
+ dictWord{11, 0, 940},
+ dictWord{12, 0, 144},
+ dictWord{12, 0, 325},
+ dictWord{12, 0, 329},
+ dictWord{12, 0, 389},
+ dictWord{
+ 12,
+ 0,
+ 403,
+ },
+ dictWord{12, 0, 451},
+ dictWord{12, 0, 515},
+ dictWord{12, 0, 604},
+ dictWord{12, 0, 616},
+ dictWord{12, 0, 626},
+ dictWord{13, 0, 66},
+ dictWord{
+ 13,
+ 0,
+ 131,
+ },
+ dictWord{13, 0, 167},
+ dictWord{13, 0, 236},
+ dictWord{13, 0, 368},
+ dictWord{13, 0, 411},
+ dictWord{13, 0, 434},
+ dictWord{13, 0, 453},
+ dictWord{13, 0, 461},
+ dictWord{13, 0, 474},
+ dictWord{14, 0, 59},
+ dictWord{14, 0, 60},
+ dictWord{14, 0, 139},
+ dictWord{14, 0, 152},
+ dictWord{14, 0, 276},
+ dictWord{14, 0, 353},
+ dictWord{
+ 14,
+ 0,
+ 402,
+ },
+ dictWord{15, 0, 28},
+ dictWord{15, 0, 81},
+ dictWord{15, 0, 123},
+ dictWord{15, 0, 152},
+ dictWord{18, 0, 136},
+ dictWord{148, 0, 88},
+ dictWord{
+ 4,
+ 11,
+ 929,
+ },
+ dictWord{133, 11, 799},
+ dictWord{136, 11, 46},
+ dictWord{142, 0, 307},
+ dictWord{4, 0, 609},
+ dictWord{7, 0, 756},
+ dictWord{9, 0, 544},
+ dictWord{
+ 11,
+ 0,
+ 413,
+ },
+ dictWord{144, 0, 25},
+ dictWord{10, 0, 687},
+ dictWord{7, 10, 619},
+ dictWord{10, 10, 547},
+ dictWord{11, 10, 122},
+ dictWord{140, 10, 601},
+ dictWord{
+ 4,
+ 0,
+ 930,
+ },
+ dictWord{133, 0, 947},
+ dictWord{133, 0, 939},
+ dictWord{142, 0, 21},
+ dictWord{4, 11, 892},
+ dictWord{133, 11, 770},
+ dictWord{133, 0, 962},
+ dictWord{
+ 5,
+ 0,
+ 651,
+ },
+ dictWord{8, 0, 170},
+ dictWord{9, 0, 61},
+ dictWord{9, 0, 63},
+ dictWord{10, 0, 23},
+ dictWord{10, 0, 37},
+ dictWord{10, 0, 834},
+ dictWord{11, 0, 4},
+ dictWord{
+ 11,
+ 0,
+ 187,
+ },
+ dictWord{11, 0, 281},
+ dictWord{11, 0, 503},
+ dictWord{11, 0, 677},
+ dictWord{12, 0, 96},
+ dictWord{12, 0, 130},
+ dictWord{12, 0, 244},
+ dictWord{14, 0, 5},
+ dictWord{14, 0, 40},
+ dictWord{14, 0, 162},
+ dictWord{14, 0, 202},
+ dictWord{146, 0, 133},
+ dictWord{4, 0, 406},
+ dictWord{5, 0, 579},
+ dictWord{12, 0, 492},
+ dictWord{
+ 150,
+ 0,
+ 15,
+ },
+ dictWord{135, 11, 158},
+ dictWord{135, 0, 597},
+ dictWord{132, 0, 981},
+ dictWord{132, 10, 888},
+ dictWord{4, 10, 149},
+ dictWord{138, 10, 368},
+ dictWord{132, 0, 545},
+ dictWord{4, 10, 154},
+ dictWord{7, 10, 1134},
+ dictWord{136, 10, 105},
+ dictWord{135, 11, 2001},
+ dictWord{134, 0, 1558},
+ dictWord{
+ 4,
+ 10,
+ 31,
+ },
+ dictWord{6, 10, 429},
+ dictWord{7, 10, 962},
+ dictWord{9, 10, 458},
+ dictWord{139, 10, 691},
+ dictWord{132, 10, 312},
+ dictWord{135, 10, 1642},
+ dictWord{
+ 6,
+ 0,
+ 17,
+ },
+ dictWord{6, 0, 1304},
+ dictWord{7, 0, 16},
+ dictWord{7, 0, 1001},
+ dictWord{9, 0, 886},
+ dictWord{10, 0, 489},
+ dictWord{10, 0, 800},
+ dictWord{11, 0, 782},
+ dictWord{12, 0, 320},
+ dictWord{13, 0, 467},
+ dictWord{14, 0, 145},
+ dictWord{14, 0, 387},
+ dictWord{143, 0, 119},
+ dictWord{135, 0, 1982},
+ dictWord{17, 0, 17},
+ dictWord{7, 11, 1461},
+ dictWord{140, 11, 91},
+ dictWord{4, 10, 236},
+ dictWord{132, 11, 602},
+ dictWord{138, 0, 907},
+ dictWord{136, 0, 110},
+ dictWord{7, 0, 272},
+ dictWord{19, 0, 53},
+ dictWord{5, 10, 836},
+ dictWord{5, 10, 857},
+ dictWord{134, 10, 1680},
+ dictWord{5, 0, 458},
+ dictWord{7, 11, 1218},
+ dictWord{136, 11, 303},
+ dictWord{7, 0, 1983},
+ dictWord{8, 0, 0},
+ dictWord{8, 0, 171},
+ dictWord{9, 0, 120},
+ dictWord{9, 0, 732},
+ dictWord{10, 0, 473},
+ dictWord{11, 0, 656},
+ dictWord{
+ 11,
+ 0,
+ 998,
+ },
+ dictWord{18, 0, 0},
+ dictWord{18, 0, 2},
+ dictWord{19, 0, 21},
+ dictWord{10, 10, 68},
+ dictWord{139, 10, 494},
+ dictWord{137, 11, 662},
+ dictWord{4, 11, 13},
+ dictWord{5, 11, 567},
+ dictWord{7, 11, 1498},
+ dictWord{9, 11, 124},
+ dictWord{11, 11, 521},
+ dictWord{140, 11, 405},
+ dictWord{4, 10, 81},
+ dictWord{139, 10, 867},
+ dictWord{135, 11, 1006},
+ dictWord{7, 11, 800},
+ dictWord{7, 11, 1783},
+ dictWord{138, 11, 12},
+ dictWord{9, 0, 295},
+ dictWord{10, 0, 443},
+ dictWord{
+ 5,
+ 10,
+ 282,
+ },
+ dictWord{8, 10, 650},
+ dictWord{137, 10, 907},
+ dictWord{132, 11, 735},
+ dictWord{4, 11, 170},
+ dictWord{4, 10, 775},
+ dictWord{135, 11, 323},
+ dictWord{
+ 6,
+ 0,
+ 1844,
+ },
+ dictWord{10, 0, 924},
+ dictWord{11, 11, 844},
+ dictWord{12, 11, 104},
+ dictWord{140, 11, 625},
+ dictWord{5, 11, 304},
+ dictWord{7, 11, 1403},
+ dictWord{140, 11, 498},
+ dictWord{134, 0, 1232},
+ dictWord{4, 0, 519},
+ dictWord{10, 0, 70},
+ dictWord{12, 0, 26},
+ dictWord{14, 0, 17},
+ dictWord{14, 0, 178},
+ dictWord{
+ 15,
+ 0,
+ 34,
+ },
+ dictWord{149, 0, 12},
+ dictWord{132, 0, 993},
+ dictWord{4, 11, 148},
+ dictWord{133, 11, 742},
+ dictWord{6, 0, 31},
+ dictWord{7, 0, 491},
+ dictWord{7, 0, 530},
+ dictWord{8, 0, 592},
+ dictWord{11, 0, 53},
+ dictWord{11, 0, 779},
+ dictWord{12, 0, 167},
+ dictWord{12, 0, 411},
+ dictWord{14, 0, 14},
+ dictWord{14, 0, 136},
+ dictWord{
+ 15,
+ 0,
+ 72,
+ },
+ dictWord{16, 0, 17},
+ dictWord{144, 0, 72},
+ dictWord{133, 0, 907},
+ dictWord{134, 0, 733},
+ dictWord{133, 11, 111},
+ dictWord{4, 10, 71},
+ dictWord{
+ 5,
+ 10,
+ 376,
+ },
+ dictWord{7, 10, 119},
+ dictWord{138, 10, 665},
+ dictWord{136, 0, 55},
+ dictWord{8, 0, 430},
+ dictWord{136, 11, 430},
+ dictWord{4, 0, 208},
+ dictWord{
+ 5,
+ 0,
+ 106,
+ },
+ dictWord{6, 0, 531},
+ dictWord{8, 0, 408},
+ dictWord{9, 0, 188},
+ dictWord{138, 0, 572},
+ dictWord{12, 0, 56},
+ dictWord{11, 10, 827},
+ dictWord{14, 10, 34},
+ dictWord{143, 10, 148},
+ dictWord{134, 0, 1693},
+ dictWord{133, 11, 444},
+ dictWord{132, 10, 479},
+ dictWord{140, 0, 441},
+ dictWord{9, 0, 449},
+ dictWord{
+ 10,
+ 0,
+ 192,
+ },
+ dictWord{138, 0, 740},
+ dictWord{134, 0, 928},
+ dictWord{4, 0, 241},
+ dictWord{7, 10, 607},
+ dictWord{136, 10, 99},
+ dictWord{8, 11, 123},
+ dictWord{
+ 15,
+ 11,
+ 6,
+ },
+ dictWord{144, 11, 7},
+ dictWord{6, 11, 285},
+ dictWord{8, 11, 654},
+ dictWord{11, 11, 749},
+ dictWord{12, 11, 190},
+ dictWord{12, 11, 327},
+ dictWord{
+ 13,
+ 11,
+ 120,
+ },
+ dictWord{13, 11, 121},
+ dictWord{13, 11, 327},
+ dictWord{15, 11, 47},
+ dictWord{146, 11, 40},
+ dictWord{4, 10, 41},
+ dictWord{5, 10, 74},
+ dictWord{
+ 7,
+ 10,
+ 1627,
+ },
+ dictWord{11, 10, 871},
+ dictWord{140, 10, 619},
+ dictWord{7, 0, 1525},
+ dictWord{11, 10, 329},
+ dictWord{11, 10, 965},
+ dictWord{12, 10, 241},
+ dictWord{14, 10, 354},
+ dictWord{15, 10, 22},
+ dictWord{148, 10, 63},
+ dictWord{132, 0, 259},
+ dictWord{135, 11, 183},
+ dictWord{9, 10, 209},
+ dictWord{
+ 137,
+ 10,
+ 300,
+ },
+ dictWord{5, 11, 937},
+ dictWord{135, 11, 100},
+ dictWord{133, 10, 98},
+ dictWord{4, 0, 173},
+ dictWord{5, 0, 312},
+ dictWord{5, 0, 512},
+ dictWord{
+ 135,
+ 0,
+ 1285,
+ },
+ dictWord{141, 0, 185},
+ dictWord{7, 0, 1603},
+ dictWord{7, 0, 1691},
+ dictWord{9, 0, 464},
+ dictWord{11, 0, 195},
+ dictWord{12, 0, 279},
+ dictWord{
+ 12,
+ 0,
+ 448,
+ },
+ dictWord{14, 0, 11},
+ dictWord{147, 0, 102},
+ dictWord{135, 0, 1113},
+ dictWord{133, 10, 984},
+ dictWord{4, 0, 452},
+ dictWord{5, 0, 583},
+ dictWord{
+ 135,
+ 0,
+ 720,
+ },
+ dictWord{4, 0, 547},
+ dictWord{5, 0, 817},
+ dictWord{6, 0, 433},
+ dictWord{7, 0, 593},
+ dictWord{7, 0, 1378},
+ dictWord{8, 0, 161},
+ dictWord{9, 0, 284},
+ dictWord{
+ 10,
+ 0,
+ 313,
+ },
+ dictWord{139, 0, 886},
+ dictWord{8, 0, 722},
+ dictWord{4, 10, 182},
+ dictWord{6, 10, 205},
+ dictWord{135, 10, 220},
+ dictWord{150, 0, 13},
+ dictWord{
+ 4,
+ 10,
+ 42,
+ },
+ dictWord{9, 10, 205},
+ dictWord{9, 10, 786},
+ dictWord{138, 10, 659},
+ dictWord{6, 0, 289},
+ dictWord{7, 0, 1670},
+ dictWord{12, 0, 57},
+ dictWord{151, 0, 4},
+ dictWord{132, 10, 635},
+ dictWord{14, 0, 43},
+ dictWord{146, 0, 21},
+ dictWord{139, 10, 533},
+ dictWord{135, 0, 1694},
+ dictWord{8, 0, 420},
+ dictWord{
+ 139,
+ 0,
+ 193,
+ },
+ dictWord{135, 0, 409},
+ dictWord{132, 10, 371},
+ dictWord{4, 10, 272},
+ dictWord{135, 10, 836},
+ dictWord{5, 10, 825},
+ dictWord{134, 10, 1640},
+ dictWord{5, 11, 251},
+ dictWord{5, 11, 956},
+ dictWord{8, 11, 268},
+ dictWord{9, 11, 214},
+ dictWord{146, 11, 142},
+ dictWord{138, 0, 308},
+ dictWord{6, 0, 1863},
+ dictWord{141, 11, 37},
+ dictWord{137, 10, 879},
+ dictWord{7, 10, 317},
+ dictWord{135, 10, 569},
+ dictWord{132, 11, 294},
+ dictWord{134, 0, 790},
+ dictWord{
+ 5,
+ 0,
+ 1002,
+ },
+ dictWord{136, 0, 745},
+ dictWord{5, 11, 346},
+ dictWord{5, 11, 711},
+ dictWord{136, 11, 390},
+ dictWord{135, 0, 289},
+ dictWord{5, 0, 504},
+ dictWord{
+ 11,
+ 0,
+ 68,
+ },
+ dictWord{137, 10, 307},
+ dictWord{4, 0, 239},
+ dictWord{6, 0, 477},
+ dictWord{7, 0, 1607},
+ dictWord{139, 0, 617},
+ dictWord{149, 0, 13},
+ dictWord{
+ 133,
+ 0,
+ 609,
+ },
+ dictWord{133, 11, 624},
+ dictWord{5, 11, 783},
+ dictWord{7, 11, 1998},
+ dictWord{135, 11, 2047},
+ dictWord{133, 10, 525},
+ dictWord{132, 0, 367},
+ dictWord{132, 11, 594},
+ dictWord{6, 0, 528},
+ dictWord{133, 10, 493},
+ dictWord{4, 10, 174},
+ dictWord{135, 10, 911},
+ dictWord{8, 10, 417},
+ dictWord{
+ 137,
+ 10,
+ 782,
+ },
+ dictWord{132, 0, 694},
+ dictWord{7, 0, 548},
+ dictWord{137, 0, 58},
+ dictWord{4, 10, 32},
+ dictWord{5, 10, 215},
+ dictWord{6, 10, 269},
+ dictWord{7, 10, 1782},
+ dictWord{7, 10, 1892},
+ dictWord{10, 10, 16},
+ dictWord{11, 10, 822},
+ dictWord{11, 10, 954},
+ dictWord{141, 10, 481},
+ dictWord{140, 0, 687},
+ dictWord{
+ 7,
+ 0,
+ 1749,
+ },
+ dictWord{136, 10, 477},
+ dictWord{132, 11, 569},
+ dictWord{133, 10, 308},
+ dictWord{135, 10, 1088},
+ dictWord{4, 0, 661},
+ dictWord{138, 0, 1004},
+ dictWord{5, 11, 37},
+ dictWord{6, 11, 39},
+ dictWord{6, 11, 451},
+ dictWord{7, 11, 218},
+ dictWord{7, 11, 667},
+ dictWord{7, 11, 1166},
+ dictWord{7, 11, 1687},
+ dictWord{8, 11, 662},
+ dictWord{144, 11, 2},
+ dictWord{9, 0, 445},
+ dictWord{12, 0, 53},
+ dictWord{13, 0, 492},
+ dictWord{5, 10, 126},
+ dictWord{8, 10, 297},
+ dictWord{
+ 9,
+ 10,
+ 366,
+ },
+ dictWord{140, 10, 374},
+ dictWord{7, 10, 1551},
+ dictWord{139, 10, 361},
+ dictWord{148, 0, 74},
+ dictWord{134, 11, 508},
+ dictWord{135, 0, 213},
+ dictWord{132, 10, 175},
+ dictWord{132, 10, 685},
+ dictWord{6, 0, 760},
+ dictWord{6, 0, 834},
+ dictWord{134, 0, 1248},
+ dictWord{7, 11, 453},
+ dictWord{7, 11, 635},
+ dictWord{7, 11, 796},
+ dictWord{8, 11, 331},
+ dictWord{9, 11, 328},
+ dictWord{9, 11, 330},
+ dictWord{9, 11, 865},
+ dictWord{10, 11, 119},
+ dictWord{10, 11, 235},
+ dictWord{11, 11, 111},
+ dictWord{11, 11, 129},
+ dictWord{11, 11, 240},
+ dictWord{12, 11, 31},
+ dictWord{12, 11, 66},
+ dictWord{12, 11, 222},
+ dictWord{12, 11, 269},
+ dictWord{12, 11, 599},
+ dictWord{12, 11, 689},
+ dictWord{13, 11, 186},
+ dictWord{13, 11, 364},
+ dictWord{142, 11, 345},
+ dictWord{7, 0, 1672},
+ dictWord{
+ 139,
+ 0,
+ 189,
+ },
+ dictWord{133, 10, 797},
+ dictWord{133, 10, 565},
+ dictWord{6, 0, 1548},
+ dictWord{6, 11, 98},
+ dictWord{7, 11, 585},
+ dictWord{135, 11, 702},
+ dictWord{
+ 9,
+ 0,
+ 968,
+ },
+ dictWord{15, 0, 192},
+ dictWord{149, 0, 56},
+ dictWord{4, 10, 252},
+ dictWord{6, 11, 37},
+ dictWord{7, 11, 299},
+ dictWord{7, 10, 1068},
+ dictWord{
+ 7,
+ 11,
+ 1666,
+ },
+ dictWord{8, 11, 195},
+ dictWord{8, 11, 316},
+ dictWord{9, 11, 178},
+ dictWord{9, 11, 276},
+ dictWord{9, 11, 339},
+ dictWord{9, 11, 536},
+ dictWord{
+ 10,
+ 11,
+ 102,
+ },
+ dictWord{10, 11, 362},
+ dictWord{10, 10, 434},
+ dictWord{10, 11, 785},
+ dictWord{11, 11, 55},
+ dictWord{11, 11, 149},
+ dictWord{11, 10, 228},
+ dictWord{
+ 11,
+ 10,
+ 426,
+ },
+ dictWord{11, 11, 773},
+ dictWord{13, 10, 231},
+ dictWord{13, 11, 416},
+ dictWord{13, 11, 419},
+ dictWord{14, 11, 38},
+ dictWord{14, 11, 41},
+ dictWord{14, 11, 210},
+ dictWord{18, 10, 106},
+ dictWord{148, 10, 87},
+ dictWord{4, 0, 751},
+ dictWord{11, 0, 390},
+ dictWord{140, 0, 32},
+ dictWord{4, 0, 409},
+ dictWord{133, 0, 78},
+ dictWord{11, 11, 458},
+ dictWord{12, 11, 15},
+ dictWord{140, 11, 432},
+ dictWord{7, 0, 1602},
+ dictWord{10, 0, 257},
+ dictWord{10, 0, 698},
+ dictWord{11, 0, 544},
+ dictWord{11, 0, 585},
+ dictWord{12, 0, 212},
+ dictWord{13, 0, 307},
+ dictWord{5, 10, 231},
+ dictWord{7, 10, 601},
+ dictWord{9, 10, 277},
+ dictWord{
+ 9,
+ 10,
+ 674,
+ },
+ dictWord{10, 10, 178},
+ dictWord{10, 10, 418},
+ dictWord{10, 10, 509},
+ dictWord{11, 10, 531},
+ dictWord{12, 10, 113},
+ dictWord{12, 10, 475},
+ dictWord{13, 10, 99},
+ dictWord{142, 10, 428},
+ dictWord{6, 0, 473},
+ dictWord{145, 0, 105},
+ dictWord{6, 0, 1949},
+ dictWord{15, 0, 156},
+ dictWord{133, 11, 645},
+ dictWord{7, 10, 1591},
+ dictWord{144, 10, 43},
+ dictWord{135, 0, 1779},
+ dictWord{135, 10, 1683},
+ dictWord{4, 11, 290},
+ dictWord{135, 11, 1356},
+ dictWord{134, 0, 763},
+ dictWord{6, 11, 70},
+ dictWord{7, 11, 1292},
+ dictWord{10, 11, 762},
+ dictWord{139, 11, 288},
+ dictWord{142, 0, 29},
+ dictWord{140, 11, 428},
+ dictWord{7, 0, 883},
+ dictWord{7, 11, 131},
+ dictWord{7, 11, 422},
+ dictWord{8, 11, 210},
+ dictWord{140, 11, 573},
+ dictWord{134, 0, 488},
+ dictWord{4, 10, 399},
+ dictWord{5, 10, 119},
+ dictWord{5, 10, 494},
+ dictWord{7, 10, 751},
+ dictWord{137, 10, 556},
+ dictWord{133, 0, 617},
+ dictWord{132, 11, 936},
+ dictWord{
+ 139,
+ 0,
+ 50,
+ },
+ dictWord{7, 0, 1518},
+ dictWord{139, 0, 694},
+ dictWord{137, 0, 785},
+ dictWord{4, 0, 546},
+ dictWord{135, 0, 2042},
+ dictWord{7, 11, 716},
+ dictWord{
+ 13,
+ 11,
+ 97,
+ },
+ dictWord{141, 11, 251},
+ dictWord{132, 11, 653},
+ dictWord{145, 0, 22},
+ dictWord{134, 0, 1016},
+ dictWord{4, 0, 313},
+ dictWord{133, 0, 577},
+ dictWord{
+ 136,
+ 11,
+ 657,
+ },
+ dictWord{8, 0, 184},
+ dictWord{141, 0, 433},
+ dictWord{135, 0, 935},
+ dictWord{6, 0, 720},
+ dictWord{9, 0, 114},
+ dictWord{146, 11, 80},
+ dictWord{
+ 12,
+ 0,
+ 186,
+ },
+ dictWord{12, 0, 292},
+ dictWord{14, 0, 100},
+ dictWord{18, 0, 70},
+ dictWord{7, 10, 594},
+ dictWord{7, 10, 851},
+ dictWord{7, 10, 1858},
+ dictWord{
+ 9,
+ 10,
+ 411,
+ },
+ dictWord{9, 10, 574},
+ dictWord{9, 10, 666},
+ dictWord{9, 10, 737},
+ dictWord{10, 10, 346},
+ dictWord{10, 10, 712},
+ dictWord{11, 10, 246},
+ dictWord{
+ 11,
+ 10,
+ 432,
+ },
+ dictWord{11, 10, 517},
+ dictWord{11, 10, 647},
+ dictWord{11, 10, 679},
+ dictWord{11, 10, 727},
+ dictWord{12, 10, 304},
+ dictWord{12, 10, 305},
+ dictWord{12, 10, 323},
+ dictWord{12, 10, 483},
+ dictWord{12, 10, 572},
+ dictWord{12, 10, 593},
+ dictWord{12, 10, 602},
+ dictWord{13, 10, 95},
+ dictWord{13, 10, 101},
+ dictWord{13, 10, 171},
+ dictWord{13, 10, 315},
+ dictWord{13, 10, 378},
+ dictWord{13, 10, 425},
+ dictWord{13, 10, 475},
+ dictWord{14, 10, 63},
+ dictWord{
+ 14,
+ 10,
+ 380,
+ },
+ dictWord{14, 10, 384},
+ dictWord{15, 10, 133},
+ dictWord{18, 10, 112},
+ dictWord{148, 10, 72},
+ dictWord{135, 10, 1093},
+ dictWord{135, 11, 1836},
+ dictWord{132, 10, 679},
+ dictWord{137, 10, 203},
+ dictWord{11, 0, 402},
+ dictWord{12, 0, 109},
+ dictWord{12, 0, 431},
+ dictWord{13, 0, 179},
+ dictWord{13, 0, 206},
+ dictWord{14, 0, 217},
+ dictWord{16, 0, 3},
+ dictWord{148, 0, 53},
+ dictWord{7, 11, 1368},
+ dictWord{8, 11, 232},
+ dictWord{8, 11, 361},
+ dictWord{10, 11, 682},
+ dictWord{138, 11, 742},
+ dictWord{137, 10, 714},
+ dictWord{5, 0, 886},
+ dictWord{6, 0, 46},
+ dictWord{6, 0, 1790},
+ dictWord{7, 0, 14},
+ dictWord{7, 0, 732},
+ dictWord{
+ 7,
+ 0,
+ 1654,
+ },
+ dictWord{8, 0, 95},
+ dictWord{8, 0, 327},
+ dictWord{8, 0, 616},
+ dictWord{9, 0, 892},
+ dictWord{10, 0, 598},
+ dictWord{10, 0, 769},
+ dictWord{11, 0, 134},
+ dictWord{11, 0, 747},
+ dictWord{12, 0, 378},
+ dictWord{14, 0, 97},
+ dictWord{137, 11, 534},
+ dictWord{4, 0, 969},
+ dictWord{136, 10, 825},
+ dictWord{137, 11, 27},
+ dictWord{6, 0, 727},
+ dictWord{142, 11, 12},
+ dictWord{133, 0, 1021},
+ dictWord{134, 0, 1190},
+ dictWord{134, 11, 1657},
+ dictWord{5, 10, 143},
+ dictWord{
+ 5,
+ 10,
+ 769,
+ },
+ dictWord{6, 10, 1760},
+ dictWord{7, 10, 682},
+ dictWord{7, 10, 1992},
+ dictWord{136, 10, 736},
+ dictWord{132, 0, 153},
+ dictWord{135, 11, 127},
+ dictWord{133, 0, 798},
+ dictWord{132, 0, 587},
+ dictWord{6, 0, 598},
+ dictWord{7, 0, 42},
+ dictWord{8, 0, 695},
+ dictWord{10, 0, 212},
+ dictWord{11, 0, 158},
+ dictWord{
+ 14,
+ 0,
+ 196,
+ },
+ dictWord{145, 0, 85},
+ dictWord{133, 10, 860},
+ dictWord{6, 0, 1929},
+ dictWord{134, 0, 1933},
+ dictWord{5, 0, 957},
+ dictWord{5, 0, 1008},
+ dictWord{
+ 9,
+ 0,
+ 577,
+ },
+ dictWord{12, 0, 141},
+ dictWord{6, 10, 422},
+ dictWord{7, 10, 0},
+ dictWord{7, 10, 1544},
+ dictWord{8, 11, 364},
+ dictWord{11, 10, 990},
+ dictWord{
+ 12,
+ 10,
+ 453,
+ },
+ dictWord{13, 10, 47},
+ dictWord{141, 10, 266},
+ dictWord{134, 0, 1319},
+ dictWord{4, 0, 129},
+ dictWord{135, 0, 465},
+ dictWord{7, 0, 470},
+ dictWord{
+ 7,
+ 0,
+ 1057,
+ },
+ dictWord{7, 0, 1201},
+ dictWord{9, 0, 755},
+ dictWord{11, 0, 906},
+ dictWord{140, 0, 527},
+ dictWord{7, 0, 908},
+ dictWord{146, 0, 7},
+ dictWord{5, 0, 148},
+ dictWord{136, 0, 450},
+ dictWord{5, 10, 515},
+ dictWord{137, 10, 131},
+ dictWord{7, 10, 1605},
+ dictWord{11, 10, 962},
+ dictWord{146, 10, 139},
+ dictWord{
+ 132,
+ 10,
+ 646,
+ },
+ dictWord{134, 0, 1166},
+ dictWord{4, 10, 396},
+ dictWord{7, 10, 728},
+ dictWord{9, 10, 117},
+ dictWord{13, 10, 202},
+ dictWord{148, 10, 51},
+ dictWord{
+ 6,
+ 10,
+ 121,
+ },
+ dictWord{6, 10, 124},
+ dictWord{6, 10, 357},
+ dictWord{7, 10, 1138},
+ dictWord{7, 10, 1295},
+ dictWord{8, 10, 162},
+ dictWord{139, 10, 655},
+ dictWord{14, 0, 374},
+ dictWord{142, 11, 374},
+ dictWord{138, 0, 253},
+ dictWord{139, 0, 1003},
+ dictWord{5, 11, 909},
+ dictWord{9, 11, 849},
+ dictWord{
+ 138,
+ 11,
+ 805,
+ },
+ dictWord{133, 10, 237},
+ dictWord{7, 11, 525},
+ dictWord{7, 11, 1579},
+ dictWord{8, 11, 497},
+ dictWord{136, 11, 573},
+ dictWord{137, 0, 46},
+ dictWord{
+ 132,
+ 0,
+ 879,
+ },
+ dictWord{134, 0, 806},
+ dictWord{135, 0, 1868},
+ dictWord{6, 0, 1837},
+ dictWord{134, 0, 1846},
+ dictWord{6, 0, 730},
+ dictWord{134, 0, 881},
+ dictWord{7, 0, 965},
+ dictWord{7, 0, 1460},
+ dictWord{7, 0, 1604},
+ dictWord{7, 11, 193},
+ dictWord{7, 11, 397},
+ dictWord{7, 11, 1105},
+ dictWord{8, 11, 124},
+ dictWord{
+ 8,
+ 11,
+ 619,
+ },
+ dictWord{9, 11, 305},
+ dictWord{10, 11, 264},
+ dictWord{11, 11, 40},
+ dictWord{12, 11, 349},
+ dictWord{13, 11, 134},
+ dictWord{13, 11, 295},
+ dictWord{14, 11, 155},
+ dictWord{15, 11, 120},
+ dictWord{146, 11, 105},
+ dictWord{136, 0, 506},
+ dictWord{143, 0, 10},
+ dictWord{4, 11, 262},
+ dictWord{7, 11, 342},
+ dictWord{7, 10, 571},
+ dictWord{7, 10, 1877},
+ dictWord{10, 10, 366},
+ dictWord{141, 11, 23},
+ dictWord{133, 11, 641},
+ dictWord{10, 0, 22},
+ dictWord{9, 10, 513},
+ dictWord{10, 10, 39},
+ dictWord{12, 10, 122},
+ dictWord{140, 10, 187},
+ dictWord{135, 11, 1431},
+ dictWord{150, 11, 49},
+ dictWord{4, 11, 99},
+ dictWord{
+ 6,
+ 11,
+ 250,
+ },
+ dictWord{6, 11, 346},
+ dictWord{8, 11, 127},
+ dictWord{138, 11, 81},
+ dictWord{6, 0, 2014},
+ dictWord{8, 0, 928},
+ dictWord{10, 0, 960},
+ dictWord{10, 0, 979},
+ dictWord{140, 0, 996},
+ dictWord{134, 0, 296},
+ dictWord{132, 11, 915},
+ dictWord{5, 11, 75},
+ dictWord{9, 11, 517},
+ dictWord{10, 11, 470},
+ dictWord{
+ 12,
+ 11,
+ 155,
+ },
+ dictWord{141, 11, 224},
+ dictWord{137, 10, 873},
+ dictWord{4, 0, 854},
+ dictWord{140, 11, 18},
+ dictWord{134, 0, 587},
+ dictWord{7, 10, 107},
+ dictWord{
+ 7,
+ 10,
+ 838,
+ },
+ dictWord{8, 10, 550},
+ dictWord{138, 10, 401},
+ dictWord{11, 0, 636},
+ dictWord{15, 0, 145},
+ dictWord{17, 0, 34},
+ dictWord{19, 0, 50},
+ dictWord{
+ 23,
+ 0,
+ 20,
+ },
+ dictWord{11, 10, 588},
+ dictWord{11, 10, 864},
+ dictWord{11, 10, 968},
+ dictWord{143, 10, 160},
+ dictWord{135, 11, 216},
+ dictWord{7, 0, 982},
+ dictWord{
+ 10,
+ 0,
+ 32,
+ },
+ dictWord{143, 0, 56},
+ dictWord{133, 10, 768},
+ dictWord{133, 11, 954},
+ dictWord{6, 11, 304},
+ dictWord{7, 11, 1114},
+ dictWord{8, 11, 418},
+ dictWord{
+ 10,
+ 11,
+ 345,
+ },
+ dictWord{11, 11, 341},
+ dictWord{11, 11, 675},
+ dictWord{141, 11, 40},
+ dictWord{9, 11, 410},
+ dictWord{139, 11, 425},
+ dictWord{136, 0, 941},
+ dictWord{5, 0, 435},
+ dictWord{132, 10, 894},
+ dictWord{5, 0, 85},
+ dictWord{6, 0, 419},
+ dictWord{7, 0, 134},
+ dictWord{7, 0, 305},
+ dictWord{7, 0, 361},
+ dictWord{
+ 7,
+ 0,
+ 1337,
+ },
+ dictWord{8, 0, 71},
+ dictWord{140, 0, 519},
+ dictWord{140, 0, 688},
+ dictWord{135, 0, 740},
+ dictWord{5, 0, 691},
+ dictWord{7, 0, 345},
+ dictWord{9, 0, 94},
+ dictWord{140, 0, 169},
+ dictWord{5, 0, 183},
+ dictWord{6, 0, 582},
+ dictWord{10, 0, 679},
+ dictWord{140, 0, 435},
+ dictWord{134, 11, 14},
+ dictWord{6, 0, 945},
+ dictWord{135, 0, 511},
+ dictWord{134, 11, 1708},
+ dictWord{5, 11, 113},
+ dictWord{6, 11, 243},
+ dictWord{7, 11, 1865},
+ dictWord{11, 11, 161},
+ dictWord{16, 11, 37},
+ dictWord{145, 11, 99},
+ dictWord{132, 11, 274},
+ dictWord{137, 0, 539},
+ dictWord{7, 0, 1993},
+ dictWord{8, 0, 684},
+ dictWord{134, 10, 272},
+ dictWord{
+ 6,
+ 0,
+ 659,
+ },
+ dictWord{134, 0, 982},
+ dictWord{4, 10, 9},
+ dictWord{5, 10, 128},
+ dictWord{7, 10, 368},
+ dictWord{11, 10, 480},
+ dictWord{148, 10, 3},
+ dictWord{
+ 134,
+ 0,
+ 583,
+ },
+ dictWord{132, 0, 803},
+ dictWord{133, 0, 704},
+ dictWord{4, 0, 179},
+ dictWord{5, 0, 198},
+ dictWord{133, 0, 697},
+ dictWord{7, 0, 347},
+ dictWord{7, 0, 971},
+ dictWord{8, 0, 181},
+ dictWord{10, 0, 711},
+ dictWord{135, 11, 166},
+ dictWord{136, 10, 682},
+ dictWord{4, 10, 2},
+ dictWord{7, 10, 545},
+ dictWord{7, 10, 894},
+ dictWord{136, 11, 521},
+ dictWord{135, 0, 481},
+ dictWord{132, 0, 243},
+ dictWord{5, 0, 203},
+ dictWord{7, 0, 19},
+ dictWord{7, 0, 71},
+ dictWord{7, 0, 113},
+ dictWord{
+ 10,
+ 0,
+ 405,
+ },
+ dictWord{11, 0, 357},
+ dictWord{142, 0, 240},
+ dictWord{5, 11, 725},
+ dictWord{5, 11, 727},
+ dictWord{135, 11, 1811},
+ dictWord{6, 0, 826},
+ dictWord{
+ 137,
+ 11,
+ 304,
+ },
+ dictWord{7, 0, 1450},
+ dictWord{139, 0, 99},
+ dictWord{133, 11, 654},
+ dictWord{134, 0, 492},
+ dictWord{5, 0, 134},
+ dictWord{6, 0, 408},
+ dictWord{
+ 6,
+ 0,
+ 495,
+ },
+ dictWord{7, 0, 1593},
+ dictWord{6, 11, 273},
+ dictWord{10, 11, 188},
+ dictWord{13, 11, 377},
+ dictWord{146, 11, 77},
+ dictWord{9, 10, 769},
+ dictWord{
+ 140,
+ 10,
+ 185,
+ },
+ dictWord{135, 11, 410},
+ dictWord{142, 0, 4},
+ dictWord{4, 0, 665},
+ dictWord{134, 11, 1785},
+ dictWord{4, 0, 248},
+ dictWord{7, 0, 137},
+ dictWord{
+ 137,
+ 0,
+ 349,
+ },
+ dictWord{5, 10, 530},
+ dictWord{142, 10, 113},
+ dictWord{7, 0, 1270},
+ dictWord{139, 0, 612},
+ dictWord{132, 11, 780},
+ dictWord{5, 0, 371},
+ dictWord{135, 0, 563},
+ dictWord{135, 0, 826},
+ dictWord{6, 0, 1535},
+ dictWord{23, 0, 21},
+ dictWord{151, 0, 23},
+ dictWord{4, 0, 374},
+ dictWord{7, 0, 547},
+ dictWord{
+ 7,
+ 0,
+ 1700,
+ },
+ dictWord{7, 0, 1833},
+ dictWord{139, 0, 858},
+ dictWord{133, 10, 556},
+ dictWord{7, 11, 612},
+ dictWord{8, 11, 545},
+ dictWord{8, 11, 568},
+ dictWord{
+ 8,
+ 11,
+ 642,
+ },
+ dictWord{9, 11, 717},
+ dictWord{10, 11, 541},
+ dictWord{10, 11, 763},
+ dictWord{11, 11, 449},
+ dictWord{12, 11, 489},
+ dictWord{13, 11, 153},
+ dictWord{
+ 13,
+ 11,
+ 296,
+ },
+ dictWord{14, 11, 138},
+ dictWord{14, 11, 392},
+ dictWord{15, 11, 50},
+ dictWord{16, 11, 6},
+ dictWord{16, 11, 12},
+ dictWord{148, 11, 9},
+ dictWord{
+ 9,
+ 0,
+ 311,
+ },
+ dictWord{141, 0, 42},
+ dictWord{8, 10, 16},
+ dictWord{140, 10, 568},
+ dictWord{6, 0, 1968},
+ dictWord{6, 0, 2027},
+ dictWord{138, 0, 991},
+ dictWord{
+ 6,
+ 0,
+ 1647,
+ },
+ dictWord{7, 0, 1552},
+ dictWord{7, 0, 2010},
+ dictWord{9, 0, 494},
+ dictWord{137, 0, 509},
+ dictWord{133, 11, 948},
+ dictWord{6, 10, 186},
+ dictWord{
+ 137,
+ 10,
+ 426,
+ },
+ dictWord{134, 0, 769},
+ dictWord{134, 0, 642},
+ dictWord{132, 10, 585},
+ dictWord{6, 0, 123},
+ dictWord{7, 0, 214},
+ dictWord{9, 0, 728},
+ dictWord{
+ 10,
+ 0,
+ 157,
+ },
+ dictWord{11, 0, 346},
+ dictWord{11, 0, 662},
+ dictWord{143, 0, 106},
+ dictWord{142, 11, 381},
+ dictWord{135, 0, 1435},
+ dictWord{4, 11, 532},
+ dictWord{
+ 5,
+ 11,
+ 706,
+ },
+ dictWord{135, 11, 662},
+ dictWord{5, 11, 837},
+ dictWord{134, 11, 1651},
+ dictWord{4, 10, 93},
+ dictWord{5, 10, 252},
+ dictWord{6, 10, 229},
+ dictWord{
+ 7,
+ 10,
+ 291,
+ },
+ dictWord{9, 10, 550},
+ dictWord{139, 10, 644},
+ dictWord{148, 0, 79},
+ dictWord{137, 10, 749},
+ dictWord{134, 0, 1425},
+ dictWord{
+ 137,
+ 10,
+ 162,
+ },
+ dictWord{4, 11, 362},
+ dictWord{7, 11, 52},
+ dictWord{7, 11, 303},
+ dictWord{140, 11, 166},
+ dictWord{132, 10, 381},
+ dictWord{4, 11, 330},
+ dictWord{
+ 7,
+ 11,
+ 933,
+ },
+ dictWord{7, 11, 2012},
+ dictWord{136, 11, 292},
+ dictWord{135, 11, 767},
+ dictWord{4, 0, 707},
+ dictWord{5, 0, 588},
+ dictWord{6, 0, 393},
+ dictWord{
+ 13,
+ 0,
+ 106,
+ },
+ dictWord{18, 0, 49},
+ dictWord{147, 0, 41},
+ dictWord{6, 0, 211},
+ dictWord{7, 0, 1690},
+ dictWord{11, 0, 486},
+ dictWord{140, 0, 369},
+ dictWord{
+ 137,
+ 11,
+ 883,
+ },
+ dictWord{4, 11, 703},
+ dictWord{135, 11, 207},
+ dictWord{4, 0, 187},
+ dictWord{5, 0, 184},
+ dictWord{5, 0, 690},
+ dictWord{7, 0, 1869},
+ dictWord{10, 0, 756},
+ dictWord{139, 0, 783},
+ dictWord{132, 11, 571},
+ dictWord{134, 0, 1382},
+ dictWord{5, 0, 175},
+ dictWord{6, 10, 77},
+ dictWord{6, 10, 157},
+ dictWord{7, 10, 974},
+ dictWord{7, 10, 1301},
+ dictWord{7, 10, 1339},
+ dictWord{7, 10, 1490},
+ dictWord{7, 10, 1873},
+ dictWord{137, 10, 628},
+ dictWord{134, 0, 1493},
+ dictWord{
+ 5,
+ 11,
+ 873,
+ },
+ dictWord{133, 11, 960},
+ dictWord{134, 0, 1007},
+ dictWord{12, 11, 93},
+ dictWord{12, 11, 501},
+ dictWord{13, 11, 362},
+ dictWord{14, 11, 151},
+ dictWord{15, 11, 40},
+ dictWord{15, 11, 59},
+ dictWord{16, 11, 46},
+ dictWord{17, 11, 25},
+ dictWord{18, 11, 14},
+ dictWord{18, 11, 134},
+ dictWord{19, 11, 25},
+ dictWord{
+ 19,
+ 11,
+ 69,
+ },
+ dictWord{20, 11, 16},
+ dictWord{20, 11, 19},
+ dictWord{20, 11, 66},
+ dictWord{21, 11, 23},
+ dictWord{21, 11, 25},
+ dictWord{150, 11, 42},
+ dictWord{
+ 11,
+ 10,
+ 919,
+ },
+ dictWord{141, 10, 409},
+ dictWord{134, 0, 219},
+ dictWord{5, 0, 582},
+ dictWord{6, 0, 1646},
+ dictWord{7, 0, 99},
+ dictWord{7, 0, 1962},
+ dictWord{
+ 7,
+ 0,
+ 1986,
+ },
+ dictWord{8, 0, 515},
+ dictWord{8, 0, 773},
+ dictWord{9, 0, 23},
+ dictWord{9, 0, 491},
+ dictWord{12, 0, 620},
+ dictWord{142, 0, 93},
+ dictWord{133, 0, 851},
+ dictWord{5, 11, 33},
+ dictWord{134, 11, 470},
+ dictWord{135, 11, 1291},
+ dictWord{134, 0, 1278},
+ dictWord{135, 11, 1882},
+ dictWord{135, 10, 1489},
+ dictWord{132, 0, 1000},
+ dictWord{138, 0, 982},
+ dictWord{8, 0, 762},
+ dictWord{8, 0, 812},
+ dictWord{137, 0, 910},
+ dictWord{6, 11, 47},
+ dictWord{7, 11, 90},
+ dictWord{
+ 7,
+ 11,
+ 664,
+ },
+ dictWord{7, 11, 830},
+ dictWord{7, 11, 1380},
+ dictWord{7, 11, 2025},
+ dictWord{8, 11, 448},
+ dictWord{136, 11, 828},
+ dictWord{4, 0, 98},
+ dictWord{
+ 4,
+ 0,
+ 940,
+ },
+ dictWord{6, 0, 1819},
+ dictWord{6, 0, 1834},
+ dictWord{6, 0, 1841},
+ dictWord{7, 0, 1365},
+ dictWord{8, 0, 859},
+ dictWord{8, 0, 897},
+ dictWord{8, 0, 918},
+ dictWord{9, 0, 422},
+ dictWord{9, 0, 670},
+ dictWord{10, 0, 775},
+ dictWord{10, 0, 894},
+ dictWord{10, 0, 909},
+ dictWord{10, 0, 910},
+ dictWord{10, 0, 935},
+ dictWord{
+ 11,
+ 0,
+ 210,
+ },
+ dictWord{12, 0, 750},
+ dictWord{12, 0, 755},
+ dictWord{13, 0, 26},
+ dictWord{13, 0, 457},
+ dictWord{13, 0, 476},
+ dictWord{16, 0, 100},
+ dictWord{16, 0, 109},
+ dictWord{18, 0, 173},
+ dictWord{18, 0, 175},
+ dictWord{8, 10, 398},
+ dictWord{9, 10, 681},
+ dictWord{139, 10, 632},
+ dictWord{9, 11, 417},
+ dictWord{
+ 137,
+ 11,
+ 493,
+ },
+ dictWord{136, 10, 645},
+ dictWord{138, 0, 906},
+ dictWord{134, 0, 1730},
+ dictWord{134, 10, 20},
+ dictWord{133, 11, 1019},
+ dictWord{134, 0, 1185},
+ dictWord{10, 0, 40},
+ dictWord{136, 10, 769},
+ dictWord{9, 0, 147},
+ dictWord{134, 11, 208},
+ dictWord{140, 0, 650},
+ dictWord{5, 0, 209},
+ dictWord{6, 0, 30},
+ dictWord{11, 0, 56},
+ dictWord{139, 0, 305},
+ dictWord{132, 0, 553},
+ dictWord{138, 11, 344},
+ dictWord{6, 11, 68},
+ dictWord{7, 11, 398},
+ dictWord{7, 11, 448},
+ dictWord{
+ 7,
+ 11,
+ 1629,
+ },
+ dictWord{7, 11, 1813},
+ dictWord{8, 11, 387},
+ dictWord{8, 11, 442},
+ dictWord{9, 11, 710},
+ dictWord{10, 11, 282},
+ dictWord{138, 11, 722},
+ dictWord{5, 0, 597},
+ dictWord{14, 0, 20},
+ dictWord{142, 11, 20},
+ dictWord{135, 0, 1614},
+ dictWord{135, 10, 1757},
+ dictWord{4, 0, 150},
+ dictWord{5, 0, 303},
+ dictWord{6, 0, 327},
+ dictWord{135, 10, 937},
+ dictWord{16, 0, 49},
+ dictWord{7, 10, 1652},
+ dictWord{144, 11, 49},
+ dictWord{8, 0, 192},
+ dictWord{10, 0, 78},
+ dictWord{
+ 141,
+ 0,
+ 359,
+ },
+ dictWord{135, 0, 786},
+ dictWord{143, 0, 134},
+ dictWord{6, 0, 1638},
+ dictWord{7, 0, 79},
+ dictWord{7, 0, 496},
+ dictWord{9, 0, 138},
+ dictWord{
+ 10,
+ 0,
+ 336,
+ },
+ dictWord{11, 0, 12},
+ dictWord{12, 0, 412},
+ dictWord{12, 0, 440},
+ dictWord{142, 0, 305},
+ dictWord{136, 11, 491},
+ dictWord{4, 10, 579},
+ dictWord{
+ 5,
+ 10,
+ 226,
+ },
+ dictWord{5, 10, 323},
+ dictWord{135, 10, 960},
+ dictWord{7, 0, 204},
+ dictWord{7, 0, 415},
+ dictWord{8, 0, 42},
+ dictWord{10, 0, 85},
+ dictWord{139, 0, 564},
+ dictWord{132, 0, 614},
+ dictWord{4, 11, 403},
+ dictWord{5, 11, 441},
+ dictWord{7, 11, 450},
+ dictWord{11, 11, 101},
+ dictWord{12, 11, 193},
+ dictWord{141, 11, 430},
+ dictWord{135, 11, 1927},
+ dictWord{135, 11, 1330},
+ dictWord{4, 0, 3},
+ dictWord{5, 0, 247},
+ dictWord{5, 0, 644},
+ dictWord{7, 0, 744},
+ dictWord{7, 0, 1207},
+ dictWord{7, 0, 1225},
+ dictWord{7, 0, 1909},
+ dictWord{146, 0, 147},
+ dictWord{136, 0, 942},
+ dictWord{4, 0, 1019},
+ dictWord{134, 0, 2023},
+ dictWord{5, 11, 679},
+ dictWord{133, 10, 973},
+ dictWord{5, 0, 285},
+ dictWord{9, 0, 67},
+ dictWord{13, 0, 473},
+ dictWord{143, 0, 82},
+ dictWord{7, 11, 328},
+ dictWord{137, 11, 326},
+ dictWord{151, 0, 8},
+ dictWord{6, 10, 135},
+ dictWord{135, 10, 1176},
+ dictWord{135, 11, 1128},
+ dictWord{134, 0, 1309},
+ dictWord{135, 11, 1796},
+ dictWord{
+ 135,
+ 10,
+ 314,
+ },
+ dictWord{4, 11, 574},
+ dictWord{7, 11, 350},
+ dictWord{7, 11, 1024},
+ dictWord{8, 11, 338},
+ dictWord{9, 11, 677},
+ dictWord{10, 11, 808},
+ dictWord{
+ 139,
+ 11,
+ 508,
+ },
+ dictWord{7, 11, 818},
+ dictWord{17, 11, 14},
+ dictWord{17, 11, 45},
+ dictWord{18, 11, 75},
+ dictWord{148, 11, 18},
+ dictWord{146, 10, 4},
+ dictWord{
+ 135,
+ 11,
+ 1081,
+ },
+ dictWord{4, 0, 29},
+ dictWord{6, 0, 532},
+ dictWord{7, 0, 1628},
+ dictWord{7, 0, 1648},
+ dictWord{9, 0, 350},
+ dictWord{10, 0, 433},
+ dictWord{11, 0, 97},
+ dictWord{11, 0, 557},
+ dictWord{11, 0, 745},
+ dictWord{12, 0, 289},
+ dictWord{12, 0, 335},
+ dictWord{12, 0, 348},
+ dictWord{12, 0, 606},
+ dictWord{13, 0, 116},
+ dictWord{13, 0, 233},
+ dictWord{13, 0, 466},
+ dictWord{14, 0, 181},
+ dictWord{14, 0, 209},
+ dictWord{14, 0, 232},
+ dictWord{14, 0, 236},
+ dictWord{14, 0, 300},
+ dictWord{
+ 16,
+ 0,
+ 41,
+ },
+ dictWord{148, 0, 97},
+ dictWord{7, 0, 318},
+ dictWord{6, 10, 281},
+ dictWord{8, 10, 282},
+ dictWord{8, 10, 480},
+ dictWord{8, 10, 499},
+ dictWord{9, 10, 198},
+ dictWord{10, 10, 143},
+ dictWord{10, 10, 169},
+ dictWord{10, 10, 211},
+ dictWord{10, 10, 417},
+ dictWord{10, 10, 574},
+ dictWord{11, 10, 147},
+ dictWord{
+ 11,
+ 10,
+ 395,
+ },
+ dictWord{12, 10, 75},
+ dictWord{12, 10, 407},
+ dictWord{12, 10, 608},
+ dictWord{13, 10, 500},
+ dictWord{142, 10, 251},
+ dictWord{135, 11, 1676},
+ dictWord{135, 11, 2037},
+ dictWord{135, 0, 1692},
+ dictWord{5, 0, 501},
+ dictWord{7, 0, 1704},
+ dictWord{9, 0, 553},
+ dictWord{11, 0, 520},
+ dictWord{12, 0, 557},
+ dictWord{141, 0, 249},
+ dictWord{6, 0, 1527},
+ dictWord{14, 0, 324},
+ dictWord{15, 0, 55},
+ dictWord{15, 0, 80},
+ dictWord{14, 11, 324},
+ dictWord{15, 11, 55},
+ dictWord{143, 11, 80},
+ dictWord{135, 10, 1776},
+ dictWord{8, 0, 988},
+ dictWord{137, 11, 297},
+ dictWord{132, 10, 419},
+ dictWord{142, 0, 223},
+ dictWord{
+ 139,
+ 11,
+ 234,
+ },
+ dictWord{7, 0, 1123},
+ dictWord{12, 0, 508},
+ dictWord{14, 0, 102},
+ dictWord{14, 0, 226},
+ dictWord{144, 0, 57},
+ dictWord{4, 10, 138},
+ dictWord{
+ 7,
+ 10,
+ 1012,
+ },
+ dictWord{7, 10, 1280},
+ dictWord{137, 10, 76},
+ dictWord{7, 0, 1764},
+ dictWord{5, 10, 29},
+ dictWord{140, 10, 638},
+ dictWord{134, 0, 2015},
+ dictWord{134, 0, 1599},
+ dictWord{138, 11, 56},
+ dictWord{6, 11, 306},
+ dictWord{7, 11, 1140},
+ dictWord{7, 11, 1340},
+ dictWord{8, 11, 133},
+ dictWord{
+ 138,
+ 11,
+ 449,
+ },
+ dictWord{139, 11, 1011},
+ dictWord{6, 10, 1710},
+ dictWord{135, 10, 2038},
+ dictWord{7, 11, 1763},
+ dictWord{140, 11, 310},
+ dictWord{6, 0, 129},
+ dictWord{4, 10, 17},
+ dictWord{5, 10, 23},
+ dictWord{7, 10, 995},
+ dictWord{11, 10, 383},
+ dictWord{11, 10, 437},
+ dictWord{12, 10, 460},
+ dictWord{140, 10, 532},
+ dictWord{5, 11, 329},
+ dictWord{136, 11, 260},
+ dictWord{133, 10, 862},
+ dictWord{132, 0, 534},
+ dictWord{6, 0, 811},
+ dictWord{135, 0, 626},
+ dictWord{
+ 132,
+ 11,
+ 657,
+ },
+ dictWord{4, 0, 25},
+ dictWord{5, 0, 60},
+ dictWord{6, 0, 504},
+ dictWord{7, 0, 614},
+ dictWord{7, 0, 1155},
+ dictWord{12, 0, 0},
+ dictWord{152, 11, 7},
+ dictWord{
+ 7,
+ 0,
+ 1248,
+ },
+ dictWord{11, 0, 621},
+ dictWord{139, 0, 702},
+ dictWord{137, 0, 321},
+ dictWord{8, 10, 70},
+ dictWord{12, 10, 171},
+ dictWord{141, 10, 272},
+ dictWord{
+ 10,
+ 10,
+ 233,
+ },
+ dictWord{139, 10, 76},
+ dictWord{4, 0, 379},
+ dictWord{7, 0, 1397},
+ dictWord{134, 10, 442},
+ dictWord{5, 11, 66},
+ dictWord{7, 11, 1896},
+ dictWord{
+ 136,
+ 11,
+ 288,
+ },
+ dictWord{134, 11, 1643},
+ dictWord{134, 10, 1709},
+ dictWord{4, 11, 21},
+ dictWord{5, 11, 91},
+ dictWord{5, 11, 570},
+ dictWord{5, 11, 648},
+ dictWord{5, 11, 750},
+ dictWord{5, 11, 781},
+ dictWord{6, 11, 54},
+ dictWord{6, 11, 112},
+ dictWord{6, 11, 402},
+ dictWord{6, 11, 1732},
+ dictWord{7, 11, 315},
+ dictWord{
+ 7,
+ 11,
+ 749,
+ },
+ dictWord{7, 11, 1347},
+ dictWord{7, 11, 1900},
+ dictWord{9, 11, 78},
+ dictWord{9, 11, 508},
+ dictWord{10, 11, 611},
+ dictWord{11, 11, 510},
+ dictWord{
+ 11,
+ 11,
+ 728,
+ },
+ dictWord{13, 11, 36},
+ dictWord{14, 11, 39},
+ dictWord{16, 11, 83},
+ dictWord{17, 11, 124},
+ dictWord{148, 11, 30},
+ dictWord{4, 0, 118},
+ dictWord{
+ 6,
+ 0,
+ 274,
+ },
+ dictWord{6, 0, 361},
+ dictWord{7, 0, 75},
+ dictWord{141, 0, 441},
+ dictWord{10, 11, 322},
+ dictWord{10, 11, 719},
+ dictWord{139, 11, 407},
+ dictWord{
+ 147,
+ 10,
+ 119,
+ },
+ dictWord{12, 11, 549},
+ dictWord{14, 11, 67},
+ dictWord{147, 11, 60},
+ dictWord{11, 10, 69},
+ dictWord{12, 10, 105},
+ dictWord{12, 10, 117},
+ dictWord{13, 10, 213},
+ dictWord{14, 10, 13},
+ dictWord{14, 10, 62},
+ dictWord{14, 10, 177},
+ dictWord{14, 10, 421},
+ dictWord{15, 10, 19},
+ dictWord{146, 10, 141},
+ dictWord{9, 0, 841},
+ dictWord{137, 10, 309},
+ dictWord{7, 10, 608},
+ dictWord{7, 10, 976},
+ dictWord{8, 11, 125},
+ dictWord{8, 11, 369},
+ dictWord{8, 11, 524},
+ dictWord{9, 10, 146},
+ dictWord{10, 10, 206},
+ dictWord{10, 11, 486},
+ dictWord{10, 10, 596},
+ dictWord{11, 11, 13},
+ dictWord{11, 11, 381},
+ dictWord{11, 11, 736},
+ dictWord{11, 11, 766},
+ dictWord{11, 11, 845},
+ dictWord{13, 11, 114},
+ dictWord{13, 10, 218},
+ dictWord{13, 11, 292},
+ dictWord{14, 11, 47},
+ dictWord{
+ 142,
+ 10,
+ 153,
+ },
+ dictWord{12, 0, 693},
+ dictWord{135, 11, 759},
+ dictWord{5, 0, 314},
+ dictWord{6, 0, 221},
+ dictWord{7, 0, 419},
+ dictWord{10, 0, 650},
+ dictWord{11, 0, 396},
+ dictWord{12, 0, 156},
+ dictWord{13, 0, 369},
+ dictWord{14, 0, 333},
+ dictWord{145, 0, 47},
+ dictWord{6, 11, 1684},
+ dictWord{6, 11, 1731},
+ dictWord{7, 11, 356},
+ dictWord{7, 11, 1932},
+ dictWord{8, 11, 54},
+ dictWord{8, 11, 221},
+ dictWord{9, 11, 225},
+ dictWord{9, 11, 356},
+ dictWord{10, 11, 77},
+ dictWord{10, 11, 446},
+ dictWord{10, 11, 731},
+ dictWord{12, 11, 404},
+ dictWord{141, 11, 491},
+ dictWord{132, 11, 375},
+ dictWord{4, 10, 518},
+ dictWord{135, 10, 1136},
+ dictWord{
+ 4,
+ 0,
+ 913,
+ },
+ dictWord{4, 11, 411},
+ dictWord{11, 11, 643},
+ dictWord{140, 11, 115},
+ dictWord{4, 11, 80},
+ dictWord{133, 11, 44},
+ dictWord{8, 10, 689},
+ dictWord{
+ 137,
+ 10,
+ 863,
+ },
+ dictWord{138, 0, 880},
+ dictWord{4, 10, 18},
+ dictWord{7, 10, 145},
+ dictWord{7, 10, 444},
+ dictWord{7, 10, 1278},
+ dictWord{8, 10, 49},
+ dictWord{
+ 8,
+ 10,
+ 400,
+ },
+ dictWord{9, 10, 71},
+ dictWord{9, 10, 250},
+ dictWord{10, 10, 459},
+ dictWord{12, 10, 160},
+ dictWord{144, 10, 24},
+ dictWord{136, 0, 475},
+ dictWord{
+ 5,
+ 0,
+ 1016,
+ },
+ dictWord{5, 11, 299},
+ dictWord{135, 11, 1083},
+ dictWord{7, 0, 602},
+ dictWord{8, 0, 179},
+ dictWord{10, 0, 781},
+ dictWord{140, 0, 126},
+ dictWord{
+ 6,
+ 0,
+ 329,
+ },
+ dictWord{138, 0, 111},
+ dictWord{135, 0, 1864},
+ dictWord{4, 11, 219},
+ dictWord{7, 11, 1761},
+ dictWord{137, 11, 86},
+ dictWord{6, 0, 1888},
+ dictWord{
+ 6,
+ 0,
+ 1892,
+ },
+ dictWord{6, 0, 1901},
+ dictWord{6, 0, 1904},
+ dictWord{9, 0, 953},
+ dictWord{9, 0, 985},
+ dictWord{9, 0, 991},
+ dictWord{9, 0, 1001},
+ dictWord{12, 0, 818},
+ dictWord{12, 0, 846},
+ dictWord{12, 0, 847},
+ dictWord{12, 0, 861},
+ dictWord{12, 0, 862},
+ dictWord{12, 0, 873},
+ dictWord{12, 0, 875},
+ dictWord{12, 0, 877},
+ dictWord{12, 0, 879},
+ dictWord{12, 0, 881},
+ dictWord{12, 0, 884},
+ dictWord{12, 0, 903},
+ dictWord{12, 0, 915},
+ dictWord{12, 0, 926},
+ dictWord{12, 0, 939},
+ dictWord{
+ 15,
+ 0,
+ 182,
+ },
+ dictWord{15, 0, 219},
+ dictWord{15, 0, 255},
+ dictWord{18, 0, 191},
+ dictWord{18, 0, 209},
+ dictWord{18, 0, 211},
+ dictWord{149, 0, 41},
+ dictWord{
+ 5,
+ 11,
+ 328,
+ },
+ dictWord{135, 11, 918},
+ dictWord{137, 0, 780},
+ dictWord{12, 0, 82},
+ dictWord{143, 0, 36},
+ dictWord{133, 10, 1010},
+ dictWord{5, 0, 821},
+ dictWord{
+ 134,
+ 0,
+ 1687,
+ },
+ dictWord{133, 11, 514},
+ dictWord{132, 0, 956},
+ dictWord{134, 0, 1180},
+ dictWord{10, 0, 112},
+ dictWord{5, 10, 87},
+ dictWord{7, 10, 313},
+ dictWord{
+ 7,
+ 10,
+ 1103,
+ },
+ dictWord{10, 10, 582},
+ dictWord{11, 10, 389},
+ dictWord{11, 10, 813},
+ dictWord{12, 10, 385},
+ dictWord{13, 10, 286},
+ dictWord{14, 10, 124},
+ dictWord{146, 10, 108},
+ dictWord{5, 0, 71},
+ dictWord{7, 0, 1407},
+ dictWord{9, 0, 704},
+ dictWord{10, 0, 261},
+ dictWord{10, 0, 619},
+ dictWord{11, 0, 547},
+ dictWord{11, 0, 619},
+ dictWord{143, 0, 157},
+ dictWord{4, 0, 531},
+ dictWord{5, 0, 455},
+ dictWord{5, 11, 301},
+ dictWord{6, 11, 571},
+ dictWord{14, 11, 49},
+ dictWord{
+ 146,
+ 11,
+ 102,
+ },
+ dictWord{132, 10, 267},
+ dictWord{6, 0, 385},
+ dictWord{7, 0, 2008},
+ dictWord{9, 0, 337},
+ dictWord{138, 0, 517},
+ dictWord{133, 11, 726},
+ dictWord{133, 11, 364},
+ dictWord{4, 11, 76},
+ dictWord{7, 11, 1550},
+ dictWord{9, 11, 306},
+ dictWord{9, 11, 430},
+ dictWord{9, 11, 663},
+ dictWord{10, 11, 683},
+ dictWord{11, 11, 427},
+ dictWord{11, 11, 753},
+ dictWord{12, 11, 334},
+ dictWord{12, 11, 442},
+ dictWord{14, 11, 258},
+ dictWord{14, 11, 366},
+ dictWord{
+ 143,
+ 11,
+ 131,
+ },
+ dictWord{6, 0, 1865},
+ dictWord{6, 0, 1879},
+ dictWord{6, 0, 1881},
+ dictWord{6, 0, 1894},
+ dictWord{6, 0, 1908},
+ dictWord{9, 0, 915},
+ dictWord{9, 0, 926},
+ dictWord{9, 0, 940},
+ dictWord{9, 0, 943},
+ dictWord{9, 0, 966},
+ dictWord{9, 0, 980},
+ dictWord{9, 0, 989},
+ dictWord{9, 0, 1005},
+ dictWord{9, 0, 1010},
+ dictWord{
+ 12,
+ 0,
+ 813,
+ },
+ dictWord{12, 0, 817},
+ dictWord{12, 0, 840},
+ dictWord{12, 0, 843},
+ dictWord{12, 0, 855},
+ dictWord{12, 0, 864},
+ dictWord{12, 0, 871},
+ dictWord{12, 0, 872},
+ dictWord{12, 0, 899},
+ dictWord{12, 0, 905},
+ dictWord{12, 0, 924},
+ dictWord{15, 0, 171},
+ dictWord{15, 0, 181},
+ dictWord{15, 0, 224},
+ dictWord{15, 0, 235},
+ dictWord{15, 0, 251},
+ dictWord{146, 0, 184},
+ dictWord{137, 11, 52},
+ dictWord{5, 0, 16},
+ dictWord{6, 0, 86},
+ dictWord{6, 0, 603},
+ dictWord{7, 0, 292},
+ dictWord{7, 0, 561},
+ dictWord{8, 0, 257},
+ dictWord{8, 0, 382},
+ dictWord{9, 0, 721},
+ dictWord{9, 0, 778},
+ dictWord{11, 0, 581},
+ dictWord{140, 0, 466},
+ dictWord{4, 0, 486},
+ dictWord{
+ 5,
+ 0,
+ 491,
+ },
+ dictWord{135, 10, 1121},
+ dictWord{4, 0, 72},
+ dictWord{6, 0, 265},
+ dictWord{135, 0, 1300},
+ dictWord{135, 11, 1183},
+ dictWord{10, 10, 249},
+ dictWord{139, 10, 209},
+ dictWord{132, 10, 561},
+ dictWord{137, 11, 519},
+ dictWord{4, 11, 656},
+ dictWord{4, 10, 760},
+ dictWord{135, 11, 779},
+ dictWord{
+ 9,
+ 10,
+ 154,
+ },
+ dictWord{140, 10, 485},
+ dictWord{135, 11, 1793},
+ dictWord{135, 11, 144},
+ dictWord{136, 10, 255},
+ dictWord{133, 0, 621},
+ dictWord{4, 10, 368},
+ dictWord{135, 10, 641},
+ dictWord{135, 11, 1373},
+ dictWord{7, 11, 554},
+ dictWord{7, 11, 605},
+ dictWord{141, 11, 10},
+ dictWord{137, 0, 234},
+ dictWord{
+ 5,
+ 0,
+ 815,
+ },
+ dictWord{6, 0, 1688},
+ dictWord{134, 0, 1755},
+ dictWord{5, 11, 838},
+ dictWord{5, 11, 841},
+ dictWord{134, 11, 1649},
+ dictWord{7, 0, 1987},
+ dictWord{
+ 7,
+ 0,
+ 2040,
+ },
+ dictWord{136, 0, 743},
+ dictWord{133, 11, 1012},
+ dictWord{6, 0, 197},
+ dictWord{136, 0, 205},
+ dictWord{6, 0, 314},
+ dictWord{134, 11, 314},
+ dictWord{144, 11, 53},
+ dictWord{6, 11, 251},
+ dictWord{7, 11, 365},
+ dictWord{7, 11, 1357},
+ dictWord{7, 11, 1497},
+ dictWord{8, 11, 154},
+ dictWord{141, 11, 281},
+ dictWord{133, 11, 340},
+ dictWord{6, 0, 452},
+ dictWord{7, 0, 312},
+ dictWord{138, 0, 219},
+ dictWord{138, 0, 589},
+ dictWord{4, 0, 333},
+ dictWord{9, 0, 176},
+ dictWord{12, 0, 353},
+ dictWord{141, 0, 187},
+ dictWord{9, 10, 92},
+ dictWord{147, 10, 91},
+ dictWord{134, 0, 1110},
+ dictWord{11, 0, 47},
+ dictWord{139, 11, 495},
+ dictWord{6, 10, 525},
+ dictWord{8, 10, 806},
+ dictWord{9, 10, 876},
+ dictWord{140, 10, 284},
+ dictWord{8, 11, 261},
+ dictWord{9, 11, 144},
+ dictWord{9, 11, 466},
+ dictWord{10, 11, 370},
+ dictWord{12, 11, 470},
+ dictWord{13, 11, 144},
+ dictWord{142, 11, 348},
+ dictWord{137, 11, 897},
+ dictWord{8, 0, 863},
+ dictWord{8, 0, 864},
+ dictWord{8, 0, 868},
+ dictWord{8, 0, 884},
+ dictWord{10, 0, 866},
+ dictWord{10, 0, 868},
+ dictWord{10, 0, 873},
+ dictWord{10, 0, 911},
+ dictWord{10, 0, 912},
+ dictWord{
+ 10,
+ 0,
+ 944,
+ },
+ dictWord{12, 0, 727},
+ dictWord{6, 11, 248},
+ dictWord{9, 11, 546},
+ dictWord{10, 11, 535},
+ dictWord{11, 11, 681},
+ dictWord{141, 11, 135},
+ dictWord{
+ 6,
+ 0,
+ 300,
+ },
+ dictWord{135, 0, 1515},
+ dictWord{134, 0, 1237},
+ dictWord{139, 10, 958},
+ dictWord{133, 10, 594},
+ dictWord{140, 11, 250},
+ dictWord{
+ 134,
+ 0,
+ 1685,
+ },
+ dictWord{134, 11, 567},
+ dictWord{7, 0, 135},
+ dictWord{8, 0, 7},
+ dictWord{8, 0, 62},
+ dictWord{9, 0, 243},
+ dictWord{10, 0, 658},
+ dictWord{10, 0, 697},
+ dictWord{11, 0, 456},
+ dictWord{139, 0, 756},
+ dictWord{9, 0, 395},
+ dictWord{138, 0, 79},
+ dictWord{6, 10, 1641},
+ dictWord{136, 10, 820},
+ dictWord{4, 10, 302},
+ dictWord{135, 10, 1766},
+ dictWord{134, 11, 174},
+ dictWord{135, 10, 1313},
+ dictWord{135, 0, 631},
+ dictWord{134, 10, 1674},
+ dictWord{134, 11, 395},
+ dictWord{138, 0, 835},
+ dictWord{7, 0, 406},
+ dictWord{7, 0, 459},
+ dictWord{8, 0, 606},
+ dictWord{139, 0, 726},
+ dictWord{134, 11, 617},
+ dictWord{134, 0, 979},
+ dictWord{
+ 6,
+ 10,
+ 389,
+ },
+ dictWord{7, 10, 149},
+ dictWord{9, 10, 142},
+ dictWord{138, 10, 94},
+ dictWord{5, 11, 878},
+ dictWord{133, 11, 972},
+ dictWord{6, 10, 8},
+ dictWord{
+ 7,
+ 10,
+ 1881,
+ },
+ dictWord{8, 10, 91},
+ dictWord{136, 11, 511},
+ dictWord{133, 0, 612},
+ dictWord{132, 11, 351},
+ dictWord{4, 0, 372},
+ dictWord{7, 0, 482},
+ dictWord{
+ 8,
+ 0,
+ 158,
+ },
+ dictWord{9, 0, 602},
+ dictWord{9, 0, 615},
+ dictWord{10, 0, 245},
+ dictWord{10, 0, 678},
+ dictWord{10, 0, 744},
+ dictWord{11, 0, 248},
+ dictWord{
+ 139,
+ 0,
+ 806,
+ },
+ dictWord{5, 0, 854},
+ dictWord{135, 0, 1991},
+ dictWord{132, 11, 286},
+ dictWord{135, 11, 344},
+ dictWord{7, 11, 438},
+ dictWord{7, 11, 627},
+ dictWord{
+ 7,
+ 11,
+ 1516,
+ },
+ dictWord{8, 11, 40},
+ dictWord{9, 11, 56},
+ dictWord{9, 11, 294},
+ dictWord{10, 11, 30},
+ dictWord{10, 11, 259},
+ dictWord{11, 11, 969},
+ dictWord{
+ 146,
+ 11,
+ 148,
+ },
+ dictWord{135, 0, 1492},
+ dictWord{5, 11, 259},
+ dictWord{7, 11, 414},
+ dictWord{7, 11, 854},
+ dictWord{142, 11, 107},
+ dictWord{135, 10, 1746},
+ dictWord{6, 0, 833},
+ dictWord{134, 0, 998},
+ dictWord{135, 10, 24},
+ dictWord{6, 0, 750},
+ dictWord{135, 0, 1739},
+ dictWord{4, 10, 503},
+ dictWord{
+ 135,
+ 10,
+ 1661,
+ },
+ dictWord{5, 10, 130},
+ dictWord{7, 10, 1314},
+ dictWord{9, 10, 610},
+ dictWord{10, 10, 718},
+ dictWord{11, 10, 601},
+ dictWord{11, 10, 819},
+ dictWord{
+ 11,
+ 10,
+ 946,
+ },
+ dictWord{140, 10, 536},
+ dictWord{10, 10, 149},
+ dictWord{11, 10, 280},
+ dictWord{142, 10, 336},
+ dictWord{132, 11, 738},
+ dictWord{
+ 135,
+ 10,
+ 1946,
+ },
+ dictWord{5, 0, 195},
+ dictWord{135, 0, 1685},
+ dictWord{7, 0, 1997},
+ dictWord{8, 0, 730},
+ dictWord{139, 0, 1006},
+ dictWord{151, 11, 17},
+ dictWord{
+ 133,
+ 11,
+ 866,
+ },
+ dictWord{14, 0, 463},
+ dictWord{14, 0, 470},
+ dictWord{150, 0, 61},
+ dictWord{5, 0, 751},
+ dictWord{8, 0, 266},
+ dictWord{11, 0, 578},
+ dictWord{
+ 4,
+ 10,
+ 392,
+ },
+ dictWord{135, 10, 1597},
+ dictWord{5, 10, 433},
+ dictWord{9, 10, 633},
+ dictWord{139, 10, 629},
+ dictWord{135, 0, 821},
+ dictWord{6, 0, 715},
+ dictWord{
+ 134,
+ 0,
+ 1325,
+ },
+ dictWord{133, 11, 116},
+ dictWord{6, 0, 868},
+ dictWord{132, 11, 457},
+ dictWord{134, 0, 959},
+ dictWord{6, 10, 234},
+ dictWord{138, 11, 199},
+ dictWord{7, 0, 1053},
+ dictWord{7, 10, 1950},
+ dictWord{8, 10, 680},
+ dictWord{11, 10, 817},
+ dictWord{147, 10, 88},
+ dictWord{7, 10, 1222},
+ dictWord{
+ 138,
+ 10,
+ 386,
+ },
+ dictWord{5, 0, 950},
+ dictWord{5, 0, 994},
+ dictWord{6, 0, 351},
+ dictWord{134, 0, 1124},
+ dictWord{134, 0, 1081},
+ dictWord{7, 0, 1595},
+ dictWord{6, 10, 5},
+ dictWord{11, 10, 249},
+ dictWord{12, 10, 313},
+ dictWord{16, 10, 66},
+ dictWord{145, 10, 26},
+ dictWord{148, 0, 59},
+ dictWord{5, 11, 527},
+ dictWord{6, 11, 189},
+ dictWord{135, 11, 859},
+ dictWord{5, 10, 963},
+ dictWord{6, 10, 1773},
+ dictWord{11, 11, 104},
+ dictWord{11, 11, 554},
+ dictWord{15, 11, 60},
+ dictWord{
+ 143,
+ 11,
+ 125,
+ },
+ dictWord{135, 0, 47},
+ dictWord{137, 0, 684},
+ dictWord{134, 11, 116},
+ dictWord{134, 0, 1606},
+ dictWord{134, 0, 777},
+ dictWord{7, 0, 1020},
+ dictWord{
+ 8,
+ 10,
+ 509,
+ },
+ dictWord{136, 10, 792},
+ dictWord{135, 0, 1094},
+ dictWord{132, 0, 350},
+ dictWord{133, 11, 487},
+ dictWord{4, 11, 86},
+ dictWord{5, 11, 667},
+ dictWord{5, 11, 753},
+ dictWord{6, 11, 316},
+ dictWord{6, 11, 455},
+ dictWord{135, 11, 946},
+ dictWord{7, 0, 1812},
+ dictWord{13, 0, 259},
+ dictWord{13, 0, 356},
+ dictWord{14, 0, 242},
+ dictWord{147, 0, 114},
+ dictWord{132, 10, 931},
+ dictWord{133, 0, 967},
+ dictWord{4, 0, 473},
+ dictWord{7, 0, 623},
+ dictWord{8, 0, 808},
+ dictWord{
+ 9,
+ 0,
+ 871,
+ },
+ dictWord{9, 0, 893},
+ dictWord{11, 0, 38},
+ dictWord{11, 0, 431},
+ dictWord{12, 0, 112},
+ dictWord{12, 0, 217},
+ dictWord{12, 0, 243},
+ dictWord{12, 0, 562},
+ dictWord{12, 0, 663},
+ dictWord{12, 0, 683},
+ dictWord{13, 0, 141},
+ dictWord{13, 0, 197},
+ dictWord{13, 0, 227},
+ dictWord{13, 0, 406},
+ dictWord{13, 0, 487},
+ dictWord{14, 0, 156},
+ dictWord{14, 0, 203},
+ dictWord{14, 0, 224},
+ dictWord{14, 0, 256},
+ dictWord{18, 0, 58},
+ dictWord{150, 0, 0},
+ dictWord{138, 0, 286},
+ dictWord{
+ 7,
+ 10,
+ 943,
+ },
+ dictWord{139, 10, 614},
+ dictWord{135, 10, 1837},
+ dictWord{150, 11, 45},
+ dictWord{132, 0, 798},
+ dictWord{4, 0, 222},
+ dictWord{7, 0, 286},
+ dictWord{136, 0, 629},
+ dictWord{4, 11, 79},
+ dictWord{7, 11, 1773},
+ dictWord{10, 11, 450},
+ dictWord{11, 11, 589},
+ dictWord{13, 11, 332},
+ dictWord{13, 11, 493},
+ dictWord{14, 11, 183},
+ dictWord{14, 11, 334},
+ dictWord{14, 11, 362},
+ dictWord{14, 11, 368},
+ dictWord{14, 11, 376},
+ dictWord{14, 11, 379},
+ dictWord{
+ 19,
+ 11,
+ 90,
+ },
+ dictWord{19, 11, 103},
+ dictWord{19, 11, 127},
+ dictWord{148, 11, 90},
+ dictWord{5, 0, 337},
+ dictWord{11, 0, 513},
+ dictWord{11, 0, 889},
+ dictWord{
+ 11,
+ 0,
+ 961,
+ },
+ dictWord{12, 0, 461},
+ dictWord{13, 0, 79},
+ dictWord{15, 0, 121},
+ dictWord{4, 10, 90},
+ dictWord{5, 10, 545},
+ dictWord{7, 10, 754},
+ dictWord{9, 10, 186},
+ dictWord{10, 10, 72},
+ dictWord{10, 10, 782},
+ dictWord{11, 10, 577},
+ dictWord{11, 10, 610},
+ dictWord{12, 10, 354},
+ dictWord{12, 10, 362},
+ dictWord{
+ 140,
+ 10,
+ 595,
+ },
+ dictWord{141, 0, 306},
+ dictWord{136, 0, 146},
+ dictWord{7, 0, 1646},
+ dictWord{9, 10, 329},
+ dictWord{11, 10, 254},
+ dictWord{141, 11, 124},
+ dictWord{
+ 4,
+ 0,
+ 465,
+ },
+ dictWord{135, 0, 1663},
+ dictWord{132, 0, 525},
+ dictWord{133, 11, 663},
+ dictWord{10, 0, 299},
+ dictWord{18, 0, 74},
+ dictWord{9, 10, 187},
+ dictWord{
+ 11,
+ 10,
+ 1016,
+ },
+ dictWord{145, 10, 44},
+ dictWord{7, 0, 165},
+ dictWord{7, 0, 919},
+ dictWord{4, 10, 506},
+ dictWord{136, 10, 517},
+ dictWord{5, 10, 295},
+ dictWord{
+ 135,
+ 10,
+ 1680,
+ },
+ dictWord{133, 11, 846},
+ dictWord{134, 0, 1064},
+ dictWord{5, 11, 378},
+ dictWord{7, 11, 1402},
+ dictWord{7, 11, 1414},
+ dictWord{8, 11, 465},
+ dictWord{9, 11, 286},
+ dictWord{10, 11, 185},
+ dictWord{10, 11, 562},
+ dictWord{10, 11, 635},
+ dictWord{11, 11, 31},
+ dictWord{11, 11, 393},
+ dictWord{
+ 12,
+ 11,
+ 456,
+ },
+ dictWord{13, 11, 312},
+ dictWord{18, 11, 65},
+ dictWord{18, 11, 96},
+ dictWord{147, 11, 89},
+ dictWord{132, 0, 596},
+ dictWord{7, 10, 987},
+ dictWord{
+ 9,
+ 10,
+ 688,
+ },
+ dictWord{10, 10, 522},
+ dictWord{11, 10, 788},
+ dictWord{140, 10, 566},
+ dictWord{6, 0, 82},
+ dictWord{7, 0, 138},
+ dictWord{7, 0, 517},
+ dictWord{7, 0, 1741},
+ dictWord{11, 0, 238},
+ dictWord{4, 11, 648},
+ dictWord{134, 10, 1775},
+ dictWord{7, 0, 1233},
+ dictWord{7, 10, 700},
+ dictWord{7, 10, 940},
+ dictWord{8, 10, 514},
+ dictWord{9, 10, 116},
+ dictWord{9, 10, 535},
+ dictWord{10, 10, 118},
+ dictWord{11, 10, 107},
+ dictWord{11, 10, 148},
+ dictWord{11, 10, 922},
+ dictWord{
+ 12,
+ 10,
+ 254,
+ },
+ dictWord{12, 10, 421},
+ dictWord{142, 10, 238},
+ dictWord{4, 0, 962},
+ dictWord{6, 0, 1824},
+ dictWord{8, 0, 894},
+ dictWord{12, 0, 708},
+ dictWord{
+ 12,
+ 0,
+ 725,
+ },
+ dictWord{14, 0, 451},
+ dictWord{20, 0, 94},
+ dictWord{22, 0, 59},
+ dictWord{150, 0, 62},
+ dictWord{5, 11, 945},
+ dictWord{6, 11, 1656},
+ dictWord{6, 11, 1787},
+ dictWord{7, 11, 167},
+ dictWord{8, 11, 824},
+ dictWord{9, 11, 391},
+ dictWord{10, 11, 375},
+ dictWord{139, 11, 185},
+ dictWord{5, 0, 495},
+ dictWord{7, 0, 834},
+ dictWord{9, 0, 733},
+ dictWord{139, 0, 378},
+ dictWord{4, 10, 743},
+ dictWord{135, 11, 1273},
+ dictWord{6, 0, 1204},
+ dictWord{7, 11, 1645},
+ dictWord{8, 11, 352},
+ dictWord{137, 11, 249},
+ dictWord{139, 10, 292},
+ dictWord{133, 0, 559},
+ dictWord{132, 11, 152},
+ dictWord{9, 0, 499},
+ dictWord{10, 0, 341},
+ dictWord{
+ 15,
+ 0,
+ 144,
+ },
+ dictWord{19, 0, 49},
+ dictWord{7, 10, 1283},
+ dictWord{9, 10, 227},
+ dictWord{11, 10, 325},
+ dictWord{11, 10, 408},
+ dictWord{14, 10, 180},
+ dictWord{
+ 146,
+ 10,
+ 47,
+ },
+ dictWord{6, 0, 21},
+ dictWord{6, 0, 1737},
+ dictWord{7, 0, 1444},
+ dictWord{136, 0, 224},
+ dictWord{133, 11, 1006},
+ dictWord{7, 0, 1446},
+ dictWord{
+ 9,
+ 0,
+ 97,
+ },
+ dictWord{17, 0, 15},
+ dictWord{5, 10, 81},
+ dictWord{7, 10, 146},
+ dictWord{7, 10, 1342},
+ dictWord{8, 10, 53},
+ dictWord{8, 10, 561},
+ dictWord{8, 10, 694},
+ dictWord{8, 10, 754},
+ dictWord{9, 10, 115},
+ dictWord{9, 10, 894},
+ dictWord{10, 10, 462},
+ dictWord{10, 10, 813},
+ dictWord{11, 10, 230},
+ dictWord{11, 10, 657},
+ dictWord{11, 10, 699},
+ dictWord{11, 10, 748},
+ dictWord{12, 10, 119},
+ dictWord{12, 10, 200},
+ dictWord{12, 10, 283},
+ dictWord{142, 10, 273},
+ dictWord{
+ 5,
+ 10,
+ 408,
+ },
+ dictWord{137, 10, 747},
+ dictWord{135, 11, 431},
+ dictWord{135, 11, 832},
+ dictWord{6, 0, 729},
+ dictWord{134, 0, 953},
+ dictWord{4, 0, 727},
+ dictWord{
+ 8,
+ 0,
+ 565,
+ },
+ dictWord{5, 11, 351},
+ dictWord{7, 11, 264},
+ dictWord{136, 11, 565},
+ dictWord{134, 0, 1948},
+ dictWord{5, 0, 519},
+ dictWord{5, 11, 40},
+ dictWord{
+ 7,
+ 11,
+ 598,
+ },
+ dictWord{7, 11, 1638},
+ dictWord{8, 11, 78},
+ dictWord{9, 11, 166},
+ dictWord{9, 11, 640},
+ dictWord{9, 11, 685},
+ dictWord{9, 11, 773},
+ dictWord{
+ 11,
+ 11,
+ 215,
+ },
+ dictWord{13, 11, 65},
+ dictWord{14, 11, 172},
+ dictWord{14, 11, 317},
+ dictWord{145, 11, 6},
+ dictWord{8, 11, 60},
+ dictWord{9, 11, 343},
+ dictWord{
+ 139,
+ 11,
+ 769,
+ },
+ dictWord{137, 11, 455},
+ dictWord{134, 0, 1193},
+ dictWord{140, 0, 790},
+ dictWord{7, 11, 1951},
+ dictWord{8, 11, 765},
+ dictWord{8, 11, 772},
+ dictWord{140, 11, 671},
+ dictWord{7, 11, 108},
+ dictWord{8, 11, 219},
+ dictWord{8, 11, 388},
+ dictWord{9, 11, 639},
+ dictWord{9, 11, 775},
+ dictWord{11, 11, 275},
+ dictWord{140, 11, 464},
+ dictWord{132, 11, 468},
+ dictWord{7, 10, 30},
+ dictWord{8, 10, 86},
+ dictWord{8, 10, 315},
+ dictWord{8, 10, 700},
+ dictWord{9, 10, 576},
+ dictWord{
+ 9,
+ 10,
+ 858,
+ },
+ dictWord{11, 10, 310},
+ dictWord{11, 10, 888},
+ dictWord{11, 10, 904},
+ dictWord{12, 10, 361},
+ dictWord{141, 10, 248},
+ dictWord{5, 11, 15},
+ dictWord{6, 11, 56},
+ dictWord{7, 11, 1758},
+ dictWord{8, 11, 500},
+ dictWord{9, 11, 730},
+ dictWord{11, 11, 331},
+ dictWord{13, 11, 150},
+ dictWord{142, 11, 282},
+ dictWord{4, 0, 402},
+ dictWord{7, 0, 2},
+ dictWord{8, 0, 323},
+ dictWord{136, 0, 479},
+ dictWord{138, 10, 839},
+ dictWord{11, 0, 580},
+ dictWord{142, 0, 201},
+ dictWord{
+ 5,
+ 0,
+ 59,
+ },
+ dictWord{135, 0, 672},
+ dictWord{137, 10, 617},
+ dictWord{146, 0, 34},
+ dictWord{134, 11, 1886},
+ dictWord{4, 0, 961},
+ dictWord{136, 0, 896},
+ dictWord{
+ 6,
+ 0,
+ 1285,
+ },
+ dictWord{5, 11, 205},
+ dictWord{6, 11, 438},
+ dictWord{137, 11, 711},
+ dictWord{134, 10, 428},
+ dictWord{7, 10, 524},
+ dictWord{8, 10, 169},
+ dictWord{8, 10, 234},
+ dictWord{9, 10, 480},
+ dictWord{138, 10, 646},
+ dictWord{148, 0, 46},
+ dictWord{141, 0, 479},
+ dictWord{133, 11, 534},
+ dictWord{6, 0, 2019},
+ dictWord{134, 10, 1648},
+ dictWord{4, 0, 85},
+ dictWord{7, 0, 549},
+ dictWord{7, 10, 1205},
+ dictWord{138, 10, 637},
+ dictWord{4, 0, 663},
+ dictWord{5, 0, 94},
+ dictWord{
+ 7,
+ 11,
+ 235,
+ },
+ dictWord{7, 11, 1475},
+ dictWord{15, 11, 68},
+ dictWord{146, 11, 120},
+ dictWord{6, 11, 443},
+ dictWord{9, 11, 237},
+ dictWord{9, 11, 571},
+ dictWord{
+ 9,
+ 11,
+ 695,
+ },
+ dictWord{10, 11, 139},
+ dictWord{11, 11, 715},
+ dictWord{12, 11, 417},
+ dictWord{141, 11, 421},
+ dictWord{132, 0, 783},
+ dictWord{4, 0, 682},
+ dictWord{8, 0, 65},
+ dictWord{9, 10, 39},
+ dictWord{10, 10, 166},
+ dictWord{11, 10, 918},
+ dictWord{12, 10, 635},
+ dictWord{20, 10, 10},
+ dictWord{22, 10, 27},
+ dictWord{
+ 22,
+ 10,
+ 43,
+ },
+ dictWord{150, 10, 52},
+ dictWord{6, 0, 11},
+ dictWord{135, 0, 187},
+ dictWord{132, 0, 522},
+ dictWord{4, 0, 52},
+ dictWord{135, 0, 661},
+ dictWord{
+ 4,
+ 0,
+ 383,
+ },
+ dictWord{133, 0, 520},
+ dictWord{135, 11, 546},
+ dictWord{11, 0, 343},
+ dictWord{142, 0, 127},
+ dictWord{4, 11, 578},
+ dictWord{7, 10, 157},
+ dictWord{
+ 7,
+ 11,
+ 624,
+ },
+ dictWord{7, 11, 916},
+ dictWord{8, 10, 279},
+ dictWord{10, 11, 256},
+ dictWord{11, 11, 87},
+ dictWord{139, 11, 703},
+ dictWord{134, 10, 604},
+ dictWord{
+ 4,
+ 0,
+ 281,
+ },
+ dictWord{5, 0, 38},
+ dictWord{7, 0, 194},
+ dictWord{7, 0, 668},
+ dictWord{7, 0, 1893},
+ dictWord{137, 0, 397},
+ dictWord{7, 10, 945},
+ dictWord{11, 10, 713},
+ dictWord{139, 10, 744},
+ dictWord{139, 10, 1022},
+ dictWord{9, 0, 635},
+ dictWord{139, 0, 559},
+ dictWord{5, 11, 923},
+ dictWord{7, 11, 490},
+ dictWord{
+ 12,
+ 11,
+ 553,
+ },
+ dictWord{13, 11, 100},
+ dictWord{14, 11, 118},
+ dictWord{143, 11, 75},
+ dictWord{132, 0, 975},
+ dictWord{132, 10, 567},
+ dictWord{137, 10, 859},
+ dictWord{7, 10, 1846},
+ dictWord{7, 11, 1846},
+ dictWord{8, 10, 628},
+ dictWord{136, 11, 628},
+ dictWord{148, 0, 116},
+ dictWord{138, 11, 750},
+ dictWord{14, 0, 51},
+ dictWord{14, 11, 51},
+ dictWord{15, 11, 7},
+ dictWord{148, 11, 20},
+ dictWord{132, 0, 858},
+ dictWord{134, 0, 1075},
+ dictWord{4, 11, 924},
+ dictWord{
+ 133,
+ 10,
+ 762,
+ },
+ dictWord{136, 0, 535},
+ dictWord{133, 0, 448},
+ dictWord{10, 10, 784},
+ dictWord{141, 10, 191},
+ dictWord{133, 10, 298},
+ dictWord{7, 0, 610},
+ dictWord{135, 0, 1501},
+ dictWord{7, 10, 633},
+ dictWord{7, 10, 905},
+ dictWord{7, 10, 909},
+ dictWord{7, 10, 1538},
+ dictWord{9, 10, 767},
+ dictWord{140, 10, 636},
+ dictWord{4, 11, 265},
+ dictWord{7, 11, 807},
+ dictWord{135, 11, 950},
+ dictWord{5, 11, 93},
+ dictWord{12, 11, 267},
+ dictWord{144, 11, 26},
+ dictWord{136, 0, 191},
+ dictWord{139, 10, 301},
+ dictWord{135, 10, 1970},
+ dictWord{135, 0, 267},
+ dictWord{4, 0, 319},
+ dictWord{5, 0, 699},
+ dictWord{138, 0, 673},
+ dictWord{
+ 6,
+ 0,
+ 336,
+ },
+ dictWord{7, 0, 92},
+ dictWord{7, 0, 182},
+ dictWord{8, 0, 453},
+ dictWord{8, 0, 552},
+ dictWord{9, 0, 204},
+ dictWord{9, 0, 285},
+ dictWord{10, 0, 99},
+ dictWord{
+ 11,
+ 0,
+ 568,
+ },
+ dictWord{11, 0, 950},
+ dictWord{12, 0, 94},
+ dictWord{16, 0, 20},
+ dictWord{16, 0, 70},
+ dictWord{19, 0, 55},
+ dictWord{12, 10, 644},
+ dictWord{144, 10, 90},
+ dictWord{6, 0, 551},
+ dictWord{7, 0, 1308},
+ dictWord{7, 10, 845},
+ dictWord{7, 11, 994},
+ dictWord{8, 10, 160},
+ dictWord{137, 10, 318},
+ dictWord{19, 11, 1},
+ dictWord{
+ 19,
+ 11,
+ 26,
+ },
+ dictWord{150, 11, 9},
+ dictWord{7, 0, 1406},
+ dictWord{9, 0, 218},
+ dictWord{141, 0, 222},
+ dictWord{5, 0, 256},
+ dictWord{138, 0, 69},
+ dictWord{
+ 5,
+ 11,
+ 233,
+ },
+ dictWord{5, 11, 320},
+ dictWord{6, 11, 140},
+ dictWord{7, 11, 330},
+ dictWord{136, 11, 295},
+ dictWord{6, 0, 1980},
+ dictWord{136, 0, 952},
+ dictWord{
+ 4,
+ 0,
+ 833,
+ },
+ dictWord{137, 11, 678},
+ dictWord{133, 11, 978},
+ dictWord{4, 11, 905},
+ dictWord{6, 11, 1701},
+ dictWord{137, 11, 843},
+ dictWord{138, 10, 735},
+ dictWord{136, 10, 76},
+ dictWord{17, 0, 39},
+ dictWord{148, 0, 36},
+ dictWord{18, 0, 81},
+ dictWord{146, 11, 81},
+ dictWord{14, 0, 352},
+ dictWord{17, 0, 53},
+ dictWord{
+ 18,
+ 0,
+ 146,
+ },
+ dictWord{18, 0, 152},
+ dictWord{19, 0, 11},
+ dictWord{150, 0, 54},
+ dictWord{135, 0, 634},
+ dictWord{138, 10, 841},
+ dictWord{132, 0, 618},
+ dictWord{
+ 4,
+ 0,
+ 339,
+ },
+ dictWord{7, 0, 259},
+ dictWord{17, 0, 73},
+ dictWord{4, 11, 275},
+ dictWord{140, 11, 376},
+ dictWord{132, 11, 509},
+ dictWord{7, 11, 273},
+ dictWord{
+ 139,
+ 11,
+ 377,
+ },
+ dictWord{4, 0, 759},
+ dictWord{13, 0, 169},
+ dictWord{137, 10, 804},
+ dictWord{6, 10, 96},
+ dictWord{135, 10, 1426},
+ dictWord{4, 10, 651},
+ dictWord{133, 10, 289},
+ dictWord{7, 0, 1075},
+ dictWord{8, 10, 35},
+ dictWord{9, 10, 511},
+ dictWord{10, 10, 767},
+ dictWord{147, 10, 118},
+ dictWord{6, 0, 649},
+ dictWord{6, 0, 670},
+ dictWord{136, 0, 482},
+ dictWord{5, 0, 336},
+ dictWord{6, 0, 341},
+ dictWord{6, 0, 478},
+ dictWord{6, 0, 1763},
+ dictWord{136, 0, 386},
+ dictWord{
+ 5,
+ 11,
+ 802,
+ },
+ dictWord{7, 11, 2021},
+ dictWord{8, 11, 805},
+ dictWord{14, 11, 94},
+ dictWord{15, 11, 65},
+ dictWord{16, 11, 4},
+ dictWord{16, 11, 77},
+ dictWord{16, 11, 80},
+ dictWord{145, 11, 5},
+ dictWord{6, 0, 1035},
+ dictWord{5, 11, 167},
+ dictWord{5, 11, 899},
+ dictWord{6, 11, 410},
+ dictWord{137, 11, 777},
+ dictWord{
+ 134,
+ 11,
+ 1705,
+ },
+ dictWord{5, 0, 924},
+ dictWord{133, 0, 969},
+ dictWord{132, 10, 704},
+ dictWord{135, 0, 73},
+ dictWord{135, 11, 10},
+ dictWord{135, 10, 1078},
+ dictWord{
+ 5,
+ 11,
+ 11,
+ },
+ dictWord{6, 11, 117},
+ dictWord{6, 11, 485},
+ dictWord{7, 11, 1133},
+ dictWord{9, 11, 582},
+ dictWord{9, 11, 594},
+ dictWord{11, 11, 21},
+ dictWord{
+ 11,
+ 11,
+ 818,
+ },
+ dictWord{12, 11, 535},
+ dictWord{141, 11, 86},
+ dictWord{135, 0, 1971},
+ dictWord{4, 11, 264},
+ dictWord{7, 11, 1067},
+ dictWord{8, 11, 204},
+ dictWord{8, 11, 385},
+ dictWord{139, 11, 953},
+ dictWord{6, 0, 1458},
+ dictWord{135, 0, 1344},
+ dictWord{5, 0, 396},
+ dictWord{134, 0, 501},
+ dictWord{4, 10, 720},
+ dictWord{133, 10, 306},
+ dictWord{4, 0, 929},
+ dictWord{5, 0, 799},
+ dictWord{8, 0, 46},
+ dictWord{8, 0, 740},
+ dictWord{133, 10, 431},
+ dictWord{7, 11, 646},
+ dictWord{
+ 7,
+ 11,
+ 1730,
+ },
+ dictWord{11, 11, 446},
+ dictWord{141, 11, 178},
+ dictWord{7, 0, 276},
+ dictWord{5, 10, 464},
+ dictWord{6, 10, 236},
+ dictWord{7, 10, 696},
+ dictWord{
+ 7,
+ 10,
+ 914,
+ },
+ dictWord{7, 10, 1108},
+ dictWord{7, 10, 1448},
+ dictWord{9, 10, 15},
+ dictWord{9, 10, 564},
+ dictWord{10, 10, 14},
+ dictWord{12, 10, 565},
+ dictWord{
+ 13,
+ 10,
+ 449,
+ },
+ dictWord{14, 10, 53},
+ dictWord{15, 10, 13},
+ dictWord{16, 10, 64},
+ dictWord{145, 10, 41},
+ dictWord{4, 0, 892},
+ dictWord{133, 0, 770},
+ dictWord{
+ 6,
+ 10,
+ 1767,
+ },
+ dictWord{12, 10, 194},
+ dictWord{145, 10, 107},
+ dictWord{135, 0, 158},
+ dictWord{5, 10, 840},
+ dictWord{138, 11, 608},
+ dictWord{134, 0, 1432},
+ dictWord{138, 11, 250},
+ dictWord{8, 11, 794},
+ dictWord{9, 11, 400},
+ dictWord{10, 11, 298},
+ dictWord{142, 11, 228},
+ dictWord{151, 0, 25},
+ dictWord{
+ 7,
+ 11,
+ 1131,
+ },
+ dictWord{135, 11, 1468},
+ dictWord{135, 0, 2001},
+ dictWord{9, 10, 642},
+ dictWord{11, 10, 236},
+ dictWord{142, 10, 193},
+ dictWord{4, 10, 68},
+ dictWord{5, 10, 634},
+ dictWord{6, 10, 386},
+ dictWord{7, 10, 794},
+ dictWord{8, 10, 273},
+ dictWord{9, 10, 563},
+ dictWord{10, 10, 105},
+ dictWord{10, 10, 171},
+ dictWord{11, 10, 94},
+ dictWord{139, 10, 354},
+ dictWord{136, 11, 724},
+ dictWord{132, 0, 478},
+ dictWord{11, 11, 512},
+ dictWord{13, 11, 205},
+ dictWord{
+ 19,
+ 11,
+ 30,
+ },
+ dictWord{22, 11, 36},
+ dictWord{151, 11, 19},
+ dictWord{7, 0, 1461},
+ dictWord{140, 0, 91},
+ dictWord{6, 11, 190},
+ dictWord{7, 11, 768},
+ dictWord{
+ 135,
+ 11,
+ 1170,
+ },
+ dictWord{4, 0, 602},
+ dictWord{8, 0, 211},
+ dictWord{4, 10, 95},
+ dictWord{7, 10, 416},
+ dictWord{139, 10, 830},
+ dictWord{7, 10, 731},
+ dictWord{13, 10, 20},
+ dictWord{143, 10, 11},
+ dictWord{6, 0, 1068},
+ dictWord{135, 0, 1872},
+ dictWord{4, 0, 13},
+ dictWord{5, 0, 567},
+ dictWord{7, 0, 1498},
+ dictWord{9, 0, 124},
+ dictWord{11, 0, 521},
+ dictWord{12, 0, 405},
+ dictWord{135, 11, 1023},
+ dictWord{135, 0, 1006},
+ dictWord{132, 0, 735},
+ dictWord{138, 0, 812},
+ dictWord{4, 0, 170},
+ dictWord{135, 0, 323},
+ dictWord{6, 11, 137},
+ dictWord{9, 11, 75},
+ dictWord{9, 11, 253},
+ dictWord{10, 11, 194},
+ dictWord{138, 11, 444},
+ dictWord{5, 0, 304},
+ dictWord{7, 0, 1403},
+ dictWord{5, 10, 864},
+ dictWord{10, 10, 648},
+ dictWord{11, 10, 671},
+ dictWord{143, 10, 46},
+ dictWord{135, 11, 1180},
+ dictWord{
+ 133,
+ 10,
+ 928,
+ },
+ dictWord{4, 0, 148},
+ dictWord{133, 0, 742},
+ dictWord{11, 10, 986},
+ dictWord{140, 10, 682},
+ dictWord{133, 0, 523},
+ dictWord{135, 11, 1743},
+ dictWord{7, 0, 730},
+ dictWord{18, 0, 144},
+ dictWord{19, 0, 61},
+ dictWord{8, 10, 44},
+ dictWord{9, 10, 884},
+ dictWord{10, 10, 580},
+ dictWord{11, 10, 399},
+ dictWord{
+ 11,
+ 10,
+ 894,
+ },
+ dictWord{143, 10, 122},
+ dictWord{5, 11, 760},
+ dictWord{7, 11, 542},
+ dictWord{8, 11, 135},
+ dictWord{136, 11, 496},
+ dictWord{136, 0, 981},
+ dictWord{133, 0, 111},
+ dictWord{10, 0, 132},
+ dictWord{11, 0, 191},
+ dictWord{11, 0, 358},
+ dictWord{139, 0, 460},
+ dictWord{7, 11, 319},
+ dictWord{7, 11, 355},
+ dictWord{
+ 7,
+ 11,
+ 763,
+ },
+ dictWord{10, 11, 389},
+ dictWord{145, 11, 43},
+ dictWord{134, 0, 890},
+ dictWord{134, 0, 1420},
+ dictWord{136, 11, 557},
+ dictWord{
+ 133,
+ 10,
+ 518,
+ },
+ dictWord{133, 0, 444},
+ dictWord{135, 0, 1787},
+ dictWord{135, 10, 1852},
+ dictWord{8, 0, 123},
+ dictWord{15, 0, 6},
+ dictWord{144, 0, 7},
+ dictWord{
+ 6,
+ 0,
+ 2041,
+ },
+ dictWord{10, 11, 38},
+ dictWord{139, 11, 784},
+ dictWord{136, 0, 932},
+ dictWord{5, 0, 937},
+ dictWord{135, 0, 100},
+ dictWord{6, 0, 995},
+ dictWord{
+ 4,
+ 11,
+ 58,
+ },
+ dictWord{5, 11, 286},
+ dictWord{6, 11, 319},
+ dictWord{7, 11, 402},
+ dictWord{7, 11, 1254},
+ dictWord{7, 11, 1903},
+ dictWord{8, 11, 356},
+ dictWord{
+ 140,
+ 11,
+ 408,
+ },
+ dictWord{4, 11, 389},
+ dictWord{9, 11, 181},
+ dictWord{9, 11, 255},
+ dictWord{10, 11, 8},
+ dictWord{10, 11, 29},
+ dictWord{10, 11, 816},
+ dictWord{
+ 11,
+ 11,
+ 311,
+ },
+ dictWord{11, 11, 561},
+ dictWord{12, 11, 67},
+ dictWord{141, 11, 181},
+ dictWord{138, 0, 255},
+ dictWord{5, 0, 138},
+ dictWord{4, 10, 934},
+ dictWord{
+ 136,
+ 10,
+ 610,
+ },
+ dictWord{4, 0, 965},
+ dictWord{10, 0, 863},
+ dictWord{138, 0, 898},
+ dictWord{10, 10, 804},
+ dictWord{138, 10, 832},
+ dictWord{12, 0, 631},
+ dictWord{
+ 8,
+ 10,
+ 96,
+ },
+ dictWord{9, 10, 36},
+ dictWord{10, 10, 607},
+ dictWord{11, 10, 423},
+ dictWord{11, 10, 442},
+ dictWord{12, 10, 309},
+ dictWord{14, 10, 199},
+ dictWord{
+ 15,
+ 10,
+ 90,
+ },
+ dictWord{145, 10, 110},
+ dictWord{134, 0, 1394},
+ dictWord{4, 0, 652},
+ dictWord{8, 0, 320},
+ dictWord{22, 0, 6},
+ dictWord{22, 0, 16},
+ dictWord{
+ 9,
+ 10,
+ 13,
+ },
+ dictWord{9, 10, 398},
+ dictWord{9, 10, 727},
+ dictWord{10, 10, 75},
+ dictWord{10, 10, 184},
+ dictWord{10, 10, 230},
+ dictWord{10, 10, 564},
+ dictWord{
+ 10,
+ 10,
+ 569,
+ },
+ dictWord{11, 10, 973},
+ dictWord{12, 10, 70},
+ dictWord{12, 10, 189},
+ dictWord{13, 10, 57},
+ dictWord{141, 10, 257},
+ dictWord{6, 0, 897},
+ dictWord{
+ 134,
+ 0,
+ 1333,
+ },
+ dictWord{4, 0, 692},
+ dictWord{133, 0, 321},
+ dictWord{133, 11, 373},
+ dictWord{135, 0, 922},
+ dictWord{5, 0, 619},
+ dictWord{133, 0, 698},
+ dictWord{
+ 137,
+ 10,
+ 631,
+ },
+ dictWord{5, 10, 345},
+ dictWord{135, 10, 1016},
+ dictWord{9, 0, 957},
+ dictWord{9, 0, 1018},
+ dictWord{12, 0, 828},
+ dictWord{12, 0, 844},
+ dictWord{
+ 12,
+ 0,
+ 897,
+ },
+ dictWord{12, 0, 901},
+ dictWord{12, 0, 943},
+ dictWord{15, 0, 180},
+ dictWord{18, 0, 197},
+ dictWord{18, 0, 200},
+ dictWord{18, 0, 213},
+ dictWord{
+ 18,
+ 0,
+ 214,
+ },
+ dictWord{146, 0, 226},
+ dictWord{5, 0, 917},
+ dictWord{134, 0, 1659},
+ dictWord{135, 0, 1100},
+ dictWord{134, 0, 1173},
+ dictWord{134, 0, 1930},
+ dictWord{5, 0, 251},
+ dictWord{5, 0, 956},
+ dictWord{8, 0, 268},
+ dictWord{9, 0, 214},
+ dictWord{146, 0, 142},
+ dictWord{133, 10, 673},
+ dictWord{137, 10, 850},
+ dictWord{
+ 4,
+ 10,
+ 287,
+ },
+ dictWord{133, 10, 1018},
+ dictWord{132, 11, 672},
+ dictWord{5, 0, 346},
+ dictWord{5, 0, 711},
+ dictWord{8, 0, 390},
+ dictWord{11, 11, 752},
+ dictWord{139, 11, 885},
+ dictWord{5, 10, 34},
+ dictWord{10, 10, 724},
+ dictWord{12, 10, 444},
+ dictWord{13, 10, 354},
+ dictWord{18, 10, 32},
+ dictWord{23, 10, 24},
+ dictWord{23, 10, 31},
+ dictWord{152, 10, 5},
+ dictWord{4, 11, 710},
+ dictWord{134, 11, 606},
+ dictWord{134, 0, 744},
+ dictWord{134, 10, 382},
+ dictWord{
+ 133,
+ 11,
+ 145,
+ },
+ dictWord{4, 10, 329},
+ dictWord{7, 11, 884},
+ dictWord{140, 11, 124},
+ dictWord{4, 11, 467},
+ dictWord{5, 11, 405},
+ dictWord{134, 11, 544},
+ dictWord{
+ 9,
+ 10,
+ 846,
+ },
+ dictWord{138, 10, 827},
+ dictWord{133, 0, 624},
+ dictWord{9, 11, 372},
+ dictWord{15, 11, 2},
+ dictWord{19, 11, 10},
+ dictWord{147, 11, 18},
+ dictWord{
+ 4,
+ 11,
+ 387,
+ },
+ dictWord{135, 11, 1288},
+ dictWord{5, 0, 783},
+ dictWord{7, 0, 1998},
+ dictWord{135, 0, 2047},
+ dictWord{132, 10, 906},
+ dictWord{136, 10, 366},
+ dictWord{135, 11, 550},
+ dictWord{4, 10, 123},
+ dictWord{4, 10, 649},
+ dictWord{5, 10, 605},
+ dictWord{7, 10, 1509},
+ dictWord{136, 10, 36},
+ dictWord{
+ 134,
+ 0,
+ 1125,
+ },
+ dictWord{132, 0, 594},
+ dictWord{133, 10, 767},
+ dictWord{135, 11, 1227},
+ dictWord{136, 11, 467},
+ dictWord{4, 11, 576},
+ dictWord{
+ 135,
+ 11,
+ 1263,
+ },
+ dictWord{4, 0, 268},
+ dictWord{7, 0, 1534},
+ dictWord{135, 11, 1534},
+ dictWord{4, 10, 273},
+ dictWord{5, 10, 658},
+ dictWord{5, 11, 919},
+ dictWord{
+ 5,
+ 10,
+ 995,
+ },
+ dictWord{134, 11, 1673},
+ dictWord{133, 0, 563},
+ dictWord{134, 10, 72},
+ dictWord{135, 10, 1345},
+ dictWord{4, 11, 82},
+ dictWord{5, 11, 333},
+ dictWord{
+ 5,
+ 11,
+ 904,
+ },
+ dictWord{6, 11, 207},
+ dictWord{7, 11, 325},
+ dictWord{7, 11, 1726},
+ dictWord{8, 11, 101},
+ dictWord{10, 11, 778},
+ dictWord{139, 11, 220},
+ dictWord{5, 0, 37},
+ dictWord{6, 0, 39},
+ dictWord{6, 0, 451},
+ dictWord{7, 0, 218},
+ dictWord{7, 0, 667},
+ dictWord{7, 0, 1166},
+ dictWord{7, 0, 1687},
+ dictWord{8, 0, 662},
+ dictWord{16, 0, 2},
+ dictWord{133, 10, 589},
+ dictWord{134, 0, 1332},
+ dictWord{133, 11, 903},
+ dictWord{134, 0, 508},
+ dictWord{5, 10, 117},
+ dictWord{6, 10, 514},
+ dictWord{6, 10, 541},
+ dictWord{7, 10, 1164},
+ dictWord{7, 10, 1436},
+ dictWord{8, 10, 220},
+ dictWord{8, 10, 648},
+ dictWord{10, 10, 688},
+ dictWord{11, 10, 560},
+ dictWord{140, 11, 147},
+ dictWord{6, 11, 555},
+ dictWord{135, 11, 485},
+ dictWord{133, 10, 686},
+ dictWord{7, 0, 453},
+ dictWord{7, 0, 635},
+ dictWord{7, 0, 796},
+ dictWord{8, 0, 331},
+ dictWord{9, 0, 330},
+ dictWord{9, 0, 865},
+ dictWord{10, 0, 119},
+ dictWord{10, 0, 235},
+ dictWord{11, 0, 111},
+ dictWord{11, 0, 129},
+ dictWord{
+ 11,
+ 0,
+ 240,
+ },
+ dictWord{12, 0, 31},
+ dictWord{12, 0, 66},
+ dictWord{12, 0, 222},
+ dictWord{12, 0, 269},
+ dictWord{12, 0, 599},
+ dictWord{12, 0, 684},
+ dictWord{12, 0, 689},
+ dictWord{12, 0, 691},
+ dictWord{142, 0, 345},
+ dictWord{135, 0, 1834},
+ dictWord{4, 11, 705},
+ dictWord{7, 11, 615},
+ dictWord{138, 11, 251},
+ dictWord{
+ 136,
+ 11,
+ 345,
+ },
+ dictWord{137, 0, 527},
+ dictWord{6, 0, 98},
+ dictWord{7, 0, 702},
+ dictWord{135, 0, 991},
+ dictWord{11, 0, 576},
+ dictWord{14, 0, 74},
+ dictWord{7, 10, 196},
+ dictWord{10, 10, 765},
+ dictWord{11, 10, 347},
+ dictWord{11, 10, 552},
+ dictWord{11, 10, 790},
+ dictWord{12, 10, 263},
+ dictWord{13, 10, 246},
+ dictWord{
+ 13,
+ 10,
+ 270,
+ },
+ dictWord{13, 10, 395},
+ dictWord{14, 10, 176},
+ dictWord{14, 10, 190},
+ dictWord{14, 10, 398},
+ dictWord{14, 10, 412},
+ dictWord{15, 10, 32},
+ dictWord{
+ 15,
+ 10,
+ 63,
+ },
+ dictWord{16, 10, 88},
+ dictWord{147, 10, 105},
+ dictWord{134, 11, 90},
+ dictWord{13, 0, 84},
+ dictWord{141, 0, 122},
+ dictWord{6, 0, 37},
+ dictWord{
+ 7,
+ 0,
+ 299,
+ },
+ dictWord{7, 0, 1666},
+ dictWord{8, 0, 195},
+ dictWord{8, 0, 316},
+ dictWord{9, 0, 178},
+ dictWord{9, 0, 276},
+ dictWord{9, 0, 339},
+ dictWord{9, 0, 536},
+ dictWord{
+ 10,
+ 0,
+ 102,
+ },
+ dictWord{10, 0, 362},
+ dictWord{10, 0, 785},
+ dictWord{11, 0, 55},
+ dictWord{11, 0, 149},
+ dictWord{11, 0, 773},
+ dictWord{13, 0, 416},
+ dictWord{
+ 13,
+ 0,
+ 419,
+ },
+ dictWord{14, 0, 38},
+ dictWord{14, 0, 41},
+ dictWord{142, 0, 210},
+ dictWord{5, 10, 381},
+ dictWord{135, 10, 1792},
+ dictWord{7, 11, 813},
+ dictWord{
+ 12,
+ 11,
+ 497,
+ },
+ dictWord{141, 11, 56},
+ dictWord{7, 10, 616},
+ dictWord{138, 10, 413},
+ dictWord{133, 0, 645},
+ dictWord{6, 11, 125},
+ dictWord{135, 11, 1277},
+ dictWord{132, 0, 290},
+ dictWord{6, 0, 70},
+ dictWord{7, 0, 1292},
+ dictWord{10, 0, 762},
+ dictWord{139, 0, 288},
+ dictWord{6, 10, 120},
+ dictWord{7, 10, 1188},
+ dictWord{
+ 7,
+ 10,
+ 1710,
+ },
+ dictWord{8, 10, 286},
+ dictWord{9, 10, 667},
+ dictWord{11, 10, 592},
+ dictWord{139, 10, 730},
+ dictWord{135, 11, 1784},
+ dictWord{7, 0, 1315},
+ dictWord{135, 11, 1315},
+ dictWord{134, 0, 1955},
+ dictWord{135, 10, 1146},
+ dictWord{7, 0, 131},
+ dictWord{7, 0, 422},
+ dictWord{8, 0, 210},
+ dictWord{
+ 140,
+ 0,
+ 573,
+ },
+ dictWord{4, 10, 352},
+ dictWord{135, 10, 687},
+ dictWord{139, 0, 797},
+ dictWord{143, 0, 38},
+ dictWord{14, 0, 179},
+ dictWord{15, 0, 151},
+ dictWord{
+ 150,
+ 0,
+ 11,
+ },
+ dictWord{7, 0, 488},
+ dictWord{4, 10, 192},
+ dictWord{5, 10, 49},
+ dictWord{6, 10, 200},
+ dictWord{6, 10, 293},
+ dictWord{134, 10, 1696},
+ dictWord{
+ 132,
+ 0,
+ 936,
+ },
+ dictWord{135, 11, 703},
+ dictWord{6, 11, 160},
+ dictWord{7, 11, 1106},
+ dictWord{9, 11, 770},
+ dictWord{10, 11, 618},
+ dictWord{11, 11, 112},
+ dictWord{
+ 140,
+ 11,
+ 413,
+ },
+ dictWord{5, 0, 453},
+ dictWord{134, 0, 441},
+ dictWord{135, 0, 595},
+ dictWord{132, 10, 650},
+ dictWord{132, 10, 147},
+ dictWord{6, 0, 991},
+ dictWord{6, 0, 1182},
+ dictWord{12, 11, 271},
+ dictWord{145, 11, 109},
+ dictWord{133, 10, 934},
+ dictWord{140, 11, 221},
+ dictWord{132, 0, 653},
+ dictWord{
+ 7,
+ 0,
+ 505,
+ },
+ dictWord{135, 0, 523},
+ dictWord{134, 0, 903},
+ dictWord{135, 11, 479},
+ dictWord{7, 11, 304},
+ dictWord{9, 11, 646},
+ dictWord{9, 11, 862},
+ dictWord{
+ 10,
+ 11,
+ 262,
+ },
+ dictWord{11, 11, 696},
+ dictWord{12, 11, 208},
+ dictWord{15, 11, 79},
+ dictWord{147, 11, 108},
+ dictWord{146, 0, 80},
+ dictWord{135, 11, 981},
+ dictWord{142, 0, 432},
+ dictWord{132, 0, 314},
+ dictWord{137, 11, 152},
+ dictWord{7, 0, 1368},
+ dictWord{8, 0, 232},
+ dictWord{8, 0, 361},
+ dictWord{10, 0, 682},
+ dictWord{138, 0, 742},
+ dictWord{135, 11, 1586},
+ dictWord{9, 0, 534},
+ dictWord{4, 11, 434},
+ dictWord{11, 11, 663},
+ dictWord{12, 11, 210},
+ dictWord{13, 11, 166},
+ dictWord{13, 11, 310},
+ dictWord{14, 11, 373},
+ dictWord{147, 11, 43},
+ dictWord{7, 11, 1091},
+ dictWord{135, 11, 1765},
+ dictWord{6, 11, 550},
+ dictWord{
+ 135,
+ 11,
+ 652,
+ },
+ dictWord{137, 0, 27},
+ dictWord{142, 0, 12},
+ dictWord{4, 10, 637},
+ dictWord{5, 11, 553},
+ dictWord{7, 11, 766},
+ dictWord{138, 11, 824},
+ dictWord{
+ 7,
+ 11,
+ 737,
+ },
+ dictWord{8, 11, 298},
+ dictWord{136, 11, 452},
+ dictWord{7, 0, 736},
+ dictWord{139, 0, 264},
+ dictWord{134, 0, 1657},
+ dictWord{133, 11, 292},
+ dictWord{138, 11, 135},
+ dictWord{6, 0, 844},
+ dictWord{134, 0, 1117},
+ dictWord{135, 0, 127},
+ dictWord{9, 10, 867},
+ dictWord{138, 10, 837},
+ dictWord{
+ 6,
+ 0,
+ 1184,
+ },
+ dictWord{134, 0, 1208},
+ dictWord{134, 0, 1294},
+ dictWord{136, 0, 364},
+ dictWord{6, 0, 1415},
+ dictWord{7, 0, 1334},
+ dictWord{11, 0, 125},
+ dictWord{
+ 6,
+ 10,
+ 170,
+ },
+ dictWord{7, 11, 393},
+ dictWord{8, 10, 395},
+ dictWord{8, 10, 487},
+ dictWord{10, 11, 603},
+ dictWord{11, 11, 206},
+ dictWord{141, 10, 147},
+ dictWord{137, 11, 748},
+ dictWord{4, 11, 912},
+ dictWord{137, 11, 232},
+ dictWord{4, 10, 535},
+ dictWord{136, 10, 618},
+ dictWord{137, 0, 792},
+ dictWord{
+ 7,
+ 11,
+ 1973,
+ },
+ dictWord{136, 11, 716},
+ dictWord{135, 11, 98},
+ dictWord{5, 0, 909},
+ dictWord{9, 0, 849},
+ dictWord{138, 0, 805},
+ dictWord{4, 0, 630},
+ dictWord{
+ 132,
+ 0,
+ 699,
+ },
+ dictWord{5, 11, 733},
+ dictWord{14, 11, 103},
+ dictWord{150, 10, 23},
+ dictWord{12, 11, 158},
+ dictWord{18, 11, 8},
+ dictWord{19, 11, 62},
+ dictWord{
+ 20,
+ 11,
+ 6,
+ },
+ dictWord{22, 11, 4},
+ dictWord{23, 11, 2},
+ dictWord{151, 11, 9},
+ dictWord{132, 0, 968},
+ dictWord{132, 10, 778},
+ dictWord{132, 10, 46},
+ dictWord{5, 10, 811},
+ dictWord{6, 10, 1679},
+ dictWord{6, 10, 1714},
+ dictWord{135, 10, 2032},
+ dictWord{6, 0, 1446},
+ dictWord{7, 10, 1458},
+ dictWord{9, 10, 407},
+ dictWord{
+ 139,
+ 10,
+ 15,
+ },
+ dictWord{7, 0, 206},
+ dictWord{7, 0, 397},
+ dictWord{7, 0, 621},
+ dictWord{7, 0, 640},
+ dictWord{8, 0, 124},
+ dictWord{8, 0, 619},
+ dictWord{9, 0, 305},
+ dictWord{
+ 9,
+ 0,
+ 643,
+ },
+ dictWord{10, 0, 264},
+ dictWord{10, 0, 628},
+ dictWord{11, 0, 40},
+ dictWord{12, 0, 349},
+ dictWord{13, 0, 134},
+ dictWord{13, 0, 295},
+ dictWord{
+ 14,
+ 0,
+ 155,
+ },
+ dictWord{15, 0, 120},
+ dictWord{18, 0, 105},
+ dictWord{6, 10, 34},
+ dictWord{7, 10, 1089},
+ dictWord{8, 10, 708},
+ dictWord{8, 10, 721},
+ dictWord{9, 10, 363},
+ dictWord{148, 10, 98},
+ dictWord{4, 0, 262},
+ dictWord{5, 0, 641},
+ dictWord{135, 0, 342},
+ dictWord{137, 11, 72},
+ dictWord{4, 0, 99},
+ dictWord{6, 0, 250},
+ dictWord{
+ 6,
+ 0,
+ 346,
+ },
+ dictWord{8, 0, 127},
+ dictWord{138, 0, 81},
+ dictWord{132, 0, 915},
+ dictWord{5, 0, 75},
+ dictWord{9, 0, 517},
+ dictWord{10, 0, 470},
+ dictWord{12, 0, 155},
+ dictWord{141, 0, 224},
+ dictWord{132, 10, 462},
+ dictWord{11, 11, 600},
+ dictWord{11, 11, 670},
+ dictWord{141, 11, 245},
+ dictWord{142, 0, 83},
+ dictWord{
+ 5,
+ 10,
+ 73,
+ },
+ dictWord{6, 10, 23},
+ dictWord{134, 10, 338},
+ dictWord{6, 0, 1031},
+ dictWord{139, 11, 923},
+ dictWord{7, 11, 164},
+ dictWord{7, 11, 1571},
+ dictWord{
+ 9,
+ 11,
+ 107,
+ },
+ dictWord{140, 11, 225},
+ dictWord{134, 0, 1470},
+ dictWord{133, 0, 954},
+ dictWord{6, 0, 304},
+ dictWord{8, 0, 418},
+ dictWord{10, 0, 345},
+ dictWord{
+ 11,
+ 0,
+ 341,
+ },
+ dictWord{139, 0, 675},
+ dictWord{9, 0, 410},
+ dictWord{139, 0, 425},
+ dictWord{4, 11, 27},
+ dictWord{5, 11, 484},
+ dictWord{5, 11, 510},
+ dictWord{6, 11, 434},
+ dictWord{7, 11, 1000},
+ dictWord{7, 11, 1098},
+ dictWord{8, 11, 2},
+ dictWord{136, 11, 200},
+ dictWord{134, 0, 734},
+ dictWord{140, 11, 257},
+ dictWord{
+ 7,
+ 10,
+ 725,
+ },
+ dictWord{8, 10, 498},
+ dictWord{139, 10, 268},
+ dictWord{134, 0, 1822},
+ dictWord{135, 0, 1798},
+ dictWord{135, 10, 773},
+ dictWord{132, 11, 460},
+ dictWord{4, 11, 932},
+ dictWord{133, 11, 891},
+ dictWord{134, 0, 14},
+ dictWord{132, 10, 583},
+ dictWord{7, 10, 1462},
+ dictWord{8, 11, 625},
+ dictWord{
+ 139,
+ 10,
+ 659,
+ },
+ dictWord{5, 0, 113},
+ dictWord{6, 0, 243},
+ dictWord{6, 0, 1708},
+ dictWord{7, 0, 1865},
+ dictWord{11, 0, 161},
+ dictWord{16, 0, 37},
+ dictWord{17, 0, 99},
+ dictWord{133, 10, 220},
+ dictWord{134, 11, 76},
+ dictWord{5, 11, 461},
+ dictWord{135, 11, 1925},
+ dictWord{140, 0, 69},
+ dictWord{8, 11, 92},
+ dictWord{
+ 137,
+ 11,
+ 221,
+ },
+ dictWord{139, 10, 803},
+ dictWord{132, 10, 544},
+ dictWord{4, 0, 274},
+ dictWord{134, 0, 922},
+ dictWord{132, 0, 541},
+ dictWord{5, 0, 627},
+ dictWord{
+ 6,
+ 10,
+ 437,
+ },
+ dictWord{6, 10, 564},
+ dictWord{11, 10, 181},
+ dictWord{141, 10, 183},
+ dictWord{135, 10, 1192},
+ dictWord{7, 0, 166},
+ dictWord{132, 11, 763},
+ dictWord{133, 11, 253},
+ dictWord{134, 0, 849},
+ dictWord{9, 11, 73},
+ dictWord{10, 11, 110},
+ dictWord{14, 11, 185},
+ dictWord{145, 11, 119},
+ dictWord{5, 11, 212},
+ dictWord{12, 11, 35},
+ dictWord{141, 11, 382},
+ dictWord{133, 0, 717},
+ dictWord{137, 0, 304},
+ dictWord{136, 0, 600},
+ dictWord{133, 0, 654},
+ dictWord{
+ 6,
+ 0,
+ 273,
+ },
+ dictWord{10, 0, 188},
+ dictWord{13, 0, 377},
+ dictWord{146, 0, 77},
+ dictWord{4, 10, 790},
+ dictWord{5, 10, 273},
+ dictWord{134, 10, 394},
+ dictWord{
+ 132,
+ 0,
+ 543,
+ },
+ dictWord{135, 0, 410},
+ dictWord{11, 0, 98},
+ dictWord{11, 0, 524},
+ dictWord{141, 0, 87},
+ dictWord{132, 0, 941},
+ dictWord{135, 11, 1175},
+ dictWord{
+ 4,
+ 0,
+ 250,
+ },
+ dictWord{7, 0, 1612},
+ dictWord{11, 0, 186},
+ dictWord{12, 0, 133},
+ dictWord{6, 10, 127},
+ dictWord{7, 10, 1511},
+ dictWord{8, 10, 613},
+ dictWord{
+ 12,
+ 10,
+ 495,
+ },
+ dictWord{12, 10, 586},
+ dictWord{12, 10, 660},
+ dictWord{12, 10, 668},
+ dictWord{14, 10, 385},
+ dictWord{15, 10, 118},
+ dictWord{17, 10, 20},
+ dictWord{
+ 146,
+ 10,
+ 98,
+ },
+ dictWord{6, 0, 1785},
+ dictWord{133, 11, 816},
+ dictWord{134, 0, 1339},
+ dictWord{7, 0, 961},
+ dictWord{7, 0, 1085},
+ dictWord{7, 0, 1727},
+ dictWord{
+ 8,
+ 0,
+ 462,
+ },
+ dictWord{6, 10, 230},
+ dictWord{135, 11, 1727},
+ dictWord{9, 0, 636},
+ dictWord{135, 10, 1954},
+ dictWord{132, 0, 780},
+ dictWord{5, 11, 869},
+ dictWord{5, 11, 968},
+ dictWord{6, 11, 1626},
+ dictWord{8, 11, 734},
+ dictWord{136, 11, 784},
+ dictWord{4, 11, 542},
+ dictWord{6, 11, 1716},
+ dictWord{6, 11, 1727},
+ dictWord{7, 11, 1082},
+ dictWord{7, 11, 1545},
+ dictWord{8, 11, 56},
+ dictWord{8, 11, 118},
+ dictWord{8, 11, 412},
+ dictWord{8, 11, 564},
+ dictWord{9, 11, 888},
+ dictWord{9, 11, 908},
+ dictWord{10, 11, 50},
+ dictWord{10, 11, 423},
+ dictWord{11, 11, 685},
+ dictWord{11, 11, 697},
+ dictWord{11, 11, 933},
+ dictWord{12, 11, 299},
+ dictWord{13, 11, 126},
+ dictWord{13, 11, 136},
+ dictWord{13, 11, 170},
+ dictWord{141, 11, 190},
+ dictWord{134, 11, 226},
+ dictWord{4, 11, 232},
+ dictWord{
+ 9,
+ 11,
+ 202,
+ },
+ dictWord{10, 11, 474},
+ dictWord{140, 11, 433},
+ dictWord{137, 11, 500},
+ dictWord{5, 0, 529},
+ dictWord{136, 10, 68},
+ dictWord{132, 10, 654},
+ dictWord{
+ 4,
+ 10,
+ 156,
+ },
+ dictWord{7, 10, 998},
+ dictWord{7, 10, 1045},
+ dictWord{7, 10, 1860},
+ dictWord{9, 10, 48},
+ dictWord{9, 10, 692},
+ dictWord{11, 10, 419},
+ dictWord{139, 10, 602},
+ dictWord{7, 0, 1276},
+ dictWord{8, 0, 474},
+ dictWord{9, 0, 652},
+ dictWord{6, 11, 108},
+ dictWord{7, 11, 1003},
+ dictWord{7, 11, 1181},
+ dictWord{136, 11, 343},
+ dictWord{7, 11, 1264},
+ dictWord{7, 11, 1678},
+ dictWord{11, 11, 945},
+ dictWord{12, 11, 341},
+ dictWord{12, 11, 471},
+ dictWord{
+ 140,
+ 11,
+ 569,
+ },
+ dictWord{134, 11, 1712},
+ dictWord{5, 0, 948},
+ dictWord{12, 0, 468},
+ dictWord{19, 0, 96},
+ dictWord{148, 0, 24},
+ dictWord{4, 11, 133},
+ dictWord{
+ 7,
+ 11,
+ 711,
+ },
+ dictWord{7, 11, 1298},
+ dictWord{7, 11, 1585},
+ dictWord{135, 11, 1929},
+ dictWord{6, 0, 753},
+ dictWord{140, 0, 657},
+ dictWord{139, 0, 941},
+ dictWord{
+ 6,
+ 11,
+ 99,
+ },
+ dictWord{7, 11, 1808},
+ dictWord{145, 11, 57},
+ dictWord{6, 11, 574},
+ dictWord{7, 11, 428},
+ dictWord{7, 11, 1250},
+ dictWord{10, 11, 669},
+ dictWord{
+ 11,
+ 11,
+ 485,
+ },
+ dictWord{11, 11, 840},
+ dictWord{12, 11, 300},
+ dictWord{142, 11, 250},
+ dictWord{4, 0, 532},
+ dictWord{5, 0, 706},
+ dictWord{135, 0, 662},
+ dictWord{
+ 5,
+ 0,
+ 837,
+ },
+ dictWord{6, 0, 1651},
+ dictWord{139, 0, 985},
+ dictWord{7, 0, 1861},
+ dictWord{9, 10, 197},
+ dictWord{10, 10, 300},
+ dictWord{12, 10, 473},
+ dictWord{
+ 13,
+ 10,
+ 90,
+ },
+ dictWord{141, 10, 405},
+ dictWord{137, 11, 252},
+ dictWord{6, 11, 323},
+ dictWord{135, 11, 1564},
+ dictWord{4, 0, 330},
+ dictWord{4, 0, 863},
+ dictWord{7, 0, 933},
+ dictWord{7, 0, 2012},
+ dictWord{8, 0, 292},
+ dictWord{7, 11, 461},
+ dictWord{8, 11, 775},
+ dictWord{138, 11, 435},
+ dictWord{132, 10, 606},
+ dictWord{
+ 4,
+ 11,
+ 655,
+ },
+ dictWord{7, 11, 850},
+ dictWord{17, 11, 75},
+ dictWord{146, 11, 137},
+ dictWord{135, 0, 767},
+ dictWord{7, 10, 1978},
+ dictWord{136, 10, 676},
+ dictWord{132, 0, 641},
+ dictWord{135, 11, 1559},
+ dictWord{134, 0, 1233},
+ dictWord{137, 0, 242},
+ dictWord{17, 0, 114},
+ dictWord{4, 10, 361},
+ dictWord{
+ 133,
+ 10,
+ 315,
+ },
+ dictWord{137, 0, 883},
+ dictWord{132, 10, 461},
+ dictWord{138, 0, 274},
+ dictWord{134, 0, 2008},
+ dictWord{134, 0, 1794},
+ dictWord{4, 0, 703},
+ dictWord{135, 0, 207},
+ dictWord{12, 0, 285},
+ dictWord{132, 10, 472},
+ dictWord{132, 0, 571},
+ dictWord{5, 0, 873},
+ dictWord{5, 0, 960},
+ dictWord{8, 0, 823},
+ dictWord{9, 0, 881},
+ dictWord{136, 11, 577},
+ dictWord{7, 0, 617},
+ dictWord{10, 0, 498},
+ dictWord{11, 0, 501},
+ dictWord{12, 0, 16},
+ dictWord{140, 0, 150},
+ dictWord{
+ 138,
+ 10,
+ 747,
+ },
+ dictWord{132, 0, 431},
+ dictWord{133, 10, 155},
+ dictWord{11, 0, 283},
+ dictWord{11, 0, 567},
+ dictWord{7, 10, 163},
+ dictWord{8, 10, 319},
+ dictWord{
+ 9,
+ 10,
+ 402,
+ },
+ dictWord{10, 10, 24},
+ dictWord{10, 10, 681},
+ dictWord{11, 10, 200},
+ dictWord{12, 10, 253},
+ dictWord{12, 10, 410},
+ dictWord{142, 10, 219},
+ dictWord{4, 11, 413},
+ dictWord{5, 11, 677},
+ dictWord{8, 11, 432},
+ dictWord{140, 11, 280},
+ dictWord{9, 0, 401},
+ dictWord{5, 10, 475},
+ dictWord{7, 10, 1780},
+ dictWord{11, 10, 297},
+ dictWord{11, 10, 558},
+ dictWord{14, 10, 322},
+ dictWord{147, 10, 76},
+ dictWord{6, 0, 781},
+ dictWord{9, 0, 134},
+ dictWord{10, 0, 2},
+ dictWord{
+ 10,
+ 0,
+ 27,
+ },
+ dictWord{10, 0, 333},
+ dictWord{11, 0, 722},
+ dictWord{143, 0, 1},
+ dictWord{5, 0, 33},
+ dictWord{6, 0, 470},
+ dictWord{139, 0, 424},
+ dictWord{
+ 135,
+ 0,
+ 2006,
+ },
+ dictWord{12, 0, 783},
+ dictWord{135, 10, 1956},
+ dictWord{136, 0, 274},
+ dictWord{135, 0, 1882},
+ dictWord{132, 0, 794},
+ dictWord{135, 0, 1848},
+ dictWord{5, 10, 944},
+ dictWord{134, 10, 1769},
+ dictWord{6, 0, 47},
+ dictWord{7, 0, 90},
+ dictWord{7, 0, 664},
+ dictWord{7, 0, 830},
+ dictWord{7, 0, 1380},
+ dictWord{
+ 7,
+ 0,
+ 2025,
+ },
+ dictWord{8, 0, 448},
+ dictWord{136, 0, 828},
+ dictWord{132, 10, 144},
+ dictWord{134, 0, 1199},
+ dictWord{4, 11, 395},
+ dictWord{139, 11, 762},
+ dictWord{135, 11, 1504},
+ dictWord{9, 0, 417},
+ dictWord{137, 0, 493},
+ dictWord{9, 11, 174},
+ dictWord{10, 11, 164},
+ dictWord{11, 11, 440},
+ dictWord{11, 11, 841},
+ dictWord{143, 11, 98},
+ dictWord{134, 11, 426},
+ dictWord{139, 11, 1002},
+ dictWord{134, 0, 295},
+ dictWord{134, 0, 816},
+ dictWord{6, 10, 247},
+ dictWord{
+ 137,
+ 10,
+ 555,
+ },
+ dictWord{133, 0, 1019},
+ dictWord{4, 0, 620},
+ dictWord{5, 11, 476},
+ dictWord{10, 10, 280},
+ dictWord{138, 10, 797},
+ dictWord{139, 0, 464},
+ dictWord{5, 11, 76},
+ dictWord{6, 11, 458},
+ dictWord{6, 11, 497},
+ dictWord{7, 11, 764},
+ dictWord{7, 11, 868},
+ dictWord{9, 11, 658},
+ dictWord{10, 11, 594},
+ dictWord{
+ 11,
+ 11,
+ 173,
+ },
+ dictWord{11, 11, 566},
+ dictWord{12, 11, 20},
+ dictWord{12, 11, 338},
+ dictWord{141, 11, 200},
+ dictWord{134, 0, 208},
+ dictWord{4, 11, 526},
+ dictWord{7, 11, 1029},
+ dictWord{135, 11, 1054},
+ dictWord{132, 11, 636},
+ dictWord{6, 11, 233},
+ dictWord{7, 11, 660},
+ dictWord{7, 11, 1124},
+ dictWord{
+ 17,
+ 11,
+ 31,
+ },
+ dictWord{19, 11, 22},
+ dictWord{151, 11, 14},
+ dictWord{10, 0, 442},
+ dictWord{133, 10, 428},
+ dictWord{10, 0, 930},
+ dictWord{140, 0, 778},
+ dictWord{
+ 6,
+ 0,
+ 68,
+ },
+ dictWord{7, 0, 448},
+ dictWord{7, 0, 1629},
+ dictWord{7, 0, 1769},
+ dictWord{7, 0, 1813},
+ dictWord{8, 0, 442},
+ dictWord{8, 0, 516},
+ dictWord{9, 0, 710},
+ dictWord{
+ 10,
+ 0,
+ 282,
+ },
+ dictWord{10, 0, 722},
+ dictWord{7, 10, 1717},
+ dictWord{138, 10, 546},
+ dictWord{134, 0, 1128},
+ dictWord{11, 0, 844},
+ dictWord{12, 0, 104},
+ dictWord{140, 0, 625},
+ dictWord{4, 11, 432},
+ dictWord{135, 11, 824},
+ dictWord{138, 10, 189},
+ dictWord{133, 0, 787},
+ dictWord{133, 10, 99},
+ dictWord{
+ 4,
+ 11,
+ 279,
+ },
+ dictWord{7, 11, 301},
+ dictWord{137, 11, 362},
+ dictWord{8, 0, 491},
+ dictWord{4, 10, 397},
+ dictWord{136, 10, 555},
+ dictWord{4, 11, 178},
+ dictWord{
+ 133,
+ 11,
+ 399,
+ },
+ dictWord{134, 0, 711},
+ dictWord{144, 0, 9},
+ dictWord{4, 0, 403},
+ dictWord{5, 0, 441},
+ dictWord{7, 0, 450},
+ dictWord{10, 0, 840},
+ dictWord{11, 0, 101},
+ dictWord{12, 0, 193},
+ dictWord{141, 0, 430},
+ dictWord{135, 11, 1246},
+ dictWord{12, 10, 398},
+ dictWord{20, 10, 39},
+ dictWord{21, 10, 11},
+ dictWord{
+ 150,
+ 10,
+ 41,
+ },
+ dictWord{4, 10, 485},
+ dictWord{7, 10, 353},
+ dictWord{135, 10, 1523},
+ dictWord{6, 10, 366},
+ dictWord{7, 10, 1384},
+ dictWord{7, 10, 1601},
+ dictWord{
+ 135,
+ 11,
+ 1912,
+ },
+ dictWord{7, 0, 396},
+ dictWord{10, 0, 160},
+ dictWord{135, 11, 396},
+ dictWord{137, 10, 282},
+ dictWord{134, 11, 1692},
+ dictWord{4, 10, 157},
+ dictWord{5, 10, 471},
+ dictWord{6, 11, 202},
+ dictWord{10, 11, 448},
+ dictWord{11, 11, 208},
+ dictWord{12, 11, 360},
+ dictWord{17, 11, 117},
+ dictWord{
+ 17,
+ 11,
+ 118,
+ },
+ dictWord{18, 11, 27},
+ dictWord{148, 11, 67},
+ dictWord{133, 0, 679},
+ dictWord{137, 0, 326},
+ dictWord{136, 10, 116},
+ dictWord{7, 11, 872},
+ dictWord{
+ 10,
+ 11,
+ 516,
+ },
+ dictWord{139, 11, 167},
+ dictWord{132, 11, 224},
+ dictWord{5, 11, 546},
+ dictWord{7, 11, 35},
+ dictWord{8, 11, 11},
+ dictWord{8, 11, 12},
+ dictWord{
+ 9,
+ 11,
+ 315,
+ },
+ dictWord{9, 11, 533},
+ dictWord{10, 11, 802},
+ dictWord{11, 11, 166},
+ dictWord{12, 11, 525},
+ dictWord{142, 11, 243},
+ dictWord{7, 0, 1128},
+ dictWord{135, 11, 1920},
+ dictWord{5, 11, 241},
+ dictWord{8, 11, 242},
+ dictWord{9, 11, 451},
+ dictWord{10, 11, 667},
+ dictWord{11, 11, 598},
+ dictWord{
+ 140,
+ 11,
+ 429,
+ },
+ dictWord{6, 0, 737},
+ dictWord{5, 10, 160},
+ dictWord{7, 10, 363},
+ dictWord{7, 10, 589},
+ dictWord{10, 10, 170},
+ dictWord{141, 10, 55},
+ dictWord{
+ 135,
+ 0,
+ 1796,
+ },
+ dictWord{142, 11, 254},
+ dictWord{4, 0, 574},
+ dictWord{7, 0, 350},
+ dictWord{7, 0, 1024},
+ dictWord{8, 0, 338},
+ dictWord{9, 0, 677},
+ dictWord{138, 0, 808},
+ dictWord{134, 0, 1096},
+ dictWord{137, 11, 516},
+ dictWord{7, 0, 405},
+ dictWord{10, 0, 491},
+ dictWord{4, 10, 108},
+ dictWord{4, 11, 366},
+ dictWord{
+ 139,
+ 10,
+ 498,
+ },
+ dictWord{11, 11, 337},
+ dictWord{142, 11, 303},
+ dictWord{134, 11, 1736},
+ dictWord{7, 0, 1081},
+ dictWord{140, 11, 364},
+ dictWord{7, 10, 1005},
+ dictWord{140, 10, 609},
+ dictWord{7, 0, 1676},
+ dictWord{4, 10, 895},
+ dictWord{133, 10, 772},
+ dictWord{135, 0, 2037},
+ dictWord{6, 0, 1207},
+ dictWord{
+ 11,
+ 11,
+ 916,
+ },
+ dictWord{142, 11, 419},
+ dictWord{14, 11, 140},
+ dictWord{148, 11, 41},
+ dictWord{6, 11, 331},
+ dictWord{136, 11, 623},
+ dictWord{9, 0, 944},
+ dictWord{
+ 9,
+ 0,
+ 969,
+ },
+ dictWord{9, 0, 1022},
+ dictWord{12, 0, 913},
+ dictWord{12, 0, 936},
+ dictWord{15, 0, 177},
+ dictWord{15, 0, 193},
+ dictWord{4, 10, 926},
+ dictWord{
+ 133,
+ 10,
+ 983,
+ },
+ dictWord{5, 0, 354},
+ dictWord{135, 11, 506},
+ dictWord{8, 0, 598},
+ dictWord{9, 0, 664},
+ dictWord{138, 0, 441},
+ dictWord{4, 11, 640},
+ dictWord{
+ 133,
+ 11,
+ 513,
+ },
+ dictWord{137, 0, 297},
+ dictWord{132, 10, 538},
+ dictWord{6, 10, 294},
+ dictWord{7, 10, 1267},
+ dictWord{136, 10, 624},
+ dictWord{7, 0, 1772},
+ dictWord{
+ 7,
+ 11,
+ 1888,
+ },
+ dictWord{8, 11, 289},
+ dictWord{11, 11, 45},
+ dictWord{12, 11, 278},
+ dictWord{140, 11, 537},
+ dictWord{135, 10, 1325},
+ dictWord{138, 0, 751},
+ dictWord{141, 0, 37},
+ dictWord{134, 0, 1828},
+ dictWord{132, 10, 757},
+ dictWord{132, 11, 394},
+ dictWord{6, 0, 257},
+ dictWord{135, 0, 1522},
+ dictWord{
+ 4,
+ 0,
+ 582,
+ },
+ dictWord{9, 0, 191},
+ dictWord{135, 11, 1931},
+ dictWord{7, 11, 574},
+ dictWord{7, 11, 1719},
+ dictWord{137, 11, 145},
+ dictWord{132, 11, 658},
+ dictWord{10, 0, 790},
+ dictWord{132, 11, 369},
+ dictWord{9, 11, 781},
+ dictWord{10, 11, 144},
+ dictWord{11, 11, 385},
+ dictWord{13, 11, 161},
+ dictWord{13, 11, 228},
+ dictWord{13, 11, 268},
+ dictWord{148, 11, 107},
+ dictWord{8, 0, 469},
+ dictWord{10, 0, 47},
+ dictWord{136, 11, 374},
+ dictWord{6, 0, 306},
+ dictWord{7, 0, 1140},
+ dictWord{7, 0, 1340},
+ dictWord{8, 0, 133},
+ dictWord{138, 0, 449},
+ dictWord{139, 0, 1011},
+ dictWord{7, 10, 1875},
+ dictWord{139, 10, 124},
+ dictWord{
+ 4,
+ 11,
+ 344,
+ },
+ dictWord{6, 11, 498},
+ dictWord{139, 11, 323},
+ dictWord{137, 0, 299},
+ dictWord{132, 0, 837},
+ dictWord{133, 11, 906},
+ dictWord{5, 0, 329},
+ dictWord{
+ 8,
+ 0,
+ 260,
+ },
+ dictWord{138, 0, 10},
+ dictWord{134, 0, 1320},
+ dictWord{4, 0, 657},
+ dictWord{146, 0, 158},
+ dictWord{135, 0, 1191},
+ dictWord{152, 0, 7},
+ dictWord{
+ 6,
+ 0,
+ 1939,
+ },
+ dictWord{8, 0, 974},
+ dictWord{138, 0, 996},
+ dictWord{135, 0, 1665},
+ dictWord{11, 11, 126},
+ dictWord{139, 11, 287},
+ dictWord{143, 0, 8},
+ dictWord{
+ 14,
+ 11,
+ 149,
+ },
+ dictWord{14, 11, 399},
+ dictWord{143, 11, 57},
+ dictWord{5, 0, 66},
+ dictWord{7, 0, 1896},
+ dictWord{136, 0, 288},
+ dictWord{7, 0, 175},
+ dictWord{
+ 10,
+ 0,
+ 494,
+ },
+ dictWord{5, 10, 150},
+ dictWord{8, 10, 603},
+ dictWord{9, 10, 593},
+ dictWord{9, 10, 634},
+ dictWord{10, 10, 173},
+ dictWord{11, 10, 462},
+ dictWord{
+ 11,
+ 10,
+ 515,
+ },
+ dictWord{13, 10, 216},
+ dictWord{13, 10, 288},
+ dictWord{142, 10, 400},
+ dictWord{134, 0, 1643},
+ dictWord{136, 11, 21},
+ dictWord{4, 0, 21},
+ dictWord{
+ 5,
+ 0,
+ 91,
+ },
+ dictWord{5, 0, 648},
+ dictWord{5, 0, 750},
+ dictWord{5, 0, 781},
+ dictWord{6, 0, 54},
+ dictWord{6, 0, 112},
+ dictWord{6, 0, 402},
+ dictWord{6, 0, 1732},
+ dictWord{
+ 7,
+ 0,
+ 315,
+ },
+ dictWord{7, 0, 749},
+ dictWord{7, 0, 1427},
+ dictWord{7, 0, 1900},
+ dictWord{9, 0, 78},
+ dictWord{9, 0, 508},
+ dictWord{10, 0, 611},
+ dictWord{10, 0, 811},
+ dictWord{11, 0, 510},
+ dictWord{11, 0, 728},
+ dictWord{13, 0, 36},
+ dictWord{14, 0, 39},
+ dictWord{16, 0, 83},
+ dictWord{17, 0, 124},
+ dictWord{148, 0, 30},
+ dictWord{
+ 4,
+ 0,
+ 668,
+ },
+ dictWord{136, 0, 570},
+ dictWord{10, 0, 322},
+ dictWord{10, 0, 719},
+ dictWord{139, 0, 407},
+ dictWord{135, 11, 1381},
+ dictWord{136, 11, 193},
+ dictWord{12, 10, 108},
+ dictWord{141, 10, 291},
+ dictWord{132, 11, 616},
+ dictWord{136, 11, 692},
+ dictWord{8, 0, 125},
+ dictWord{8, 0, 369},
+ dictWord{8, 0, 524},
+ dictWord{10, 0, 486},
+ dictWord{11, 0, 13},
+ dictWord{11, 0, 381},
+ dictWord{11, 0, 736},
+ dictWord{11, 0, 766},
+ dictWord{11, 0, 845},
+ dictWord{13, 0, 114},
+ dictWord{
+ 13,
+ 0,
+ 292,
+ },
+ dictWord{142, 0, 47},
+ dictWord{134, 0, 1247},
+ dictWord{6, 0, 1684},
+ dictWord{6, 0, 1731},
+ dictWord{7, 0, 356},
+ dictWord{8, 0, 54},
+ dictWord{8, 0, 221},
+ dictWord{9, 0, 225},
+ dictWord{9, 0, 356},
+ dictWord{10, 0, 77},
+ dictWord{10, 0, 446},
+ dictWord{10, 0, 731},
+ dictWord{12, 0, 404},
+ dictWord{141, 0, 491},
+ dictWord{135, 10, 1777},
+ dictWord{4, 11, 305},
+ dictWord{4, 10, 493},
+ dictWord{144, 10, 55},
+ dictWord{4, 0, 951},
+ dictWord{6, 0, 1809},
+ dictWord{6, 0, 1849},
+ dictWord{8, 0, 846},
+ dictWord{8, 0, 866},
+ dictWord{8, 0, 899},
+ dictWord{10, 0, 896},
+ dictWord{12, 0, 694},
+ dictWord{142, 0, 468},
+ dictWord{5, 11, 214},
+ dictWord{
+ 7,
+ 11,
+ 603,
+ },
+ dictWord{8, 11, 611},
+ dictWord{9, 11, 686},
+ dictWord{10, 11, 88},
+ dictWord{11, 11, 459},
+ dictWord{11, 11, 496},
+ dictWord{12, 11, 463},
+ dictWord{
+ 12,
+ 11,
+ 590,
+ },
+ dictWord{13, 11, 0},
+ dictWord{142, 11, 214},
+ dictWord{132, 0, 411},
+ dictWord{4, 0, 80},
+ dictWord{133, 0, 44},
+ dictWord{140, 11, 74},
+ dictWord{
+ 143,
+ 0,
+ 31,
+ },
+ dictWord{7, 0, 669},
+ dictWord{6, 10, 568},
+ dictWord{7, 10, 1804},
+ dictWord{8, 10, 362},
+ dictWord{8, 10, 410},
+ dictWord{8, 10, 830},
+ dictWord{9, 10, 514},
+ dictWord{11, 10, 649},
+ dictWord{142, 10, 157},
+ dictWord{7, 0, 673},
+ dictWord{134, 11, 1703},
+ dictWord{132, 10, 625},
+ dictWord{134, 0, 1303},
+ dictWord{
+ 5,
+ 0,
+ 299,
+ },
+ dictWord{135, 0, 1083},
+ dictWord{138, 0, 704},
+ dictWord{6, 0, 275},
+ dictWord{7, 0, 408},
+ dictWord{6, 10, 158},
+ dictWord{7, 10, 129},
+ dictWord{
+ 7,
+ 10,
+ 181,
+ },
+ dictWord{8, 10, 276},
+ dictWord{8, 10, 377},
+ dictWord{10, 10, 523},
+ dictWord{11, 10, 816},
+ dictWord{12, 10, 455},
+ dictWord{13, 10, 303},
+ dictWord{
+ 142,
+ 10,
+ 135,
+ },
+ dictWord{4, 0, 219},
+ dictWord{7, 0, 367},
+ dictWord{7, 0, 1713},
+ dictWord{7, 0, 1761},
+ dictWord{9, 0, 86},
+ dictWord{9, 0, 537},
+ dictWord{10, 0, 165},
+ dictWord{12, 0, 219},
+ dictWord{140, 0, 561},
+ dictWord{8, 0, 216},
+ dictWord{4, 10, 1},
+ dictWord{4, 11, 737},
+ dictWord{6, 11, 317},
+ dictWord{7, 10, 1143},
+ dictWord{
+ 7,
+ 10,
+ 1463,
+ },
+ dictWord{9, 10, 207},
+ dictWord{9, 10, 390},
+ dictWord{9, 10, 467},
+ dictWord{10, 11, 98},
+ dictWord{11, 11, 294},
+ dictWord{11, 10, 836},
+ dictWord{
+ 12,
+ 11,
+ 60,
+ },
+ dictWord{12, 11, 437},
+ dictWord{13, 11, 64},
+ dictWord{13, 11, 380},
+ dictWord{142, 11, 430},
+ dictWord{6, 11, 1758},
+ dictWord{8, 11, 520},
+ dictWord{9, 11, 345},
+ dictWord{9, 11, 403},
+ dictWord{142, 11, 350},
+ dictWord{5, 11, 47},
+ dictWord{10, 11, 242},
+ dictWord{138, 11, 579},
+ dictWord{5, 11, 139},
+ dictWord{7, 11, 1168},
+ dictWord{138, 11, 539},
+ dictWord{135, 0, 1319},
+ dictWord{4, 10, 295},
+ dictWord{4, 10, 723},
+ dictWord{5, 10, 895},
+ dictWord{
+ 7,
+ 10,
+ 1031,
+ },
+ dictWord{8, 10, 199},
+ dictWord{8, 10, 340},
+ dictWord{9, 10, 153},
+ dictWord{9, 10, 215},
+ dictWord{10, 10, 21},
+ dictWord{10, 10, 59},
+ dictWord{
+ 10,
+ 10,
+ 80,
+ },
+ dictWord{10, 10, 224},
+ dictWord{10, 10, 838},
+ dictWord{11, 10, 229},
+ dictWord{11, 10, 652},
+ dictWord{12, 10, 192},
+ dictWord{13, 10, 146},
+ dictWord{
+ 142,
+ 10,
+ 91,
+ },
+ dictWord{140, 0, 428},
+ dictWord{137, 10, 51},
+ dictWord{133, 0, 514},
+ dictWord{5, 10, 309},
+ dictWord{140, 10, 211},
+ dictWord{6, 0, 1010},
+ dictWord{5, 10, 125},
+ dictWord{8, 10, 77},
+ dictWord{138, 10, 15},
+ dictWord{4, 0, 55},
+ dictWord{5, 0, 301},
+ dictWord{6, 0, 571},
+ dictWord{142, 0, 49},
+ dictWord{
+ 146,
+ 0,
+ 102,
+ },
+ dictWord{136, 11, 370},
+ dictWord{4, 11, 107},
+ dictWord{7, 11, 613},
+ dictWord{8, 11, 358},
+ dictWord{8, 11, 439},
+ dictWord{8, 11, 504},
+ dictWord{
+ 9,
+ 11,
+ 501,
+ },
+ dictWord{10, 11, 383},
+ dictWord{139, 11, 477},
+ dictWord{132, 11, 229},
+ dictWord{133, 0, 364},
+ dictWord{133, 10, 439},
+ dictWord{4, 11, 903},
+ dictWord{135, 11, 1816},
+ dictWord{11, 0, 379},
+ dictWord{140, 10, 76},
+ dictWord{4, 0, 76},
+ dictWord{4, 0, 971},
+ dictWord{7, 0, 1550},
+ dictWord{9, 0, 306},
+ dictWord{
+ 9,
+ 0,
+ 430,
+ },
+ dictWord{9, 0, 663},
+ dictWord{10, 0, 683},
+ dictWord{10, 0, 921},
+ dictWord{11, 0, 427},
+ dictWord{11, 0, 753},
+ dictWord{12, 0, 334},
+ dictWord{12, 0, 442},
+ dictWord{14, 0, 258},
+ dictWord{14, 0, 366},
+ dictWord{143, 0, 131},
+ dictWord{137, 0, 52},
+ dictWord{4, 11, 47},
+ dictWord{6, 11, 373},
+ dictWord{7, 11, 452},
+ dictWord{7, 11, 543},
+ dictWord{7, 11, 1714},
+ dictWord{7, 11, 1856},
+ dictWord{9, 11, 6},
+ dictWord{11, 11, 257},
+ dictWord{139, 11, 391},
+ dictWord{4, 10, 8},
+ dictWord{
+ 7,
+ 10,
+ 1152,
+ },
+ dictWord{7, 10, 1153},
+ dictWord{7, 10, 1715},
+ dictWord{9, 10, 374},
+ dictWord{10, 10, 478},
+ dictWord{139, 10, 648},
+ dictWord{4, 11, 785},
+ dictWord{133, 11, 368},
+ dictWord{135, 10, 1099},
+ dictWord{135, 11, 860},
+ dictWord{5, 11, 980},
+ dictWord{134, 11, 1754},
+ dictWord{134, 0, 1258},
+ dictWord{
+ 6,
+ 0,
+ 1058,
+ },
+ dictWord{6, 0, 1359},
+ dictWord{7, 11, 536},
+ dictWord{7, 11, 1331},
+ dictWord{136, 11, 143},
+ dictWord{4, 0, 656},
+ dictWord{135, 0, 779},
+ dictWord{136, 10, 87},
+ dictWord{5, 11, 19},
+ dictWord{6, 11, 533},
+ dictWord{146, 11, 126},
+ dictWord{7, 0, 144},
+ dictWord{138, 10, 438},
+ dictWord{5, 11, 395},
+ dictWord{5, 11, 951},
+ dictWord{134, 11, 1776},
+ dictWord{135, 0, 1373},
+ dictWord{7, 0, 554},
+ dictWord{7, 0, 605},
+ dictWord{141, 0, 10},
+ dictWord{4, 10, 69},
+ dictWord{
+ 5,
+ 10,
+ 122,
+ },
+ dictWord{9, 10, 656},
+ dictWord{138, 10, 464},
+ dictWord{5, 10, 849},
+ dictWord{134, 10, 1633},
+ dictWord{5, 0, 838},
+ dictWord{5, 0, 841},
+ dictWord{134, 0, 1649},
+ dictWord{133, 0, 1012},
+ dictWord{139, 10, 499},
+ dictWord{7, 10, 476},
+ dictWord{7, 10, 1592},
+ dictWord{138, 10, 87},
+ dictWord{
+ 6,
+ 0,
+ 251,
+ },
+ dictWord{7, 0, 365},
+ dictWord{7, 0, 1357},
+ dictWord{7, 0, 1497},
+ dictWord{8, 0, 154},
+ dictWord{141, 0, 281},
+ dictWord{132, 11, 441},
+ dictWord{
+ 132,
+ 11,
+ 695,
+ },
+ dictWord{7, 11, 497},
+ dictWord{9, 11, 387},
+ dictWord{147, 11, 81},
+ dictWord{133, 0, 340},
+ dictWord{14, 10, 283},
+ dictWord{142, 11, 283},
+ dictWord{
+ 134,
+ 0,
+ 810,
+ },
+ dictWord{135, 11, 1894},
+ dictWord{139, 0, 495},
+ dictWord{5, 11, 284},
+ dictWord{6, 11, 49},
+ dictWord{6, 11, 350},
+ dictWord{7, 11, 1},
+ dictWord{
+ 7,
+ 11,
+ 377,
+ },
+ dictWord{7, 11, 1693},
+ dictWord{8, 11, 18},
+ dictWord{8, 11, 678},
+ dictWord{9, 11, 161},
+ dictWord{9, 11, 585},
+ dictWord{9, 11, 671},
+ dictWord{
+ 9,
+ 11,
+ 839,
+ },
+ dictWord{11, 11, 912},
+ dictWord{141, 11, 427},
+ dictWord{5, 10, 859},
+ dictWord{7, 10, 1160},
+ dictWord{8, 10, 107},
+ dictWord{9, 10, 291},
+ dictWord{
+ 9,
+ 10,
+ 439,
+ },
+ dictWord{10, 10, 663},
+ dictWord{11, 10, 609},
+ dictWord{140, 10, 197},
+ dictWord{8, 0, 261},
+ dictWord{9, 0, 144},
+ dictWord{9, 0, 466},
+ dictWord{
+ 10,
+ 0,
+ 370,
+ },
+ dictWord{12, 0, 470},
+ dictWord{13, 0, 144},
+ dictWord{142, 0, 348},
+ dictWord{137, 0, 897},
+ dictWord{6, 0, 248},
+ dictWord{9, 0, 546},
+ dictWord{10, 0, 535},
+ dictWord{11, 0, 681},
+ dictWord{141, 0, 135},
+ dictWord{4, 0, 358},
+ dictWord{135, 0, 1496},
+ dictWord{134, 0, 567},
+ dictWord{136, 0, 445},
+ dictWord{
+ 4,
+ 10,
+ 117,
+ },
+ dictWord{6, 10, 372},
+ dictWord{7, 10, 1905},
+ dictWord{142, 10, 323},
+ dictWord{4, 10, 722},
+ dictWord{139, 10, 471},
+ dictWord{6, 0, 697},
+ dictWord{
+ 134,
+ 0,
+ 996,
+ },
+ dictWord{7, 11, 2007},
+ dictWord{9, 11, 101},
+ dictWord{9, 11, 450},
+ dictWord{10, 11, 66},
+ dictWord{10, 11, 842},
+ dictWord{11, 11, 536},
+ dictWord{
+ 140,
+ 11,
+ 587,
+ },
+ dictWord{132, 0, 577},
+ dictWord{134, 0, 1336},
+ dictWord{9, 10, 5},
+ dictWord{12, 10, 216},
+ dictWord{12, 10, 294},
+ dictWord{12, 10, 298},
+ dictWord{12, 10, 400},
+ dictWord{12, 10, 518},
+ dictWord{13, 10, 229},
+ dictWord{143, 10, 139},
+ dictWord{6, 0, 174},
+ dictWord{138, 0, 917},
+ dictWord{
+ 134,
+ 10,
+ 1774,
+ },
+ dictWord{5, 10, 12},
+ dictWord{7, 10, 375},
+ dictWord{9, 10, 88},
+ dictWord{9, 10, 438},
+ dictWord{11, 11, 62},
+ dictWord{139, 10, 270},
+ dictWord{
+ 134,
+ 11,
+ 1766,
+ },
+ dictWord{6, 11, 0},
+ dictWord{7, 11, 84},
+ dictWord{7, 10, 816},
+ dictWord{7, 10, 1241},
+ dictWord{9, 10, 283},
+ dictWord{9, 10, 520},
+ dictWord{10, 10, 213},
+ dictWord{10, 10, 307},
+ dictWord{10, 10, 463},
+ dictWord{10, 10, 671},
+ dictWord{10, 10, 746},
+ dictWord{11, 10, 401},
+ dictWord{11, 10, 794},
+ dictWord{
+ 11,
+ 11,
+ 895,
+ },
+ dictWord{12, 10, 517},
+ dictWord{17, 11, 11},
+ dictWord{18, 10, 107},
+ dictWord{147, 10, 115},
+ dictWord{5, 0, 878},
+ dictWord{133, 0, 972},
+ dictWord{
+ 6,
+ 11,
+ 1665,
+ },
+ dictWord{7, 11, 256},
+ dictWord{7, 11, 1388},
+ dictWord{138, 11, 499},
+ dictWord{4, 10, 258},
+ dictWord{136, 10, 639},
+ dictWord{4, 11, 22},
+ dictWord{5, 11, 10},
+ dictWord{6, 10, 22},
+ dictWord{7, 11, 848},
+ dictWord{7, 10, 903},
+ dictWord{7, 10, 1963},
+ dictWord{8, 11, 97},
+ dictWord{138, 10, 577},
+ dictWord{
+ 5,
+ 10,
+ 681,
+ },
+ dictWord{136, 10, 782},
+ dictWord{133, 11, 481},
+ dictWord{132, 0, 351},
+ dictWord{4, 10, 664},
+ dictWord{5, 10, 804},
+ dictWord{139, 10, 1013},
+ dictWord{6, 11, 134},
+ dictWord{7, 11, 437},
+ dictWord{7, 11, 959},
+ dictWord{9, 11, 37},
+ dictWord{14, 11, 285},
+ dictWord{14, 11, 371},
+ dictWord{144, 11, 60},
+ dictWord{7, 11, 486},
+ dictWord{8, 11, 155},
+ dictWord{11, 11, 93},
+ dictWord{140, 11, 164},
+ dictWord{132, 0, 286},
+ dictWord{7, 0, 438},
+ dictWord{7, 0, 627},
+ dictWord{7, 0, 1516},
+ dictWord{8, 0, 40},
+ dictWord{9, 0, 56},
+ dictWord{9, 0, 294},
+ dictWord{10, 0, 30},
+ dictWord{11, 0, 969},
+ dictWord{11, 0, 995},
+ dictWord{146, 0, 148},
+ dictWord{5, 11, 591},
+ dictWord{135, 11, 337},
+ dictWord{134, 0, 1950},
+ dictWord{133, 10, 32},
+ dictWord{138, 11, 500},
+ dictWord{5, 11, 380},
+ dictWord{
+ 5,
+ 11,
+ 650,
+ },
+ dictWord{136, 11, 310},
+ dictWord{4, 11, 364},
+ dictWord{7, 11, 1156},
+ dictWord{7, 11, 1187},
+ dictWord{137, 11, 409},
+ dictWord{4, 0, 738},
+ dictWord{134, 11, 482},
+ dictWord{4, 11, 781},
+ dictWord{6, 11, 487},
+ dictWord{7, 11, 926},
+ dictWord{8, 11, 263},
+ dictWord{139, 11, 500},
+ dictWord{135, 11, 418},
+ dictWord{6, 0, 2047},
+ dictWord{10, 0, 969},
+ dictWord{4, 10, 289},
+ dictWord{7, 10, 629},
+ dictWord{7, 10, 1698},
+ dictWord{7, 10, 1711},
+ dictWord{
+ 140,
+ 10,
+ 215,
+ },
+ dictWord{6, 10, 450},
+ dictWord{136, 10, 109},
+ dictWord{134, 0, 818},
+ dictWord{136, 10, 705},
+ dictWord{133, 0, 866},
+ dictWord{4, 11, 94},
+ dictWord{
+ 135,
+ 11,
+ 1265,
+ },
+ dictWord{132, 11, 417},
+ dictWord{134, 0, 1467},
+ dictWord{135, 10, 1238},
+ dictWord{4, 0, 972},
+ dictWord{6, 0, 1851},
+ dictWord{
+ 134,
+ 0,
+ 1857,
+ },
+ dictWord{134, 0, 355},
+ dictWord{133, 0, 116},
+ dictWord{132, 0, 457},
+ dictWord{135, 11, 1411},
+ dictWord{4, 11, 408},
+ dictWord{4, 11, 741},
+ dictWord{135, 11, 500},
+ dictWord{134, 10, 26},
+ dictWord{142, 11, 137},
+ dictWord{5, 0, 527},
+ dictWord{6, 0, 189},
+ dictWord{7, 0, 859},
+ dictWord{136, 0, 267},
+ dictWord{11, 0, 104},
+ dictWord{11, 0, 554},
+ dictWord{15, 0, 60},
+ dictWord{143, 0, 125},
+ dictWord{134, 0, 1613},
+ dictWord{4, 10, 414},
+ dictWord{5, 10, 467},
+ dictWord{
+ 9,
+ 10,
+ 654,
+ },
+ dictWord{10, 10, 451},
+ dictWord{12, 10, 59},
+ dictWord{141, 10, 375},
+ dictWord{135, 10, 17},
+ dictWord{134, 0, 116},
+ dictWord{135, 11, 541},
+ dictWord{135, 10, 955},
+ dictWord{6, 11, 73},
+ dictWord{135, 11, 177},
+ dictWord{133, 11, 576},
+ dictWord{134, 0, 886},
+ dictWord{133, 0, 487},
+ dictWord{
+ 4,
+ 0,
+ 86,
+ },
+ dictWord{5, 0, 667},
+ dictWord{5, 0, 753},
+ dictWord{6, 0, 316},
+ dictWord{6, 0, 455},
+ dictWord{135, 0, 946},
+ dictWord{142, 11, 231},
+ dictWord{150, 0, 45},
+ dictWord{134, 0, 863},
+ dictWord{134, 0, 1953},
+ dictWord{6, 10, 280},
+ dictWord{10, 10, 502},
+ dictWord{11, 10, 344},
+ dictWord{140, 10, 38},
+ dictWord{4, 0, 79},
+ dictWord{7, 0, 1773},
+ dictWord{10, 0, 450},
+ dictWord{11, 0, 589},
+ dictWord{13, 0, 332},
+ dictWord{13, 0, 493},
+ dictWord{14, 0, 183},
+ dictWord{14, 0, 334},
+ dictWord{14, 0, 362},
+ dictWord{14, 0, 368},
+ dictWord{14, 0, 376},
+ dictWord{14, 0, 379},
+ dictWord{19, 0, 90},
+ dictWord{19, 0, 103},
+ dictWord{19, 0, 127},
+ dictWord{
+ 148,
+ 0,
+ 90,
+ },
+ dictWord{5, 10, 45},
+ dictWord{7, 10, 1161},
+ dictWord{11, 10, 448},
+ dictWord{11, 10, 880},
+ dictWord{13, 10, 139},
+ dictWord{13, 10, 407},
+ dictWord{
+ 15,
+ 10,
+ 16,
+ },
+ dictWord{17, 10, 95},
+ dictWord{18, 10, 66},
+ dictWord{18, 10, 88},
+ dictWord{18, 10, 123},
+ dictWord{149, 10, 7},
+ dictWord{136, 10, 777},
+ dictWord{
+ 4,
+ 10,
+ 410,
+ },
+ dictWord{135, 10, 521},
+ dictWord{135, 10, 1778},
+ dictWord{135, 11, 538},
+ dictWord{142, 0, 381},
+ dictWord{133, 11, 413},
+ dictWord{
+ 134,
+ 0,
+ 1142,
+ },
+ dictWord{6, 0, 1189},
+ dictWord{136, 11, 495},
+ dictWord{5, 0, 663},
+ dictWord{6, 0, 1962},
+ dictWord{134, 0, 2003},
+ dictWord{7, 11, 54},
+ dictWord{
+ 8,
+ 11,
+ 312,
+ },
+ dictWord{10, 11, 191},
+ dictWord{10, 11, 614},
+ dictWord{140, 11, 567},
+ dictWord{132, 10, 436},
+ dictWord{133, 0, 846},
+ dictWord{10, 0, 528},
+ dictWord{11, 0, 504},
+ dictWord{7, 10, 1587},
+ dictWord{135, 10, 1707},
+ dictWord{5, 0, 378},
+ dictWord{8, 0, 465},
+ dictWord{9, 0, 286},
+ dictWord{10, 0, 185},
+ dictWord{
+ 10,
+ 0,
+ 562,
+ },
+ dictWord{10, 0, 635},
+ dictWord{11, 0, 31},
+ dictWord{11, 0, 393},
+ dictWord{13, 0, 312},
+ dictWord{18, 0, 65},
+ dictWord{18, 0, 96},
+ dictWord{147, 0, 89},
+ dictWord{7, 0, 899},
+ dictWord{14, 0, 325},
+ dictWord{6, 11, 468},
+ dictWord{7, 11, 567},
+ dictWord{7, 11, 1478},
+ dictWord{8, 11, 530},
+ dictWord{142, 11, 290},
+ dictWord{7, 0, 1880},
+ dictWord{9, 0, 680},
+ dictWord{139, 0, 798},
+ dictWord{134, 0, 1770},
+ dictWord{132, 0, 648},
+ dictWord{150, 11, 35},
+ dictWord{5, 0, 945},
+ dictWord{6, 0, 1656},
+ dictWord{6, 0, 1787},
+ dictWord{7, 0, 167},
+ dictWord{8, 0, 824},
+ dictWord{9, 0, 391},
+ dictWord{10, 0, 375},
+ dictWord{139, 0, 185},
+ dictWord{
+ 6,
+ 11,
+ 484,
+ },
+ dictWord{135, 11, 822},
+ dictWord{134, 0, 2046},
+ dictWord{7, 0, 1645},
+ dictWord{8, 0, 352},
+ dictWord{137, 0, 249},
+ dictWord{132, 0, 152},
+ dictWord{6, 0, 611},
+ dictWord{135, 0, 1733},
+ dictWord{6, 11, 1724},
+ dictWord{135, 11, 2022},
+ dictWord{133, 0, 1006},
+ dictWord{141, 11, 96},
+ dictWord{
+ 5,
+ 0,
+ 420,
+ },
+ dictWord{135, 0, 1449},
+ dictWord{146, 11, 149},
+ dictWord{135, 0, 832},
+ dictWord{135, 10, 663},
+ dictWord{133, 0, 351},
+ dictWord{5, 0, 40},
+ dictWord{
+ 7,
+ 0,
+ 598,
+ },
+ dictWord{7, 0, 1638},
+ dictWord{8, 0, 78},
+ dictWord{9, 0, 166},
+ dictWord{9, 0, 640},
+ dictWord{9, 0, 685},
+ dictWord{9, 0, 773},
+ dictWord{11, 0, 215},
+ dictWord{13, 0, 65},
+ dictWord{14, 0, 172},
+ dictWord{14, 0, 317},
+ dictWord{145, 0, 6},
+ dictWord{8, 0, 60},
+ dictWord{9, 0, 343},
+ dictWord{139, 0, 769},
+ dictWord{
+ 134,
+ 0,
+ 1354,
+ },
+ dictWord{132, 0, 724},
+ dictWord{137, 0, 745},
+ dictWord{132, 11, 474},
+ dictWord{7, 0, 1951},
+ dictWord{8, 0, 765},
+ dictWord{8, 0, 772},
+ dictWord{
+ 140,
+ 0,
+ 671,
+ },
+ dictWord{7, 0, 108},
+ dictWord{8, 0, 219},
+ dictWord{8, 0, 388},
+ dictWord{9, 0, 775},
+ dictWord{11, 0, 275},
+ dictWord{140, 0, 464},
+ dictWord{137, 0, 639},
+ dictWord{135, 10, 503},
+ dictWord{133, 11, 366},
+ dictWord{5, 0, 15},
+ dictWord{6, 0, 56},
+ dictWord{7, 0, 1758},
+ dictWord{8, 0, 500},
+ dictWord{9, 0, 730},
+ dictWord{
+ 11,
+ 0,
+ 331,
+ },
+ dictWord{13, 0, 150},
+ dictWord{14, 0, 282},
+ dictWord{5, 11, 305},
+ dictWord{9, 11, 560},
+ dictWord{141, 11, 208},
+ dictWord{4, 10, 113},
+ dictWord{
+ 5,
+ 10,
+ 163,
+ },
+ dictWord{5, 10, 735},
+ dictWord{7, 10, 1009},
+ dictWord{9, 10, 9},
+ dictWord{9, 10, 771},
+ dictWord{12, 10, 90},
+ dictWord{13, 10, 138},
+ dictWord{
+ 13,
+ 10,
+ 410,
+ },
+ dictWord{143, 10, 128},
+ dictWord{4, 10, 324},
+ dictWord{138, 10, 104},
+ dictWord{135, 11, 466},
+ dictWord{142, 11, 27},
+ dictWord{134, 0, 1886},
+ dictWord{5, 0, 205},
+ dictWord{6, 0, 438},
+ dictWord{9, 0, 711},
+ dictWord{4, 11, 480},
+ dictWord{6, 11, 167},
+ dictWord{6, 11, 302},
+ dictWord{6, 11, 1642},
+ dictWord{
+ 7,
+ 11,
+ 130,
+ },
+ dictWord{7, 11, 656},
+ dictWord{7, 11, 837},
+ dictWord{7, 11, 1547},
+ dictWord{7, 11, 1657},
+ dictWord{8, 11, 429},
+ dictWord{9, 11, 228},
+ dictWord{
+ 10,
+ 11,
+ 643,
+ },
+ dictWord{13, 11, 289},
+ dictWord{13, 11, 343},
+ dictWord{147, 11, 101},
+ dictWord{134, 0, 865},
+ dictWord{6, 0, 2025},
+ dictWord{136, 0, 965},
+ dictWord{
+ 7,
+ 11,
+ 278,
+ },
+ dictWord{10, 11, 739},
+ dictWord{11, 11, 708},
+ dictWord{141, 11, 348},
+ dictWord{133, 0, 534},
+ dictWord{135, 11, 1922},
+ dictWord{
+ 137,
+ 0,
+ 691,
+ },
+ dictWord{4, 10, 935},
+ dictWord{133, 10, 823},
+ dictWord{6, 0, 443},
+ dictWord{9, 0, 237},
+ dictWord{9, 0, 571},
+ dictWord{9, 0, 695},
+ dictWord{10, 0, 139},
+ dictWord{11, 0, 715},
+ dictWord{12, 0, 417},
+ dictWord{141, 0, 421},
+ dictWord{5, 10, 269},
+ dictWord{7, 10, 434},
+ dictWord{7, 10, 891},
+ dictWord{8, 10, 339},
+ dictWord{
+ 9,
+ 10,
+ 702,
+ },
+ dictWord{11, 10, 594},
+ dictWord{11, 10, 718},
+ dictWord{145, 10, 100},
+ dictWord{6, 0, 1555},
+ dictWord{7, 0, 878},
+ dictWord{9, 10, 485},
+ dictWord{141, 10, 264},
+ dictWord{134, 10, 1713},
+ dictWord{7, 10, 1810},
+ dictWord{11, 10, 866},
+ dictWord{12, 10, 103},
+ dictWord{141, 10, 495},
+ dictWord{
+ 135,
+ 10,
+ 900,
+ },
+ dictWord{6, 0, 1410},
+ dictWord{9, 11, 316},
+ dictWord{139, 11, 256},
+ dictWord{4, 0, 995},
+ dictWord{135, 0, 1033},
+ dictWord{132, 0, 578},
+ dictWord{10, 0, 881},
+ dictWord{12, 0, 740},
+ dictWord{12, 0, 743},
+ dictWord{140, 0, 759},
+ dictWord{132, 0, 822},
+ dictWord{133, 0, 923},
+ dictWord{142, 10, 143},
+ dictWord{135, 11, 1696},
+ dictWord{6, 11, 363},
+ dictWord{7, 11, 1955},
+ dictWord{136, 11, 725},
+ dictWord{132, 0, 924},
+ dictWord{133, 0, 665},
+ dictWord{
+ 135,
+ 10,
+ 2029,
+ },
+ dictWord{135, 0, 1901},
+ dictWord{4, 0, 265},
+ dictWord{6, 0, 1092},
+ dictWord{6, 0, 1417},
+ dictWord{7, 0, 807},
+ dictWord{135, 0, 950},
+ dictWord{
+ 5,
+ 0,
+ 93,
+ },
+ dictWord{12, 0, 267},
+ dictWord{141, 0, 498},
+ dictWord{135, 0, 1451},
+ dictWord{5, 11, 813},
+ dictWord{135, 11, 2046},
+ dictWord{5, 10, 625},
+ dictWord{135, 10, 1617},
+ dictWord{135, 0, 747},
+ dictWord{6, 0, 788},
+ dictWord{137, 0, 828},
+ dictWord{7, 0, 184},
+ dictWord{11, 0, 307},
+ dictWord{11, 0, 400},
+ dictWord{15, 0, 130},
+ dictWord{5, 11, 712},
+ dictWord{7, 11, 1855},
+ dictWord{8, 10, 425},
+ dictWord{8, 10, 693},
+ dictWord{9, 10, 720},
+ dictWord{10, 10, 380},
+ dictWord{10, 10, 638},
+ dictWord{11, 11, 17},
+ dictWord{11, 10, 473},
+ dictWord{12, 10, 61},
+ dictWord{13, 11, 321},
+ dictWord{144, 11, 67},
+ dictWord{135, 0, 198},
+ dictWord{6, 11, 320},
+ dictWord{7, 11, 781},
+ dictWord{7, 11, 1921},
+ dictWord{9, 11, 55},
+ dictWord{10, 11, 186},
+ dictWord{10, 11, 273},
+ dictWord{10, 11, 664},
+ dictWord{10, 11, 801},
+ dictWord{11, 11, 996},
+ dictWord{11, 11, 997},
+ dictWord{13, 11, 157},
+ dictWord{142, 11, 170},
+ dictWord{136, 11, 271},
+ dictWord{
+ 135,
+ 0,
+ 994,
+ },
+ dictWord{7, 11, 103},
+ dictWord{7, 11, 863},
+ dictWord{11, 11, 184},
+ dictWord{14, 11, 299},
+ dictWord{145, 11, 62},
+ dictWord{11, 10, 551},
+ dictWord{142, 10, 159},
+ dictWord{5, 0, 233},
+ dictWord{5, 0, 320},
+ dictWord{6, 0, 140},
+ dictWord{8, 0, 295},
+ dictWord{8, 0, 615},
+ dictWord{136, 11, 615},
+ dictWord{
+ 133,
+ 0,
+ 978,
+ },
+ dictWord{4, 0, 905},
+ dictWord{6, 0, 1701},
+ dictWord{137, 0, 843},
+ dictWord{132, 10, 168},
+ dictWord{4, 0, 974},
+ dictWord{8, 0, 850},
+ dictWord{
+ 12,
+ 0,
+ 709,
+ },
+ dictWord{12, 0, 768},
+ dictWord{140, 0, 786},
+ dictWord{135, 10, 91},
+ dictWord{152, 0, 6},
+ dictWord{138, 10, 532},
+ dictWord{135, 10, 1884},
+ dictWord{132, 0, 509},
+ dictWord{6, 0, 1307},
+ dictWord{135, 0, 273},
+ dictWord{5, 11, 77},
+ dictWord{7, 11, 1455},
+ dictWord{10, 11, 843},
+ dictWord{19, 11, 73},
+ dictWord{150, 11, 5},
+ dictWord{132, 11, 458},
+ dictWord{135, 11, 1420},
+ dictWord{6, 11, 109},
+ dictWord{138, 11, 382},
+ dictWord{6, 0, 201},
+ dictWord{6, 11, 330},
+ dictWord{7, 10, 70},
+ dictWord{7, 11, 1084},
+ dictWord{10, 10, 240},
+ dictWord{11, 11, 142},
+ dictWord{147, 10, 93},
+ dictWord{7, 0, 1041},
+ dictWord{
+ 140,
+ 11,
+ 328,
+ },
+ dictWord{133, 11, 354},
+ dictWord{134, 0, 1040},
+ dictWord{133, 0, 693},
+ dictWord{134, 0, 774},
+ dictWord{139, 0, 234},
+ dictWord{132, 0, 336},
+ dictWord{7, 0, 1399},
+ dictWord{139, 10, 392},
+ dictWord{20, 0, 22},
+ dictWord{148, 11, 22},
+ dictWord{5, 0, 802},
+ dictWord{7, 0, 2021},
+ dictWord{136, 0, 805},
+ dictWord{
+ 5,
+ 0,
+ 167,
+ },
+ dictWord{5, 0, 899},
+ dictWord{6, 0, 410},
+ dictWord{137, 0, 777},
+ dictWord{137, 0, 789},
+ dictWord{134, 0, 1705},
+ dictWord{7, 10, 655},
+ dictWord{
+ 135,
+ 10,
+ 1844,
+ },
+ dictWord{4, 10, 145},
+ dictWord{6, 10, 176},
+ dictWord{7, 10, 395},
+ dictWord{137, 10, 562},
+ dictWord{132, 10, 501},
+ dictWord{135, 0, 10},
+ dictWord{5, 0, 11},
+ dictWord{6, 0, 117},
+ dictWord{6, 0, 485},
+ dictWord{7, 0, 1133},
+ dictWord{9, 0, 582},
+ dictWord{9, 0, 594},
+ dictWord{10, 0, 82},
+ dictWord{11, 0, 21},
+ dictWord{11, 0, 818},
+ dictWord{12, 0, 535},
+ dictWord{13, 0, 86},
+ dictWord{20, 0, 91},
+ dictWord{23, 0, 13},
+ dictWord{134, 10, 509},
+ dictWord{4, 0, 264},
+ dictWord{
+ 7,
+ 0,
+ 1067,
+ },
+ dictWord{8, 0, 204},
+ dictWord{8, 0, 385},
+ dictWord{139, 0, 953},
+ dictWord{139, 11, 737},
+ dictWord{138, 0, 56},
+ dictWord{134, 0, 1917},
+ dictWord{
+ 133,
+ 0,
+ 470,
+ },
+ dictWord{10, 11, 657},
+ dictWord{14, 11, 297},
+ dictWord{142, 11, 361},
+ dictWord{135, 11, 412},
+ dictWord{7, 0, 1198},
+ dictWord{7, 11, 1198},
+ dictWord{8, 11, 556},
+ dictWord{14, 11, 123},
+ dictWord{14, 11, 192},
+ dictWord{143, 11, 27},
+ dictWord{7, 11, 1985},
+ dictWord{14, 11, 146},
+ dictWord{15, 11, 42},
+ dictWord{16, 11, 23},
+ dictWord{17, 11, 86},
+ dictWord{146, 11, 17},
+ dictWord{11, 0, 1015},
+ dictWord{136, 11, 122},
+ dictWord{4, 10, 114},
+ dictWord{
+ 9,
+ 10,
+ 492,
+ },
+ dictWord{13, 10, 462},
+ dictWord{142, 10, 215},
+ dictWord{4, 10, 77},
+ dictWord{5, 10, 361},
+ dictWord{6, 10, 139},
+ dictWord{6, 10, 401},
+ dictWord{
+ 6,
+ 10,
+ 404,
+ },
+ dictWord{7, 10, 413},
+ dictWord{7, 10, 715},
+ dictWord{7, 10, 1716},
+ dictWord{11, 10, 279},
+ dictWord{12, 10, 179},
+ dictWord{12, 10, 258},
+ dictWord{
+ 13,
+ 10,
+ 244,
+ },
+ dictWord{142, 10, 358},
+ dictWord{134, 10, 1717},
+ dictWord{7, 10, 1061},
+ dictWord{8, 10, 82},
+ dictWord{11, 10, 250},
+ dictWord{12, 10, 420},
+ dictWord{141, 10, 184},
+ dictWord{133, 0, 715},
+ dictWord{135, 10, 724},
+ dictWord{9, 0, 919},
+ dictWord{9, 0, 922},
+ dictWord{9, 0, 927},
+ dictWord{9, 0, 933},
+ dictWord{9, 0, 962},
+ dictWord{9, 0, 1000},
+ dictWord{9, 0, 1002},
+ dictWord{9, 0, 1021},
+ dictWord{12, 0, 890},
+ dictWord{12, 0, 907},
+ dictWord{12, 0, 930},
+ dictWord{
+ 15,
+ 0,
+ 207,
+ },
+ dictWord{15, 0, 228},
+ dictWord{15, 0, 238},
+ dictWord{149, 0, 61},
+ dictWord{8, 0, 794},
+ dictWord{9, 0, 400},
+ dictWord{10, 0, 298},
+ dictWord{142, 0, 228},
+ dictWord{5, 11, 430},
+ dictWord{5, 11, 932},
+ dictWord{6, 11, 131},
+ dictWord{7, 11, 417},
+ dictWord{9, 11, 522},
+ dictWord{11, 11, 314},
+ dictWord{141, 11, 390},
+ dictWord{132, 0, 867},
+ dictWord{8, 0, 724},
+ dictWord{132, 11, 507},
+ dictWord{137, 11, 261},
+ dictWord{4, 11, 343},
+ dictWord{133, 11, 511},
+ dictWord{
+ 6,
+ 0,
+ 190,
+ },
+ dictWord{7, 0, 768},
+ dictWord{135, 0, 1170},
+ dictWord{6, 10, 513},
+ dictWord{135, 10, 1052},
+ dictWord{7, 11, 455},
+ dictWord{138, 11, 591},
+ dictWord{134, 0, 1066},
+ dictWord{137, 10, 899},
+ dictWord{14, 0, 67},
+ dictWord{147, 0, 60},
+ dictWord{4, 0, 948},
+ dictWord{18, 0, 174},
+ dictWord{146, 0, 176},
+ dictWord{135, 0, 1023},
+ dictWord{7, 10, 1417},
+ dictWord{12, 10, 382},
+ dictWord{17, 10, 48},
+ dictWord{152, 10, 12},
+ dictWord{134, 11, 575},
+ dictWord{
+ 132,
+ 0,
+ 764,
+ },
+ dictWord{6, 10, 545},
+ dictWord{7, 10, 565},
+ dictWord{7, 10, 1669},
+ dictWord{10, 10, 114},
+ dictWord{11, 10, 642},
+ dictWord{140, 10, 618},
+ dictWord{
+ 6,
+ 0,
+ 137,
+ },
+ dictWord{9, 0, 75},
+ dictWord{9, 0, 253},
+ dictWord{10, 0, 194},
+ dictWord{138, 0, 444},
+ dictWord{4, 0, 756},
+ dictWord{133, 10, 5},
+ dictWord{8, 0, 1008},
+ dictWord{135, 10, 192},
+ dictWord{132, 0, 842},
+ dictWord{11, 0, 643},
+ dictWord{12, 0, 115},
+ dictWord{136, 10, 763},
+ dictWord{139, 0, 67},
+ dictWord{
+ 133,
+ 10,
+ 759,
+ },
+ dictWord{4, 0, 821},
+ dictWord{5, 0, 760},
+ dictWord{7, 0, 542},
+ dictWord{8, 0, 135},
+ dictWord{8, 0, 496},
+ dictWord{135, 11, 580},
+ dictWord{7, 10, 370},
+ dictWord{7, 10, 1007},
+ dictWord{7, 10, 1177},
+ dictWord{135, 10, 1565},
+ dictWord{135, 10, 1237},
+ dictWord{140, 0, 736},
+ dictWord{7, 0, 319},
+ dictWord{
+ 7,
+ 0,
+ 355,
+ },
+ dictWord{7, 0, 763},
+ dictWord{10, 0, 389},
+ dictWord{145, 0, 43},
+ dictWord{8, 11, 333},
+ dictWord{138, 11, 182},
+ dictWord{4, 10, 87},
+ dictWord{5, 10, 250},
+ dictWord{141, 10, 298},
+ dictWord{138, 0, 786},
+ dictWord{134, 0, 2044},
+ dictWord{8, 11, 330},
+ dictWord{140, 11, 477},
+ dictWord{135, 11, 1338},
+ dictWord{132, 11, 125},
+ dictWord{134, 0, 1030},
+ dictWord{134, 0, 1083},
+ dictWord{132, 11, 721},
+ dictWord{135, 10, 814},
+ dictWord{7, 11, 776},
+ dictWord{
+ 8,
+ 11,
+ 145,
+ },
+ dictWord{147, 11, 56},
+ dictWord{134, 0, 1226},
+ dictWord{4, 10, 57},
+ dictWord{7, 10, 1195},
+ dictWord{7, 10, 1438},
+ dictWord{7, 10, 1548},
+ dictWord{
+ 7,
+ 10,
+ 1835,
+ },
+ dictWord{7, 10, 1904},
+ dictWord{9, 10, 757},
+ dictWord{10, 10, 604},
+ dictWord{139, 10, 519},
+ dictWord{7, 11, 792},
+ dictWord{8, 11, 147},
+ dictWord{10, 11, 821},
+ dictWord{139, 11, 1021},
+ dictWord{137, 11, 797},
+ dictWord{4, 0, 58},
+ dictWord{5, 0, 286},
+ dictWord{6, 0, 319},
+ dictWord{7, 0, 402},
+ dictWord{
+ 7,
+ 0,
+ 1254,
+ },
+ dictWord{7, 0, 1903},
+ dictWord{8, 0, 356},
+ dictWord{140, 0, 408},
+ dictWord{4, 0, 389},
+ dictWord{4, 0, 815},
+ dictWord{9, 0, 181},
+ dictWord{9, 0, 255},
+ dictWord{10, 0, 8},
+ dictWord{10, 0, 29},
+ dictWord{10, 0, 816},
+ dictWord{11, 0, 311},
+ dictWord{11, 0, 561},
+ dictWord{12, 0, 67},
+ dictWord{141, 0, 181},
+ dictWord{
+ 7,
+ 11,
+ 1472,
+ },
+ dictWord{135, 11, 1554},
+ dictWord{7, 11, 1071},
+ dictWord{7, 11, 1541},
+ dictWord{7, 11, 1767},
+ dictWord{7, 11, 1806},
+ dictWord{7, 11, 1999},
+ dictWord{9, 11, 248},
+ dictWord{10, 11, 400},
+ dictWord{11, 11, 162},
+ dictWord{11, 11, 178},
+ dictWord{11, 11, 242},
+ dictWord{12, 11, 605},
+ dictWord{
+ 15,
+ 11,
+ 26,
+ },
+ dictWord{144, 11, 44},
+ dictWord{5, 11, 168},
+ dictWord{5, 11, 930},
+ dictWord{8, 11, 74},
+ dictWord{9, 11, 623},
+ dictWord{12, 11, 500},
+ dictWord{
+ 12,
+ 11,
+ 579,
+ },
+ dictWord{13, 11, 41},
+ dictWord{143, 11, 93},
+ dictWord{6, 11, 220},
+ dictWord{7, 11, 1101},
+ dictWord{141, 11, 105},
+ dictWord{5, 0, 474},
+ dictWord{
+ 7,
+ 0,
+ 507,
+ },
+ dictWord{4, 10, 209},
+ dictWord{7, 11, 507},
+ dictWord{135, 10, 902},
+ dictWord{132, 0, 427},
+ dictWord{6, 0, 413},
+ dictWord{7, 10, 335},
+ dictWord{
+ 7,
+ 10,
+ 1437,
+ },
+ dictWord{7, 10, 1668},
+ dictWord{8, 10, 553},
+ dictWord{8, 10, 652},
+ dictWord{8, 10, 656},
+ dictWord{9, 10, 558},
+ dictWord{11, 10, 743},
+ dictWord{
+ 149,
+ 10,
+ 18,
+ },
+ dictWord{132, 0, 730},
+ dictWord{6, 11, 19},
+ dictWord{7, 11, 1413},
+ dictWord{139, 11, 428},
+ dictWord{133, 0, 373},
+ dictWord{132, 10, 559},
+ dictWord{7, 11, 96},
+ dictWord{8, 11, 401},
+ dictWord{137, 11, 896},
+ dictWord{7, 0, 799},
+ dictWord{7, 0, 1972},
+ dictWord{5, 10, 1017},
+ dictWord{138, 10, 511},
+ dictWord{135, 0, 1793},
+ dictWord{7, 11, 1961},
+ dictWord{7, 11, 1965},
+ dictWord{8, 11, 702},
+ dictWord{136, 11, 750},
+ dictWord{8, 11, 150},
+ dictWord{8, 11, 737},
+ dictWord{140, 11, 366},
+ dictWord{132, 0, 322},
+ dictWord{133, 10, 709},
+ dictWord{8, 11, 800},
+ dictWord{9, 11, 148},
+ dictWord{9, 11, 872},
+ dictWord{
+ 9,
+ 11,
+ 890,
+ },
+ dictWord{11, 11, 309},
+ dictWord{11, 11, 1001},
+ dictWord{13, 11, 267},
+ dictWord{141, 11, 323},
+ dictWord{134, 10, 1745},
+ dictWord{7, 0, 290},
+ dictWord{136, 10, 206},
+ dictWord{7, 0, 1651},
+ dictWord{145, 0, 89},
+ dictWord{139, 0, 2},
+ dictWord{132, 0, 672},
+ dictWord{6, 0, 1860},
+ dictWord{8, 0, 905},
+ dictWord{
+ 10,
+ 0,
+ 844,
+ },
+ dictWord{10, 0, 846},
+ dictWord{10, 0, 858},
+ dictWord{12, 0, 699},
+ dictWord{12, 0, 746},
+ dictWord{140, 0, 772},
+ dictWord{135, 11, 424},
+ dictWord{133, 11, 547},
+ dictWord{133, 0, 737},
+ dictWord{5, 11, 490},
+ dictWord{6, 11, 615},
+ dictWord{6, 11, 620},
+ dictWord{135, 11, 683},
+ dictWord{6, 0, 746},
+ dictWord{134, 0, 1612},
+ dictWord{132, 10, 776},
+ dictWord{9, 11, 385},
+ dictWord{149, 11, 17},
+ dictWord{133, 0, 145},
+ dictWord{135, 10, 1272},
+ dictWord{
+ 7,
+ 0,
+ 884,
+ },
+ dictWord{140, 0, 124},
+ dictWord{4, 0, 387},
+ dictWord{135, 0, 1288},
+ dictWord{5, 11, 133},
+ dictWord{136, 10, 406},
+ dictWord{136, 11, 187},
+ dictWord{
+ 6,
+ 0,
+ 679,
+ },
+ dictWord{8, 11, 8},
+ dictWord{138, 11, 0},
+ dictWord{135, 0, 550},
+ dictWord{135, 11, 798},
+ dictWord{136, 11, 685},
+ dictWord{7, 11, 1086},
+ dictWord{145, 11, 46},
+ dictWord{8, 10, 175},
+ dictWord{10, 10, 168},
+ dictWord{138, 10, 573},
+ dictWord{135, 0, 1305},
+ dictWord{4, 0, 576},
+ dictWord{
+ 135,
+ 0,
+ 1263,
+ },
+ dictWord{6, 0, 686},
+ dictWord{134, 0, 1563},
+ dictWord{134, 0, 607},
+ dictWord{5, 0, 919},
+ dictWord{134, 0, 1673},
+ dictWord{148, 0, 37},
+ dictWord{
+ 8,
+ 11,
+ 774,
+ },
+ dictWord{10, 11, 670},
+ dictWord{140, 11, 51},
+ dictWord{133, 10, 784},
+ dictWord{139, 10, 882},
+ dictWord{4, 0, 82},
+ dictWord{5, 0, 333},
+ dictWord{
+ 5,
+ 0,
+ 904,
+ },
+ dictWord{6, 0, 207},
+ dictWord{7, 0, 325},
+ dictWord{7, 0, 1726},
+ dictWord{8, 0, 101},
+ dictWord{10, 0, 778},
+ dictWord{139, 0, 220},
+ dictWord{135, 11, 371},
+ dictWord{132, 0, 958},
+ dictWord{133, 0, 903},
+ dictWord{4, 11, 127},
+ dictWord{5, 11, 350},
+ dictWord{6, 11, 356},
+ dictWord{8, 11, 426},
+ dictWord{9, 11, 572},
+ dictWord{10, 11, 247},
+ dictWord{139, 11, 312},
+ dictWord{140, 0, 147},
+ dictWord{6, 11, 59},
+ dictWord{7, 11, 885},
+ dictWord{9, 11, 603},
+ dictWord{
+ 141,
+ 11,
+ 397,
+ },
+ dictWord{10, 0, 367},
+ dictWord{9, 10, 14},
+ dictWord{9, 10, 441},
+ dictWord{139, 10, 9},
+ dictWord{11, 10, 966},
+ dictWord{12, 10, 287},
+ dictWord{
+ 13,
+ 10,
+ 342,
+ },
+ dictWord{13, 10, 402},
+ dictWord{15, 10, 110},
+ dictWord{143, 10, 163},
+ dictWord{134, 0, 690},
+ dictWord{132, 0, 705},
+ dictWord{9, 0, 651},
+ dictWord{
+ 11,
+ 0,
+ 971,
+ },
+ dictWord{13, 0, 273},
+ dictWord{7, 10, 1428},
+ dictWord{7, 10, 1640},
+ dictWord{7, 10, 1867},
+ dictWord{9, 10, 169},
+ dictWord{9, 10, 182},
+ dictWord{
+ 9,
+ 10,
+ 367,
+ },
+ dictWord{9, 10, 478},
+ dictWord{9, 10, 506},
+ dictWord{9, 10, 551},
+ dictWord{9, 10, 557},
+ dictWord{9, 10, 648},
+ dictWord{9, 10, 697},
+ dictWord{
+ 9,
+ 10,
+ 705,
+ },
+ dictWord{9, 10, 725},
+ dictWord{9, 10, 787},
+ dictWord{9, 10, 794},
+ dictWord{10, 10, 198},
+ dictWord{10, 10, 214},
+ dictWord{10, 10, 267},
+ dictWord{
+ 10,
+ 10,
+ 275,
+ },
+ dictWord{10, 10, 456},
+ dictWord{10, 10, 551},
+ dictWord{10, 10, 561},
+ dictWord{10, 10, 613},
+ dictWord{10, 10, 627},
+ dictWord{10, 10, 668},
+ dictWord{10, 10, 675},
+ dictWord{10, 10, 691},
+ dictWord{10, 10, 695},
+ dictWord{10, 10, 707},
+ dictWord{10, 10, 715},
+ dictWord{11, 10, 183},
+ dictWord{
+ 11,
+ 10,
+ 201,
+ },
+ dictWord{11, 10, 262},
+ dictWord{11, 10, 352},
+ dictWord{11, 10, 439},
+ dictWord{11, 10, 493},
+ dictWord{11, 10, 572},
+ dictWord{11, 10, 591},
+ dictWord{
+ 11,
+ 10,
+ 608,
+ },
+ dictWord{11, 10, 611},
+ dictWord{11, 10, 646},
+ dictWord{11, 10, 674},
+ dictWord{11, 10, 711},
+ dictWord{11, 10, 751},
+ dictWord{11, 10, 761},
+ dictWord{11, 10, 776},
+ dictWord{11, 10, 785},
+ dictWord{11, 10, 850},
+ dictWord{11, 10, 853},
+ dictWord{11, 10, 862},
+ dictWord{11, 10, 865},
+ dictWord{
+ 11,
+ 10,
+ 868,
+ },
+ dictWord{11, 10, 875},
+ dictWord{11, 10, 898},
+ dictWord{11, 10, 902},
+ dictWord{11, 10, 903},
+ dictWord{11, 10, 910},
+ dictWord{11, 10, 932},
+ dictWord{
+ 11,
+ 10,
+ 942,
+ },
+ dictWord{11, 10, 957},
+ dictWord{11, 10, 967},
+ dictWord{11, 10, 972},
+ dictWord{12, 10, 148},
+ dictWord{12, 10, 195},
+ dictWord{12, 10, 220},
+ dictWord{12, 10, 237},
+ dictWord{12, 10, 318},
+ dictWord{12, 10, 339},
+ dictWord{12, 10, 393},
+ dictWord{12, 10, 445},
+ dictWord{12, 10, 450},
+ dictWord{
+ 12,
+ 10,
+ 474,
+ },
+ dictWord{12, 10, 505},
+ dictWord{12, 10, 509},
+ dictWord{12, 10, 533},
+ dictWord{12, 10, 591},
+ dictWord{12, 10, 594},
+ dictWord{12, 10, 597},
+ dictWord{
+ 12,
+ 10,
+ 621,
+ },
+ dictWord{12, 10, 633},
+ dictWord{12, 10, 642},
+ dictWord{13, 10, 59},
+ dictWord{13, 10, 60},
+ dictWord{13, 10, 145},
+ dictWord{13, 10, 239},
+ dictWord{13, 10, 250},
+ dictWord{13, 10, 329},
+ dictWord{13, 10, 344},
+ dictWord{13, 10, 365},
+ dictWord{13, 10, 372},
+ dictWord{13, 10, 387},
+ dictWord{
+ 13,
+ 10,
+ 403,
+ },
+ dictWord{13, 10, 414},
+ dictWord{13, 10, 456},
+ dictWord{13, 10, 470},
+ dictWord{13, 10, 478},
+ dictWord{13, 10, 483},
+ dictWord{13, 10, 489},
+ dictWord{
+ 14,
+ 10,
+ 55,
+ },
+ dictWord{14, 10, 57},
+ dictWord{14, 10, 81},
+ dictWord{14, 10, 90},
+ dictWord{14, 10, 148},
+ dictWord{14, 10, 239},
+ dictWord{14, 10, 266},
+ dictWord{
+ 14,
+ 10,
+ 321,
+ },
+ dictWord{14, 10, 326},
+ dictWord{14, 10, 327},
+ dictWord{14, 10, 330},
+ dictWord{14, 10, 347},
+ dictWord{14, 10, 355},
+ dictWord{14, 10, 401},
+ dictWord{14, 10, 404},
+ dictWord{14, 10, 411},
+ dictWord{14, 10, 414},
+ dictWord{14, 10, 416},
+ dictWord{14, 10, 420},
+ dictWord{15, 10, 61},
+ dictWord{
+ 15,
+ 10,
+ 74,
+ },
+ dictWord{15, 10, 87},
+ dictWord{15, 10, 88},
+ dictWord{15, 10, 94},
+ dictWord{15, 10, 96},
+ dictWord{15, 10, 116},
+ dictWord{15, 10, 149},
+ dictWord{
+ 15,
+ 10,
+ 154,
+ },
+ dictWord{16, 10, 50},
+ dictWord{16, 10, 63},
+ dictWord{16, 10, 73},
+ dictWord{17, 10, 2},
+ dictWord{17, 10, 66},
+ dictWord{17, 10, 92},
+ dictWord{17, 10, 103},
+ dictWord{17, 10, 112},
+ dictWord{17, 10, 120},
+ dictWord{18, 10, 50},
+ dictWord{18, 10, 54},
+ dictWord{18, 10, 82},
+ dictWord{18, 10, 86},
+ dictWord{18, 10, 90},
+ dictWord{18, 10, 111},
+ dictWord{18, 10, 115},
+ dictWord{18, 10, 156},
+ dictWord{19, 10, 40},
+ dictWord{19, 10, 79},
+ dictWord{20, 10, 78},
+ dictWord{149, 10, 22},
+ dictWord{7, 0, 887},
+ dictWord{5, 10, 161},
+ dictWord{135, 10, 839},
+ dictWord{142, 11, 98},
+ dictWord{134, 0, 90},
+ dictWord{138, 11, 356},
+ dictWord{
+ 135,
+ 11,
+ 441,
+ },
+ dictWord{6, 11, 111},
+ dictWord{7, 11, 4},
+ dictWord{8, 11, 163},
+ dictWord{8, 11, 776},
+ dictWord{138, 11, 566},
+ dictWord{134, 0, 908},
+ dictWord{
+ 134,
+ 0,
+ 1261,
+ },
+ dictWord{7, 0, 813},
+ dictWord{12, 0, 497},
+ dictWord{141, 0, 56},
+ dictWord{134, 0, 1235},
+ dictWord{135, 0, 429},
+ dictWord{135, 11, 1994},
+ dictWord{138, 0, 904},
+ dictWord{6, 0, 125},
+ dictWord{7, 0, 1277},
+ dictWord{137, 0, 772},
+ dictWord{151, 0, 12},
+ dictWord{4, 0, 841},
+ dictWord{5, 0, 386},
+ dictWord{
+ 133,
+ 11,
+ 386,
+ },
+ dictWord{5, 11, 297},
+ dictWord{135, 11, 1038},
+ dictWord{6, 0, 860},
+ dictWord{6, 0, 1069},
+ dictWord{135, 11, 309},
+ dictWord{136, 0, 946},
+ dictWord{135, 10, 1814},
+ dictWord{141, 11, 418},
+ dictWord{136, 11, 363},
+ dictWord{10, 0, 768},
+ dictWord{139, 0, 787},
+ dictWord{22, 11, 30},
+ dictWord{
+ 150,
+ 11,
+ 33,
+ },
+ dictWord{6, 0, 160},
+ dictWord{7, 0, 1106},
+ dictWord{9, 0, 770},
+ dictWord{11, 0, 112},
+ dictWord{140, 0, 413},
+ dictWord{11, 11, 216},
+ dictWord{
+ 139,
+ 11,
+ 340,
+ },
+ dictWord{136, 10, 139},
+ dictWord{135, 11, 1390},
+ dictWord{135, 11, 808},
+ dictWord{132, 11, 280},
+ dictWord{12, 0, 271},
+ dictWord{17, 0, 109},
+ dictWord{7, 10, 643},
+ dictWord{136, 10, 236},
+ dictWord{140, 11, 54},
+ dictWord{4, 11, 421},
+ dictWord{133, 11, 548},
+ dictWord{11, 0, 719},
+ dictWord{12, 0, 36},
+ dictWord{141, 0, 337},
+ dictWord{7, 0, 581},
+ dictWord{9, 0, 644},
+ dictWord{137, 0, 699},
+ dictWord{11, 11, 511},
+ dictWord{13, 11, 394},
+ dictWord{14, 11, 298},
+ dictWord{14, 11, 318},
+ dictWord{146, 11, 103},
+ dictWord{7, 0, 304},
+ dictWord{9, 0, 646},
+ dictWord{9, 0, 862},
+ dictWord{11, 0, 696},
+ dictWord{12, 0, 208},
+ dictWord{15, 0, 79},
+ dictWord{147, 0, 108},
+ dictWord{4, 0, 631},
+ dictWord{7, 0, 1126},
+ dictWord{135, 0, 1536},
+ dictWord{135, 11, 1527},
+ dictWord{8, 0, 880},
+ dictWord{10, 0, 869},
+ dictWord{138, 0, 913},
+ dictWord{7, 0, 1513},
+ dictWord{5, 10, 54},
+ dictWord{6, 11, 254},
+ dictWord{9, 11, 109},
+ dictWord{138, 11, 103},
+ dictWord{135, 0, 981},
+ dictWord{133, 11, 729},
+ dictWord{132, 10, 744},
+ dictWord{132, 0, 434},
+ dictWord{134, 0, 550},
+ dictWord{7, 0, 930},
+ dictWord{10, 0, 476},
+ dictWord{13, 0, 452},
+ dictWord{19, 0, 104},
+ dictWord{6, 11, 1630},
+ dictWord{10, 10, 402},
+ dictWord{146, 10, 55},
+ dictWord{5, 0, 553},
+ dictWord{138, 0, 824},
+ dictWord{136, 0, 452},
+ dictWord{8, 0, 151},
+ dictWord{137, 10, 624},
+ dictWord{132, 10, 572},
+ dictWord{132, 0, 772},
+ dictWord{133, 11, 671},
+ dictWord{
+ 133,
+ 0,
+ 292,
+ },
+ dictWord{138, 0, 135},
+ dictWord{132, 11, 889},
+ dictWord{140, 11, 207},
+ dictWord{9, 0, 504},
+ dictWord{6, 10, 43},
+ dictWord{7, 10, 38},
+ dictWord{
+ 8,
+ 10,
+ 248,
+ },
+ dictWord{138, 10, 513},
+ dictWord{6, 0, 1089},
+ dictWord{135, 11, 1910},
+ dictWord{4, 11, 627},
+ dictWord{133, 11, 775},
+ dictWord{135, 0, 783},
+ dictWord{133, 10, 766},
+ dictWord{133, 10, 363},
+ dictWord{7, 0, 387},
+ dictWord{135, 11, 387},
+ dictWord{7, 0, 393},
+ dictWord{10, 0, 603},
+ dictWord{11, 0, 206},
+ dictWord{7, 11, 202},
+ dictWord{11, 11, 362},
+ dictWord{11, 11, 948},
+ dictWord{140, 11, 388},
+ dictWord{6, 11, 507},
+ dictWord{7, 11, 451},
+ dictWord{8, 11, 389},
+ dictWord{12, 11, 490},
+ dictWord{13, 11, 16},
+ dictWord{13, 11, 215},
+ dictWord{13, 11, 351},
+ dictWord{18, 11, 132},
+ dictWord{147, 11, 125},
+ dictWord{
+ 4,
+ 0,
+ 912,
+ },
+ dictWord{9, 0, 232},
+ dictWord{135, 11, 841},
+ dictWord{6, 10, 258},
+ dictWord{140, 10, 409},
+ dictWord{5, 10, 249},
+ dictWord{148, 10, 82},
+ dictWord{
+ 136,
+ 11,
+ 566,
+ },
+ dictWord{6, 0, 977},
+ dictWord{135, 11, 1214},
+ dictWord{7, 0, 1973},
+ dictWord{136, 0, 716},
+ dictWord{135, 0, 98},
+ dictWord{133, 0, 733},
+ dictWord{
+ 5,
+ 11,
+ 912,
+ },
+ dictWord{134, 11, 1695},
+ dictWord{5, 10, 393},
+ dictWord{6, 10, 378},
+ dictWord{7, 10, 1981},
+ dictWord{9, 10, 32},
+ dictWord{9, 10, 591},
+ dictWord{10, 10, 685},
+ dictWord{10, 10, 741},
+ dictWord{142, 10, 382},
+ dictWord{133, 10, 788},
+ dictWord{10, 0, 19},
+ dictWord{11, 0, 911},
+ dictWord{7, 10, 1968},
+ dictWord{141, 10, 509},
+ dictWord{5, 0, 668},
+ dictWord{5, 11, 236},
+ dictWord{6, 11, 572},
+ dictWord{8, 11, 492},
+ dictWord{11, 11, 618},
+ dictWord{144, 11, 56},
+ dictWord{135, 11, 1789},
+ dictWord{4, 0, 360},
+ dictWord{5, 0, 635},
+ dictWord{5, 0, 700},
+ dictWord{5, 10, 58},
+ dictWord{5, 10, 171},
+ dictWord{5, 10, 683},
+ dictWord{
+ 6,
+ 10,
+ 291,
+ },
+ dictWord{6, 10, 566},
+ dictWord{7, 10, 1650},
+ dictWord{11, 10, 523},
+ dictWord{12, 10, 273},
+ dictWord{12, 10, 303},
+ dictWord{15, 10, 39},
+ dictWord{143, 10, 111},
+ dictWord{133, 0, 901},
+ dictWord{134, 10, 589},
+ dictWord{5, 11, 190},
+ dictWord{136, 11, 318},
+ dictWord{140, 0, 656},
+ dictWord{
+ 7,
+ 0,
+ 726,
+ },
+ dictWord{152, 0, 9},
+ dictWord{4, 10, 917},
+ dictWord{133, 10, 1005},
+ dictWord{135, 10, 1598},
+ dictWord{134, 11, 491},
+ dictWord{4, 10, 919},
+ dictWord{133, 11, 434},
+ dictWord{137, 0, 72},
+ dictWord{6, 0, 1269},
+ dictWord{6, 0, 1566},
+ dictWord{134, 0, 1621},
+ dictWord{9, 0, 463},
+ dictWord{10, 0, 595},
+ dictWord{4, 10, 255},
+ dictWord{5, 10, 302},
+ dictWord{6, 10, 132},
+ dictWord{7, 10, 128},
+ dictWord{7, 10, 283},
+ dictWord{7, 10, 1299},
+ dictWord{10, 10, 52},
+ dictWord{
+ 10,
+ 10,
+ 514,
+ },
+ dictWord{11, 10, 925},
+ dictWord{13, 10, 92},
+ dictWord{142, 10, 309},
+ dictWord{135, 0, 1454},
+ dictWord{134, 0, 1287},
+ dictWord{11, 0, 600},
+ dictWord{13, 0, 245},
+ dictWord{137, 10, 173},
+ dictWord{136, 0, 989},
+ dictWord{7, 0, 164},
+ dictWord{7, 0, 1571},
+ dictWord{9, 0, 107},
+ dictWord{140, 0, 225},
+ dictWord{6, 0, 1061},
+ dictWord{141, 10, 442},
+ dictWord{4, 0, 27},
+ dictWord{5, 0, 484},
+ dictWord{5, 0, 510},
+ dictWord{6, 0, 434},
+ dictWord{7, 0, 1000},
+ dictWord{
+ 7,
+ 0,
+ 1098,
+ },
+ dictWord{136, 0, 2},
+ dictWord{7, 11, 85},
+ dictWord{7, 11, 247},
+ dictWord{8, 11, 585},
+ dictWord{10, 11, 163},
+ dictWord{138, 11, 316},
+ dictWord{
+ 11,
+ 11,
+ 103,
+ },
+ dictWord{142, 11, 0},
+ dictWord{134, 0, 1127},
+ dictWord{4, 0, 460},
+ dictWord{134, 0, 852},
+ dictWord{134, 10, 210},
+ dictWord{4, 0, 932},
+ dictWord{
+ 133,
+ 0,
+ 891,
+ },
+ dictWord{6, 0, 588},
+ dictWord{147, 11, 83},
+ dictWord{8, 0, 625},
+ dictWord{4, 10, 284},
+ dictWord{134, 10, 223},
+ dictWord{134, 0, 76},
+ dictWord{8, 0, 92},
+ dictWord{137, 0, 221},
+ dictWord{4, 11, 124},
+ dictWord{10, 11, 457},
+ dictWord{11, 11, 121},
+ dictWord{11, 11, 169},
+ dictWord{11, 11, 422},
+ dictWord{
+ 11,
+ 11,
+ 870,
+ },
+ dictWord{12, 11, 214},
+ dictWord{13, 11, 389},
+ dictWord{14, 11, 187},
+ dictWord{143, 11, 77},
+ dictWord{9, 11, 618},
+ dictWord{138, 11, 482},
+ dictWord{
+ 4,
+ 10,
+ 218,
+ },
+ dictWord{7, 10, 526},
+ dictWord{143, 10, 137},
+ dictWord{13, 0, 9},
+ dictWord{14, 0, 104},
+ dictWord{14, 0, 311},
+ dictWord{4, 10, 270},
+ dictWord{
+ 5,
+ 10,
+ 192,
+ },
+ dictWord{6, 10, 332},
+ dictWord{135, 10, 1322},
+ dictWord{140, 10, 661},
+ dictWord{135, 11, 1193},
+ dictWord{6, 11, 107},
+ dictWord{7, 11, 638},
+ dictWord{7, 11, 1632},
+ dictWord{137, 11, 396},
+ dictWord{132, 0, 763},
+ dictWord{4, 0, 622},
+ dictWord{5, 11, 370},
+ dictWord{134, 11, 1756},
+ dictWord{
+ 133,
+ 0,
+ 253,
+ },
+ dictWord{135, 0, 546},
+ dictWord{9, 0, 73},
+ dictWord{10, 0, 110},
+ dictWord{14, 0, 185},
+ dictWord{17, 0, 119},
+ dictWord{133, 11, 204},
+ dictWord{7, 0, 624},
+ dictWord{7, 0, 916},
+ dictWord{10, 0, 256},
+ dictWord{139, 0, 87},
+ dictWord{7, 10, 379},
+ dictWord{8, 10, 481},
+ dictWord{137, 10, 377},
+ dictWord{5, 0, 212},
+ dictWord{12, 0, 35},
+ dictWord{13, 0, 382},
+ dictWord{5, 11, 970},
+ dictWord{134, 11, 1706},
+ dictWord{9, 0, 746},
+ dictWord{5, 10, 1003},
+ dictWord{134, 10, 149},
+ dictWord{10, 0, 150},
+ dictWord{11, 0, 849},
+ dictWord{13, 0, 330},
+ dictWord{8, 10, 262},
+ dictWord{9, 10, 627},
+ dictWord{11, 10, 214},
+ dictWord{11, 10, 404},
+ dictWord{11, 10, 457},
+ dictWord{11, 10, 780},
+ dictWord{11, 10, 913},
+ dictWord{13, 10, 401},
+ dictWord{142, 10, 200},
+ dictWord{134, 0, 1466},
+ dictWord{
+ 135,
+ 11,
+ 3,
+ },
+ dictWord{6, 0, 1299},
+ dictWord{4, 11, 35},
+ dictWord{5, 11, 121},
+ dictWord{5, 11, 483},
+ dictWord{5, 11, 685},
+ dictWord{6, 11, 489},
+ dictWord{7, 11, 1204},
+ dictWord{136, 11, 394},
+ dictWord{135, 10, 742},
+ dictWord{4, 10, 142},
+ dictWord{136, 10, 304},
+ dictWord{4, 11, 921},
+ dictWord{133, 11, 1007},
+ dictWord{
+ 134,
+ 0,
+ 1518,
+ },
+ dictWord{6, 0, 1229},
+ dictWord{135, 0, 1175},
+ dictWord{133, 0, 816},
+ dictWord{12, 0, 159},
+ dictWord{4, 10, 471},
+ dictWord{4, 11, 712},
+ dictWord{
+ 5,
+ 10,
+ 51,
+ },
+ dictWord{6, 10, 602},
+ dictWord{7, 10, 925},
+ dictWord{8, 10, 484},
+ dictWord{138, 10, 195},
+ dictWord{134, 11, 1629},
+ dictWord{5, 0, 869},
+ dictWord{
+ 5,
+ 0,
+ 968,
+ },
+ dictWord{6, 0, 1626},
+ dictWord{8, 0, 734},
+ dictWord{136, 0, 784},
+ dictWord{4, 0, 542},
+ dictWord{6, 0, 1716},
+ dictWord{6, 0, 1727},
+ dictWord{
+ 7,
+ 0,
+ 1082,
+ },
+ dictWord{7, 0, 1545},
+ dictWord{8, 0, 56},
+ dictWord{8, 0, 118},
+ dictWord{8, 0, 412},
+ dictWord{8, 0, 564},
+ dictWord{9, 0, 888},
+ dictWord{9, 0, 908},
+ dictWord{
+ 10,
+ 0,
+ 50,
+ },
+ dictWord{10, 0, 423},
+ dictWord{11, 0, 685},
+ dictWord{11, 0, 697},
+ dictWord{11, 0, 933},
+ dictWord{12, 0, 299},
+ dictWord{13, 0, 126},
+ dictWord{
+ 13,
+ 0,
+ 136,
+ },
+ dictWord{13, 0, 170},
+ dictWord{13, 0, 190},
+ dictWord{136, 10, 688},
+ dictWord{132, 10, 697},
+ dictWord{4, 0, 232},
+ dictWord{9, 0, 202},
+ dictWord{
+ 10,
+ 0,
+ 474,
+ },
+ dictWord{140, 0, 433},
+ dictWord{136, 0, 212},
+ dictWord{6, 0, 108},
+ dictWord{7, 0, 1003},
+ dictWord{7, 0, 1181},
+ dictWord{8, 0, 111},
+ dictWord{
+ 136,
+ 0,
+ 343,
+ },
+ dictWord{5, 10, 221},
+ dictWord{135, 11, 1255},
+ dictWord{133, 11, 485},
+ dictWord{134, 0, 1712},
+ dictWord{142, 0, 216},
+ dictWord{5, 0, 643},
+ dictWord{
+ 6,
+ 0,
+ 516,
+ },
+ dictWord{4, 11, 285},
+ dictWord{5, 11, 317},
+ dictWord{6, 11, 301},
+ dictWord{7, 11, 7},
+ dictWord{8, 11, 153},
+ dictWord{10, 11, 766},
+ dictWord{
+ 11,
+ 11,
+ 468,
+ },
+ dictWord{12, 11, 467},
+ dictWord{141, 11, 143},
+ dictWord{4, 0, 133},
+ dictWord{7, 0, 711},
+ dictWord{7, 0, 1298},
+ dictWord{135, 0, 1585},
+ dictWord{
+ 134,
+ 0,
+ 650,
+ },
+ dictWord{135, 11, 512},
+ dictWord{6, 0, 99},
+ dictWord{7, 0, 1808},
+ dictWord{145, 0, 57},
+ dictWord{6, 0, 246},
+ dictWord{6, 0, 574},
+ dictWord{7, 0, 428},
+ dictWord{9, 0, 793},
+ dictWord{10, 0, 669},
+ dictWord{11, 0, 485},
+ dictWord{11, 0, 840},
+ dictWord{12, 0, 300},
+ dictWord{14, 0, 250},
+ dictWord{145, 0, 55},
+ dictWord{
+ 4,
+ 10,
+ 132,
+ },
+ dictWord{5, 10, 69},
+ dictWord{135, 10, 1242},
+ dictWord{136, 0, 1023},
+ dictWord{7, 0, 302},
+ dictWord{132, 10, 111},
+ dictWord{135, 0, 1871},
+ dictWord{132, 0, 728},
+ dictWord{9, 0, 252},
+ dictWord{132, 10, 767},
+ dictWord{6, 0, 461},
+ dictWord{7, 0, 1590},
+ dictWord{7, 10, 1416},
+ dictWord{7, 10, 2005},
+ dictWord{8, 10, 131},
+ dictWord{8, 10, 466},
+ dictWord{9, 10, 672},
+ dictWord{13, 10, 252},
+ dictWord{148, 10, 103},
+ dictWord{6, 0, 323},
+ dictWord{135, 0, 1564},
+ dictWord{7, 0, 461},
+ dictWord{136, 0, 775},
+ dictWord{6, 10, 44},
+ dictWord{136, 10, 368},
+ dictWord{139, 0, 172},
+ dictWord{132, 0, 464},
+ dictWord{4, 10, 570},
+ dictWord{133, 10, 120},
+ dictWord{137, 11, 269},
+ dictWord{6, 10, 227},
+ dictWord{135, 10, 1589},
+ dictWord{6, 11, 1719},
+ dictWord{6, 11, 1735},
+ dictWord{
+ 7,
+ 11,
+ 2016,
+ },
+ dictWord{7, 11, 2020},
+ dictWord{8, 11, 837},
+ dictWord{137, 11, 852},
+ dictWord{7, 0, 727},
+ dictWord{146, 0, 73},
+ dictWord{132, 0, 1023},
+ dictWord{135, 11, 852},
+ dictWord{135, 10, 1529},
+ dictWord{136, 0, 577},
+ dictWord{138, 11, 568},
+ dictWord{134, 0, 1037},
+ dictWord{8, 11, 67},
+ dictWord{
+ 138,
+ 11,
+ 419,
+ },
+ dictWord{4, 0, 413},
+ dictWord{5, 0, 677},
+ dictWord{8, 0, 432},
+ dictWord{140, 0, 280},
+ dictWord{10, 0, 600},
+ dictWord{6, 10, 1667},
+ dictWord{
+ 7,
+ 11,
+ 967,
+ },
+ dictWord{7, 10, 2036},
+ dictWord{141, 11, 11},
+ dictWord{6, 10, 511},
+ dictWord{140, 10, 132},
+ dictWord{6, 0, 799},
+ dictWord{5, 10, 568},
+ dictWord{
+ 6,
+ 10,
+ 138,
+ },
+ dictWord{135, 10, 1293},
+ dictWord{8, 0, 159},
+ dictWord{4, 10, 565},
+ dictWord{136, 10, 827},
+ dictWord{7, 0, 646},
+ dictWord{7, 0, 1730},
+ dictWord{
+ 11,
+ 0,
+ 446,
+ },
+ dictWord{141, 0, 178},
+ dictWord{4, 10, 922},
+ dictWord{133, 10, 1023},
+ dictWord{135, 11, 11},
+ dictWord{132, 0, 395},
+ dictWord{11, 0, 145},
+ dictWord{135, 10, 1002},
+ dictWord{9, 0, 174},
+ dictWord{10, 0, 164},
+ dictWord{11, 0, 440},
+ dictWord{11, 0, 514},
+ dictWord{11, 0, 841},
+ dictWord{15, 0, 98},
+ dictWord{149, 0, 20},
+ dictWord{134, 0, 426},
+ dictWord{10, 0, 608},
+ dictWord{139, 0, 1002},
+ dictWord{7, 11, 320},
+ dictWord{8, 11, 51},
+ dictWord{12, 11, 481},
+ dictWord{12, 11, 570},
+ dictWord{148, 11, 106},
+ dictWord{9, 0, 977},
+ dictWord{9, 0, 983},
+ dictWord{132, 11, 445},
+ dictWord{138, 0, 250},
+ dictWord{139, 0, 100},
+ dictWord{6, 0, 1982},
+ dictWord{136, 10, 402},
+ dictWord{133, 11, 239},
+ dictWord{4, 10, 716},
+ dictWord{141, 10, 31},
+ dictWord{5, 0, 476},
+ dictWord{7, 11, 83},
+ dictWord{7, 11, 1990},
+ dictWord{8, 11, 130},
+ dictWord{139, 11, 720},
+ dictWord{8, 10, 691},
+ dictWord{136, 10, 731},
+ dictWord{5, 11, 123},
+ dictWord{
+ 6,
+ 11,
+ 530,
+ },
+ dictWord{7, 11, 348},
+ dictWord{135, 11, 1419},
+ dictWord{5, 0, 76},
+ dictWord{6, 0, 458},
+ dictWord{6, 0, 497},
+ dictWord{7, 0, 868},
+ dictWord{9, 0, 658},
+ dictWord{10, 0, 594},
+ dictWord{11, 0, 173},
+ dictWord{11, 0, 566},
+ dictWord{12, 0, 20},
+ dictWord{12, 0, 338},
+ dictWord{141, 0, 200},
+ dictWord{9, 11, 139},
+ dictWord{
+ 10,
+ 11,
+ 399,
+ },
+ dictWord{11, 11, 469},
+ dictWord{12, 11, 634},
+ dictWord{141, 11, 223},
+ dictWord{9, 10, 840},
+ dictWord{138, 10, 803},
+ dictWord{133, 10, 847},
+ dictWord{11, 11, 223},
+ dictWord{140, 11, 168},
+ dictWord{132, 11, 210},
+ dictWord{8, 0, 447},
+ dictWord{9, 10, 53},
+ dictWord{9, 10, 268},
+ dictWord{9, 10, 901},
+ dictWord{10, 10, 518},
+ dictWord{10, 10, 829},
+ dictWord{11, 10, 188},
+ dictWord{13, 10, 74},
+ dictWord{14, 10, 46},
+ dictWord{15, 10, 17},
+ dictWord{15, 10, 33},
+ dictWord{17, 10, 40},
+ dictWord{18, 10, 36},
+ dictWord{19, 10, 20},
+ dictWord{22, 10, 1},
+ dictWord{152, 10, 2},
+ dictWord{4, 0, 526},
+ dictWord{7, 0, 1029},
+ dictWord{135, 0, 1054},
+ dictWord{19, 11, 59},
+ dictWord{150, 11, 2},
+ dictWord{4, 0, 636},
+ dictWord{6, 0, 1875},
+ dictWord{6, 0, 1920},
+ dictWord{9, 0, 999},
+ dictWord{
+ 12,
+ 0,
+ 807,
+ },
+ dictWord{12, 0, 825},
+ dictWord{15, 0, 179},
+ dictWord{15, 0, 190},
+ dictWord{18, 0, 182},
+ dictWord{136, 10, 532},
+ dictWord{6, 0, 1699},
+ dictWord{
+ 7,
+ 0,
+ 660,
+ },
+ dictWord{7, 0, 1124},
+ dictWord{17, 0, 31},
+ dictWord{19, 0, 22},
+ dictWord{151, 0, 14},
+ dictWord{135, 10, 681},
+ dictWord{132, 11, 430},
+ dictWord{
+ 140,
+ 10,
+ 677,
+ },
+ dictWord{4, 10, 684},
+ dictWord{136, 10, 384},
+ dictWord{132, 11, 756},
+ dictWord{133, 11, 213},
+ dictWord{7, 0, 188},
+ dictWord{7, 10, 110},
+ dictWord{
+ 8,
+ 10,
+ 290,
+ },
+ dictWord{8, 10, 591},
+ dictWord{9, 10, 382},
+ dictWord{9, 10, 649},
+ dictWord{11, 10, 71},
+ dictWord{11, 10, 155},
+ dictWord{11, 10, 313},
+ dictWord{
+ 12,
+ 10,
+ 5,
+ },
+ dictWord{13, 10, 325},
+ dictWord{142, 10, 287},
+ dictWord{7, 10, 360},
+ dictWord{7, 10, 425},
+ dictWord{9, 10, 66},
+ dictWord{9, 10, 278},
+ dictWord{
+ 138,
+ 10,
+ 644,
+ },
+ dictWord{142, 11, 164},
+ dictWord{4, 0, 279},
+ dictWord{7, 0, 301},
+ dictWord{137, 0, 362},
+ dictWord{134, 11, 586},
+ dictWord{135, 0, 1743},
+ dictWord{4, 0, 178},
+ dictWord{133, 0, 399},
+ dictWord{4, 10, 900},
+ dictWord{133, 10, 861},
+ dictWord{5, 10, 254},
+ dictWord{7, 10, 985},
+ dictWord{136, 10, 73},
+ dictWord{133, 11, 108},
+ dictWord{7, 10, 1959},
+ dictWord{136, 10, 683},
+ dictWord{133, 11, 219},
+ dictWord{4, 11, 193},
+ dictWord{5, 11, 916},
+ dictWord{
+ 7,
+ 11,
+ 364,
+ },
+ dictWord{10, 11, 398},
+ dictWord{10, 11, 726},
+ dictWord{11, 11, 317},
+ dictWord{11, 11, 626},
+ dictWord{12, 11, 142},
+ dictWord{12, 11, 288},
+ dictWord{
+ 12,
+ 11,
+ 678,
+ },
+ dictWord{13, 11, 313},
+ dictWord{15, 11, 113},
+ dictWord{18, 11, 114},
+ dictWord{21, 11, 30},
+ dictWord{150, 11, 53},
+ dictWord{6, 11, 241},
+ dictWord{7, 11, 907},
+ dictWord{8, 11, 832},
+ dictWord{9, 11, 342},
+ dictWord{10, 11, 729},
+ dictWord{11, 11, 284},
+ dictWord{11, 11, 445},
+ dictWord{11, 11, 651},
+ dictWord{11, 11, 863},
+ dictWord{13, 11, 398},
+ dictWord{146, 11, 99},
+ dictWord{132, 0, 872},
+ dictWord{134, 0, 831},
+ dictWord{134, 0, 1692},
+ dictWord{
+ 6,
+ 0,
+ 202,
+ },
+ dictWord{6, 0, 1006},
+ dictWord{9, 0, 832},
+ dictWord{10, 0, 636},
+ dictWord{11, 0, 208},
+ dictWord{12, 0, 360},
+ dictWord{17, 0, 118},
+ dictWord{18, 0, 27},
+ dictWord{20, 0, 67},
+ dictWord{137, 11, 734},
+ dictWord{132, 10, 725},
+ dictWord{7, 11, 993},
+ dictWord{138, 11, 666},
+ dictWord{134, 0, 1954},
+ dictWord{
+ 134,
+ 10,
+ 196,
+ },
+ dictWord{7, 0, 872},
+ dictWord{10, 0, 516},
+ dictWord{139, 0, 167},
+ dictWord{133, 10, 831},
+ dictWord{4, 11, 562},
+ dictWord{9, 11, 254},
+ dictWord{
+ 139,
+ 11,
+ 879,
+ },
+ dictWord{137, 0, 313},
+ dictWord{4, 0, 224},
+ dictWord{132, 11, 786},
+ dictWord{11, 0, 24},
+ dictWord{12, 0, 170},
+ dictWord{136, 10, 723},
+ dictWord{
+ 5,
+ 0,
+ 546,
+ },
+ dictWord{7, 0, 35},
+ dictWord{8, 0, 11},
+ dictWord{8, 0, 12},
+ dictWord{9, 0, 315},
+ dictWord{9, 0, 533},
+ dictWord{10, 0, 802},
+ dictWord{11, 0, 166},
+ dictWord{
+ 12,
+ 0,
+ 525,
+ },
+ dictWord{142, 0, 243},
+ dictWord{7, 0, 1937},
+ dictWord{13, 10, 80},
+ dictWord{13, 10, 437},
+ dictWord{145, 10, 74},
+ dictWord{5, 0, 241},
+ dictWord{
+ 8,
+ 0,
+ 242,
+ },
+ dictWord{9, 0, 451},
+ dictWord{10, 0, 667},
+ dictWord{11, 0, 598},
+ dictWord{140, 0, 429},
+ dictWord{150, 0, 46},
+ dictWord{6, 0, 1273},
+ dictWord{
+ 137,
+ 0,
+ 830,
+ },
+ dictWord{5, 10, 848},
+ dictWord{6, 10, 66},
+ dictWord{136, 10, 764},
+ dictWord{6, 0, 825},
+ dictWord{134, 0, 993},
+ dictWord{4, 0, 1006},
+ dictWord{
+ 10,
+ 0,
+ 327,
+ },
+ dictWord{13, 0, 271},
+ dictWord{4, 10, 36},
+ dictWord{7, 10, 1387},
+ dictWord{139, 10, 755},
+ dictWord{134, 0, 1023},
+ dictWord{135, 0, 1580},
+ dictWord{
+ 4,
+ 0,
+ 366,
+ },
+ dictWord{137, 0, 516},
+ dictWord{132, 10, 887},
+ dictWord{6, 0, 1736},
+ dictWord{135, 0, 1891},
+ dictWord{6, 11, 216},
+ dictWord{7, 11, 901},
+ dictWord{
+ 7,
+ 11,
+ 1343,
+ },
+ dictWord{136, 11, 493},
+ dictWord{6, 10, 165},
+ dictWord{138, 10, 388},
+ dictWord{7, 11, 341},
+ dictWord{139, 11, 219},
+ dictWord{4, 10, 719},
+ dictWord{135, 10, 155},
+ dictWord{134, 0, 1935},
+ dictWord{132, 0, 826},
+ dictWord{6, 0, 331},
+ dictWord{6, 0, 1605},
+ dictWord{8, 0, 623},
+ dictWord{11, 0, 139},
+ dictWord{139, 0, 171},
+ dictWord{135, 11, 1734},
+ dictWord{10, 11, 115},
+ dictWord{11, 11, 420},
+ dictWord{12, 11, 154},
+ dictWord{13, 11, 404},
+ dictWord{
+ 14,
+ 11,
+ 346,
+ },
+ dictWord{15, 11, 54},
+ dictWord{143, 11, 112},
+ dictWord{7, 0, 288},
+ dictWord{4, 10, 353},
+ dictWord{6, 10, 146},
+ dictWord{6, 10, 1789},
+ dictWord{
+ 7,
+ 10,
+ 990,
+ },
+ dictWord{7, 10, 1348},
+ dictWord{9, 10, 665},
+ dictWord{9, 10, 898},
+ dictWord{11, 10, 893},
+ dictWord{142, 10, 212},
+ dictWord{6, 0, 916},
+ dictWord{134, 0, 1592},
+ dictWord{7, 0, 1888},
+ dictWord{4, 10, 45},
+ dictWord{135, 10, 1257},
+ dictWord{5, 11, 1011},
+ dictWord{136, 11, 701},
+ dictWord{
+ 139,
+ 11,
+ 596,
+ },
+ dictWord{4, 11, 54},
+ dictWord{5, 11, 666},
+ dictWord{7, 11, 1039},
+ dictWord{7, 11, 1130},
+ dictWord{9, 11, 195},
+ dictWord{138, 11, 302},
+ dictWord{
+ 134,
+ 0,
+ 1471,
+ },
+ dictWord{134, 0, 1570},
+ dictWord{132, 0, 394},
+ dictWord{140, 10, 65},
+ dictWord{136, 10, 816},
+ dictWord{135, 0, 1931},
+ dictWord{7, 0, 574},
+ dictWord{135, 0, 1719},
+ dictWord{134, 11, 467},
+ dictWord{132, 0, 658},
+ dictWord{9, 0, 781},
+ dictWord{10, 0, 144},
+ dictWord{11, 0, 385},
+ dictWord{13, 0, 161},
+ dictWord{13, 0, 228},
+ dictWord{13, 0, 268},
+ dictWord{20, 0, 107},
+ dictWord{134, 11, 1669},
+ dictWord{136, 0, 374},
+ dictWord{135, 0, 735},
+ dictWord{4, 0, 344},
+ dictWord{6, 0, 498},
+ dictWord{139, 0, 323},
+ dictWord{7, 0, 586},
+ dictWord{7, 0, 1063},
+ dictWord{6, 10, 559},
+ dictWord{134, 10, 1691},
+ dictWord{137, 0, 155},
+ dictWord{133, 0, 906},
+ dictWord{7, 11, 122},
+ dictWord{9, 11, 259},
+ dictWord{10, 11, 84},
+ dictWord{11, 11, 470},
+ dictWord{12, 11, 541},
+ dictWord{
+ 141,
+ 11,
+ 379,
+ },
+ dictWord{134, 0, 1139},
+ dictWord{10, 0, 108},
+ dictWord{139, 0, 116},
+ dictWord{134, 10, 456},
+ dictWord{133, 10, 925},
+ dictWord{5, 11, 82},
+ dictWord{
+ 5,
+ 11,
+ 131,
+ },
+ dictWord{7, 11, 1755},
+ dictWord{8, 11, 31},
+ dictWord{9, 11, 168},
+ dictWord{9, 11, 764},
+ dictWord{139, 11, 869},
+ dictWord{134, 11, 605},
+ dictWord{
+ 5,
+ 11,
+ 278,
+ },
+ dictWord{137, 11, 68},
+ dictWord{4, 11, 163},
+ dictWord{5, 11, 201},
+ dictWord{5, 11, 307},
+ dictWord{5, 11, 310},
+ dictWord{6, 11, 335},
+ dictWord{
+ 7,
+ 11,
+ 284,
+ },
+ dictWord{136, 11, 165},
+ dictWord{135, 11, 1660},
+ dictWord{6, 11, 33},
+ dictWord{135, 11, 1244},
+ dictWord{4, 0, 616},
+ dictWord{136, 11, 483},
+ dictWord{8, 0, 857},
+ dictWord{8, 0, 902},
+ dictWord{8, 0, 910},
+ dictWord{10, 0, 879},
+ dictWord{12, 0, 726},
+ dictWord{4, 11, 199},
+ dictWord{139, 11, 34},
+ dictWord{136, 0, 692},
+ dictWord{6, 10, 193},
+ dictWord{7, 10, 240},
+ dictWord{7, 10, 1682},
+ dictWord{10, 10, 51},
+ dictWord{10, 10, 640},
+ dictWord{11, 10, 410},
+ dictWord{13, 10, 82},
+ dictWord{14, 10, 247},
+ dictWord{14, 10, 331},
+ dictWord{142, 10, 377},
+ dictWord{6, 0, 823},
+ dictWord{134, 0, 983},
+ dictWord{
+ 139,
+ 10,
+ 411,
+ },
+ dictWord{132, 0, 305},
+ dictWord{136, 10, 633},
+ dictWord{138, 11, 203},
+ dictWord{134, 0, 681},
+ dictWord{6, 11, 326},
+ dictWord{7, 11, 677},
+ dictWord{137, 11, 425},
+ dictWord{5, 0, 214},
+ dictWord{7, 0, 603},
+ dictWord{8, 0, 611},
+ dictWord{9, 0, 686},
+ dictWord{10, 0, 88},
+ dictWord{11, 0, 459},
+ dictWord{
+ 11,
+ 0,
+ 496,
+ },
+ dictWord{12, 0, 463},
+ dictWord{12, 0, 590},
+ dictWord{141, 0, 0},
+ dictWord{136, 0, 1004},
+ dictWord{142, 0, 23},
+ dictWord{134, 0, 1703},
+ dictWord{
+ 147,
+ 11,
+ 8,
+ },
+ dictWord{145, 11, 56},
+ dictWord{135, 0, 1443},
+ dictWord{4, 10, 237},
+ dictWord{135, 10, 514},
+ dictWord{6, 0, 714},
+ dictWord{145, 0, 19},
+ dictWord{
+ 5,
+ 11,
+ 358,
+ },
+ dictWord{7, 11, 473},
+ dictWord{7, 11, 1184},
+ dictWord{10, 11, 662},
+ dictWord{13, 11, 212},
+ dictWord{13, 11, 304},
+ dictWord{13, 11, 333},
+ dictWord{145, 11, 98},
+ dictWord{4, 0, 737},
+ dictWord{10, 0, 98},
+ dictWord{11, 0, 294},
+ dictWord{12, 0, 60},
+ dictWord{12, 0, 437},
+ dictWord{13, 0, 64},
+ dictWord{
+ 13,
+ 0,
+ 380,
+ },
+ dictWord{142, 0, 430},
+ dictWord{6, 10, 392},
+ dictWord{7, 10, 65},
+ dictWord{135, 10, 2019},
+ dictWord{6, 0, 1758},
+ dictWord{8, 0, 520},
+ dictWord{
+ 9,
+ 0,
+ 345,
+ },
+ dictWord{9, 0, 403},
+ dictWord{142, 0, 350},
+ dictWord{5, 0, 47},
+ dictWord{10, 0, 242},
+ dictWord{138, 0, 579},
+ dictWord{5, 0, 139},
+ dictWord{7, 0, 1168},
+ dictWord{138, 0, 539},
+ dictWord{134, 0, 1459},
+ dictWord{13, 0, 388},
+ dictWord{141, 11, 388},
+ dictWord{134, 0, 253},
+ dictWord{7, 10, 1260},
+ dictWord{
+ 135,
+ 10,
+ 1790,
+ },
+ dictWord{10, 0, 252},
+ dictWord{9, 10, 222},
+ dictWord{139, 10, 900},
+ dictWord{140, 0, 745},
+ dictWord{133, 11, 946},
+ dictWord{4, 0, 107},
+ dictWord{
+ 7,
+ 0,
+ 613,
+ },
+ dictWord{8, 0, 439},
+ dictWord{8, 0, 504},
+ dictWord{9, 0, 501},
+ dictWord{10, 0, 383},
+ dictWord{139, 0, 477},
+ dictWord{135, 11, 1485},
+ dictWord{
+ 132,
+ 0,
+ 871,
+ },
+ dictWord{7, 11, 411},
+ dictWord{7, 11, 590},
+ dictWord{8, 11, 631},
+ dictWord{9, 11, 323},
+ dictWord{10, 11, 355},
+ dictWord{11, 11, 491},
+ dictWord{
+ 12,
+ 11,
+ 143,
+ },
+ dictWord{12, 11, 402},
+ dictWord{13, 11, 73},
+ dictWord{14, 11, 408},
+ dictWord{15, 11, 107},
+ dictWord{146, 11, 71},
+ dictWord{132, 0, 229},
+ dictWord{132, 0, 903},
+ dictWord{140, 0, 71},
+ dictWord{133, 0, 549},
+ dictWord{4, 0, 47},
+ dictWord{6, 0, 373},
+ dictWord{7, 0, 452},
+ dictWord{7, 0, 543},
+ dictWord{
+ 7,
+ 0,
+ 1828,
+ },
+ dictWord{7, 0, 1856},
+ dictWord{9, 0, 6},
+ dictWord{11, 0, 257},
+ dictWord{139, 0, 391},
+ dictWord{7, 11, 1467},
+ dictWord{8, 11, 328},
+ dictWord{
+ 10,
+ 11,
+ 544,
+ },
+ dictWord{11, 11, 955},
+ dictWord{13, 11, 320},
+ dictWord{145, 11, 83},
+ dictWord{5, 0, 980},
+ dictWord{134, 0, 1754},
+ dictWord{136, 0, 865},
+ dictWord{
+ 5,
+ 0,
+ 705,
+ },
+ dictWord{137, 0, 606},
+ dictWord{7, 0, 161},
+ dictWord{8, 10, 201},
+ dictWord{136, 10, 605},
+ dictWord{143, 11, 35},
+ dictWord{5, 11, 835},
+ dictWord{
+ 6,
+ 11,
+ 483,
+ },
+ dictWord{140, 10, 224},
+ dictWord{7, 0, 536},
+ dictWord{7, 0, 1331},
+ dictWord{136, 0, 143},
+ dictWord{134, 0, 1388},
+ dictWord{5, 0, 724},
+ dictWord{
+ 10,
+ 0,
+ 305,
+ },
+ dictWord{11, 0, 151},
+ dictWord{12, 0, 33},
+ dictWord{12, 0, 121},
+ dictWord{12, 0, 381},
+ dictWord{17, 0, 3},
+ dictWord{17, 0, 27},
+ dictWord{17, 0, 78},
+ dictWord{18, 0, 18},
+ dictWord{19, 0, 54},
+ dictWord{149, 0, 5},
+ dictWord{4, 10, 523},
+ dictWord{133, 10, 638},
+ dictWord{5, 0, 19},
+ dictWord{134, 0, 533},
+ dictWord{
+ 5,
+ 0,
+ 395,
+ },
+ dictWord{5, 0, 951},
+ dictWord{134, 0, 1776},
+ dictWord{135, 0, 1908},
+ dictWord{132, 0, 846},
+ dictWord{10, 0, 74},
+ dictWord{11, 0, 663},
+ dictWord{
+ 12,
+ 0,
+ 210,
+ },
+ dictWord{13, 0, 166},
+ dictWord{13, 0, 310},
+ dictWord{14, 0, 373},
+ dictWord{18, 0, 95},
+ dictWord{19, 0, 43},
+ dictWord{6, 10, 242},
+ dictWord{7, 10, 227},
+ dictWord{7, 10, 1581},
+ dictWord{8, 10, 104},
+ dictWord{9, 10, 113},
+ dictWord{9, 10, 220},
+ dictWord{9, 10, 427},
+ dictWord{10, 10, 239},
+ dictWord{11, 10, 579},
+ dictWord{11, 10, 1023},
+ dictWord{13, 10, 4},
+ dictWord{13, 10, 204},
+ dictWord{13, 10, 316},
+ dictWord{148, 10, 86},
+ dictWord{9, 11, 716},
+ dictWord{11, 11, 108},
+ dictWord{13, 11, 123},
+ dictWord{14, 11, 252},
+ dictWord{19, 11, 38},
+ dictWord{21, 11, 3},
+ dictWord{151, 11, 11},
+ dictWord{8, 0, 372},
+ dictWord{9, 0, 122},
+ dictWord{138, 0, 175},
+ dictWord{132, 11, 677},
+ dictWord{7, 11, 1374},
+ dictWord{136, 11, 540},
+ dictWord{135, 10, 861},
+ dictWord{132, 0, 695},
+ dictWord{
+ 7,
+ 0,
+ 497,
+ },
+ dictWord{9, 0, 387},
+ dictWord{147, 0, 81},
+ dictWord{136, 0, 937},
+ dictWord{134, 0, 718},
+ dictWord{7, 0, 1328},
+ dictWord{136, 10, 494},
+ dictWord{
+ 132,
+ 11,
+ 331,
+ },
+ dictWord{6, 0, 1581},
+ dictWord{133, 11, 747},
+ dictWord{5, 0, 284},
+ dictWord{6, 0, 49},
+ dictWord{6, 0, 350},
+ dictWord{7, 0, 1},
+ dictWord{7, 0, 377},
+ dictWord{7, 0, 1693},
+ dictWord{8, 0, 18},
+ dictWord{8, 0, 678},
+ dictWord{9, 0, 161},
+ dictWord{9, 0, 585},
+ dictWord{9, 0, 671},
+ dictWord{9, 0, 839},
+ dictWord{11, 0, 912},
+ dictWord{141, 0, 427},
+ dictWord{7, 10, 1306},
+ dictWord{8, 10, 505},
+ dictWord{9, 10, 482},
+ dictWord{10, 10, 126},
+ dictWord{11, 10, 225},
+ dictWord{12, 10, 347},
+ dictWord{12, 10, 449},
+ dictWord{13, 10, 19},
+ dictWord{14, 10, 218},
+ dictWord{142, 10, 435},
+ dictWord{10, 10, 764},
+ dictWord{12, 10, 120},
+ dictWord{
+ 13,
+ 10,
+ 39,
+ },
+ dictWord{145, 10, 127},
+ dictWord{4, 0, 597},
+ dictWord{133, 10, 268},
+ dictWord{134, 0, 1094},
+ dictWord{4, 0, 1008},
+ dictWord{134, 0, 1973},
+ dictWord{132, 0, 811},
+ dictWord{139, 0, 908},
+ dictWord{135, 0, 1471},
+ dictWord{133, 11, 326},
+ dictWord{4, 10, 384},
+ dictWord{135, 10, 1022},
+ dictWord{
+ 7,
+ 0,
+ 1935,
+ },
+ dictWord{8, 0, 324},
+ dictWord{12, 0, 42},
+ dictWord{4, 11, 691},
+ dictWord{7, 11, 1935},
+ dictWord{8, 11, 324},
+ dictWord{9, 11, 35},
+ dictWord{10, 11, 680},
+ dictWord{11, 11, 364},
+ dictWord{12, 11, 42},
+ dictWord{13, 11, 357},
+ dictWord{146, 11, 16},
+ dictWord{135, 0, 2014},
+ dictWord{7, 0, 2007},
+ dictWord{
+ 9,
+ 0,
+ 101,
+ },
+ dictWord{9, 0, 450},
+ dictWord{10, 0, 66},
+ dictWord{10, 0, 842},
+ dictWord{11, 0, 536},
+ dictWord{12, 0, 587},
+ dictWord{6, 11, 32},
+ dictWord{7, 11, 385},
+ dictWord{7, 11, 757},
+ dictWord{7, 11, 1916},
+ dictWord{8, 11, 37},
+ dictWord{8, 11, 94},
+ dictWord{8, 11, 711},
+ dictWord{9, 11, 541},
+ dictWord{10, 11, 162},
+ dictWord{
+ 10,
+ 11,
+ 795,
+ },
+ dictWord{11, 11, 989},
+ dictWord{11, 11, 1010},
+ dictWord{12, 11, 14},
+ dictWord{142, 11, 308},
+ dictWord{139, 0, 586},
+ dictWord{
+ 135,
+ 10,
+ 1703,
+ },
+ dictWord{7, 0, 1077},
+ dictWord{11, 0, 28},
+ dictWord{9, 10, 159},
+ dictWord{140, 10, 603},
+ dictWord{6, 0, 1221},
+ dictWord{136, 10, 583},
+ dictWord{
+ 6,
+ 11,
+ 152,
+ },
+ dictWord{6, 11, 349},
+ dictWord{6, 11, 1682},
+ dictWord{7, 11, 1252},
+ dictWord{8, 11, 112},
+ dictWord{9, 11, 435},
+ dictWord{9, 11, 668},
+ dictWord{
+ 10,
+ 11,
+ 290,
+ },
+ dictWord{10, 11, 319},
+ dictWord{10, 11, 815},
+ dictWord{11, 11, 180},
+ dictWord{11, 11, 837},
+ dictWord{12, 11, 240},
+ dictWord{13, 11, 152},
+ dictWord{13, 11, 219},
+ dictWord{142, 11, 158},
+ dictWord{139, 0, 62},
+ dictWord{132, 10, 515},
+ dictWord{8, 10, 632},
+ dictWord{8, 10, 697},
+ dictWord{
+ 137,
+ 10,
+ 854,
+ },
+ dictWord{134, 0, 1766},
+ dictWord{132, 11, 581},
+ dictWord{6, 11, 126},
+ dictWord{7, 11, 573},
+ dictWord{8, 11, 397},
+ dictWord{142, 11, 44},
+ dictWord{
+ 150,
+ 0,
+ 28,
+ },
+ dictWord{11, 0, 670},
+ dictWord{22, 0, 25},
+ dictWord{4, 10, 136},
+ dictWord{133, 10, 551},
+ dictWord{6, 0, 1665},
+ dictWord{7, 0, 256},
+ dictWord{
+ 7,
+ 0,
+ 1388,
+ },
+ dictWord{138, 0, 499},
+ dictWord{4, 0, 22},
+ dictWord{5, 0, 10},
+ dictWord{7, 0, 1576},
+ dictWord{136, 0, 97},
+ dictWord{134, 10, 1782},
+ dictWord{5, 0, 481},
+ dictWord{7, 10, 1287},
+ dictWord{9, 10, 44},
+ dictWord{10, 10, 552},
+ dictWord{10, 10, 642},
+ dictWord{11, 10, 839},
+ dictWord{12, 10, 274},
+ dictWord{
+ 12,
+ 10,
+ 275,
+ },
+ dictWord{12, 10, 372},
+ dictWord{13, 10, 91},
+ dictWord{142, 10, 125},
+ dictWord{133, 11, 926},
+ dictWord{7, 11, 1232},
+ dictWord{137, 11, 531},
+ dictWord{6, 0, 134},
+ dictWord{7, 0, 437},
+ dictWord{7, 0, 1824},
+ dictWord{9, 0, 37},
+ dictWord{14, 0, 285},
+ dictWord{142, 0, 371},
+ dictWord{7, 0, 486},
+ dictWord{8, 0, 155},
+ dictWord{11, 0, 93},
+ dictWord{140, 0, 164},
+ dictWord{6, 0, 1391},
+ dictWord{134, 0, 1442},
+ dictWord{133, 11, 670},
+ dictWord{133, 0, 591},
+ dictWord{
+ 6,
+ 10,
+ 147,
+ },
+ dictWord{7, 10, 886},
+ dictWord{7, 11, 1957},
+ dictWord{9, 10, 753},
+ dictWord{138, 10, 268},
+ dictWord{5, 0, 380},
+ dictWord{5, 0, 650},
+ dictWord{
+ 7,
+ 0,
+ 1173,
+ },
+ dictWord{136, 0, 310},
+ dictWord{4, 0, 364},
+ dictWord{7, 0, 1156},
+ dictWord{7, 0, 1187},
+ dictWord{137, 0, 409},
+ dictWord{135, 11, 1621},
+ dictWord{
+ 134,
+ 0,
+ 482,
+ },
+ dictWord{133, 11, 506},
+ dictWord{4, 0, 781},
+ dictWord{6, 0, 487},
+ dictWord{7, 0, 926},
+ dictWord{8, 0, 263},
+ dictWord{139, 0, 500},
+ dictWord{
+ 138,
+ 10,
+ 137,
+ },
+ dictWord{135, 11, 242},
+ dictWord{139, 11, 96},
+ dictWord{133, 10, 414},
+ dictWord{135, 10, 1762},
+ dictWord{134, 0, 804},
+ dictWord{5, 11, 834},
+ dictWord{7, 11, 1202},
+ dictWord{8, 11, 14},
+ dictWord{9, 11, 481},
+ dictWord{137, 11, 880},
+ dictWord{134, 10, 599},
+ dictWord{4, 0, 94},
+ dictWord{135, 0, 1265},
+ dictWord{4, 0, 415},
+ dictWord{132, 0, 417},
+ dictWord{5, 0, 348},
+ dictWord{6, 0, 522},
+ dictWord{6, 10, 1749},
+ dictWord{7, 11, 1526},
+ dictWord{138, 11, 465},
+ dictWord{134, 10, 1627},
+ dictWord{132, 0, 1012},
+ dictWord{132, 10, 488},
+ dictWord{4, 11, 357},
+ dictWord{6, 11, 172},
+ dictWord{7, 11, 143},
+ dictWord{
+ 137,
+ 11,
+ 413,
+ },
+ dictWord{4, 10, 83},
+ dictWord{4, 11, 590},
+ dictWord{146, 11, 76},
+ dictWord{140, 10, 676},
+ dictWord{7, 11, 287},
+ dictWord{8, 11, 355},
+ dictWord{
+ 9,
+ 11,
+ 293,
+ },
+ dictWord{137, 11, 743},
+ dictWord{134, 10, 278},
+ dictWord{6, 0, 1803},
+ dictWord{18, 0, 165},
+ dictWord{24, 0, 21},
+ dictWord{5, 11, 169},
+ dictWord{
+ 7,
+ 11,
+ 333,
+ },
+ dictWord{136, 11, 45},
+ dictWord{12, 10, 97},
+ dictWord{140, 11, 97},
+ dictWord{4, 0, 408},
+ dictWord{4, 0, 741},
+ dictWord{135, 0, 500},
+ dictWord{
+ 132,
+ 11,
+ 198,
+ },
+ dictWord{7, 10, 388},
+ dictWord{7, 10, 644},
+ dictWord{139, 10, 781},
+ dictWord{4, 11, 24},
+ dictWord{5, 11, 140},
+ dictWord{5, 11, 185},
+ dictWord{
+ 7,
+ 11,
+ 1500,
+ },
+ dictWord{11, 11, 565},
+ dictWord{139, 11, 838},
+ dictWord{6, 0, 1321},
+ dictWord{9, 0, 257},
+ dictWord{7, 10, 229},
+ dictWord{8, 10, 59},
+ dictWord{
+ 9,
+ 10,
+ 190,
+ },
+ dictWord{10, 10, 378},
+ dictWord{140, 10, 191},
+ dictWord{4, 11, 334},
+ dictWord{133, 11, 593},
+ dictWord{135, 11, 1885},
+ dictWord{134, 0, 1138},
+ dictWord{4, 0, 249},
+ dictWord{6, 0, 73},
+ dictWord{135, 0, 177},
+ dictWord{133, 0, 576},
+ dictWord{142, 0, 231},
+ dictWord{137, 0, 288},
+ dictWord{132, 10, 660},
+ dictWord{7, 10, 1035},
+ dictWord{138, 10, 737},
+ dictWord{135, 0, 1487},
+ dictWord{6, 0, 989},
+ dictWord{9, 0, 433},
+ dictWord{7, 10, 690},
+ dictWord{9, 10, 587},
+ dictWord{140, 10, 521},
+ dictWord{7, 0, 1264},
+ dictWord{7, 0, 1678},
+ dictWord{11, 0, 945},
+ dictWord{12, 0, 341},
+ dictWord{12, 0, 471},
+ dictWord{140, 0, 569},
+ dictWord{132, 11, 709},
+ dictWord{133, 11, 897},
+ dictWord{5, 11, 224},
+ dictWord{13, 11, 174},
+ dictWord{146, 11, 52},
+ dictWord{135, 11, 1840},
+ dictWord{
+ 134,
+ 10,
+ 1744,
+ },
+ dictWord{12, 0, 87},
+ dictWord{16, 0, 74},
+ dictWord{4, 10, 733},
+ dictWord{9, 10, 194},
+ dictWord{10, 10, 92},
+ dictWord{11, 10, 198},
+ dictWord{
+ 12,
+ 10,
+ 84,
+ },
+ dictWord{141, 10, 128},
+ dictWord{140, 0, 779},
+ dictWord{135, 0, 538},
+ dictWord{4, 11, 608},
+ dictWord{133, 11, 497},
+ dictWord{133, 0, 413},
+ dictWord{7, 11, 1375},
+ dictWord{7, 11, 1466},
+ dictWord{138, 11, 331},
+ dictWord{136, 0, 495},
+ dictWord{6, 11, 540},
+ dictWord{136, 11, 136},
+ dictWord{7, 0, 54},
+ dictWord{8, 0, 312},
+ dictWord{10, 0, 191},
+ dictWord{10, 0, 614},
+ dictWord{140, 0, 567},
+ dictWord{6, 0, 468},
+ dictWord{7, 0, 567},
+ dictWord{7, 0, 1478},
+ dictWord{
+ 8,
+ 0,
+ 530,
+ },
+ dictWord{14, 0, 290},
+ dictWord{133, 11, 999},
+ dictWord{4, 11, 299},
+ dictWord{7, 10, 306},
+ dictWord{135, 11, 1004},
+ dictWord{142, 11, 296},
+ dictWord{134, 0, 1484},
+ dictWord{133, 10, 979},
+ dictWord{6, 0, 609},
+ dictWord{9, 0, 815},
+ dictWord{12, 11, 137},
+ dictWord{14, 11, 9},
+ dictWord{14, 11, 24},
+ dictWord{142, 11, 64},
+ dictWord{133, 11, 456},
+ dictWord{6, 0, 484},
+ dictWord{135, 0, 822},
+ dictWord{133, 10, 178},
+ dictWord{136, 11, 180},
+ dictWord{
+ 132,
+ 11,
+ 755,
+ },
+ dictWord{137, 0, 900},
+ dictWord{135, 0, 1335},
+ dictWord{6, 0, 1724},
+ dictWord{135, 0, 2022},
+ dictWord{135, 11, 1139},
+ dictWord{5, 0, 640},
+ dictWord{132, 10, 390},
+ dictWord{6, 0, 1831},
+ dictWord{138, 11, 633},
+ dictWord{135, 11, 566},
+ dictWord{4, 11, 890},
+ dictWord{5, 11, 805},
+ dictWord{5, 11, 819},
+ dictWord{5, 11, 961},
+ dictWord{6, 11, 396},
+ dictWord{6, 11, 1631},
+ dictWord{6, 11, 1678},
+ dictWord{7, 11, 1967},
+ dictWord{7, 11, 2041},
+ dictWord{
+ 9,
+ 11,
+ 630,
+ },
+ dictWord{11, 11, 8},
+ dictWord{11, 11, 1019},
+ dictWord{12, 11, 176},
+ dictWord{13, 11, 225},
+ dictWord{14, 11, 292},
+ dictWord{149, 11, 24},
+ dictWord{
+ 132,
+ 0,
+ 474,
+ },
+ dictWord{134, 0, 1103},
+ dictWord{135, 0, 1504},
+ dictWord{134, 0, 1576},
+ dictWord{6, 0, 961},
+ dictWord{6, 0, 1034},
+ dictWord{140, 0, 655},
+ dictWord{11, 11, 514},
+ dictWord{149, 11, 20},
+ dictWord{5, 0, 305},
+ dictWord{135, 11, 1815},
+ dictWord{7, 11, 1505},
+ dictWord{10, 11, 190},
+ dictWord{
+ 10,
+ 11,
+ 634,
+ },
+ dictWord{11, 11, 792},
+ dictWord{12, 11, 358},
+ dictWord{140, 11, 447},
+ dictWord{5, 11, 0},
+ dictWord{6, 11, 536},
+ dictWord{7, 11, 604},
+ dictWord{
+ 13,
+ 11,
+ 445,
+ },
+ dictWord{145, 11, 126},
+ dictWord{7, 0, 1236},
+ dictWord{133, 10, 105},
+ dictWord{4, 0, 480},
+ dictWord{6, 0, 217},
+ dictWord{6, 0, 302},
+ dictWord{
+ 6,
+ 0,
+ 1642,
+ },
+ dictWord{7, 0, 130},
+ dictWord{7, 0, 837},
+ dictWord{7, 0, 1321},
+ dictWord{7, 0, 1547},
+ dictWord{7, 0, 1657},
+ dictWord{8, 0, 429},
+ dictWord{9, 0, 228},
+ dictWord{13, 0, 289},
+ dictWord{13, 0, 343},
+ dictWord{19, 0, 101},
+ dictWord{6, 11, 232},
+ dictWord{6, 11, 412},
+ dictWord{7, 11, 1074},
+ dictWord{8, 11, 9},
+ dictWord{
+ 8,
+ 11,
+ 157,
+ },
+ dictWord{8, 11, 786},
+ dictWord{9, 11, 196},
+ dictWord{9, 11, 352},
+ dictWord{9, 11, 457},
+ dictWord{10, 11, 337},
+ dictWord{11, 11, 232},
+ dictWord{
+ 11,
+ 11,
+ 877,
+ },
+ dictWord{12, 11, 480},
+ dictWord{140, 11, 546},
+ dictWord{5, 10, 438},
+ dictWord{7, 11, 958},
+ dictWord{9, 10, 694},
+ dictWord{12, 10, 627},
+ dictWord{
+ 13,
+ 11,
+ 38,
+ },
+ dictWord{141, 10, 210},
+ dictWord{4, 11, 382},
+ dictWord{136, 11, 579},
+ dictWord{7, 0, 278},
+ dictWord{10, 0, 739},
+ dictWord{11, 0, 708},
+ dictWord{
+ 141,
+ 0,
+ 348,
+ },
+ dictWord{4, 11, 212},
+ dictWord{135, 11, 1206},
+ dictWord{135, 11, 1898},
+ dictWord{6, 0, 708},
+ dictWord{6, 0, 1344},
+ dictWord{152, 10, 11},
+ dictWord{137, 11, 768},
+ dictWord{134, 0, 1840},
+ dictWord{140, 0, 233},
+ dictWord{8, 10, 25},
+ dictWord{138, 10, 826},
+ dictWord{6, 0, 2017},
+ dictWord{
+ 133,
+ 11,
+ 655,
+ },
+ dictWord{6, 0, 1488},
+ dictWord{139, 11, 290},
+ dictWord{132, 10, 308},
+ dictWord{134, 0, 1590},
+ dictWord{134, 0, 1800},
+ dictWord{134, 0, 1259},
+ dictWord{16, 0, 28},
+ dictWord{6, 11, 231},
+ dictWord{7, 11, 95},
+ dictWord{136, 11, 423},
+ dictWord{133, 11, 300},
+ dictWord{135, 10, 150},
+ dictWord{
+ 136,
+ 10,
+ 649,
+ },
+ dictWord{7, 11, 1874},
+ dictWord{137, 11, 641},
+ dictWord{6, 11, 237},
+ dictWord{7, 11, 611},
+ dictWord{8, 11, 100},
+ dictWord{9, 11, 416},
+ dictWord{
+ 11,
+ 11,
+ 335,
+ },
+ dictWord{12, 11, 173},
+ dictWord{146, 11, 101},
+ dictWord{137, 0, 45},
+ dictWord{134, 10, 521},
+ dictWord{17, 0, 36},
+ dictWord{14, 11, 26},
+ dictWord{
+ 146,
+ 11,
+ 150,
+ },
+ dictWord{7, 0, 1442},
+ dictWord{14, 0, 22},
+ dictWord{5, 10, 339},
+ dictWord{15, 10, 41},
+ dictWord{15, 10, 166},
+ dictWord{147, 10, 66},
+ dictWord{
+ 8,
+ 0,
+ 378,
+ },
+ dictWord{6, 11, 581},
+ dictWord{135, 11, 1119},
+ dictWord{134, 0, 1507},
+ dictWord{147, 11, 117},
+ dictWord{139, 0, 39},
+ dictWord{134, 0, 1054},
+ dictWord{6, 0, 363},
+ dictWord{7, 0, 1955},
+ dictWord{136, 0, 725},
+ dictWord{134, 0, 2036},
+ dictWord{133, 11, 199},
+ dictWord{6, 0, 1871},
+ dictWord{9, 0, 935},
+ dictWord{9, 0, 961},
+ dictWord{9, 0, 1004},
+ dictWord{9, 0, 1016},
+ dictWord{12, 0, 805},
+ dictWord{12, 0, 852},
+ dictWord{12, 0, 853},
+ dictWord{12, 0, 869},
+ dictWord{
+ 12,
+ 0,
+ 882,
+ },
+ dictWord{12, 0, 896},
+ dictWord{12, 0, 906},
+ dictWord{12, 0, 917},
+ dictWord{12, 0, 940},
+ dictWord{15, 0, 170},
+ dictWord{15, 0, 176},
+ dictWord{
+ 15,
+ 0,
+ 188,
+ },
+ dictWord{15, 0, 201},
+ dictWord{15, 0, 205},
+ dictWord{15, 0, 212},
+ dictWord{15, 0, 234},
+ dictWord{15, 0, 244},
+ dictWord{18, 0, 181},
+ dictWord{18, 0, 193},
+ dictWord{18, 0, 196},
+ dictWord{18, 0, 201},
+ dictWord{18, 0, 202},
+ dictWord{18, 0, 210},
+ dictWord{18, 0, 217},
+ dictWord{18, 0, 235},
+ dictWord{18, 0, 236},
+ dictWord{18, 0, 237},
+ dictWord{21, 0, 54},
+ dictWord{21, 0, 55},
+ dictWord{21, 0, 58},
+ dictWord{21, 0, 59},
+ dictWord{152, 0, 22},
+ dictWord{134, 10, 1628},
+ dictWord{
+ 137,
+ 0,
+ 805,
+ },
+ dictWord{5, 0, 813},
+ dictWord{135, 0, 2046},
+ dictWord{142, 11, 42},
+ dictWord{5, 0, 712},
+ dictWord{6, 0, 1240},
+ dictWord{11, 0, 17},
+ dictWord{
+ 13,
+ 0,
+ 321,
+ },
+ dictWord{144, 0, 67},
+ dictWord{132, 0, 617},
+ dictWord{135, 10, 829},
+ dictWord{6, 0, 320},
+ dictWord{7, 0, 781},
+ dictWord{7, 0, 1921},
+ dictWord{9, 0, 55},
+ dictWord{10, 0, 186},
+ dictWord{10, 0, 273},
+ dictWord{10, 0, 664},
+ dictWord{10, 0, 801},
+ dictWord{11, 0, 996},
+ dictWord{11, 0, 997},
+ dictWord{13, 0, 157},
+ dictWord{142, 0, 170},
+ dictWord{136, 0, 271},
+ dictWord{5, 10, 486},
+ dictWord{135, 10, 1349},
+ dictWord{18, 11, 91},
+ dictWord{147, 11, 70},
+ dictWord{10, 0, 445},
+ dictWord{7, 10, 1635},
+ dictWord{8, 10, 17},
+ dictWord{138, 10, 295},
+ dictWord{136, 11, 404},
+ dictWord{7, 0, 103},
+ dictWord{7, 0, 863},
+ dictWord{11, 0, 184},
+ dictWord{145, 0, 62},
+ dictWord{138, 10, 558},
+ dictWord{137, 0, 659},
+ dictWord{6, 11, 312},
+ dictWord{6, 11, 1715},
+ dictWord{10, 11, 584},
+ dictWord{
+ 11,
+ 11,
+ 546,
+ },
+ dictWord{11, 11, 692},
+ dictWord{12, 11, 259},
+ dictWord{12, 11, 295},
+ dictWord{13, 11, 46},
+ dictWord{141, 11, 154},
+ dictWord{134, 0, 676},
+ dictWord{132, 11, 588},
+ dictWord{4, 11, 231},
+ dictWord{5, 11, 61},
+ dictWord{6, 11, 104},
+ dictWord{7, 11, 729},
+ dictWord{7, 11, 964},
+ dictWord{7, 11, 1658},
+ dictWord{140, 11, 414},
+ dictWord{6, 11, 263},
+ dictWord{138, 11, 757},
+ dictWord{11, 0, 337},
+ dictWord{142, 0, 303},
+ dictWord{135, 11, 1363},
+ dictWord{
+ 132,
+ 11,
+ 320,
+ },
+ dictWord{140, 0, 506},
+ dictWord{134, 10, 447},
+ dictWord{5, 0, 77},
+ dictWord{7, 0, 1455},
+ dictWord{10, 0, 843},
+ dictWord{147, 0, 73},
+ dictWord{
+ 7,
+ 10,
+ 577,
+ },
+ dictWord{7, 10, 1432},
+ dictWord{9, 10, 475},
+ dictWord{9, 10, 505},
+ dictWord{9, 10, 526},
+ dictWord{9, 10, 609},
+ dictWord{9, 10, 689},
+ dictWord{
+ 9,
+ 10,
+ 726,
+ },
+ dictWord{9, 10, 735},
+ dictWord{9, 10, 738},
+ dictWord{10, 10, 556},
+ dictWord{10, 10, 674},
+ dictWord{10, 10, 684},
+ dictWord{11, 10, 89},
+ dictWord{
+ 11,
+ 10,
+ 202,
+ },
+ dictWord{11, 10, 272},
+ dictWord{11, 10, 380},
+ dictWord{11, 10, 415},
+ dictWord{11, 10, 505},
+ dictWord{11, 10, 537},
+ dictWord{11, 10, 550},
+ dictWord{11, 10, 562},
+ dictWord{11, 10, 640},
+ dictWord{11, 10, 667},
+ dictWord{11, 10, 688},
+ dictWord{11, 10, 847},
+ dictWord{11, 10, 927},
+ dictWord{
+ 11,
+ 10,
+ 930,
+ },
+ dictWord{11, 10, 940},
+ dictWord{12, 10, 144},
+ dictWord{12, 10, 325},
+ dictWord{12, 10, 329},
+ dictWord{12, 10, 389},
+ dictWord{12, 10, 403},
+ dictWord{
+ 12,
+ 10,
+ 451,
+ },
+ dictWord{12, 10, 515},
+ dictWord{12, 10, 604},
+ dictWord{12, 10, 616},
+ dictWord{12, 10, 626},
+ dictWord{13, 10, 66},
+ dictWord{13, 10, 131},
+ dictWord{13, 10, 167},
+ dictWord{13, 10, 236},
+ dictWord{13, 10, 368},
+ dictWord{13, 10, 411},
+ dictWord{13, 10, 434},
+ dictWord{13, 10, 453},
+ dictWord{
+ 13,
+ 10,
+ 461,
+ },
+ dictWord{13, 10, 474},
+ dictWord{14, 10, 59},
+ dictWord{14, 10, 60},
+ dictWord{14, 10, 139},
+ dictWord{14, 10, 152},
+ dictWord{14, 10, 276},
+ dictWord{
+ 14,
+ 10,
+ 353,
+ },
+ dictWord{14, 10, 402},
+ dictWord{15, 10, 28},
+ dictWord{15, 10, 81},
+ dictWord{15, 10, 123},
+ dictWord{15, 10, 152},
+ dictWord{18, 10, 136},
+ dictWord{148, 10, 88},
+ dictWord{132, 0, 458},
+ dictWord{135, 0, 1420},
+ dictWord{6, 0, 109},
+ dictWord{10, 0, 382},
+ dictWord{4, 11, 405},
+ dictWord{4, 10, 609},
+ dictWord{7, 10, 756},
+ dictWord{7, 11, 817},
+ dictWord{9, 10, 544},
+ dictWord{11, 10, 413},
+ dictWord{14, 11, 58},
+ dictWord{14, 10, 307},
+ dictWord{16, 10, 25},
+ dictWord{17, 11, 37},
+ dictWord{146, 11, 124},
+ dictWord{6, 0, 330},
+ dictWord{7, 0, 1084},
+ dictWord{11, 0, 142},
+ dictWord{133, 11, 974},
+ dictWord{4, 10, 930},
+ dictWord{133, 10, 947},
+ dictWord{5, 10, 939},
+ dictWord{142, 11, 394},
+ dictWord{16, 0, 91},
+ dictWord{145, 0, 87},
+ dictWord{5, 11, 235},
+ dictWord{5, 10, 962},
+ dictWord{7, 11, 1239},
+ dictWord{11, 11, 131},
+ dictWord{140, 11, 370},
+ dictWord{11, 0, 492},
+ dictWord{5, 10, 651},
+ dictWord{8, 10, 170},
+ dictWord{9, 10, 61},
+ dictWord{9, 10, 63},
+ dictWord{10, 10, 23},
+ dictWord{10, 10, 37},
+ dictWord{10, 10, 834},
+ dictWord{11, 10, 4},
+ dictWord{11, 10, 281},
+ dictWord{11, 10, 503},
+ dictWord{
+ 11,
+ 10,
+ 677,
+ },
+ dictWord{12, 10, 96},
+ dictWord{12, 10, 130},
+ dictWord{12, 10, 244},
+ dictWord{14, 10, 5},
+ dictWord{14, 10, 40},
+ dictWord{14, 10, 162},
+ dictWord{
+ 14,
+ 10,
+ 202,
+ },
+ dictWord{146, 10, 133},
+ dictWord{4, 10, 406},
+ dictWord{5, 10, 579},
+ dictWord{12, 10, 492},
+ dictWord{150, 10, 15},
+ dictWord{9, 11, 137},
+ dictWord{138, 11, 221},
+ dictWord{134, 0, 1239},
+ dictWord{11, 0, 211},
+ dictWord{140, 0, 145},
+ dictWord{7, 11, 390},
+ dictWord{138, 11, 140},
+ dictWord{
+ 135,
+ 11,
+ 1418,
+ },
+ dictWord{135, 11, 1144},
+ dictWord{134, 0, 1049},
+ dictWord{7, 0, 321},
+ dictWord{6, 10, 17},
+ dictWord{7, 10, 1001},
+ dictWord{7, 10, 1982},
+ dictWord{
+ 9,
+ 10,
+ 886,
+ },
+ dictWord{10, 10, 489},
+ dictWord{10, 10, 800},
+ dictWord{11, 10, 782},
+ dictWord{12, 10, 320},
+ dictWord{13, 10, 467},
+ dictWord{14, 10, 145},
+ dictWord{14, 10, 387},
+ dictWord{143, 10, 119},
+ dictWord{145, 10, 17},
+ dictWord{5, 11, 407},
+ dictWord{11, 11, 489},
+ dictWord{19, 11, 37},
+ dictWord{20, 11, 73},
+ dictWord{150, 11, 38},
+ dictWord{133, 10, 458},
+ dictWord{135, 0, 1985},
+ dictWord{7, 10, 1983},
+ dictWord{8, 10, 0},
+ dictWord{8, 10, 171},
+ dictWord{
+ 9,
+ 10,
+ 120,
+ },
+ dictWord{9, 10, 732},
+ dictWord{10, 10, 473},
+ dictWord{11, 10, 656},
+ dictWord{11, 10, 998},
+ dictWord{18, 10, 0},
+ dictWord{18, 10, 2},
+ dictWord{
+ 147,
+ 10,
+ 21,
+ },
+ dictWord{5, 11, 325},
+ dictWord{7, 11, 1483},
+ dictWord{8, 11, 5},
+ dictWord{8, 11, 227},
+ dictWord{9, 11, 105},
+ dictWord{10, 11, 585},
+ dictWord{
+ 140,
+ 11,
+ 614,
+ },
+ dictWord{136, 0, 122},
+ dictWord{132, 0, 234},
+ dictWord{135, 11, 1196},
+ dictWord{6, 0, 976},
+ dictWord{6, 0, 1098},
+ dictWord{134, 0, 1441},
+ dictWord{
+ 7,
+ 0,
+ 253,
+ },
+ dictWord{136, 0, 549},
+ dictWord{6, 11, 621},
+ dictWord{13, 11, 504},
+ dictWord{144, 11, 19},
+ dictWord{132, 10, 519},
+ dictWord{5, 0, 430},
+ dictWord{
+ 5,
+ 0,
+ 932,
+ },
+ dictWord{6, 0, 131},
+ dictWord{7, 0, 417},
+ dictWord{9, 0, 522},
+ dictWord{11, 0, 314},
+ dictWord{141, 0, 390},
+ dictWord{14, 0, 149},
+ dictWord{14, 0, 399},
+ dictWord{143, 0, 57},
+ dictWord{5, 10, 907},
+ dictWord{6, 10, 31},
+ dictWord{6, 11, 218},
+ dictWord{7, 10, 491},
+ dictWord{7, 10, 530},
+ dictWord{8, 10, 592},
+ dictWord{11, 10, 53},
+ dictWord{11, 10, 779},
+ dictWord{12, 10, 167},
+ dictWord{12, 10, 411},
+ dictWord{14, 10, 14},
+ dictWord{14, 10, 136},
+ dictWord{15, 10, 72},
+ dictWord{16, 10, 17},
+ dictWord{144, 10, 72},
+ dictWord{140, 11, 330},
+ dictWord{7, 11, 454},
+ dictWord{7, 11, 782},
+ dictWord{136, 11, 768},
+ dictWord{
+ 132,
+ 0,
+ 507,
+ },
+ dictWord{10, 11, 676},
+ dictWord{140, 11, 462},
+ dictWord{6, 0, 630},
+ dictWord{9, 0, 811},
+ dictWord{4, 10, 208},
+ dictWord{5, 10, 106},
+ dictWord{
+ 6,
+ 10,
+ 531,
+ },
+ dictWord{8, 10, 408},
+ dictWord{9, 10, 188},
+ dictWord{138, 10, 572},
+ dictWord{4, 0, 343},
+ dictWord{5, 0, 511},
+ dictWord{134, 10, 1693},
+ dictWord{
+ 134,
+ 11,
+ 164,
+ },
+ dictWord{132, 0, 448},
+ dictWord{7, 0, 455},
+ dictWord{138, 0, 591},
+ dictWord{135, 0, 1381},
+ dictWord{12, 10, 441},
+ dictWord{150, 11, 50},
+ dictWord{9, 10, 449},
+ dictWord{10, 10, 192},
+ dictWord{138, 10, 740},
+ dictWord{6, 0, 575},
+ dictWord{132, 10, 241},
+ dictWord{134, 0, 1175},
+ dictWord{
+ 134,
+ 0,
+ 653,
+ },
+ dictWord{134, 0, 1761},
+ dictWord{134, 0, 1198},
+ dictWord{132, 10, 259},
+ dictWord{6, 11, 343},
+ dictWord{7, 11, 195},
+ dictWord{9, 11, 226},
+ dictWord{
+ 10,
+ 11,
+ 197,
+ },
+ dictWord{10, 11, 575},
+ dictWord{11, 11, 502},
+ dictWord{139, 11, 899},
+ dictWord{7, 0, 1127},
+ dictWord{7, 0, 1572},
+ dictWord{10, 0, 297},
+ dictWord{10, 0, 422},
+ dictWord{11, 0, 764},
+ dictWord{11, 0, 810},
+ dictWord{12, 0, 264},
+ dictWord{13, 0, 102},
+ dictWord{13, 0, 300},
+ dictWord{13, 0, 484},
+ dictWord{
+ 14,
+ 0,
+ 147,
+ },
+ dictWord{14, 0, 229},
+ dictWord{17, 0, 71},
+ dictWord{18, 0, 118},
+ dictWord{147, 0, 120},
+ dictWord{135, 11, 666},
+ dictWord{132, 0, 678},
+ dictWord{
+ 4,
+ 10,
+ 173,
+ },
+ dictWord{5, 10, 312},
+ dictWord{5, 10, 512},
+ dictWord{135, 10, 1285},
+ dictWord{7, 10, 1603},
+ dictWord{7, 10, 1691},
+ dictWord{9, 10, 464},
+ dictWord{11, 10, 195},
+ dictWord{12, 10, 279},
+ dictWord{12, 10, 448},
+ dictWord{14, 10, 11},
+ dictWord{147, 10, 102},
+ dictWord{16, 0, 99},
+ dictWord{146, 0, 164},
+ dictWord{7, 11, 1125},
+ dictWord{9, 11, 143},
+ dictWord{11, 11, 61},
+ dictWord{14, 11, 405},
+ dictWord{150, 11, 21},
+ dictWord{137, 11, 260},
+ dictWord{
+ 4,
+ 10,
+ 452,
+ },
+ dictWord{5, 10, 583},
+ dictWord{5, 10, 817},
+ dictWord{6, 10, 433},
+ dictWord{7, 10, 593},
+ dictWord{7, 10, 720},
+ dictWord{7, 10, 1378},
+ dictWord{
+ 8,
+ 10,
+ 161,
+ },
+ dictWord{9, 10, 284},
+ dictWord{10, 10, 313},
+ dictWord{139, 10, 886},
+ dictWord{132, 10, 547},
+ dictWord{136, 10, 722},
+ dictWord{14, 0, 35},
+ dictWord{142, 0, 191},
+ dictWord{141, 0, 45},
+ dictWord{138, 0, 121},
+ dictWord{132, 0, 125},
+ dictWord{134, 0, 1622},
+ dictWord{133, 11, 959},
+ dictWord{
+ 8,
+ 10,
+ 420,
+ },
+ dictWord{139, 10, 193},
+ dictWord{132, 0, 721},
+ dictWord{135, 10, 409},
+ dictWord{136, 0, 145},
+ dictWord{7, 0, 792},
+ dictWord{8, 0, 147},
+ dictWord{
+ 10,
+ 0,
+ 821,
+ },
+ dictWord{11, 0, 970},
+ dictWord{11, 0, 1021},
+ dictWord{136, 11, 173},
+ dictWord{134, 11, 266},
+ dictWord{132, 0, 715},
+ dictWord{7, 0, 1999},
+ dictWord{138, 10, 308},
+ dictWord{133, 0, 531},
+ dictWord{5, 0, 168},
+ dictWord{5, 0, 930},
+ dictWord{8, 0, 74},
+ dictWord{9, 0, 623},
+ dictWord{12, 0, 500},
+ dictWord{
+ 140,
+ 0,
+ 579,
+ },
+ dictWord{144, 0, 65},
+ dictWord{138, 11, 246},
+ dictWord{6, 0, 220},
+ dictWord{7, 0, 1101},
+ dictWord{13, 0, 105},
+ dictWord{142, 11, 314},
+ dictWord{
+ 5,
+ 10,
+ 1002,
+ },
+ dictWord{136, 10, 745},
+ dictWord{134, 0, 960},
+ dictWord{20, 0, 0},
+ dictWord{148, 11, 0},
+ dictWord{4, 0, 1005},
+ dictWord{4, 10, 239},
+ dictWord{
+ 6,
+ 10,
+ 477,
+ },
+ dictWord{7, 10, 1607},
+ dictWord{11, 10, 68},
+ dictWord{139, 10, 617},
+ dictWord{6, 0, 19},
+ dictWord{7, 0, 1413},
+ dictWord{139, 0, 428},
+ dictWord{
+ 149,
+ 10,
+ 13,
+ },
+ dictWord{7, 0, 96},
+ dictWord{8, 0, 401},
+ dictWord{8, 0, 703},
+ dictWord{9, 0, 896},
+ dictWord{136, 11, 300},
+ dictWord{134, 0, 1595},
+ dictWord{145, 0, 116},
+ dictWord{136, 0, 1021},
+ dictWord{7, 0, 1961},
+ dictWord{7, 0, 1965},
+ dictWord{7, 0, 2030},
+ dictWord{8, 0, 150},
+ dictWord{8, 0, 702},
+ dictWord{8, 0, 737},
+ dictWord{
+ 8,
+ 0,
+ 750,
+ },
+ dictWord{140, 0, 366},
+ dictWord{11, 11, 75},
+ dictWord{142, 11, 267},
+ dictWord{132, 10, 367},
+ dictWord{8, 0, 800},
+ dictWord{9, 0, 148},
+ dictWord{
+ 9,
+ 0,
+ 872,
+ },
+ dictWord{9, 0, 890},
+ dictWord{11, 0, 309},
+ dictWord{11, 0, 1001},
+ dictWord{13, 0, 267},
+ dictWord{13, 0, 323},
+ dictWord{5, 11, 427},
+ dictWord{
+ 5,
+ 11,
+ 734,
+ },
+ dictWord{7, 11, 478},
+ dictWord{136, 11, 52},
+ dictWord{7, 11, 239},
+ dictWord{11, 11, 217},
+ dictWord{142, 11, 165},
+ dictWord{132, 11, 323},
+ dictWord{140, 11, 419},
+ dictWord{13, 0, 299},
+ dictWord{142, 0, 75},
+ dictWord{6, 11, 87},
+ dictWord{6, 11, 1734},
+ dictWord{7, 11, 20},
+ dictWord{7, 11, 1056},
+ dictWord{
+ 8,
+ 11,
+ 732,
+ },
+ dictWord{9, 11, 406},
+ dictWord{9, 11, 911},
+ dictWord{138, 11, 694},
+ dictWord{134, 0, 1383},
+ dictWord{132, 10, 694},
+ dictWord{
+ 133,
+ 11,
+ 613,
+ },
+ dictWord{137, 0, 779},
+ dictWord{4, 0, 598},
+ dictWord{140, 10, 687},
+ dictWord{6, 0, 970},
+ dictWord{135, 0, 424},
+ dictWord{133, 0, 547},
+ dictWord{
+ 7,
+ 11,
+ 32,
+ },
+ dictWord{7, 11, 984},
+ dictWord{8, 11, 85},
+ dictWord{8, 11, 709},
+ dictWord{9, 11, 579},
+ dictWord{9, 11, 847},
+ dictWord{9, 11, 856},
+ dictWord{10, 11, 799},
+ dictWord{11, 11, 258},
+ dictWord{11, 11, 1007},
+ dictWord{12, 11, 331},
+ dictWord{12, 11, 615},
+ dictWord{13, 11, 188},
+ dictWord{13, 11, 435},
+ dictWord{
+ 14,
+ 11,
+ 8,
+ },
+ dictWord{15, 11, 165},
+ dictWord{16, 11, 27},
+ dictWord{148, 11, 40},
+ dictWord{6, 0, 1222},
+ dictWord{134, 0, 1385},
+ dictWord{132, 0, 876},
+ dictWord{
+ 138,
+ 11,
+ 151,
+ },
+ dictWord{135, 10, 213},
+ dictWord{4, 11, 167},
+ dictWord{135, 11, 82},
+ dictWord{133, 0, 133},
+ dictWord{6, 11, 24},
+ dictWord{7, 11, 74},
+ dictWord{
+ 7,
+ 11,
+ 678,
+ },
+ dictWord{137, 11, 258},
+ dictWord{5, 11, 62},
+ dictWord{6, 11, 534},
+ dictWord{7, 11, 684},
+ dictWord{7, 11, 1043},
+ dictWord{7, 11, 1072},
+ dictWord{
+ 8,
+ 11,
+ 280,
+ },
+ dictWord{8, 11, 541},
+ dictWord{8, 11, 686},
+ dictWord{10, 11, 519},
+ dictWord{11, 11, 252},
+ dictWord{140, 11, 282},
+ dictWord{136, 0, 187},
+ dictWord{8, 0, 8},
+ dictWord{10, 0, 0},
+ dictWord{10, 0, 818},
+ dictWord{139, 0, 988},
+ dictWord{132, 11, 359},
+ dictWord{11, 0, 429},
+ dictWord{15, 0, 51},
+ dictWord{
+ 135,
+ 10,
+ 1672,
+ },
+ dictWord{136, 0, 685},
+ dictWord{5, 11, 211},
+ dictWord{7, 11, 88},
+ dictWord{136, 11, 627},
+ dictWord{134, 0, 472},
+ dictWord{136, 0, 132},
+ dictWord{
+ 6,
+ 11,
+ 145,
+ },
+ dictWord{141, 11, 336},
+ dictWord{4, 10, 751},
+ dictWord{11, 10, 390},
+ dictWord{140, 10, 32},
+ dictWord{6, 0, 938},
+ dictWord{6, 0, 1060},
+ dictWord{
+ 4,
+ 11,
+ 263,
+ },
+ dictWord{4, 10, 409},
+ dictWord{133, 10, 78},
+ dictWord{137, 0, 874},
+ dictWord{8, 0, 774},
+ dictWord{10, 0, 670},
+ dictWord{12, 0, 51},
+ dictWord{
+ 4,
+ 11,
+ 916,
+ },
+ dictWord{6, 10, 473},
+ dictWord{7, 10, 1602},
+ dictWord{10, 10, 698},
+ dictWord{12, 10, 212},
+ dictWord{13, 10, 307},
+ dictWord{145, 10, 105},
+ dictWord{146, 0, 92},
+ dictWord{143, 10, 156},
+ dictWord{132, 0, 830},
+ dictWord{137, 0, 701},
+ dictWord{4, 11, 599},
+ dictWord{6, 11, 1634},
+ dictWord{7, 11, 5},
+ dictWord{7, 11, 55},
+ dictWord{7, 11, 67},
+ dictWord{7, 11, 97},
+ dictWord{7, 11, 691},
+ dictWord{7, 11, 979},
+ dictWord{7, 11, 1697},
+ dictWord{8, 11, 207},
+ dictWord{
+ 8,
+ 11,
+ 214,
+ },
+ dictWord{8, 11, 231},
+ dictWord{8, 11, 294},
+ dictWord{8, 11, 336},
+ dictWord{8, 11, 428},
+ dictWord{8, 11, 451},
+ dictWord{8, 11, 460},
+ dictWord{8, 11, 471},
+ dictWord{8, 11, 622},
+ dictWord{8, 11, 626},
+ dictWord{8, 11, 679},
+ dictWord{8, 11, 759},
+ dictWord{8, 11, 829},
+ dictWord{9, 11, 11},
+ dictWord{9, 11, 246},
+ dictWord{
+ 9,
+ 11,
+ 484,
+ },
+ dictWord{9, 11, 573},
+ dictWord{9, 11, 706},
+ dictWord{9, 11, 762},
+ dictWord{9, 11, 798},
+ dictWord{9, 11, 855},
+ dictWord{9, 11, 870},
+ dictWord{
+ 9,
+ 11,
+ 912,
+ },
+ dictWord{10, 11, 303},
+ dictWord{10, 11, 335},
+ dictWord{10, 11, 424},
+ dictWord{10, 11, 461},
+ dictWord{10, 11, 543},
+ dictWord{10, 11, 759},
+ dictWord{10, 11, 814},
+ dictWord{11, 11, 59},
+ dictWord{11, 11, 199},
+ dictWord{11, 11, 235},
+ dictWord{11, 11, 475},
+ dictWord{11, 11, 590},
+ dictWord{11, 11, 929},
+ dictWord{11, 11, 963},
+ dictWord{12, 11, 114},
+ dictWord{12, 11, 182},
+ dictWord{12, 11, 226},
+ dictWord{12, 11, 332},
+ dictWord{12, 11, 439},
+ dictWord{
+ 12,
+ 11,
+ 575,
+ },
+ dictWord{12, 11, 598},
+ dictWord{13, 11, 8},
+ dictWord{13, 11, 125},
+ dictWord{13, 11, 194},
+ dictWord{13, 11, 287},
+ dictWord{14, 11, 197},
+ dictWord{
+ 14,
+ 11,
+ 383,
+ },
+ dictWord{15, 11, 53},
+ dictWord{17, 11, 63},
+ dictWord{19, 11, 46},
+ dictWord{19, 11, 98},
+ dictWord{19, 11, 106},
+ dictWord{148, 11, 85},
+ dictWord{
+ 4,
+ 0,
+ 127,
+ },
+ dictWord{5, 0, 350},
+ dictWord{6, 0, 356},
+ dictWord{8, 0, 426},
+ dictWord{9, 0, 572},
+ dictWord{10, 0, 247},
+ dictWord{139, 0, 312},
+ dictWord{134, 0, 1215},
+ dictWord{6, 0, 59},
+ dictWord{9, 0, 603},
+ dictWord{13, 0, 397},
+ dictWord{7, 11, 1853},
+ dictWord{138, 11, 437},
+ dictWord{134, 0, 1762},
+ dictWord{
+ 147,
+ 11,
+ 126,
+ },
+ dictWord{135, 10, 883},
+ dictWord{13, 0, 293},
+ dictWord{142, 0, 56},
+ dictWord{133, 10, 617},
+ dictWord{139, 10, 50},
+ dictWord{5, 11, 187},
+ dictWord{
+ 7,
+ 10,
+ 1518,
+ },
+ dictWord{139, 10, 694},
+ dictWord{135, 0, 441},
+ dictWord{6, 0, 111},
+ dictWord{7, 0, 4},
+ dictWord{8, 0, 163},
+ dictWord{8, 0, 776},
+ dictWord{
+ 138,
+ 0,
+ 566,
+ },
+ dictWord{132, 0, 806},
+ dictWord{4, 11, 215},
+ dictWord{9, 11, 38},
+ dictWord{10, 11, 3},
+ dictWord{11, 11, 23},
+ dictWord{11, 11, 127},
+ dictWord{
+ 139,
+ 11,
+ 796,
+ },
+ dictWord{14, 0, 233},
+ dictWord{4, 10, 546},
+ dictWord{135, 10, 2042},
+ dictWord{135, 0, 1994},
+ dictWord{134, 0, 1739},
+ dictWord{135, 11, 1530},
+ dictWord{136, 0, 393},
+ dictWord{5, 0, 297},
+ dictWord{7, 0, 1038},
+ dictWord{14, 0, 359},
+ dictWord{19, 0, 52},
+ dictWord{148, 0, 47},
+ dictWord{135, 0, 309},
+ dictWord{
+ 4,
+ 10,
+ 313,
+ },
+ dictWord{133, 10, 577},
+ dictWord{8, 10, 184},
+ dictWord{141, 10, 433},
+ dictWord{135, 10, 935},
+ dictWord{12, 10, 186},
+ dictWord{
+ 12,
+ 10,
+ 292,
+ },
+ dictWord{14, 10, 100},
+ dictWord{146, 10, 70},
+ dictWord{136, 0, 363},
+ dictWord{14, 0, 175},
+ dictWord{11, 10, 402},
+ dictWord{12, 10, 109},
+ dictWord{
+ 12,
+ 10,
+ 431,
+ },
+ dictWord{13, 10, 179},
+ dictWord{13, 10, 206},
+ dictWord{14, 10, 217},
+ dictWord{16, 10, 3},
+ dictWord{148, 10, 53},
+ dictWord{5, 10, 886},
+ dictWord{
+ 6,
+ 10,
+ 46,
+ },
+ dictWord{6, 10, 1790},
+ dictWord{7, 10, 14},
+ dictWord{7, 10, 732},
+ dictWord{7, 10, 1654},
+ dictWord{8, 10, 95},
+ dictWord{8, 10, 327},
+ dictWord{
+ 8,
+ 10,
+ 616,
+ },
+ dictWord{9, 10, 892},
+ dictWord{10, 10, 598},
+ dictWord{10, 10, 769},
+ dictWord{11, 10, 134},
+ dictWord{11, 10, 747},
+ dictWord{12, 10, 378},
+ dictWord{
+ 142,
+ 10,
+ 97,
+ },
+ dictWord{136, 0, 666},
+ dictWord{135, 0, 1675},
+ dictWord{6, 0, 655},
+ dictWord{134, 0, 1600},
+ dictWord{135, 0, 808},
+ dictWord{133, 10, 1021},
+ dictWord{4, 11, 28},
+ dictWord{5, 11, 440},
+ dictWord{7, 11, 248},
+ dictWord{11, 11, 833},
+ dictWord{140, 11, 344},
+ dictWord{134, 11, 1654},
+ dictWord{
+ 132,
+ 0,
+ 280,
+ },
+ dictWord{140, 0, 54},
+ dictWord{4, 0, 421},
+ dictWord{133, 0, 548},
+ dictWord{132, 10, 153},
+ dictWord{6, 11, 339},
+ dictWord{135, 11, 923},
+ dictWord{
+ 133,
+ 11,
+ 853,
+ },
+ dictWord{133, 10, 798},
+ dictWord{132, 10, 587},
+ dictWord{6, 11, 249},
+ dictWord{7, 11, 1234},
+ dictWord{139, 11, 573},
+ dictWord{6, 10, 598},
+ dictWord{7, 10, 42},
+ dictWord{8, 10, 695},
+ dictWord{10, 10, 212},
+ dictWord{11, 10, 158},
+ dictWord{14, 10, 196},
+ dictWord{145, 10, 85},
+ dictWord{7, 0, 249},
+ dictWord{5, 10, 957},
+ dictWord{133, 10, 1008},
+ dictWord{4, 10, 129},
+ dictWord{135, 10, 465},
+ dictWord{6, 0, 254},
+ dictWord{7, 0, 842},
+ dictWord{7, 0, 1659},
+ dictWord{9, 0, 109},
+ dictWord{10, 0, 103},
+ dictWord{7, 10, 908},
+ dictWord{7, 10, 1201},
+ dictWord{9, 10, 755},
+ dictWord{11, 10, 906},
+ dictWord{12, 10, 527},
+ dictWord{146, 10, 7},
+ dictWord{5, 0, 262},
+ dictWord{136, 10, 450},
+ dictWord{144, 0, 1},
+ dictWord{10, 11, 201},
+ dictWord{142, 11, 319},
+ dictWord{7, 11, 49},
+ dictWord{
+ 7,
+ 11,
+ 392,
+ },
+ dictWord{8, 11, 20},
+ dictWord{8, 11, 172},
+ dictWord{8, 11, 690},
+ dictWord{9, 11, 383},
+ dictWord{9, 11, 845},
+ dictWord{10, 11, 48},
+ dictWord{
+ 11,
+ 11,
+ 293,
+ },
+ dictWord{11, 11, 832},
+ dictWord{11, 11, 920},
+ dictWord{141, 11, 221},
+ dictWord{5, 11, 858},
+ dictWord{133, 11, 992},
+ dictWord{134, 0, 805},
+ dictWord{139, 10, 1003},
+ dictWord{6, 0, 1630},
+ dictWord{134, 11, 307},
+ dictWord{7, 11, 1512},
+ dictWord{135, 11, 1794},
+ dictWord{6, 11, 268},
+ dictWord{
+ 137,
+ 11,
+ 62,
+ },
+ dictWord{135, 10, 1868},
+ dictWord{133, 0, 671},
+ dictWord{4, 0, 989},
+ dictWord{8, 0, 972},
+ dictWord{136, 0, 998},
+ dictWord{132, 11, 423},
+ dictWord{132, 0, 889},
+ dictWord{135, 0, 1382},
+ dictWord{135, 0, 1910},
+ dictWord{7, 10, 965},
+ dictWord{7, 10, 1460},
+ dictWord{135, 10, 1604},
+ dictWord{
+ 4,
+ 0,
+ 627,
+ },
+ dictWord{5, 0, 775},
+ dictWord{138, 11, 106},
+ dictWord{134, 11, 348},
+ dictWord{7, 0, 202},
+ dictWord{11, 0, 362},
+ dictWord{11, 0, 948},
+ dictWord{
+ 140,
+ 0,
+ 388,
+ },
+ dictWord{138, 11, 771},
+ dictWord{6, 11, 613},
+ dictWord{136, 11, 223},
+ dictWord{6, 0, 560},
+ dictWord{7, 0, 451},
+ dictWord{8, 0, 389},
+ dictWord{
+ 12,
+ 0,
+ 490,
+ },
+ dictWord{13, 0, 16},
+ dictWord{13, 0, 215},
+ dictWord{13, 0, 351},
+ dictWord{18, 0, 132},
+ dictWord{147, 0, 125},
+ dictWord{135, 0, 841},
+ dictWord{
+ 136,
+ 0,
+ 566,
+ },
+ dictWord{136, 0, 938},
+ dictWord{132, 11, 670},
+ dictWord{5, 0, 912},
+ dictWord{6, 0, 1695},
+ dictWord{140, 11, 55},
+ dictWord{9, 11, 40},
+ dictWord{
+ 139,
+ 11,
+ 136,
+ },
+ dictWord{7, 0, 1361},
+ dictWord{7, 10, 982},
+ dictWord{10, 10, 32},
+ dictWord{143, 10, 56},
+ dictWord{11, 11, 259},
+ dictWord{140, 11, 270},
+ dictWord{
+ 5,
+ 0,
+ 236,
+ },
+ dictWord{6, 0, 572},
+ dictWord{8, 0, 492},
+ dictWord{11, 0, 618},
+ dictWord{144, 0, 56},
+ dictWord{8, 11, 572},
+ dictWord{9, 11, 310},
+ dictWord{9, 11, 682},
+ dictWord{137, 11, 698},
+ dictWord{134, 0, 1854},
+ dictWord{5, 0, 190},
+ dictWord{136, 0, 318},
+ dictWord{133, 10, 435},
+ dictWord{135, 0, 1376},
+ dictWord{
+ 4,
+ 11,
+ 296,
+ },
+ dictWord{6, 11, 352},
+ dictWord{7, 11, 401},
+ dictWord{7, 11, 1410},
+ dictWord{7, 11, 1594},
+ dictWord{7, 11, 1674},
+ dictWord{8, 11, 63},
+ dictWord{
+ 8,
+ 11,
+ 660,
+ },
+ dictWord{137, 11, 74},
+ dictWord{7, 0, 349},
+ dictWord{5, 10, 85},
+ dictWord{6, 10, 419},
+ dictWord{7, 10, 305},
+ dictWord{7, 10, 361},
+ dictWord{7, 10, 1337},
+ dictWord{8, 10, 71},
+ dictWord{140, 10, 519},
+ dictWord{4, 11, 139},
+ dictWord{4, 11, 388},
+ dictWord{140, 11, 188},
+ dictWord{6, 0, 1972},
+ dictWord{6, 0, 2013},
+ dictWord{8, 0, 951},
+ dictWord{10, 0, 947},
+ dictWord{10, 0, 974},
+ dictWord{10, 0, 1018},
+ dictWord{142, 0, 476},
+ dictWord{140, 10, 688},
+ dictWord{
+ 135,
+ 10,
+ 740,
+ },
+ dictWord{5, 10, 691},
+ dictWord{7, 10, 345},
+ dictWord{9, 10, 94},
+ dictWord{140, 10, 169},
+ dictWord{9, 0, 344},
+ dictWord{5, 10, 183},
+ dictWord{6, 10, 582},
+ dictWord{10, 10, 679},
+ dictWord{140, 10, 435},
+ dictWord{135, 10, 511},
+ dictWord{132, 0, 850},
+ dictWord{8, 11, 441},
+ dictWord{10, 11, 314},
+ dictWord{
+ 143,
+ 11,
+ 3,
+ },
+ dictWord{7, 10, 1993},
+ dictWord{136, 10, 684},
+ dictWord{4, 11, 747},
+ dictWord{6, 11, 290},
+ dictWord{6, 10, 583},
+ dictWord{7, 11, 649},
+ dictWord{
+ 7,
+ 11,
+ 1479,
+ },
+ dictWord{135, 11, 1583},
+ dictWord{133, 11, 232},
+ dictWord{133, 10, 704},
+ dictWord{134, 0, 910},
+ dictWord{4, 10, 179},
+ dictWord{5, 10, 198},
+ dictWord{133, 10, 697},
+ dictWord{7, 10, 347},
+ dictWord{7, 10, 971},
+ dictWord{8, 10, 181},
+ dictWord{138, 10, 711},
+ dictWord{136, 11, 525},
+ dictWord{
+ 14,
+ 0,
+ 19,
+ },
+ dictWord{14, 0, 28},
+ dictWord{144, 0, 29},
+ dictWord{7, 0, 85},
+ dictWord{7, 0, 247},
+ dictWord{8, 0, 585},
+ dictWord{138, 0, 163},
+ dictWord{4, 0, 487},
+ dictWord{
+ 7,
+ 11,
+ 472,
+ },
+ dictWord{7, 11, 1801},
+ dictWord{10, 11, 748},
+ dictWord{141, 11, 458},
+ dictWord{4, 10, 243},
+ dictWord{5, 10, 203},
+ dictWord{7, 10, 19},
+ dictWord{
+ 7,
+ 10,
+ 71,
+ },
+ dictWord{7, 10, 113},
+ dictWord{10, 10, 405},
+ dictWord{11, 10, 357},
+ dictWord{142, 10, 240},
+ dictWord{7, 10, 1450},
+ dictWord{139, 10, 99},
+ dictWord{132, 11, 425},
+ dictWord{138, 0, 145},
+ dictWord{147, 0, 83},
+ dictWord{6, 10, 492},
+ dictWord{137, 11, 247},
+ dictWord{4, 0, 1013},
+ dictWord{
+ 134,
+ 0,
+ 2033,
+ },
+ dictWord{5, 10, 134},
+ dictWord{6, 10, 408},
+ dictWord{6, 10, 495},
+ dictWord{135, 10, 1593},
+ dictWord{135, 0, 1922},
+ dictWord{134, 11, 1768},
+ dictWord{4, 0, 124},
+ dictWord{10, 0, 457},
+ dictWord{11, 0, 121},
+ dictWord{11, 0, 169},
+ dictWord{11, 0, 870},
+ dictWord{11, 0, 874},
+ dictWord{12, 0, 214},
+ dictWord{
+ 14,
+ 0,
+ 187,
+ },
+ dictWord{143, 0, 77},
+ dictWord{5, 0, 557},
+ dictWord{135, 0, 1457},
+ dictWord{139, 0, 66},
+ dictWord{5, 11, 943},
+ dictWord{6, 11, 1779},
+ dictWord{
+ 142,
+ 10,
+ 4,
+ },
+ dictWord{4, 10, 248},
+ dictWord{4, 10, 665},
+ dictWord{7, 10, 137},
+ dictWord{137, 10, 349},
+ dictWord{7, 0, 1193},
+ dictWord{5, 11, 245},
+ dictWord{
+ 6,
+ 11,
+ 576,
+ },
+ dictWord{7, 11, 582},
+ dictWord{136, 11, 225},
+ dictWord{144, 0, 82},
+ dictWord{7, 10, 1270},
+ dictWord{139, 10, 612},
+ dictWord{5, 0, 454},
+ dictWord{
+ 10,
+ 0,
+ 352,
+ },
+ dictWord{138, 11, 352},
+ dictWord{18, 0, 57},
+ dictWord{5, 10, 371},
+ dictWord{135, 10, 563},
+ dictWord{135, 0, 1333},
+ dictWord{6, 0, 107},
+ dictWord{
+ 7,
+ 0,
+ 638,
+ },
+ dictWord{7, 0, 1632},
+ dictWord{9, 0, 396},
+ dictWord{134, 11, 610},
+ dictWord{5, 0, 370},
+ dictWord{134, 0, 1756},
+ dictWord{4, 10, 374},
+ dictWord{
+ 7,
+ 10,
+ 547,
+ },
+ dictWord{7, 10, 1700},
+ dictWord{7, 10, 1833},
+ dictWord{139, 10, 858},
+ dictWord{133, 0, 204},
+ dictWord{6, 0, 1305},
+ dictWord{9, 10, 311},
+ dictWord{
+ 141,
+ 10,
+ 42,
+ },
+ dictWord{5, 0, 970},
+ dictWord{134, 0, 1706},
+ dictWord{6, 10, 1647},
+ dictWord{7, 10, 1552},
+ dictWord{7, 10, 2010},
+ dictWord{9, 10, 494},
+ dictWord{137, 10, 509},
+ dictWord{13, 11, 455},
+ dictWord{15, 11, 99},
+ dictWord{15, 11, 129},
+ dictWord{144, 11, 68},
+ dictWord{135, 0, 3},
+ dictWord{4, 0, 35},
+ dictWord{
+ 5,
+ 0,
+ 121,
+ },
+ dictWord{5, 0, 483},
+ dictWord{5, 0, 685},
+ dictWord{6, 0, 489},
+ dictWord{6, 0, 782},
+ dictWord{6, 0, 1032},
+ dictWord{7, 0, 1204},
+ dictWord{136, 0, 394},
+ dictWord{4, 0, 921},
+ dictWord{133, 0, 1007},
+ dictWord{8, 11, 360},
+ dictWord{138, 11, 63},
+ dictWord{135, 0, 1696},
+ dictWord{134, 0, 1519},
+ dictWord{
+ 132,
+ 11,
+ 443,
+ },
+ dictWord{135, 11, 944},
+ dictWord{6, 10, 123},
+ dictWord{7, 10, 214},
+ dictWord{9, 10, 728},
+ dictWord{10, 10, 157},
+ dictWord{11, 10, 346},
+ dictWord{11, 10, 662},
+ dictWord{143, 10, 106},
+ dictWord{137, 0, 981},
+ dictWord{135, 10, 1435},
+ dictWord{134, 0, 1072},
+ dictWord{132, 0, 712},
+ dictWord{
+ 134,
+ 0,
+ 1629,
+ },
+ dictWord{134, 0, 728},
+ dictWord{4, 11, 298},
+ dictWord{137, 11, 483},
+ dictWord{6, 0, 1177},
+ dictWord{6, 0, 1271},
+ dictWord{5, 11, 164},
+ dictWord{
+ 7,
+ 11,
+ 121,
+ },
+ dictWord{142, 11, 189},
+ dictWord{7, 0, 1608},
+ dictWord{4, 10, 707},
+ dictWord{5, 10, 588},
+ dictWord{6, 10, 393},
+ dictWord{13, 10, 106},
+ dictWord{
+ 18,
+ 10,
+ 49,
+ },
+ dictWord{147, 10, 41},
+ dictWord{23, 0, 16},
+ dictWord{151, 11, 16},
+ dictWord{6, 10, 211},
+ dictWord{7, 10, 1690},
+ dictWord{11, 10, 486},
+ dictWord{140, 10, 369},
+ dictWord{133, 0, 485},
+ dictWord{19, 11, 15},
+ dictWord{149, 11, 27},
+ dictWord{4, 11, 172},
+ dictWord{9, 11, 611},
+ dictWord{10, 11, 436},
+ dictWord{12, 11, 673},
+ dictWord{141, 11, 255},
+ dictWord{5, 11, 844},
+ dictWord{10, 11, 484},
+ dictWord{11, 11, 754},
+ dictWord{12, 11, 457},
+ dictWord{
+ 14,
+ 11,
+ 171,
+ },
+ dictWord{14, 11, 389},
+ dictWord{146, 11, 153},
+ dictWord{4, 0, 285},
+ dictWord{5, 0, 27},
+ dictWord{5, 0, 317},
+ dictWord{6, 0, 301},
+ dictWord{7, 0, 7},
+ dictWord{
+ 8,
+ 0,
+ 153,
+ },
+ dictWord{10, 0, 766},
+ dictWord{11, 0, 468},
+ dictWord{12, 0, 467},
+ dictWord{141, 0, 143},
+ dictWord{134, 0, 1462},
+ dictWord{9, 11, 263},
+ dictWord{
+ 10,
+ 11,
+ 147,
+ },
+ dictWord{138, 11, 492},
+ dictWord{133, 11, 537},
+ dictWord{6, 0, 1945},
+ dictWord{6, 0, 1986},
+ dictWord{6, 0, 1991},
+ dictWord{134, 0, 2038},
+ dictWord{134, 10, 219},
+ dictWord{137, 11, 842},
+ dictWord{14, 0, 52},
+ dictWord{17, 0, 50},
+ dictWord{5, 10, 582},
+ dictWord{6, 10, 1646},
+ dictWord{7, 10, 99},
+ dictWord{7, 10, 1962},
+ dictWord{7, 10, 1986},
+ dictWord{8, 10, 515},
+ dictWord{8, 10, 773},
+ dictWord{9, 10, 23},
+ dictWord{9, 10, 491},
+ dictWord{12, 10, 620},
+ dictWord{142, 10, 93},
+ dictWord{138, 11, 97},
+ dictWord{20, 0, 21},
+ dictWord{20, 0, 44},
+ dictWord{133, 10, 851},
+ dictWord{136, 0, 819},
+ dictWord{139, 0, 917},
+ dictWord{5, 11, 230},
+ dictWord{5, 11, 392},
+ dictWord{6, 11, 420},
+ dictWord{8, 10, 762},
+ dictWord{8, 10, 812},
+ dictWord{9, 11, 568},
+ dictWord{9, 10, 910},
+ dictWord{140, 11, 612},
+ dictWord{135, 0, 784},
+ dictWord{15, 0, 135},
+ dictWord{143, 11, 135},
+ dictWord{10, 0, 454},
+ dictWord{140, 0, 324},
+ dictWord{4, 11, 0},
+ dictWord{5, 11, 41},
+ dictWord{7, 11, 1459},
+ dictWord{7, 11, 1469},
+ dictWord{7, 11, 1618},
+ dictWord{7, 11, 1859},
+ dictWord{9, 11, 549},
+ dictWord{139, 11, 905},
+ dictWord{4, 10, 98},
+ dictWord{7, 10, 1365},
+ dictWord{9, 10, 422},
+ dictWord{9, 10, 670},
+ dictWord{10, 10, 775},
+ dictWord{11, 10, 210},
+ dictWord{13, 10, 26},
+ dictWord{13, 10, 457},
+ dictWord{141, 10, 476},
+ dictWord{6, 0, 1719},
+ dictWord{6, 0, 1735},
+ dictWord{7, 0, 2016},
+ dictWord{7, 0, 2020},
+ dictWord{8, 0, 837},
+ dictWord{137, 0, 852},
+ dictWord{133, 11, 696},
+ dictWord{135, 0, 852},
+ dictWord{132, 0, 952},
+ dictWord{134, 10, 1730},
+ dictWord{132, 11, 771},
+ dictWord{
+ 138,
+ 0,
+ 568,
+ },
+ dictWord{137, 0, 448},
+ dictWord{139, 0, 146},
+ dictWord{8, 0, 67},
+ dictWord{138, 0, 419},
+ dictWord{133, 11, 921},
+ dictWord{137, 10, 147},
+ dictWord{134, 0, 1826},
+ dictWord{10, 0, 657},
+ dictWord{14, 0, 297},
+ dictWord{142, 0, 361},
+ dictWord{6, 0, 666},
+ dictWord{6, 0, 767},
+ dictWord{134, 0, 1542},
+ dictWord{139, 0, 729},
+ dictWord{6, 11, 180},
+ dictWord{7, 11, 1137},
+ dictWord{8, 11, 751},
+ dictWord{139, 11, 805},
+ dictWord{4, 11, 183},
+ dictWord{7, 11, 271},
+ dictWord{11, 11, 824},
+ dictWord{11, 11, 952},
+ dictWord{13, 11, 278},
+ dictWord{13, 11, 339},
+ dictWord{13, 11, 482},
+ dictWord{14, 11, 424},
+ dictWord{
+ 148,
+ 11,
+ 99,
+ },
+ dictWord{4, 0, 669},
+ dictWord{5, 11, 477},
+ dictWord{5, 11, 596},
+ dictWord{6, 11, 505},
+ dictWord{7, 11, 1221},
+ dictWord{11, 11, 907},
+ dictWord{
+ 12,
+ 11,
+ 209,
+ },
+ dictWord{141, 11, 214},
+ dictWord{135, 11, 1215},
+ dictWord{5, 0, 402},
+ dictWord{6, 10, 30},
+ dictWord{11, 10, 56},
+ dictWord{139, 10, 305},
+ dictWord{
+ 7,
+ 11,
+ 564,
+ },
+ dictWord{142, 11, 168},
+ dictWord{139, 0, 152},
+ dictWord{7, 0, 912},
+ dictWord{135, 10, 1614},
+ dictWord{4, 10, 150},
+ dictWord{5, 10, 303},
+ dictWord{134, 10, 327},
+ dictWord{7, 0, 320},
+ dictWord{8, 0, 51},
+ dictWord{9, 0, 868},
+ dictWord{10, 0, 833},
+ dictWord{12, 0, 481},
+ dictWord{12, 0, 570},
+ dictWord{
+ 148,
+ 0,
+ 106,
+ },
+ dictWord{132, 0, 445},
+ dictWord{7, 11, 274},
+ dictWord{11, 11, 263},
+ dictWord{11, 11, 479},
+ dictWord{11, 11, 507},
+ dictWord{140, 11, 277},
+ dictWord{10, 0, 555},
+ dictWord{11, 0, 308},
+ dictWord{19, 0, 95},
+ dictWord{6, 11, 1645},
+ dictWord{8, 10, 192},
+ dictWord{10, 10, 78},
+ dictWord{141, 10, 359},
+ dictWord{135, 10, 786},
+ dictWord{6, 11, 92},
+ dictWord{6, 11, 188},
+ dictWord{7, 11, 1269},
+ dictWord{7, 11, 1524},
+ dictWord{7, 11, 1876},
+ dictWord{10, 11, 228},
+ dictWord{139, 11, 1020},
+ dictWord{4, 11, 459},
+ dictWord{133, 11, 966},
+ dictWord{11, 0, 386},
+ dictWord{6, 10, 1638},
+ dictWord{7, 10, 79},
+ dictWord{
+ 7,
+ 10,
+ 496,
+ },
+ dictWord{9, 10, 138},
+ dictWord{10, 10, 336},
+ dictWord{12, 10, 412},
+ dictWord{12, 10, 440},
+ dictWord{142, 10, 305},
+ dictWord{133, 0, 239},
+ dictWord{
+ 7,
+ 0,
+ 83,
+ },
+ dictWord{7, 0, 1990},
+ dictWord{8, 0, 130},
+ dictWord{139, 0, 720},
+ dictWord{138, 11, 709},
+ dictWord{4, 0, 143},
+ dictWord{5, 0, 550},
+ dictWord{
+ 133,
+ 0,
+ 752,
+ },
+ dictWord{5, 0, 123},
+ dictWord{6, 0, 530},
+ dictWord{7, 0, 348},
+ dictWord{135, 0, 1419},
+ dictWord{135, 0, 2024},
+ dictWord{6, 11, 18},
+ dictWord{7, 11, 179},
+ dictWord{7, 11, 721},
+ dictWord{7, 11, 932},
+ dictWord{8, 11, 548},
+ dictWord{8, 11, 757},
+ dictWord{9, 11, 54},
+ dictWord{9, 11, 65},
+ dictWord{9, 11, 532},
+ dictWord{
+ 9,
+ 11,
+ 844,
+ },
+ dictWord{10, 11, 113},
+ dictWord{10, 11, 117},
+ dictWord{10, 11, 236},
+ dictWord{10, 11, 315},
+ dictWord{10, 11, 430},
+ dictWord{10, 11, 798},
+ dictWord{11, 11, 153},
+ dictWord{11, 11, 351},
+ dictWord{11, 11, 375},
+ dictWord{12, 11, 78},
+ dictWord{12, 11, 151},
+ dictWord{12, 11, 392},
+ dictWord{
+ 14,
+ 11,
+ 248,
+ },
+ dictWord{143, 11, 23},
+ dictWord{7, 10, 204},
+ dictWord{7, 10, 415},
+ dictWord{8, 10, 42},
+ dictWord{10, 10, 85},
+ dictWord{139, 10, 564},
+ dictWord{
+ 134,
+ 0,
+ 958,
+ },
+ dictWord{133, 11, 965},
+ dictWord{132, 0, 210},
+ dictWord{135, 11, 1429},
+ dictWord{138, 11, 480},
+ dictWord{134, 11, 182},
+ dictWord{
+ 139,
+ 11,
+ 345,
+ },
+ dictWord{10, 11, 65},
+ dictWord{10, 11, 488},
+ dictWord{138, 11, 497},
+ dictWord{4, 10, 3},
+ dictWord{5, 10, 247},
+ dictWord{5, 10, 644},
+ dictWord{
+ 7,
+ 10,
+ 744,
+ },
+ dictWord{7, 10, 1207},
+ dictWord{7, 10, 1225},
+ dictWord{7, 10, 1909},
+ dictWord{146, 10, 147},
+ dictWord{132, 0, 430},
+ dictWord{5, 10, 285},
+ dictWord{
+ 9,
+ 10,
+ 67,
+ },
+ dictWord{13, 10, 473},
+ dictWord{143, 10, 82},
+ dictWord{144, 11, 16},
+ dictWord{7, 11, 1162},
+ dictWord{9, 11, 588},
+ dictWord{10, 11, 260},
+ dictWord{151, 10, 8},
+ dictWord{133, 0, 213},
+ dictWord{138, 0, 7},
+ dictWord{135, 0, 801},
+ dictWord{134, 11, 1786},
+ dictWord{135, 11, 308},
+ dictWord{6, 0, 936},
+ dictWord{134, 0, 1289},
+ dictWord{133, 0, 108},
+ dictWord{132, 0, 885},
+ dictWord{133, 0, 219},
+ dictWord{139, 0, 587},
+ dictWord{4, 0, 193},
+ dictWord{5, 0, 916},
+ dictWord{6, 0, 1041},
+ dictWord{7, 0, 364},
+ dictWord{10, 0, 398},
+ dictWord{10, 0, 726},
+ dictWord{11, 0, 317},
+ dictWord{11, 0, 626},
+ dictWord{12, 0, 142},
+ dictWord{12, 0, 288},
+ dictWord{12, 0, 678},
+ dictWord{13, 0, 313},
+ dictWord{15, 0, 113},
+ dictWord{146, 0, 114},
+ dictWord{135, 0, 1165},
+ dictWord{6, 0, 241},
+ dictWord{
+ 9,
+ 0,
+ 342,
+ },
+ dictWord{10, 0, 729},
+ dictWord{11, 0, 284},
+ dictWord{11, 0, 445},
+ dictWord{11, 0, 651},
+ dictWord{11, 0, 863},
+ dictWord{13, 0, 398},
+ dictWord{
+ 146,
+ 0,
+ 99,
+ },
+ dictWord{7, 0, 907},
+ dictWord{136, 0, 832},
+ dictWord{9, 0, 303},
+ dictWord{4, 10, 29},
+ dictWord{6, 10, 532},
+ dictWord{7, 10, 1628},
+ dictWord{7, 10, 1648},
+ dictWord{9, 10, 350},
+ dictWord{10, 10, 433},
+ dictWord{11, 10, 97},
+ dictWord{11, 10, 557},
+ dictWord{11, 10, 745},
+ dictWord{12, 10, 289},
+ dictWord{
+ 12,
+ 10,
+ 335,
+ },
+ dictWord{12, 10, 348},
+ dictWord{12, 10, 606},
+ dictWord{13, 10, 116},
+ dictWord{13, 10, 233},
+ dictWord{13, 10, 466},
+ dictWord{14, 10, 181},
+ dictWord{
+ 14,
+ 10,
+ 209,
+ },
+ dictWord{14, 10, 232},
+ dictWord{14, 10, 236},
+ dictWord{14, 10, 300},
+ dictWord{16, 10, 41},
+ dictWord{148, 10, 97},
+ dictWord{7, 11, 423},
+ dictWord{7, 10, 1692},
+ dictWord{136, 11, 588},
+ dictWord{6, 0, 931},
+ dictWord{134, 0, 1454},
+ dictWord{5, 10, 501},
+ dictWord{7, 10, 1704},
+ dictWord{9, 10, 553},
+ dictWord{11, 10, 520},
+ dictWord{12, 10, 557},
+ dictWord{141, 10, 249},
+ dictWord{136, 11, 287},
+ dictWord{4, 0, 562},
+ dictWord{9, 0, 254},
+ dictWord{
+ 139,
+ 0,
+ 879,
+ },
+ dictWord{132, 0, 786},
+ dictWord{14, 11, 32},
+ dictWord{18, 11, 85},
+ dictWord{20, 11, 2},
+ dictWord{152, 11, 16},
+ dictWord{135, 0, 1294},
+ dictWord{
+ 7,
+ 11,
+ 723,
+ },
+ dictWord{135, 11, 1135},
+ dictWord{6, 0, 216},
+ dictWord{7, 0, 901},
+ dictWord{7, 0, 1343},
+ dictWord{8, 0, 493},
+ dictWord{134, 11, 403},
+ dictWord{
+ 7,
+ 11,
+ 719,
+ },
+ dictWord{8, 11, 809},
+ dictWord{136, 11, 834},
+ dictWord{5, 11, 210},
+ dictWord{6, 11, 213},
+ dictWord{7, 11, 60},
+ dictWord{10, 11, 364},
+ dictWord{
+ 139,
+ 11,
+ 135,
+ },
+ dictWord{7, 0, 341},
+ dictWord{11, 0, 219},
+ dictWord{5, 11, 607},
+ dictWord{8, 11, 326},
+ dictWord{136, 11, 490},
+ dictWord{4, 11, 701},
+ dictWord{
+ 5,
+ 11,
+ 472,
+ },
+ dictWord{5, 11, 639},
+ dictWord{7, 11, 1249},
+ dictWord{9, 11, 758},
+ dictWord{139, 11, 896},
+ dictWord{135, 11, 380},
+ dictWord{135, 11, 1947},
+ dictWord{139, 0, 130},
+ dictWord{135, 0, 1734},
+ dictWord{10, 0, 115},
+ dictWord{11, 0, 420},
+ dictWord{12, 0, 154},
+ dictWord{13, 0, 404},
+ dictWord{14, 0, 346},
+ dictWord{143, 0, 54},
+ dictWord{134, 10, 129},
+ dictWord{4, 11, 386},
+ dictWord{7, 11, 41},
+ dictWord{8, 11, 405},
+ dictWord{9, 11, 497},
+ dictWord{11, 11, 110},
+ dictWord{11, 11, 360},
+ dictWord{15, 11, 37},
+ dictWord{144, 11, 84},
+ dictWord{141, 11, 282},
+ dictWord{5, 11, 46},
+ dictWord{7, 11, 1452},
+ dictWord{7, 11, 1480},
+ dictWord{8, 11, 634},
+ dictWord{140, 11, 472},
+ dictWord{4, 11, 524},
+ dictWord{136, 11, 810},
+ dictWord{10, 11, 238},
+ dictWord{141, 11, 33},
+ dictWord{
+ 133,
+ 0,
+ 604,
+ },
+ dictWord{5, 0, 1011},
+ dictWord{136, 0, 701},
+ dictWord{8, 0, 856},
+ dictWord{8, 0, 858},
+ dictWord{8, 0, 879},
+ dictWord{12, 0, 702},
+ dictWord{142, 0, 447},
+ dictWord{4, 0, 54},
+ dictWord{5, 0, 666},
+ dictWord{7, 0, 1039},
+ dictWord{7, 0, 1130},
+ dictWord{9, 0, 195},
+ dictWord{138, 0, 302},
+ dictWord{4, 10, 25},
+ dictWord{
+ 5,
+ 10,
+ 60,
+ },
+ dictWord{6, 10, 504},
+ dictWord{7, 10, 614},
+ dictWord{7, 10, 1155},
+ dictWord{140, 10, 0},
+ dictWord{7, 10, 1248},
+ dictWord{11, 10, 621},
+ dictWord{
+ 139,
+ 10,
+ 702,
+ },
+ dictWord{133, 11, 997},
+ dictWord{137, 10, 321},
+ dictWord{134, 0, 1669},
+ dictWord{134, 0, 1791},
+ dictWord{4, 10, 379},
+ dictWord{
+ 135,
+ 10,
+ 1397,
+ },
+ dictWord{138, 11, 372},
+ dictWord{5, 11, 782},
+ dictWord{5, 11, 829},
+ dictWord{134, 11, 1738},
+ dictWord{135, 0, 1228},
+ dictWord{4, 10, 118},
+ dictWord{6, 10, 274},
+ dictWord{6, 10, 361},
+ dictWord{7, 10, 75},
+ dictWord{141, 10, 441},
+ dictWord{132, 0, 623},
+ dictWord{9, 11, 279},
+ dictWord{10, 11, 407},
+ dictWord{14, 11, 84},
+ dictWord{150, 11, 18},
+ dictWord{137, 10, 841},
+ dictWord{135, 0, 798},
+ dictWord{140, 10, 693},
+ dictWord{5, 10, 314},
+ dictWord{6, 10, 221},
+ dictWord{7, 10, 419},
+ dictWord{10, 10, 650},
+ dictWord{11, 10, 396},
+ dictWord{12, 10, 156},
+ dictWord{13, 10, 369},
+ dictWord{14, 10, 333},
+ dictWord{
+ 145,
+ 10,
+ 47,
+ },
+ dictWord{135, 11, 1372},
+ dictWord{7, 0, 122},
+ dictWord{9, 0, 259},
+ dictWord{10, 0, 84},
+ dictWord{11, 0, 470},
+ dictWord{12, 0, 541},
+ dictWord{
+ 141,
+ 0,
+ 379,
+ },
+ dictWord{134, 0, 837},
+ dictWord{8, 0, 1013},
+ dictWord{4, 11, 78},
+ dictWord{5, 11, 96},
+ dictWord{5, 11, 182},
+ dictWord{7, 11, 1724},
+ dictWord{
+ 7,
+ 11,
+ 1825,
+ },
+ dictWord{10, 11, 394},
+ dictWord{10, 11, 471},
+ dictWord{11, 11, 532},
+ dictWord{14, 11, 340},
+ dictWord{145, 11, 88},
+ dictWord{134, 0, 577},
+ dictWord{135, 11, 1964},
+ dictWord{132, 10, 913},
+ dictWord{134, 0, 460},
+ dictWord{8, 0, 891},
+ dictWord{10, 0, 901},
+ dictWord{10, 0, 919},
+ dictWord{10, 0, 932},
+ dictWord{12, 0, 715},
+ dictWord{12, 0, 728},
+ dictWord{12, 0, 777},
+ dictWord{14, 0, 457},
+ dictWord{144, 0, 103},
+ dictWord{5, 0, 82},
+ dictWord{5, 0, 131},
+ dictWord{
+ 7,
+ 0,
+ 1755,
+ },
+ dictWord{8, 0, 31},
+ dictWord{9, 0, 168},
+ dictWord{9, 0, 764},
+ dictWord{139, 0, 869},
+ dictWord{136, 10, 475},
+ dictWord{6, 0, 605},
+ dictWord{
+ 5,
+ 10,
+ 1016,
+ },
+ dictWord{9, 11, 601},
+ dictWord{9, 11, 619},
+ dictWord{10, 11, 505},
+ dictWord{10, 11, 732},
+ dictWord{11, 11, 355},
+ dictWord{140, 11, 139},
+ dictWord{
+ 7,
+ 10,
+ 602,
+ },
+ dictWord{8, 10, 179},
+ dictWord{10, 10, 781},
+ dictWord{140, 10, 126},
+ dictWord{134, 0, 1246},
+ dictWord{6, 10, 329},
+ dictWord{138, 10, 111},
+ dictWord{6, 11, 215},
+ dictWord{7, 11, 1028},
+ dictWord{7, 11, 1473},
+ dictWord{7, 11, 1721},
+ dictWord{9, 11, 424},
+ dictWord{138, 11, 779},
+ dictWord{5, 0, 278},
+ dictWord{137, 0, 68},
+ dictWord{6, 0, 932},
+ dictWord{6, 0, 1084},
+ dictWord{144, 0, 86},
+ dictWord{4, 0, 163},
+ dictWord{5, 0, 201},
+ dictWord{5, 0, 307},
+ dictWord{
+ 5,
+ 0,
+ 310,
+ },
+ dictWord{6, 0, 335},
+ dictWord{7, 0, 284},
+ dictWord{7, 0, 1660},
+ dictWord{136, 0, 165},
+ dictWord{136, 0, 781},
+ dictWord{134, 0, 707},
+ dictWord{6, 0, 33},
+ dictWord{135, 0, 1244},
+ dictWord{5, 10, 821},
+ dictWord{6, 11, 67},
+ dictWord{6, 10, 1687},
+ dictWord{7, 11, 258},
+ dictWord{7, 11, 1630},
+ dictWord{9, 11, 354},
+ dictWord{9, 11, 675},
+ dictWord{10, 11, 830},
+ dictWord{14, 11, 80},
+ dictWord{145, 11, 80},
+ dictWord{6, 11, 141},
+ dictWord{7, 11, 225},
+ dictWord{9, 11, 59},
+ dictWord{9, 11, 607},
+ dictWord{10, 11, 312},
+ dictWord{11, 11, 687},
+ dictWord{12, 11, 555},
+ dictWord{13, 11, 373},
+ dictWord{13, 11, 494},
+ dictWord{148, 11, 58},
+ dictWord{134, 0, 1113},
+ dictWord{9, 0, 388},
+ dictWord{5, 10, 71},
+ dictWord{7, 10, 1407},
+ dictWord{9, 10, 704},
+ dictWord{10, 10, 261},
+ dictWord{10, 10, 619},
+ dictWord{11, 10, 547},
+ dictWord{11, 10, 619},
+ dictWord{143, 10, 157},
+ dictWord{7, 0, 1953},
+ dictWord{136, 0, 720},
+ dictWord{138, 0, 203},
+ dictWord{
+ 7,
+ 10,
+ 2008,
+ },
+ dictWord{9, 10, 337},
+ dictWord{138, 10, 517},
+ dictWord{6, 0, 326},
+ dictWord{7, 0, 677},
+ dictWord{137, 0, 425},
+ dictWord{139, 11, 81},
+ dictWord{
+ 7,
+ 0,
+ 1316,
+ },
+ dictWord{7, 0, 1412},
+ dictWord{7, 0, 1839},
+ dictWord{9, 0, 589},
+ dictWord{11, 0, 241},
+ dictWord{11, 0, 676},
+ dictWord{11, 0, 811},
+ dictWord{11, 0, 891},
+ dictWord{12, 0, 140},
+ dictWord{12, 0, 346},
+ dictWord{12, 0, 479},
+ dictWord{13, 0, 140},
+ dictWord{13, 0, 381},
+ dictWord{14, 0, 188},
+ dictWord{18, 0, 30},
+ dictWord{148, 0, 108},
+ dictWord{5, 0, 416},
+ dictWord{6, 10, 86},
+ dictWord{6, 10, 603},
+ dictWord{7, 10, 292},
+ dictWord{7, 10, 561},
+ dictWord{8, 10, 257},
+ dictWord{
+ 8,
+ 10,
+ 382,
+ },
+ dictWord{9, 10, 721},
+ dictWord{9, 10, 778},
+ dictWord{11, 10, 581},
+ dictWord{140, 10, 466},
+ dictWord{4, 10, 486},
+ dictWord{133, 10, 491},
+ dictWord{134, 0, 1300},
+ dictWord{132, 10, 72},
+ dictWord{7, 0, 847},
+ dictWord{6, 10, 265},
+ dictWord{7, 11, 430},
+ dictWord{139, 11, 46},
+ dictWord{5, 11, 602},
+ dictWord{6, 11, 106},
+ dictWord{7, 11, 1786},
+ dictWord{7, 11, 1821},
+ dictWord{7, 11, 2018},
+ dictWord{9, 11, 418},
+ dictWord{137, 11, 763},
+ dictWord{5, 0, 358},
+ dictWord{7, 0, 535},
+ dictWord{7, 0, 1184},
+ dictWord{10, 0, 662},
+ dictWord{13, 0, 212},
+ dictWord{13, 0, 304},
+ dictWord{13, 0, 333},
+ dictWord{145, 0, 98},
+ dictWord{
+ 5,
+ 11,
+ 65,
+ },
+ dictWord{6, 11, 416},
+ dictWord{7, 11, 1720},
+ dictWord{7, 11, 1924},
+ dictWord{8, 11, 677},
+ dictWord{10, 11, 109},
+ dictWord{11, 11, 14},
+ dictWord{
+ 11,
+ 11,
+ 70,
+ },
+ dictWord{11, 11, 569},
+ dictWord{11, 11, 735},
+ dictWord{15, 11, 153},
+ dictWord{148, 11, 80},
+ dictWord{6, 0, 1823},
+ dictWord{8, 0, 839},
+ dictWord{
+ 8,
+ 0,
+ 852,
+ },
+ dictWord{8, 0, 903},
+ dictWord{10, 0, 940},
+ dictWord{12, 0, 707},
+ dictWord{140, 0, 775},
+ dictWord{135, 11, 1229},
+ dictWord{6, 0, 1522},
+ dictWord{
+ 140,
+ 0,
+ 654,
+ },
+ dictWord{136, 11, 595},
+ dictWord{139, 0, 163},
+ dictWord{141, 0, 314},
+ dictWord{132, 0, 978},
+ dictWord{4, 0, 601},
+ dictWord{6, 0, 2035},
+ dictWord{137, 10, 234},
+ dictWord{5, 10, 815},
+ dictWord{6, 10, 1688},
+ dictWord{134, 10, 1755},
+ dictWord{133, 0, 946},
+ dictWord{136, 0, 434},
+ dictWord{
+ 6,
+ 10,
+ 197,
+ },
+ dictWord{136, 10, 205},
+ dictWord{7, 0, 411},
+ dictWord{7, 0, 590},
+ dictWord{8, 0, 631},
+ dictWord{9, 0, 323},
+ dictWord{10, 0, 355},
+ dictWord{11, 0, 491},
+ dictWord{12, 0, 143},
+ dictWord{12, 0, 402},
+ dictWord{13, 0, 73},
+ dictWord{14, 0, 408},
+ dictWord{15, 0, 107},
+ dictWord{146, 0, 71},
+ dictWord{7, 0, 1467},
+ dictWord{
+ 8,
+ 0,
+ 328,
+ },
+ dictWord{10, 0, 544},
+ dictWord{11, 0, 955},
+ dictWord{12, 0, 13},
+ dictWord{13, 0, 320},
+ dictWord{145, 0, 83},
+ dictWord{142, 0, 410},
+ dictWord{
+ 11,
+ 0,
+ 511,
+ },
+ dictWord{13, 0, 394},
+ dictWord{14, 0, 298},
+ dictWord{14, 0, 318},
+ dictWord{146, 0, 103},
+ dictWord{6, 10, 452},
+ dictWord{7, 10, 312},
+ dictWord{
+ 138,
+ 10,
+ 219,
+ },
+ dictWord{138, 10, 589},
+ dictWord{4, 10, 333},
+ dictWord{9, 10, 176},
+ dictWord{12, 10, 353},
+ dictWord{141, 10, 187},
+ dictWord{135, 11, 329},
+ dictWord{132, 11, 469},
+ dictWord{5, 0, 835},
+ dictWord{134, 0, 483},
+ dictWord{134, 11, 1743},
+ dictWord{5, 11, 929},
+ dictWord{6, 11, 340},
+ dictWord{8, 11, 376},
+ dictWord{136, 11, 807},
+ dictWord{134, 10, 1685},
+ dictWord{132, 0, 677},
+ dictWord{5, 11, 218},
+ dictWord{7, 11, 1610},
+ dictWord{138, 11, 83},
+ dictWord{
+ 5,
+ 11,
+ 571,
+ },
+ dictWord{135, 11, 1842},
+ dictWord{132, 11, 455},
+ dictWord{137, 0, 70},
+ dictWord{135, 0, 1405},
+ dictWord{7, 10, 135},
+ dictWord{8, 10, 7},
+ dictWord{
+ 8,
+ 10,
+ 62,
+ },
+ dictWord{9, 10, 243},
+ dictWord{10, 10, 658},
+ dictWord{10, 10, 697},
+ dictWord{11, 10, 456},
+ dictWord{139, 10, 756},
+ dictWord{9, 10, 395},
+ dictWord{138, 10, 79},
+ dictWord{137, 0, 108},
+ dictWord{6, 11, 161},
+ dictWord{7, 11, 372},
+ dictWord{137, 11, 597},
+ dictWord{132, 11, 349},
+ dictWord{
+ 132,
+ 0,
+ 777,
+ },
+ dictWord{132, 0, 331},
+ dictWord{135, 10, 631},
+ dictWord{133, 0, 747},
+ dictWord{6, 11, 432},
+ dictWord{6, 11, 608},
+ dictWord{139, 11, 322},
+ dictWord{138, 10, 835},
+ dictWord{5, 11, 468},
+ dictWord{7, 11, 1809},
+ dictWord{10, 11, 325},
+ dictWord{11, 11, 856},
+ dictWord{12, 11, 345},
+ dictWord{
+ 143,
+ 11,
+ 104,
+ },
+ dictWord{133, 11, 223},
+ dictWord{7, 10, 406},
+ dictWord{7, 10, 459},
+ dictWord{8, 10, 606},
+ dictWord{139, 10, 726},
+ dictWord{132, 11, 566},
+ dictWord{142, 0, 68},
+ dictWord{4, 11, 59},
+ dictWord{135, 11, 1394},
+ dictWord{6, 11, 436},
+ dictWord{139, 11, 481},
+ dictWord{4, 11, 48},
+ dictWord{5, 11, 271},
+ dictWord{135, 11, 953},
+ dictWord{139, 11, 170},
+ dictWord{5, 11, 610},
+ dictWord{136, 11, 457},
+ dictWord{133, 11, 755},
+ dictWord{135, 11, 1217},
+ dictWord{
+ 133,
+ 10,
+ 612,
+ },
+ dictWord{132, 11, 197},
+ dictWord{132, 0, 505},
+ dictWord{4, 10, 372},
+ dictWord{7, 10, 482},
+ dictWord{8, 10, 158},
+ dictWord{9, 10, 602},
+ dictWord{
+ 9,
+ 10,
+ 615,
+ },
+ dictWord{10, 10, 245},
+ dictWord{10, 10, 678},
+ dictWord{10, 10, 744},
+ dictWord{11, 10, 248},
+ dictWord{139, 10, 806},
+ dictWord{133, 0, 326},
+ dictWord{5, 10, 854},
+ dictWord{135, 10, 1991},
+ dictWord{4, 0, 691},
+ dictWord{146, 0, 16},
+ dictWord{6, 0, 628},
+ dictWord{9, 0, 35},
+ dictWord{10, 0, 680},
+ dictWord{10, 0, 793},
+ dictWord{11, 0, 364},
+ dictWord{13, 0, 357},
+ dictWord{143, 0, 164},
+ dictWord{138, 0, 654},
+ dictWord{6, 0, 32},
+ dictWord{7, 0, 385},
+ dictWord{
+ 7,
+ 0,
+ 757,
+ },
+ dictWord{7, 0, 1916},
+ dictWord{8, 0, 37},
+ dictWord{8, 0, 94},
+ dictWord{8, 0, 711},
+ dictWord{9, 0, 541},
+ dictWord{10, 0, 162},
+ dictWord{10, 0, 795},
+ dictWord{
+ 11,
+ 0,
+ 989,
+ },
+ dictWord{11, 0, 1010},
+ dictWord{12, 0, 14},
+ dictWord{142, 0, 308},
+ dictWord{133, 11, 217},
+ dictWord{6, 0, 152},
+ dictWord{6, 0, 349},
+ dictWord{
+ 6,
+ 0,
+ 1682,
+ },
+ dictWord{7, 0, 1252},
+ dictWord{8, 0, 112},
+ dictWord{9, 0, 435},
+ dictWord{9, 0, 668},
+ dictWord{10, 0, 290},
+ dictWord{10, 0, 319},
+ dictWord{10, 0, 815},
+ dictWord{11, 0, 180},
+ dictWord{11, 0, 837},
+ dictWord{12, 0, 240},
+ dictWord{13, 0, 152},
+ dictWord{13, 0, 219},
+ dictWord{142, 0, 158},
+ dictWord{4, 0, 581},
+ dictWord{134, 0, 726},
+ dictWord{5, 10, 195},
+ dictWord{135, 10, 1685},
+ dictWord{6, 0, 126},
+ dictWord{7, 0, 573},
+ dictWord{8, 0, 397},
+ dictWord{142, 0, 44},
+ dictWord{138, 0, 89},
+ dictWord{7, 10, 1997},
+ dictWord{8, 10, 730},
+ dictWord{139, 10, 1006},
+ dictWord{134, 0, 1531},
+ dictWord{134, 0, 1167},
+ dictWord{
+ 5,
+ 0,
+ 926,
+ },
+ dictWord{12, 0, 203},
+ dictWord{133, 10, 751},
+ dictWord{4, 11, 165},
+ dictWord{7, 11, 1398},
+ dictWord{135, 11, 1829},
+ dictWord{7, 0, 1232},
+ dictWord{137, 0, 531},
+ dictWord{135, 10, 821},
+ dictWord{134, 0, 943},
+ dictWord{133, 0, 670},
+ dictWord{4, 0, 880},
+ dictWord{139, 0, 231},
+ dictWord{
+ 134,
+ 0,
+ 1617,
+ },
+ dictWord{135, 0, 1957},
+ dictWord{5, 11, 9},
+ dictWord{7, 11, 297},
+ dictWord{7, 11, 966},
+ dictWord{140, 11, 306},
+ dictWord{6, 0, 975},
+ dictWord{
+ 134,
+ 0,
+ 985,
+ },
+ dictWord{5, 10, 950},
+ dictWord{5, 10, 994},
+ dictWord{134, 10, 351},
+ dictWord{12, 11, 21},
+ dictWord{151, 11, 7},
+ dictWord{5, 11, 146},
+ dictWord{
+ 6,
+ 11,
+ 411,
+ },
+ dictWord{138, 11, 721},
+ dictWord{7, 0, 242},
+ dictWord{135, 0, 1942},
+ dictWord{6, 11, 177},
+ dictWord{135, 11, 467},
+ dictWord{5, 0, 421},
+ dictWord{
+ 7,
+ 10,
+ 47,
+ },
+ dictWord{137, 10, 684},
+ dictWord{5, 0, 834},
+ dictWord{7, 0, 1202},
+ dictWord{8, 0, 14},
+ dictWord{9, 0, 481},
+ dictWord{137, 0, 880},
+ dictWord{138, 0, 465},
+ dictWord{6, 0, 688},
+ dictWord{9, 0, 834},
+ dictWord{132, 10, 350},
+ dictWord{132, 0, 855},
+ dictWord{4, 0, 357},
+ dictWord{6, 0, 172},
+ dictWord{7, 0, 143},
+ dictWord{137, 0, 413},
+ dictWord{133, 11, 200},
+ dictWord{132, 0, 590},
+ dictWord{7, 10, 1812},
+ dictWord{13, 10, 259},
+ dictWord{13, 10, 356},
+ dictWord{
+ 14,
+ 10,
+ 242,
+ },
+ dictWord{147, 10, 114},
+ dictWord{133, 10, 967},
+ dictWord{11, 0, 114},
+ dictWord{4, 10, 473},
+ dictWord{7, 10, 623},
+ dictWord{8, 10, 808},
+ dictWord{
+ 9,
+ 10,
+ 871,
+ },
+ dictWord{9, 10, 893},
+ dictWord{11, 10, 431},
+ dictWord{12, 10, 112},
+ dictWord{12, 10, 217},
+ dictWord{12, 10, 243},
+ dictWord{12, 10, 562},
+ dictWord{
+ 12,
+ 10,
+ 663,
+ },
+ dictWord{12, 10, 683},
+ dictWord{13, 10, 141},
+ dictWord{13, 10, 197},
+ dictWord{13, 10, 227},
+ dictWord{13, 10, 406},
+ dictWord{13, 10, 487},
+ dictWord{14, 10, 156},
+ dictWord{14, 10, 203},
+ dictWord{14, 10, 224},
+ dictWord{14, 10, 256},
+ dictWord{18, 10, 58},
+ dictWord{150, 10, 0},
+ dictWord{
+ 138,
+ 10,
+ 286,
+ },
+ dictWord{4, 10, 222},
+ dictWord{7, 10, 286},
+ dictWord{136, 10, 629},
+ dictWord{5, 0, 169},
+ dictWord{7, 0, 333},
+ dictWord{136, 0, 45},
+ dictWord{
+ 134,
+ 11,
+ 481,
+ },
+ dictWord{132, 0, 198},
+ dictWord{4, 0, 24},
+ dictWord{5, 0, 140},
+ dictWord{5, 0, 185},
+ dictWord{7, 0, 1500},
+ dictWord{11, 0, 565},
+ dictWord{11, 0, 838},
+ dictWord{4, 11, 84},
+ dictWord{7, 11, 1482},
+ dictWord{10, 11, 76},
+ dictWord{138, 11, 142},
+ dictWord{133, 0, 585},
+ dictWord{141, 10, 306},
+ dictWord{
+ 133,
+ 11,
+ 1015,
+ },
+ dictWord{4, 11, 315},
+ dictWord{5, 11, 507},
+ dictWord{135, 11, 1370},
+ dictWord{136, 10, 146},
+ dictWord{6, 0, 691},
+ dictWord{134, 0, 1503},
+ dictWord{
+ 4,
+ 0,
+ 334,
+ },
+ dictWord{133, 0, 593},
+ dictWord{4, 10, 465},
+ dictWord{135, 10, 1663},
+ dictWord{142, 11, 173},
+ dictWord{135, 0, 913},
+ dictWord{12, 0, 116},
+ dictWord{134, 11, 1722},
+ dictWord{134, 0, 1360},
+ dictWord{132, 0, 802},
+ dictWord{8, 11, 222},
+ dictWord{8, 11, 476},
+ dictWord{9, 11, 238},
+ dictWord{
+ 11,
+ 11,
+ 516,
+ },
+ dictWord{11, 11, 575},
+ dictWord{15, 11, 109},
+ dictWord{146, 11, 100},
+ dictWord{6, 0, 308},
+ dictWord{9, 0, 673},
+ dictWord{7, 10, 138},
+ dictWord{
+ 7,
+ 10,
+ 517,
+ },
+ dictWord{139, 10, 238},
+ dictWord{132, 0, 709},
+ dictWord{6, 0, 1876},
+ dictWord{6, 0, 1895},
+ dictWord{9, 0, 994},
+ dictWord{9, 0, 1006},
+ dictWord{
+ 12,
+ 0,
+ 829,
+ },
+ dictWord{12, 0, 888},
+ dictWord{12, 0, 891},
+ dictWord{146, 0, 185},
+ dictWord{148, 10, 94},
+ dictWord{4, 0, 228},
+ dictWord{133, 0, 897},
+ dictWord{
+ 7,
+ 0,
+ 1840,
+ },
+ dictWord{5, 10, 495},
+ dictWord{7, 10, 834},
+ dictWord{9, 10, 733},
+ dictWord{139, 10, 378},
+ dictWord{133, 10, 559},
+ dictWord{6, 10, 21},
+ dictWord{
+ 6,
+ 10,
+ 1737,
+ },
+ dictWord{7, 10, 1444},
+ dictWord{136, 10, 224},
+ dictWord{4, 0, 608},
+ dictWord{133, 0, 497},
+ dictWord{6, 11, 40},
+ dictWord{135, 11, 1781},
+ dictWord{134, 0, 1573},
+ dictWord{135, 0, 2039},
+ dictWord{6, 0, 540},
+ dictWord{136, 0, 136},
+ dictWord{4, 0, 897},
+ dictWord{5, 0, 786},
+ dictWord{133, 10, 519},
+ dictWord{6, 0, 1878},
+ dictWord{6, 0, 1884},
+ dictWord{9, 0, 938},
+ dictWord{9, 0, 948},
+ dictWord{9, 0, 955},
+ dictWord{9, 0, 973},
+ dictWord{9, 0, 1012},
+ dictWord{
+ 12,
+ 0,
+ 895,
+ },
+ dictWord{12, 0, 927},
+ dictWord{143, 0, 254},
+ dictWord{134, 0, 1469},
+ dictWord{133, 0, 999},
+ dictWord{4, 0, 299},
+ dictWord{135, 0, 1004},
+ dictWord{
+ 4,
+ 0,
+ 745,
+ },
+ dictWord{133, 0, 578},
+ dictWord{136, 11, 574},
+ dictWord{133, 0, 456},
+ dictWord{134, 0, 1457},
+ dictWord{7, 0, 1679},
+ dictWord{132, 10, 402},
+ dictWord{7, 0, 693},
+ dictWord{8, 0, 180},
+ dictWord{12, 0, 163},
+ dictWord{8, 10, 323},
+ dictWord{136, 10, 479},
+ dictWord{11, 10, 580},
+ dictWord{142, 10, 201},
+ dictWord{5, 10, 59},
+ dictWord{135, 10, 672},
+ dictWord{132, 11, 354},
+ dictWord{146, 10, 34},
+ dictWord{4, 0, 755},
+ dictWord{135, 11, 1558},
+ dictWord{
+ 7,
+ 0,
+ 1740,
+ },
+ dictWord{146, 0, 48},
+ dictWord{4, 10, 85},
+ dictWord{135, 10, 549},
+ dictWord{139, 0, 338},
+ dictWord{133, 10, 94},
+ dictWord{134, 0, 1091},
+ dictWord{135, 11, 469},
+ dictWord{12, 0, 695},
+ dictWord{12, 0, 704},
+ dictWord{20, 0, 113},
+ dictWord{5, 11, 830},
+ dictWord{14, 11, 338},
+ dictWord{148, 11, 81},
+ dictWord{135, 0, 1464},
+ dictWord{6, 10, 11},
+ dictWord{135, 10, 187},
+ dictWord{135, 0, 975},
+ dictWord{13, 0, 335},
+ dictWord{132, 10, 522},
+ dictWord{
+ 134,
+ 0,
+ 1979,
+ },
+ dictWord{5, 11, 496},
+ dictWord{135, 11, 203},
+ dictWord{4, 10, 52},
+ dictWord{135, 10, 661},
+ dictWord{7, 0, 1566},
+ dictWord{8, 0, 269},
+ dictWord{
+ 9,
+ 0,
+ 212,
+ },
+ dictWord{9, 0, 718},
+ dictWord{14, 0, 15},
+ dictWord{14, 0, 132},
+ dictWord{142, 0, 227},
+ dictWord{4, 0, 890},
+ dictWord{5, 0, 805},
+ dictWord{5, 0, 819},
+ dictWord{
+ 5,
+ 0,
+ 961,
+ },
+ dictWord{6, 0, 396},
+ dictWord{6, 0, 1631},
+ dictWord{6, 0, 1678},
+ dictWord{7, 0, 1967},
+ dictWord{7, 0, 2041},
+ dictWord{9, 0, 630},
+ dictWord{11, 0, 8},
+ dictWord{11, 0, 1019},
+ dictWord{12, 0, 176},
+ dictWord{13, 0, 225},
+ dictWord{14, 0, 292},
+ dictWord{21, 0, 24},
+ dictWord{4, 10, 383},
+ dictWord{133, 10, 520},
+ dictWord{134, 11, 547},
+ dictWord{135, 11, 1748},
+ dictWord{5, 11, 88},
+ dictWord{137, 11, 239},
+ dictWord{146, 11, 128},
+ dictWord{7, 11, 650},
+ dictWord{
+ 135,
+ 11,
+ 1310,
+ },
+ dictWord{4, 10, 281},
+ dictWord{5, 10, 38},
+ dictWord{7, 10, 194},
+ dictWord{7, 10, 668},
+ dictWord{7, 10, 1893},
+ dictWord{137, 10, 397},
+ dictWord{135, 0, 1815},
+ dictWord{9, 10, 635},
+ dictWord{139, 10, 559},
+ dictWord{7, 0, 1505},
+ dictWord{10, 0, 190},
+ dictWord{10, 0, 634},
+ dictWord{11, 0, 792},
+ dictWord{12, 0, 358},
+ dictWord{140, 0, 447},
+ dictWord{5, 0, 0},
+ dictWord{6, 0, 536},
+ dictWord{7, 0, 604},
+ dictWord{13, 0, 445},
+ dictWord{145, 0, 126},
+ dictWord{
+ 7,
+ 11,
+ 1076,
+ },
+ dictWord{9, 11, 80},
+ dictWord{11, 11, 78},
+ dictWord{11, 11, 421},
+ dictWord{11, 11, 534},
+ dictWord{140, 11, 545},
+ dictWord{8, 0, 966},
+ dictWord{
+ 10,
+ 0,
+ 1023,
+ },
+ dictWord{14, 11, 369},
+ dictWord{146, 11, 72},
+ dictWord{135, 11, 1641},
+ dictWord{6, 0, 232},
+ dictWord{6, 0, 412},
+ dictWord{7, 0, 1074},
+ dictWord{
+ 8,
+ 0,
+ 9,
+ },
+ dictWord{8, 0, 157},
+ dictWord{8, 0, 786},
+ dictWord{9, 0, 196},
+ dictWord{9, 0, 352},
+ dictWord{9, 0, 457},
+ dictWord{10, 0, 337},
+ dictWord{11, 0, 232},
+ dictWord{
+ 11,
+ 0,
+ 877,
+ },
+ dictWord{12, 0, 480},
+ dictWord{140, 0, 546},
+ dictWord{135, 0, 958},
+ dictWord{4, 0, 382},
+ dictWord{136, 0, 579},
+ dictWord{4, 0, 212},
+ dictWord{
+ 135,
+ 0,
+ 1206,
+ },
+ dictWord{4, 11, 497},
+ dictWord{5, 11, 657},
+ dictWord{135, 11, 1584},
+ dictWord{132, 0, 681},
+ dictWord{8, 0, 971},
+ dictWord{138, 0, 965},
+ dictWord{
+ 5,
+ 10,
+ 448,
+ },
+ dictWord{136, 10, 535},
+ dictWord{14, 0, 16},
+ dictWord{146, 0, 44},
+ dictWord{11, 0, 584},
+ dictWord{11, 0, 616},
+ dictWord{14, 0, 275},
+ dictWord{
+ 11,
+ 11,
+ 584,
+ },
+ dictWord{11, 11, 616},
+ dictWord{142, 11, 275},
+ dictWord{136, 11, 13},
+ dictWord{7, 10, 610},
+ dictWord{135, 10, 1501},
+ dictWord{7, 11, 642},
+ dictWord{8, 11, 250},
+ dictWord{11, 11, 123},
+ dictWord{11, 11, 137},
+ dictWord{13, 11, 48},
+ dictWord{142, 11, 95},
+ dictWord{133, 0, 655},
+ dictWord{17, 0, 67},
+ dictWord{147, 0, 74},
+ dictWord{134, 0, 751},
+ dictWord{134, 0, 1967},
+ dictWord{6, 0, 231},
+ dictWord{136, 0, 423},
+ dictWord{5, 0, 300},
+ dictWord{138, 0, 1016},
+ dictWord{4, 10, 319},
+ dictWord{5, 10, 699},
+ dictWord{138, 10, 673},
+ dictWord{6, 0, 237},
+ dictWord{7, 0, 611},
+ dictWord{8, 0, 100},
+ dictWord{9, 0, 416},
+ dictWord{
+ 11,
+ 0,
+ 335,
+ },
+ dictWord{12, 0, 173},
+ dictWord{18, 0, 101},
+ dictWord{6, 10, 336},
+ dictWord{8, 10, 552},
+ dictWord{9, 10, 285},
+ dictWord{10, 10, 99},
+ dictWord{
+ 139,
+ 10,
+ 568,
+ },
+ dictWord{134, 0, 1370},
+ dictWord{7, 10, 1406},
+ dictWord{9, 10, 218},
+ dictWord{141, 10, 222},
+ dictWord{133, 10, 256},
+ dictWord{
+ 135,
+ 0,
+ 1208,
+ },
+ dictWord{14, 11, 213},
+ dictWord{148, 11, 38},
+ dictWord{6, 0, 1219},
+ dictWord{135, 11, 1642},
+ dictWord{13, 0, 417},
+ dictWord{14, 0, 129},
+ dictWord{143, 0, 15},
+ dictWord{10, 11, 545},
+ dictWord{140, 11, 301},
+ dictWord{17, 10, 39},
+ dictWord{148, 10, 36},
+ dictWord{133, 0, 199},
+ dictWord{4, 11, 904},
+ dictWord{133, 11, 794},
+ dictWord{12, 0, 427},
+ dictWord{146, 0, 38},
+ dictWord{134, 0, 949},
+ dictWord{8, 0, 665},
+ dictWord{135, 10, 634},
+ dictWord{
+ 132,
+ 10,
+ 618,
+ },
+ dictWord{135, 10, 259},
+ dictWord{132, 10, 339},
+ dictWord{133, 11, 761},
+ dictWord{141, 10, 169},
+ dictWord{132, 10, 759},
+ dictWord{5, 0, 688},
+ dictWord{7, 0, 539},
+ dictWord{135, 0, 712},
+ dictWord{7, 11, 386},
+ dictWord{138, 11, 713},
+ dictWord{134, 0, 1186},
+ dictWord{6, 11, 7},
+ dictWord{6, 11, 35},
+ dictWord{
+ 7,
+ 11,
+ 147,
+ },
+ dictWord{7, 11, 1069},
+ dictWord{7, 11, 1568},
+ dictWord{7, 11, 1575},
+ dictWord{7, 11, 1917},
+ dictWord{8, 11, 43},
+ dictWord{8, 11, 208},
+ dictWord{
+ 9,
+ 11,
+ 128,
+ },
+ dictWord{9, 11, 866},
+ dictWord{10, 11, 20},
+ dictWord{11, 11, 981},
+ dictWord{147, 11, 33},
+ dictWord{7, 11, 893},
+ dictWord{8, 10, 482},
+ dictWord{141, 11, 424},
+ dictWord{6, 0, 312},
+ dictWord{6, 0, 1715},
+ dictWord{10, 0, 584},
+ dictWord{11, 0, 546},
+ dictWord{11, 0, 692},
+ dictWord{12, 0, 259},
+ dictWord{
+ 12,
+ 0,
+ 295,
+ },
+ dictWord{13, 0, 46},
+ dictWord{141, 0, 154},
+ dictWord{5, 10, 336},
+ dictWord{6, 10, 341},
+ dictWord{6, 10, 478},
+ dictWord{6, 10, 1763},
+ dictWord{
+ 136,
+ 10,
+ 386,
+ },
+ dictWord{137, 0, 151},
+ dictWord{132, 0, 588},
+ dictWord{152, 0, 4},
+ dictWord{6, 11, 322},
+ dictWord{9, 11, 552},
+ dictWord{11, 11, 274},
+ dictWord{
+ 13,
+ 11,
+ 209,
+ },
+ dictWord{13, 11, 499},
+ dictWord{14, 11, 85},
+ dictWord{15, 11, 126},
+ dictWord{145, 11, 70},
+ dictWord{135, 10, 73},
+ dictWord{4, 0, 231},
+ dictWord{
+ 5,
+ 0,
+ 61,
+ },
+ dictWord{6, 0, 104},
+ dictWord{7, 0, 729},
+ dictWord{7, 0, 964},
+ dictWord{7, 0, 1658},
+ dictWord{140, 0, 414},
+ dictWord{6, 0, 263},
+ dictWord{138, 0, 757},
+ dictWord{135, 10, 1971},
+ dictWord{4, 0, 612},
+ dictWord{133, 0, 561},
+ dictWord{132, 0, 320},
+ dictWord{135, 10, 1344},
+ dictWord{8, 11, 83},
+ dictWord{
+ 8,
+ 11,
+ 817,
+ },
+ dictWord{9, 11, 28},
+ dictWord{9, 11, 29},
+ dictWord{9, 11, 885},
+ dictWord{10, 11, 387},
+ dictWord{11, 11, 633},
+ dictWord{11, 11, 740},
+ dictWord{
+ 13,
+ 11,
+ 235,
+ },
+ dictWord{13, 11, 254},
+ dictWord{15, 11, 143},
+ dictWord{143, 11, 146},
+ dictWord{5, 10, 396},
+ dictWord{134, 10, 501},
+ dictWord{140, 11, 49},
+ dictWord{132, 0, 225},
+ dictWord{4, 10, 929},
+ dictWord{5, 10, 799},
+ dictWord{8, 10, 46},
+ dictWord{136, 10, 740},
+ dictWord{4, 0, 405},
+ dictWord{7, 0, 817},
+ dictWord{
+ 14,
+ 0,
+ 58,
+ },
+ dictWord{17, 0, 37},
+ dictWord{146, 0, 124},
+ dictWord{133, 0, 974},
+ dictWord{4, 11, 412},
+ dictWord{133, 11, 581},
+ dictWord{4, 10, 892},
+ dictWord{
+ 133,
+ 10,
+ 770,
+ },
+ dictWord{4, 0, 996},
+ dictWord{134, 0, 2026},
+ dictWord{4, 0, 527},
+ dictWord{5, 0, 235},
+ dictWord{7, 0, 1239},
+ dictWord{11, 0, 131},
+ dictWord{
+ 140,
+ 0,
+ 370,
+ },
+ dictWord{9, 0, 16},
+ dictWord{13, 0, 386},
+ dictWord{135, 11, 421},
+ dictWord{7, 0, 956},
+ dictWord{7, 0, 1157},
+ dictWord{7, 0, 1506},
+ dictWord{7, 0, 1606},
+ dictWord{7, 0, 1615},
+ dictWord{7, 0, 1619},
+ dictWord{7, 0, 1736},
+ dictWord{7, 0, 1775},
+ dictWord{8, 0, 590},
+ dictWord{9, 0, 324},
+ dictWord{9, 0, 736},
+ dictWord{
+ 9,
+ 0,
+ 774,
+ },
+ dictWord{9, 0, 776},
+ dictWord{9, 0, 784},
+ dictWord{10, 0, 567},
+ dictWord{10, 0, 708},
+ dictWord{11, 0, 518},
+ dictWord{11, 0, 613},
+ dictWord{11, 0, 695},
+ dictWord{11, 0, 716},
+ dictWord{11, 0, 739},
+ dictWord{11, 0, 770},
+ dictWord{11, 0, 771},
+ dictWord{11, 0, 848},
+ dictWord{11, 0, 857},
+ dictWord{11, 0, 931},
+ dictWord{
+ 11,
+ 0,
+ 947,
+ },
+ dictWord{12, 0, 326},
+ dictWord{12, 0, 387},
+ dictWord{12, 0, 484},
+ dictWord{12, 0, 528},
+ dictWord{12, 0, 552},
+ dictWord{12, 0, 613},
+ dictWord{
+ 13,
+ 0,
+ 189,
+ },
+ dictWord{13, 0, 256},
+ dictWord{13, 0, 340},
+ dictWord{13, 0, 432},
+ dictWord{13, 0, 436},
+ dictWord{13, 0, 440},
+ dictWord{13, 0, 454},
+ dictWord{14, 0, 174},
+ dictWord{14, 0, 220},
+ dictWord{14, 0, 284},
+ dictWord{14, 0, 390},
+ dictWord{145, 0, 121},
+ dictWord{135, 10, 158},
+ dictWord{9, 0, 137},
+ dictWord{138, 0, 221},
+ dictWord{4, 11, 110},
+ dictWord{10, 11, 415},
+ dictWord{10, 11, 597},
+ dictWord{142, 11, 206},
+ dictWord{141, 11, 496},
+ dictWord{135, 11, 205},
+ dictWord{
+ 151,
+ 10,
+ 25,
+ },
+ dictWord{135, 11, 778},
+ dictWord{7, 11, 1656},
+ dictWord{7, 10, 2001},
+ dictWord{9, 11, 369},
+ dictWord{10, 11, 338},
+ dictWord{10, 11, 490},
+ dictWord{11, 11, 154},
+ dictWord{11, 11, 545},
+ dictWord{11, 11, 775},
+ dictWord{13, 11, 77},
+ dictWord{141, 11, 274},
+ dictWord{4, 11, 444},
+ dictWord{
+ 10,
+ 11,
+ 146,
+ },
+ dictWord{140, 11, 9},
+ dictWord{7, 0, 390},
+ dictWord{138, 0, 140},
+ dictWord{135, 0, 1144},
+ dictWord{134, 0, 464},
+ dictWord{7, 10, 1461},
+ dictWord{
+ 140,
+ 10,
+ 91,
+ },
+ dictWord{132, 10, 602},
+ dictWord{4, 11, 283},
+ dictWord{135, 11, 1194},
+ dictWord{5, 0, 407},
+ dictWord{11, 0, 204},
+ dictWord{11, 0, 243},
+ dictWord{
+ 11,
+ 0,
+ 489,
+ },
+ dictWord{12, 0, 293},
+ dictWord{19, 0, 37},
+ dictWord{20, 0, 73},
+ dictWord{150, 0, 38},
+ dictWord{7, 0, 1218},
+ dictWord{136, 0, 303},
+ dictWord{
+ 5,
+ 0,
+ 325,
+ },
+ dictWord{8, 0, 5},
+ dictWord{8, 0, 227},
+ dictWord{9, 0, 105},
+ dictWord{10, 0, 585},
+ dictWord{12, 0, 614},
+ dictWord{4, 10, 13},
+ dictWord{5, 10, 567},
+ dictWord{
+ 7,
+ 10,
+ 1498,
+ },
+ dictWord{9, 10, 124},
+ dictWord{11, 10, 521},
+ dictWord{140, 10, 405},
+ dictWord{135, 10, 1006},
+ dictWord{7, 0, 800},
+ dictWord{10, 0, 12},
+ dictWord{134, 11, 1720},
+ dictWord{135, 0, 1783},
+ dictWord{132, 10, 735},
+ dictWord{138, 10, 812},
+ dictWord{4, 10, 170},
+ dictWord{135, 10, 323},
+ dictWord{
+ 6,
+ 0,
+ 621,
+ },
+ dictWord{13, 0, 504},
+ dictWord{144, 0, 89},
+ dictWord{5, 10, 304},
+ dictWord{135, 10, 1403},
+ dictWord{137, 11, 216},
+ dictWord{6, 0, 920},
+ dictWord{
+ 6,
+ 0,
+ 1104,
+ },
+ dictWord{9, 11, 183},
+ dictWord{139, 11, 286},
+ dictWord{4, 0, 376},
+ dictWord{133, 10, 742},
+ dictWord{134, 0, 218},
+ dictWord{8, 0, 641},
+ dictWord{
+ 11,
+ 0,
+ 388,
+ },
+ dictWord{140, 0, 580},
+ dictWord{7, 0, 454},
+ dictWord{7, 0, 782},
+ dictWord{8, 0, 768},
+ dictWord{140, 0, 686},
+ dictWord{137, 11, 33},
+ dictWord{
+ 133,
+ 10,
+ 111,
+ },
+ dictWord{144, 0, 0},
+ dictWord{10, 0, 676},
+ dictWord{140, 0, 462},
+ dictWord{6, 0, 164},
+ dictWord{136, 11, 735},
+ dictWord{133, 10, 444},
+ dictWord{
+ 150,
+ 0,
+ 50,
+ },
+ dictWord{7, 11, 1862},
+ dictWord{12, 11, 491},
+ dictWord{12, 11, 520},
+ dictWord{13, 11, 383},
+ dictWord{14, 11, 244},
+ dictWord{146, 11, 12},
+ dictWord{
+ 5,
+ 11,
+ 132,
+ },
+ dictWord{9, 11, 486},
+ dictWord{9, 11, 715},
+ dictWord{10, 11, 458},
+ dictWord{11, 11, 373},
+ dictWord{11, 11, 668},
+ dictWord{11, 11, 795},
+ dictWord{11, 11, 897},
+ dictWord{12, 11, 272},
+ dictWord{12, 11, 424},
+ dictWord{12, 11, 539},
+ dictWord{12, 11, 558},
+ dictWord{14, 11, 245},
+ dictWord{
+ 14,
+ 11,
+ 263,
+ },
+ dictWord{14, 11, 264},
+ dictWord{14, 11, 393},
+ dictWord{142, 11, 403},
+ dictWord{8, 10, 123},
+ dictWord{15, 10, 6},
+ dictWord{144, 10, 7},
+ dictWord{
+ 6,
+ 0,
+ 285,
+ },
+ dictWord{8, 0, 654},
+ dictWord{11, 0, 749},
+ dictWord{12, 0, 190},
+ dictWord{12, 0, 327},
+ dictWord{13, 0, 120},
+ dictWord{13, 0, 121},
+ dictWord{13, 0, 327},
+ dictWord{15, 0, 47},
+ dictWord{146, 0, 40},
+ dictWord{5, 11, 8},
+ dictWord{6, 11, 89},
+ dictWord{6, 11, 400},
+ dictWord{7, 11, 1569},
+ dictWord{7, 11, 1623},
+ dictWord{
+ 7,
+ 11,
+ 1850,
+ },
+ dictWord{8, 11, 218},
+ dictWord{8, 11, 422},
+ dictWord{9, 11, 570},
+ dictWord{138, 11, 626},
+ dictWord{6, 11, 387},
+ dictWord{7, 11, 882},
+ dictWord{141, 11, 111},
+ dictWord{6, 0, 343},
+ dictWord{7, 0, 195},
+ dictWord{9, 0, 226},
+ dictWord{10, 0, 197},
+ dictWord{10, 0, 575},
+ dictWord{11, 0, 502},
+ dictWord{
+ 11,
+ 0,
+ 899,
+ },
+ dictWord{6, 11, 224},
+ dictWord{7, 11, 877},
+ dictWord{137, 11, 647},
+ dictWord{5, 10, 937},
+ dictWord{135, 10, 100},
+ dictWord{135, 11, 790},
+ dictWord{150, 0, 29},
+ dictWord{147, 0, 8},
+ dictWord{134, 0, 1812},
+ dictWord{149, 0, 8},
+ dictWord{135, 11, 394},
+ dictWord{7, 0, 1125},
+ dictWord{9, 0, 143},
+ dictWord{
+ 11,
+ 0,
+ 61,
+ },
+ dictWord{14, 0, 405},
+ dictWord{150, 0, 21},
+ dictWord{10, 11, 755},
+ dictWord{147, 11, 29},
+ dictWord{9, 11, 378},
+ dictWord{141, 11, 162},
+ dictWord{135, 10, 922},
+ dictWord{5, 10, 619},
+ dictWord{133, 10, 698},
+ dictWord{134, 0, 1327},
+ dictWord{6, 0, 1598},
+ dictWord{137, 0, 575},
+ dictWord{
+ 9,
+ 11,
+ 569,
+ },
+ dictWord{12, 11, 12},
+ dictWord{12, 11, 81},
+ dictWord{12, 11, 319},
+ dictWord{13, 11, 69},
+ dictWord{14, 11, 259},
+ dictWord{16, 11, 87},
+ dictWord{
+ 17,
+ 11,
+ 1,
+ },
+ dictWord{17, 11, 21},
+ dictWord{17, 11, 24},
+ dictWord{18, 11, 15},
+ dictWord{18, 11, 56},
+ dictWord{18, 11, 59},
+ dictWord{18, 11, 127},
+ dictWord{18, 11, 154},
+ dictWord{19, 11, 19},
+ dictWord{148, 11, 31},
+ dictWord{6, 0, 895},
+ dictWord{135, 11, 1231},
+ dictWord{5, 0, 959},
+ dictWord{7, 11, 124},
+ dictWord{136, 11, 38},
+ dictWord{5, 11, 261},
+ dictWord{7, 11, 78},
+ dictWord{7, 11, 199},
+ dictWord{8, 11, 815},
+ dictWord{9, 11, 126},
+ dictWord{138, 11, 342},
+ dictWord{5, 10, 917},
+ dictWord{134, 10, 1659},
+ dictWord{7, 0, 1759},
+ dictWord{5, 11, 595},
+ dictWord{135, 11, 1863},
+ dictWord{136, 0, 173},
+ dictWord{134, 0, 266},
+ dictWord{
+ 142,
+ 0,
+ 261,
+ },
+ dictWord{132, 11, 628},
+ dictWord{5, 10, 251},
+ dictWord{5, 10, 956},
+ dictWord{8, 10, 268},
+ dictWord{9, 10, 214},
+ dictWord{146, 10, 142},
+ dictWord{
+ 7,
+ 11,
+ 266,
+ },
+ dictWord{136, 11, 804},
+ dictWord{135, 11, 208},
+ dictWord{6, 11, 79},
+ dictWord{7, 11, 1021},
+ dictWord{135, 11, 1519},
+ dictWord{11, 11, 704},
+ dictWord{141, 11, 396},
+ dictWord{5, 10, 346},
+ dictWord{5, 10, 711},
+ dictWord{136, 10, 390},
+ dictWord{136, 11, 741},
+ dictWord{134, 11, 376},
+ dictWord{
+ 134,
+ 0,
+ 1427,
+ },
+ dictWord{6, 0, 1033},
+ dictWord{6, 0, 1217},
+ dictWord{136, 0, 300},
+ dictWord{133, 10, 624},
+ dictWord{6, 11, 100},
+ dictWord{7, 11, 244},
+ dictWord{
+ 7,
+ 11,
+ 632,
+ },
+ dictWord{7, 11, 1609},
+ dictWord{8, 11, 178},
+ dictWord{8, 11, 638},
+ dictWord{141, 11, 58},
+ dictWord{6, 0, 584},
+ dictWord{5, 10, 783},
+ dictWord{
+ 7,
+ 10,
+ 1998,
+ },
+ dictWord{135, 10, 2047},
+ dictWord{5, 0, 427},
+ dictWord{5, 0, 734},
+ dictWord{7, 0, 478},
+ dictWord{136, 0, 52},
+ dictWord{7, 0, 239},
+ dictWord{
+ 11,
+ 0,
+ 217,
+ },
+ dictWord{142, 0, 165},
+ dictWord{134, 0, 1129},
+ dictWord{6, 0, 168},
+ dictWord{6, 0, 1734},
+ dictWord{7, 0, 20},
+ dictWord{7, 0, 1056},
+ dictWord{8, 0, 732},
+ dictWord{9, 0, 406},
+ dictWord{9, 0, 911},
+ dictWord{138, 0, 694},
+ dictWord{132, 10, 594},
+ dictWord{133, 11, 791},
+ dictWord{7, 11, 686},
+ dictWord{8, 11, 33},
+ dictWord{8, 11, 238},
+ dictWord{10, 11, 616},
+ dictWord{11, 11, 467},
+ dictWord{11, 11, 881},
+ dictWord{13, 11, 217},
+ dictWord{13, 11, 253},
+ dictWord{
+ 142,
+ 11,
+ 268,
+ },
+ dictWord{137, 11, 476},
+ dictWord{134, 0, 418},
+ dictWord{133, 0, 613},
+ dictWord{132, 0, 632},
+ dictWord{132, 11, 447},
+ dictWord{7, 0, 32},
+ dictWord{
+ 7,
+ 0,
+ 984,
+ },
+ dictWord{8, 0, 85},
+ dictWord{8, 0, 709},
+ dictWord{9, 0, 579},
+ dictWord{9, 0, 847},
+ dictWord{9, 0, 856},
+ dictWord{10, 0, 799},
+ dictWord{11, 0, 258},
+ dictWord{
+ 11,
+ 0,
+ 1007,
+ },
+ dictWord{12, 0, 331},
+ dictWord{12, 0, 615},
+ dictWord{13, 0, 188},
+ dictWord{13, 0, 435},
+ dictWord{14, 0, 8},
+ dictWord{15, 0, 165},
+ dictWord{
+ 16,
+ 0,
+ 27,
+ },
+ dictWord{20, 0, 40},
+ dictWord{144, 11, 35},
+ dictWord{4, 11, 128},
+ dictWord{5, 11, 415},
+ dictWord{6, 11, 462},
+ dictWord{7, 11, 294},
+ dictWord{7, 11, 578},
+ dictWord{10, 11, 710},
+ dictWord{139, 11, 86},
+ dictWord{5, 0, 694},
+ dictWord{136, 0, 909},
+ dictWord{7, 0, 1109},
+ dictWord{11, 0, 7},
+ dictWord{5, 10, 37},
+ dictWord{
+ 6,
+ 10,
+ 39,
+ },
+ dictWord{6, 10, 451},
+ dictWord{7, 10, 218},
+ dictWord{7, 10, 1166},
+ dictWord{7, 10, 1687},
+ dictWord{8, 10, 662},
+ dictWord{144, 10, 2},
+ dictWord{
+ 136,
+ 11,
+ 587,
+ },
+ dictWord{6, 11, 427},
+ dictWord{7, 11, 1018},
+ dictWord{138, 11, 692},
+ dictWord{4, 11, 195},
+ dictWord{6, 10, 508},
+ dictWord{135, 11, 802},
+ dictWord{4, 0, 167},
+ dictWord{135, 0, 82},
+ dictWord{5, 0, 62},
+ dictWord{6, 0, 24},
+ dictWord{6, 0, 534},
+ dictWord{7, 0, 74},
+ dictWord{7, 0, 678},
+ dictWord{7, 0, 684},
+ dictWord{
+ 7,
+ 0,
+ 1043,
+ },
+ dictWord{7, 0, 1072},
+ dictWord{8, 0, 280},
+ dictWord{8, 0, 541},
+ dictWord{8, 0, 686},
+ dictWord{9, 0, 258},
+ dictWord{10, 0, 519},
+ dictWord{11, 0, 252},
+ dictWord{140, 0, 282},
+ dictWord{138, 0, 33},
+ dictWord{4, 0, 359},
+ dictWord{133, 11, 738},
+ dictWord{7, 0, 980},
+ dictWord{9, 0, 328},
+ dictWord{13, 0, 186},
+ dictWord{13, 0, 364},
+ dictWord{7, 10, 635},
+ dictWord{7, 10, 796},
+ dictWord{8, 10, 331},
+ dictWord{9, 10, 330},
+ dictWord{9, 10, 865},
+ dictWord{10, 10, 119},
+ dictWord{
+ 10,
+ 10,
+ 235,
+ },
+ dictWord{11, 10, 111},
+ dictWord{11, 10, 129},
+ dictWord{11, 10, 240},
+ dictWord{12, 10, 31},
+ dictWord{12, 10, 66},
+ dictWord{12, 10, 222},
+ dictWord{12, 10, 269},
+ dictWord{12, 10, 599},
+ dictWord{12, 10, 684},
+ dictWord{12, 10, 689},
+ dictWord{12, 10, 691},
+ dictWord{142, 10, 345},
+ dictWord{
+ 137,
+ 10,
+ 527,
+ },
+ dictWord{6, 0, 596},
+ dictWord{7, 0, 585},
+ dictWord{135, 10, 702},
+ dictWord{134, 11, 1683},
+ dictWord{133, 0, 211},
+ dictWord{6, 0, 145},
+ dictWord{
+ 141,
+ 0,
+ 336,
+ },
+ dictWord{134, 0, 1130},
+ dictWord{7, 0, 873},
+ dictWord{6, 10, 37},
+ dictWord{7, 10, 1666},
+ dictWord{8, 10, 195},
+ dictWord{8, 10, 316},
+ dictWord{
+ 9,
+ 10,
+ 178,
+ },
+ dictWord{9, 10, 276},
+ dictWord{9, 10, 339},
+ dictWord{9, 10, 536},
+ dictWord{10, 10, 102},
+ dictWord{10, 10, 362},
+ dictWord{10, 10, 785},
+ dictWord{
+ 11,
+ 10,
+ 55,
+ },
+ dictWord{11, 10, 149},
+ dictWord{11, 10, 773},
+ dictWord{13, 10, 416},
+ dictWord{13, 10, 419},
+ dictWord{14, 10, 38},
+ dictWord{14, 10, 41},
+ dictWord{
+ 142,
+ 10,
+ 210,
+ },
+ dictWord{8, 0, 840},
+ dictWord{136, 0, 841},
+ dictWord{132, 0, 263},
+ dictWord{5, 11, 3},
+ dictWord{8, 11, 578},
+ dictWord{9, 11, 118},
+ dictWord{
+ 10,
+ 11,
+ 705,
+ },
+ dictWord{12, 11, 383},
+ dictWord{141, 11, 279},
+ dictWord{132, 0, 916},
+ dictWord{133, 11, 229},
+ dictWord{133, 10, 645},
+ dictWord{15, 0, 155},
+ dictWord{16, 0, 79},
+ dictWord{8, 11, 102},
+ dictWord{10, 11, 578},
+ dictWord{10, 11, 672},
+ dictWord{12, 11, 496},
+ dictWord{13, 11, 408},
+ dictWord{14, 11, 121},
+ dictWord{145, 11, 106},
+ dictWord{4, 0, 599},
+ dictWord{5, 0, 592},
+ dictWord{6, 0, 1634},
+ dictWord{7, 0, 5},
+ dictWord{7, 0, 55},
+ dictWord{7, 0, 67},
+ dictWord{7, 0, 97},
+ dictWord{7, 0, 691},
+ dictWord{7, 0, 979},
+ dictWord{7, 0, 1600},
+ dictWord{7, 0, 1697},
+ dictWord{8, 0, 207},
+ dictWord{8, 0, 214},
+ dictWord{8, 0, 231},
+ dictWord{8, 0, 294},
+ dictWord{8, 0, 336},
+ dictWord{8, 0, 428},
+ dictWord{8, 0, 471},
+ dictWord{8, 0, 622},
+ dictWord{8, 0, 626},
+ dictWord{8, 0, 679},
+ dictWord{8, 0, 759},
+ dictWord{8, 0, 829},
+ dictWord{9, 0, 11},
+ dictWord{9, 0, 246},
+ dictWord{9, 0, 484},
+ dictWord{9, 0, 573},
+ dictWord{9, 0, 706},
+ dictWord{9, 0, 762},
+ dictWord{9, 0, 798},
+ dictWord{9, 0, 855},
+ dictWord{9, 0, 870},
+ dictWord{9, 0, 912},
+ dictWord{10, 0, 303},
+ dictWord{10, 0, 335},
+ dictWord{10, 0, 424},
+ dictWord{10, 0, 461},
+ dictWord{10, 0, 543},
+ dictWord{
+ 10,
+ 0,
+ 759,
+ },
+ dictWord{10, 0, 814},
+ dictWord{11, 0, 59},
+ dictWord{11, 0, 199},
+ dictWord{11, 0, 235},
+ dictWord{11, 0, 590},
+ dictWord{11, 0, 631},
+ dictWord{11, 0, 929},
+ dictWord{11, 0, 963},
+ dictWord{11, 0, 987},
+ dictWord{12, 0, 114},
+ dictWord{12, 0, 182},
+ dictWord{12, 0, 226},
+ dictWord{12, 0, 332},
+ dictWord{12, 0, 439},
+ dictWord{12, 0, 575},
+ dictWord{12, 0, 598},
+ dictWord{12, 0, 675},
+ dictWord{13, 0, 8},
+ dictWord{13, 0, 125},
+ dictWord{13, 0, 194},
+ dictWord{13, 0, 287},
+ dictWord{
+ 14,
+ 0,
+ 197,
+ },
+ dictWord{14, 0, 383},
+ dictWord{15, 0, 53},
+ dictWord{17, 0, 63},
+ dictWord{19, 0, 46},
+ dictWord{19, 0, 98},
+ dictWord{19, 0, 106},
+ dictWord{148, 0, 85},
+ dictWord{
+ 7,
+ 0,
+ 1356,
+ },
+ dictWord{132, 10, 290},
+ dictWord{6, 10, 70},
+ dictWord{7, 10, 1292},
+ dictWord{10, 10, 762},
+ dictWord{139, 10, 288},
+ dictWord{150, 11, 55},
+ dictWord{4, 0, 593},
+ dictWord{8, 11, 115},
+ dictWord{8, 11, 350},
+ dictWord{9, 11, 489},
+ dictWord{10, 11, 128},
+ dictWord{11, 11, 306},
+ dictWord{12, 11, 373},
+ dictWord{14, 11, 30},
+ dictWord{17, 11, 79},
+ dictWord{147, 11, 80},
+ dictWord{135, 11, 1235},
+ dictWord{134, 0, 1392},
+ dictWord{4, 11, 230},
+ dictWord{
+ 133,
+ 11,
+ 702,
+ },
+ dictWord{147, 0, 126},
+ dictWord{7, 10, 131},
+ dictWord{7, 10, 422},
+ dictWord{8, 10, 210},
+ dictWord{140, 10, 573},
+ dictWord{134, 0, 1179},
+ dictWord{
+ 139,
+ 11,
+ 435,
+ },
+ dictWord{139, 10, 797},
+ dictWord{134, 11, 1728},
+ dictWord{4, 0, 162},
+ dictWord{18, 11, 26},
+ dictWord{19, 11, 42},
+ dictWord{20, 11, 43},
+ dictWord{21, 11, 0},
+ dictWord{23, 11, 27},
+ dictWord{152, 11, 14},
+ dictWord{132, 10, 936},
+ dictWord{6, 0, 765},
+ dictWord{5, 10, 453},
+ dictWord{134, 10, 441},
+ dictWord{133, 0, 187},
+ dictWord{135, 0, 1286},
+ dictWord{6, 0, 635},
+ dictWord{6, 0, 904},
+ dictWord{6, 0, 1210},
+ dictWord{134, 0, 1489},
+ dictWord{4, 0, 215},
+ dictWord{
+ 8,
+ 0,
+ 890,
+ },
+ dictWord{9, 0, 38},
+ dictWord{10, 0, 923},
+ dictWord{11, 0, 23},
+ dictWord{11, 0, 127},
+ dictWord{139, 0, 796},
+ dictWord{6, 0, 1165},
+ dictWord{
+ 134,
+ 0,
+ 1306,
+ },
+ dictWord{7, 0, 716},
+ dictWord{13, 0, 97},
+ dictWord{141, 0, 251},
+ dictWord{132, 10, 653},
+ dictWord{136, 0, 657},
+ dictWord{146, 10, 80},
+ dictWord{
+ 5,
+ 11,
+ 622,
+ },
+ dictWord{7, 11, 1032},
+ dictWord{11, 11, 26},
+ dictWord{11, 11, 213},
+ dictWord{11, 11, 707},
+ dictWord{12, 11, 380},
+ dictWord{13, 11, 226},
+ dictWord{141, 11, 355},
+ dictWord{6, 0, 299},
+ dictWord{5, 11, 70},
+ dictWord{6, 11, 334},
+ dictWord{9, 11, 171},
+ dictWord{11, 11, 637},
+ dictWord{12, 11, 202},
+ dictWord{14, 11, 222},
+ dictWord{145, 11, 42},
+ dictWord{142, 0, 134},
+ dictWord{4, 11, 23},
+ dictWord{5, 11, 313},
+ dictWord{5, 11, 1014},
+ dictWord{6, 11, 50},
+ dictWord{
+ 6,
+ 11,
+ 51,
+ },
+ dictWord{7, 11, 142},
+ dictWord{7, 11, 384},
+ dictWord{9, 11, 783},
+ dictWord{139, 11, 741},
+ dictWord{4, 11, 141},
+ dictWord{7, 11, 559},
+ dictWord{
+ 8,
+ 11,
+ 640,
+ },
+ dictWord{9, 11, 460},
+ dictWord{12, 11, 183},
+ dictWord{141, 11, 488},
+ dictWord{136, 11, 614},
+ dictWord{7, 10, 1368},
+ dictWord{8, 10, 232},
+ dictWord{8, 10, 361},
+ dictWord{10, 10, 682},
+ dictWord{138, 10, 742},
+ dictWord{137, 10, 534},
+ dictWord{6, 0, 1082},
+ dictWord{140, 0, 658},
+ dictWord{
+ 137,
+ 10,
+ 27,
+ },
+ dictWord{135, 0, 2002},
+ dictWord{142, 10, 12},
+ dictWord{4, 0, 28},
+ dictWord{5, 0, 440},
+ dictWord{7, 0, 248},
+ dictWord{11, 0, 833},
+ dictWord{140, 0, 344},
+ dictWord{7, 10, 736},
+ dictWord{139, 10, 264},
+ dictWord{134, 10, 1657},
+ dictWord{134, 0, 1654},
+ dictWord{138, 0, 531},
+ dictWord{5, 11, 222},
+ dictWord{
+ 9,
+ 11,
+ 140,
+ },
+ dictWord{138, 11, 534},
+ dictWord{6, 0, 634},
+ dictWord{6, 0, 798},
+ dictWord{134, 0, 840},
+ dictWord{138, 11, 503},
+ dictWord{135, 10, 127},
+ dictWord{133, 0, 853},
+ dictWord{5, 11, 154},
+ dictWord{7, 11, 1491},
+ dictWord{10, 11, 379},
+ dictWord{138, 11, 485},
+ dictWord{6, 0, 249},
+ dictWord{7, 0, 1234},
+ dictWord{139, 0, 573},
+ dictWord{133, 11, 716},
+ dictWord{7, 11, 1570},
+ dictWord{140, 11, 542},
+ dictWord{136, 10, 364},
+ dictWord{138, 0, 527},
+ dictWord{
+ 4,
+ 11,
+ 91,
+ },
+ dictWord{5, 11, 388},
+ dictWord{5, 11, 845},
+ dictWord{6, 11, 206},
+ dictWord{6, 11, 252},
+ dictWord{6, 11, 365},
+ dictWord{7, 11, 136},
+ dictWord{7, 11, 531},
+ dictWord{8, 11, 264},
+ dictWord{136, 11, 621},
+ dictWord{134, 0, 1419},
+ dictWord{135, 11, 1441},
+ dictWord{7, 0, 49},
+ dictWord{7, 0, 392},
+ dictWord{8, 0, 20},
+ dictWord{8, 0, 172},
+ dictWord{8, 0, 690},
+ dictWord{9, 0, 383},
+ dictWord{9, 0, 845},
+ dictWord{10, 0, 48},
+ dictWord{11, 0, 293},
+ dictWord{11, 0, 832},
+ dictWord{
+ 11,
+ 0,
+ 920,
+ },
+ dictWord{11, 0, 984},
+ dictWord{141, 0, 221},
+ dictWord{5, 0, 858},
+ dictWord{133, 0, 992},
+ dictWord{5, 0, 728},
+ dictWord{137, 10, 792},
+ dictWord{
+ 5,
+ 10,
+ 909,
+ },
+ dictWord{9, 10, 849},
+ dictWord{138, 10, 805},
+ dictWord{7, 0, 525},
+ dictWord{7, 0, 1579},
+ dictWord{8, 0, 497},
+ dictWord{136, 0, 573},
+ dictWord{6, 0, 268},
+ dictWord{137, 0, 62},
+ dictWord{135, 11, 576},
+ dictWord{134, 0, 1201},
+ dictWord{5, 11, 771},
+ dictWord{5, 11, 863},
+ dictWord{5, 11, 898},
+ dictWord{
+ 6,
+ 11,
+ 1632,
+ },
+ dictWord{6, 11, 1644},
+ dictWord{134, 11, 1780},
+ dictWord{133, 11, 331},
+ dictWord{7, 0, 193},
+ dictWord{7, 0, 1105},
+ dictWord{10, 0, 495},
+ dictWord{
+ 7,
+ 10,
+ 397,
+ },
+ dictWord{8, 10, 124},
+ dictWord{8, 10, 619},
+ dictWord{9, 10, 305},
+ dictWord{11, 10, 40},
+ dictWord{12, 10, 349},
+ dictWord{13, 10, 134},
+ dictWord{
+ 13,
+ 10,
+ 295,
+ },
+ dictWord{14, 10, 155},
+ dictWord{15, 10, 120},
+ dictWord{146, 10, 105},
+ dictWord{138, 0, 106},
+ dictWord{6, 0, 859},
+ dictWord{5, 11, 107},
+ dictWord{
+ 7,
+ 11,
+ 201,
+ },
+ dictWord{136, 11, 518},
+ dictWord{6, 11, 446},
+ dictWord{135, 11, 1817},
+ dictWord{13, 0, 23},
+ dictWord{4, 10, 262},
+ dictWord{135, 10, 342},
+ dictWord{133, 10, 641},
+ dictWord{137, 11, 851},
+ dictWord{6, 0, 925},
+ dictWord{137, 0, 813},
+ dictWord{132, 11, 504},
+ dictWord{6, 0, 613},
+ dictWord{
+ 136,
+ 0,
+ 223,
+ },
+ dictWord{4, 10, 99},
+ dictWord{6, 10, 250},
+ dictWord{6, 10, 346},
+ dictWord{8, 10, 127},
+ dictWord{138, 10, 81},
+ dictWord{136, 0, 953},
+ dictWord{
+ 132,
+ 10,
+ 915,
+ },
+ dictWord{139, 11, 892},
+ dictWord{5, 10, 75},
+ dictWord{9, 10, 517},
+ dictWord{10, 10, 470},
+ dictWord{12, 10, 155},
+ dictWord{141, 10, 224},
+ dictWord{
+ 4,
+ 0,
+ 666,
+ },
+ dictWord{7, 0, 1017},
+ dictWord{7, 11, 996},
+ dictWord{138, 11, 390},
+ dictWord{5, 11, 883},
+ dictWord{133, 11, 975},
+ dictWord{14, 10, 83},
+ dictWord{
+ 142,
+ 11,
+ 83,
+ },
+ dictWord{4, 0, 670},
+ dictWord{5, 11, 922},
+ dictWord{134, 11, 1707},
+ dictWord{135, 0, 216},
+ dictWord{9, 0, 40},
+ dictWord{11, 0, 136},
+ dictWord{
+ 135,
+ 11,
+ 787,
+ },
+ dictWord{5, 10, 954},
+ dictWord{5, 11, 993},
+ dictWord{7, 11, 515},
+ dictWord{137, 11, 91},
+ dictWord{139, 0, 259},
+ dictWord{7, 0, 1114},
+ dictWord{
+ 9,
+ 0,
+ 310,
+ },
+ dictWord{9, 0, 682},
+ dictWord{10, 0, 440},
+ dictWord{13, 0, 40},
+ dictWord{6, 10, 304},
+ dictWord{8, 10, 418},
+ dictWord{11, 10, 341},
+ dictWord{
+ 139,
+ 10,
+ 675,
+ },
+ dictWord{14, 0, 296},
+ dictWord{9, 10, 410},
+ dictWord{139, 10, 425},
+ dictWord{10, 11, 377},
+ dictWord{12, 11, 363},
+ dictWord{13, 11, 68},
+ dictWord{
+ 13,
+ 11,
+ 94,
+ },
+ dictWord{14, 11, 108},
+ dictWord{142, 11, 306},
+ dictWord{7, 0, 1401},
+ dictWord{135, 0, 1476},
+ dictWord{4, 0, 296},
+ dictWord{6, 0, 475},
+ dictWord{
+ 7,
+ 0,
+ 401,
+ },
+ dictWord{7, 0, 1410},
+ dictWord{7, 0, 1594},
+ dictWord{7, 0, 1674},
+ dictWord{8, 0, 63},
+ dictWord{8, 0, 660},
+ dictWord{137, 0, 74},
+ dictWord{4, 0, 139},
+ dictWord{4, 0, 388},
+ dictWord{140, 0, 188},
+ dictWord{132, 0, 797},
+ dictWord{132, 11, 766},
+ dictWord{5, 11, 103},
+ dictWord{7, 11, 921},
+ dictWord{8, 11, 580},
+ dictWord{8, 11, 593},
+ dictWord{8, 11, 630},
+ dictWord{138, 11, 28},
+ dictWord{4, 11, 911},
+ dictWord{5, 11, 867},
+ dictWord{133, 11, 1013},
+ dictWord{134, 10, 14},
+ dictWord{134, 0, 1572},
+ dictWord{134, 10, 1708},
+ dictWord{21, 0, 39},
+ dictWord{5, 10, 113},
+ dictWord{6, 10, 243},
+ dictWord{7, 10, 1865},
+ dictWord{
+ 11,
+ 10,
+ 161,
+ },
+ dictWord{16, 10, 37},
+ dictWord{145, 10, 99},
+ dictWord{7, 11, 1563},
+ dictWord{141, 11, 182},
+ dictWord{5, 11, 135},
+ dictWord{6, 11, 519},
+ dictWord{
+ 7,
+ 11,
+ 1722,
+ },
+ dictWord{10, 11, 271},
+ dictWord{11, 11, 261},
+ dictWord{145, 11, 54},
+ dictWord{132, 10, 274},
+ dictWord{134, 0, 1594},
+ dictWord{4, 11, 300},
+ dictWord{5, 11, 436},
+ dictWord{135, 11, 484},
+ dictWord{4, 0, 747},
+ dictWord{6, 0, 290},
+ dictWord{7, 0, 649},
+ dictWord{7, 0, 1479},
+ dictWord{135, 0, 1583},
+ dictWord{133, 11, 535},
+ dictWord{147, 11, 82},
+ dictWord{133, 0, 232},
+ dictWord{137, 0, 887},
+ dictWord{135, 10, 166},
+ dictWord{136, 0, 521},
+ dictWord{4, 0, 14},
+ dictWord{7, 0, 472},
+ dictWord{7, 0, 1801},
+ dictWord{10, 0, 748},
+ dictWord{141, 0, 458},
+ dictWord{134, 0, 741},
+ dictWord{134, 0, 992},
+ dictWord{16, 0, 111},
+ dictWord{137, 10, 304},
+ dictWord{4, 0, 425},
+ dictWord{5, 11, 387},
+ dictWord{7, 11, 557},
+ dictWord{12, 11, 547},
+ dictWord{142, 11, 86},
+ dictWord{
+ 135,
+ 11,
+ 1747,
+ },
+ dictWord{5, 10, 654},
+ dictWord{135, 11, 1489},
+ dictWord{7, 0, 789},
+ dictWord{4, 11, 6},
+ dictWord{5, 11, 708},
+ dictWord{136, 11, 75},
+ dictWord{
+ 6,
+ 10,
+ 273,
+ },
+ dictWord{10, 10, 188},
+ dictWord{13, 10, 377},
+ dictWord{146, 10, 77},
+ dictWord{6, 0, 1593},
+ dictWord{4, 11, 303},
+ dictWord{7, 11, 619},
+ dictWord{
+ 10,
+ 11,
+ 547,
+ },
+ dictWord{10, 11, 687},
+ dictWord{11, 11, 122},
+ dictWord{140, 11, 601},
+ dictWord{134, 0, 1768},
+ dictWord{135, 10, 410},
+ dictWord{138, 11, 772},
+ dictWord{11, 0, 233},
+ dictWord{139, 10, 524},
+ dictWord{5, 0, 943},
+ dictWord{134, 0, 1779},
+ dictWord{134, 10, 1785},
+ dictWord{136, 11, 529},
+ dictWord{
+ 132,
+ 0,
+ 955,
+ },
+ dictWord{5, 0, 245},
+ dictWord{6, 0, 576},
+ dictWord{7, 0, 582},
+ dictWord{136, 0, 225},
+ dictWord{132, 10, 780},
+ dictWord{142, 0, 241},
+ dictWord{
+ 134,
+ 0,
+ 1943,
+ },
+ dictWord{4, 11, 106},
+ dictWord{7, 11, 310},
+ dictWord{7, 11, 1785},
+ dictWord{10, 11, 690},
+ dictWord{139, 11, 717},
+ dictWord{134, 0, 1284},
+ dictWord{5, 11, 890},
+ dictWord{133, 11, 988},
+ dictWord{6, 11, 626},
+ dictWord{142, 11, 431},
+ dictWord{10, 11, 706},
+ dictWord{145, 11, 32},
+ dictWord{
+ 137,
+ 11,
+ 332,
+ },
+ dictWord{132, 11, 698},
+ dictWord{135, 0, 709},
+ dictWord{5, 10, 948},
+ dictWord{138, 11, 17},
+ dictWord{136, 0, 554},
+ dictWord{134, 0, 1564},
+ dictWord{139, 10, 941},
+ dictWord{132, 0, 443},
+ dictWord{134, 0, 909},
+ dictWord{134, 11, 84},
+ dictWord{142, 0, 280},
+ dictWord{4, 10, 532},
+ dictWord{5, 10, 706},
+ dictWord{135, 10, 662},
+ dictWord{132, 0, 729},
+ dictWord{5, 10, 837},
+ dictWord{6, 10, 1651},
+ dictWord{139, 10, 985},
+ dictWord{135, 10, 1861},
+ dictWord{
+ 4,
+ 0,
+ 348,
+ },
+ dictWord{152, 11, 3},
+ dictWord{5, 11, 986},
+ dictWord{6, 11, 130},
+ dictWord{7, 11, 1582},
+ dictWord{8, 11, 458},
+ dictWord{10, 11, 101},
+ dictWord{
+ 10,
+ 11,
+ 318,
+ },
+ dictWord{138, 11, 823},
+ dictWord{134, 0, 758},
+ dictWord{4, 0, 298},
+ dictWord{137, 0, 848},
+ dictWord{4, 10, 330},
+ dictWord{7, 10, 933},
+ dictWord{
+ 7,
+ 10,
+ 2012,
+ },
+ dictWord{136, 10, 292},
+ dictWord{7, 11, 1644},
+ dictWord{137, 11, 129},
+ dictWord{6, 0, 1422},
+ dictWord{9, 0, 829},
+ dictWord{135, 10, 767},
+ dictWord{5, 0, 164},
+ dictWord{7, 0, 121},
+ dictWord{142, 0, 189},
+ dictWord{7, 0, 812},
+ dictWord{7, 0, 1261},
+ dictWord{7, 0, 1360},
+ dictWord{9, 0, 632},
+ dictWord{
+ 140,
+ 0,
+ 352,
+ },
+ dictWord{135, 11, 1788},
+ dictWord{139, 0, 556},
+ dictWord{135, 11, 997},
+ dictWord{145, 10, 114},
+ dictWord{4, 0, 172},
+ dictWord{9, 0, 611},
+ dictWord{10, 0, 436},
+ dictWord{12, 0, 673},
+ dictWord{13, 0, 255},
+ dictWord{137, 10, 883},
+ dictWord{11, 0, 530},
+ dictWord{138, 10, 274},
+ dictWord{133, 0, 844},
+ dictWord{134, 0, 984},
+ dictWord{13, 0, 232},
+ dictWord{18, 0, 35},
+ dictWord{4, 10, 703},
+ dictWord{135, 10, 207},
+ dictWord{132, 10, 571},
+ dictWord{9, 0, 263},
+ dictWord{10, 0, 147},
+ dictWord{138, 0, 492},
+ dictWord{7, 11, 1756},
+ dictWord{137, 11, 98},
+ dictWord{5, 10, 873},
+ dictWord{5, 10, 960},
+ dictWord{8, 10, 823},
+ dictWord{137, 10, 881},
+ dictWord{133, 0, 537},
+ dictWord{132, 0, 859},
+ dictWord{7, 11, 1046},
+ dictWord{139, 11, 160},
+ dictWord{137, 0, 842},
+ dictWord{
+ 139,
+ 10,
+ 283,
+ },
+ dictWord{5, 10, 33},
+ dictWord{6, 10, 470},
+ dictWord{139, 10, 424},
+ dictWord{6, 11, 45},
+ dictWord{7, 11, 433},
+ dictWord{8, 11, 129},
+ dictWord{
+ 9,
+ 11,
+ 21,
+ },
+ dictWord{10, 11, 392},
+ dictWord{11, 11, 79},
+ dictWord{12, 11, 499},
+ dictWord{13, 11, 199},
+ dictWord{141, 11, 451},
+ dictWord{135, 0, 1291},
+ dictWord{135, 10, 1882},
+ dictWord{7, 11, 558},
+ dictWord{136, 11, 353},
+ dictWord{134, 0, 1482},
+ dictWord{5, 0, 230},
+ dictWord{5, 0, 392},
+ dictWord{6, 0, 420},
+ dictWord{9, 0, 568},
+ dictWord{140, 0, 612},
+ dictWord{6, 0, 262},
+ dictWord{7, 10, 90},
+ dictWord{7, 10, 664},
+ dictWord{7, 10, 830},
+ dictWord{7, 10, 1380},
+ dictWord{
+ 7,
+ 10,
+ 2025,
+ },
+ dictWord{8, 11, 81},
+ dictWord{8, 10, 448},
+ dictWord{8, 10, 828},
+ dictWord{9, 11, 189},
+ dictWord{9, 11, 201},
+ dictWord{11, 11, 478},
+ dictWord{
+ 11,
+ 11,
+ 712,
+ },
+ dictWord{141, 11, 338},
+ dictWord{142, 0, 31},
+ dictWord{5, 11, 353},
+ dictWord{151, 11, 26},
+ dictWord{132, 0, 753},
+ dictWord{4, 0, 0},
+ dictWord{
+ 5,
+ 0,
+ 41,
+ },
+ dictWord{7, 0, 1459},
+ dictWord{7, 0, 1469},
+ dictWord{7, 0, 1859},
+ dictWord{9, 0, 549},
+ dictWord{139, 0, 905},
+ dictWord{9, 10, 417},
+ dictWord{
+ 137,
+ 10,
+ 493,
+ },
+ dictWord{135, 11, 1113},
+ dictWord{133, 0, 696},
+ dictWord{141, 11, 448},
+ dictWord{134, 10, 295},
+ dictWord{132, 0, 834},
+ dictWord{4, 0, 771},
+ dictWord{5, 10, 1019},
+ dictWord{6, 11, 25},
+ dictWord{7, 11, 855},
+ dictWord{7, 11, 1258},
+ dictWord{144, 11, 32},
+ dictWord{134, 0, 1076},
+ dictWord{133, 0, 921},
+ dictWord{133, 0, 674},
+ dictWord{4, 11, 4},
+ dictWord{7, 11, 1118},
+ dictWord{7, 11, 1320},
+ dictWord{7, 11, 1706},
+ dictWord{8, 11, 277},
+ dictWord{9, 11, 622},
+ dictWord{10, 11, 9},
+ dictWord{11, 11, 724},
+ dictWord{12, 11, 350},
+ dictWord{12, 11, 397},
+ dictWord{13, 11, 28},
+ dictWord{13, 11, 159},
+ dictWord{15, 11, 89},
+ dictWord{18, 11, 5},
+ dictWord{19, 11, 9},
+ dictWord{20, 11, 34},
+ dictWord{150, 11, 47},
+ dictWord{134, 10, 208},
+ dictWord{6, 0, 444},
+ dictWord{136, 0, 308},
+ dictWord{
+ 6,
+ 0,
+ 180,
+ },
+ dictWord{7, 0, 1137},
+ dictWord{8, 0, 751},
+ dictWord{139, 0, 805},
+ dictWord{4, 0, 183},
+ dictWord{7, 0, 271},
+ dictWord{11, 0, 824},
+ dictWord{
+ 11,
+ 0,
+ 952,
+ },
+ dictWord{13, 0, 278},
+ dictWord{13, 0, 339},
+ dictWord{13, 0, 482},
+ dictWord{14, 0, 424},
+ dictWord{148, 0, 99},
+ dictWord{7, 11, 317},
+ dictWord{
+ 135,
+ 11,
+ 569,
+ },
+ dictWord{4, 0, 19},
+ dictWord{5, 0, 477},
+ dictWord{5, 0, 596},
+ dictWord{6, 0, 505},
+ dictWord{7, 0, 1221},
+ dictWord{11, 0, 907},
+ dictWord{12, 0, 209},
+ dictWord{141, 0, 214},
+ dictWord{135, 0, 1215},
+ dictWord{6, 0, 271},
+ dictWord{7, 0, 398},
+ dictWord{8, 0, 387},
+ dictWord{10, 0, 344},
+ dictWord{7, 10, 448},
+ dictWord{
+ 7,
+ 10,
+ 1629,
+ },
+ dictWord{7, 10, 1813},
+ dictWord{8, 10, 442},
+ dictWord{9, 10, 710},
+ dictWord{10, 10, 282},
+ dictWord{138, 10, 722},
+ dictWord{11, 10, 844},
+ dictWord{12, 10, 104},
+ dictWord{140, 10, 625},
+ dictWord{134, 11, 255},
+ dictWord{133, 10, 787},
+ dictWord{134, 0, 1645},
+ dictWord{11, 11, 956},
+ dictWord{
+ 151,
+ 11,
+ 3,
+ },
+ dictWord{6, 0, 92},
+ dictWord{6, 0, 188},
+ dictWord{7, 0, 209},
+ dictWord{7, 0, 1269},
+ dictWord{7, 0, 1524},
+ dictWord{7, 0, 1876},
+ dictWord{8, 0, 661},
+ dictWord{10, 0, 42},
+ dictWord{10, 0, 228},
+ dictWord{11, 0, 58},
+ dictWord{11, 0, 1020},
+ dictWord{12, 0, 58},
+ dictWord{12, 0, 118},
+ dictWord{141, 0, 32},
+ dictWord{
+ 4,
+ 0,
+ 459,
+ },
+ dictWord{133, 0, 966},
+ dictWord{4, 11, 536},
+ dictWord{7, 11, 1141},
+ dictWord{10, 11, 723},
+ dictWord{139, 11, 371},
+ dictWord{140, 0, 330},
+ dictWord{134, 0, 1557},
+ dictWord{7, 11, 285},
+ dictWord{135, 11, 876},
+ dictWord{136, 10, 491},
+ dictWord{135, 11, 560},
+ dictWord{6, 0, 18},
+ dictWord{7, 0, 179},
+ dictWord{7, 0, 932},
+ dictWord{8, 0, 548},
+ dictWord{8, 0, 757},
+ dictWord{9, 0, 54},
+ dictWord{9, 0, 65},
+ dictWord{9, 0, 532},
+ dictWord{9, 0, 844},
+ dictWord{10, 0, 113},
+ dictWord{10, 0, 117},
+ dictWord{10, 0, 315},
+ dictWord{10, 0, 560},
+ dictWord{10, 0, 622},
+ dictWord{10, 0, 798},
+ dictWord{11, 0, 153},
+ dictWord{11, 0, 351},
+ dictWord{
+ 11,
+ 0,
+ 375,
+ },
+ dictWord{12, 0, 78},
+ dictWord{12, 0, 151},
+ dictWord{12, 0, 392},
+ dictWord{12, 0, 666},
+ dictWord{14, 0, 248},
+ dictWord{143, 0, 23},
+ dictWord{
+ 6,
+ 0,
+ 1742,
+ },
+ dictWord{132, 11, 690},
+ dictWord{4, 10, 403},
+ dictWord{5, 10, 441},
+ dictWord{7, 10, 450},
+ dictWord{10, 10, 840},
+ dictWord{11, 10, 101},
+ dictWord{
+ 12,
+ 10,
+ 193,
+ },
+ dictWord{141, 10, 430},
+ dictWord{133, 0, 965},
+ dictWord{134, 0, 182},
+ dictWord{10, 0, 65},
+ dictWord{10, 0, 488},
+ dictWord{138, 0, 497},
+ dictWord{135, 11, 1346},
+ dictWord{6, 0, 973},
+ dictWord{6, 0, 1158},
+ dictWord{10, 11, 200},
+ dictWord{19, 11, 2},
+ dictWord{151, 11, 22},
+ dictWord{4, 11, 190},
+ dictWord{133, 11, 554},
+ dictWord{133, 10, 679},
+ dictWord{7, 0, 328},
+ dictWord{137, 10, 326},
+ dictWord{133, 11, 1001},
+ dictWord{9, 0, 588},
+ dictWord{
+ 138,
+ 0,
+ 260,
+ },
+ dictWord{133, 11, 446},
+ dictWord{135, 10, 1128},
+ dictWord{135, 10, 1796},
+ dictWord{147, 11, 119},
+ dictWord{134, 0, 1786},
+ dictWord{
+ 6,
+ 0,
+ 1328,
+ },
+ dictWord{6, 0, 1985},
+ dictWord{8, 0, 962},
+ dictWord{138, 0, 1017},
+ dictWord{135, 0, 308},
+ dictWord{11, 0, 508},
+ dictWord{4, 10, 574},
+ dictWord{
+ 7,
+ 10,
+ 350,
+ },
+ dictWord{7, 10, 1024},
+ dictWord{8, 10, 338},
+ dictWord{9, 10, 677},
+ dictWord{138, 10, 808},
+ dictWord{138, 11, 752},
+ dictWord{135, 10, 1081},
+ dictWord{137, 11, 96},
+ dictWord{7, 10, 1676},
+ dictWord{135, 10, 2037},
+ dictWord{136, 0, 588},
+ dictWord{132, 11, 304},
+ dictWord{133, 0, 614},
+ dictWord{
+ 140,
+ 0,
+ 793,
+ },
+ dictWord{136, 0, 287},
+ dictWord{137, 10, 297},
+ dictWord{141, 10, 37},
+ dictWord{6, 11, 53},
+ dictWord{6, 11, 199},
+ dictWord{7, 11, 1408},
+ dictWord{
+ 8,
+ 11,
+ 32,
+ },
+ dictWord{8, 11, 93},
+ dictWord{9, 11, 437},
+ dictWord{10, 11, 397},
+ dictWord{10, 11, 629},
+ dictWord{11, 11, 593},
+ dictWord{11, 11, 763},
+ dictWord{
+ 13,
+ 11,
+ 326,
+ },
+ dictWord{145, 11, 35},
+ dictWord{134, 11, 105},
+ dictWord{9, 11, 320},
+ dictWord{10, 11, 506},
+ dictWord{138, 11, 794},
+ dictWord{5, 11, 114},
+ dictWord{5, 11, 255},
+ dictWord{141, 11, 285},
+ dictWord{140, 0, 290},
+ dictWord{7, 11, 2035},
+ dictWord{8, 11, 19},
+ dictWord{9, 11, 89},
+ dictWord{138, 11, 831},
+ dictWord{134, 0, 1136},
+ dictWord{7, 0, 719},
+ dictWord{8, 0, 796},
+ dictWord{8, 0, 809},
+ dictWord{8, 0, 834},
+ dictWord{6, 10, 306},
+ dictWord{7, 10, 1140},
+ dictWord{
+ 7,
+ 10,
+ 1340,
+ },
+ dictWord{8, 10, 133},
+ dictWord{138, 10, 449},
+ dictWord{139, 10, 1011},
+ dictWord{5, 0, 210},
+ dictWord{6, 0, 213},
+ dictWord{7, 0, 60},
+ dictWord{
+ 10,
+ 0,
+ 364,
+ },
+ dictWord{139, 0, 135},
+ dictWord{5, 0, 607},
+ dictWord{8, 0, 326},
+ dictWord{136, 0, 490},
+ dictWord{138, 11, 176},
+ dictWord{132, 0, 701},
+ dictWord{
+ 5,
+ 0,
+ 472,
+ },
+ dictWord{7, 0, 380},
+ dictWord{137, 0, 758},
+ dictWord{135, 0, 1947},
+ dictWord{6, 0, 1079},
+ dictWord{138, 0, 278},
+ dictWord{138, 11, 391},
+ dictWord{
+ 5,
+ 10,
+ 329,
+ },
+ dictWord{8, 10, 260},
+ dictWord{139, 11, 156},
+ dictWord{4, 0, 386},
+ dictWord{7, 0, 41},
+ dictWord{8, 0, 405},
+ dictWord{8, 0, 728},
+ dictWord{9, 0, 497},
+ dictWord{11, 0, 110},
+ dictWord{11, 0, 360},
+ dictWord{15, 0, 37},
+ dictWord{144, 0, 84},
+ dictWord{5, 0, 46},
+ dictWord{7, 0, 1452},
+ dictWord{7, 0, 1480},
+ dictWord{
+ 8,
+ 0,
+ 634,
+ },
+ dictWord{140, 0, 472},
+ dictWord{136, 0, 961},
+ dictWord{4, 0, 524},
+ dictWord{136, 0, 810},
+ dictWord{10, 0, 238},
+ dictWord{141, 0, 33},
+ dictWord{
+ 132,
+ 10,
+ 657,
+ },
+ dictWord{152, 10, 7},
+ dictWord{133, 0, 532},
+ dictWord{5, 0, 997},
+ dictWord{135, 10, 1665},
+ dictWord{7, 11, 594},
+ dictWord{7, 11, 851},
+ dictWord{
+ 7,
+ 11,
+ 1858,
+ },
+ dictWord{9, 11, 411},
+ dictWord{9, 11, 574},
+ dictWord{9, 11, 666},
+ dictWord{9, 11, 737},
+ dictWord{10, 11, 346},
+ dictWord{10, 11, 712},
+ dictWord{
+ 11,
+ 11,
+ 246,
+ },
+ dictWord{11, 11, 432},
+ dictWord{11, 11, 517},
+ dictWord{11, 11, 647},
+ dictWord{11, 11, 679},
+ dictWord{11, 11, 727},
+ dictWord{12, 11, 304},
+ dictWord{12, 11, 305},
+ dictWord{12, 11, 323},
+ dictWord{12, 11, 483},
+ dictWord{12, 11, 572},
+ dictWord{12, 11, 593},
+ dictWord{12, 11, 602},
+ dictWord{
+ 13,
+ 11,
+ 95,
+ },
+ dictWord{13, 11, 101},
+ dictWord{13, 11, 171},
+ dictWord{13, 11, 315},
+ dictWord{13, 11, 378},
+ dictWord{13, 11, 425},
+ dictWord{13, 11, 475},
+ dictWord{
+ 14,
+ 11,
+ 63,
+ },
+ dictWord{14, 11, 380},
+ dictWord{14, 11, 384},
+ dictWord{15, 11, 133},
+ dictWord{18, 11, 112},
+ dictWord{148, 11, 72},
+ dictWord{5, 11, 955},
+ dictWord{136, 11, 814},
+ dictWord{134, 0, 1301},
+ dictWord{5, 10, 66},
+ dictWord{7, 10, 1896},
+ dictWord{136, 10, 288},
+ dictWord{133, 11, 56},
+ dictWord{
+ 134,
+ 10,
+ 1643,
+ },
+ dictWord{6, 0, 1298},
+ dictWord{148, 11, 100},
+ dictWord{5, 0, 782},
+ dictWord{5, 0, 829},
+ dictWord{6, 0, 671},
+ dictWord{6, 0, 1156},
+ dictWord{6, 0, 1738},
+ dictWord{137, 11, 621},
+ dictWord{4, 0, 306},
+ dictWord{5, 0, 570},
+ dictWord{7, 0, 1347},
+ dictWord{5, 10, 91},
+ dictWord{5, 10, 648},
+ dictWord{5, 10, 750},
+ dictWord{
+ 5,
+ 10,
+ 781,
+ },
+ dictWord{6, 10, 54},
+ dictWord{6, 10, 112},
+ dictWord{6, 10, 402},
+ dictWord{6, 10, 1732},
+ dictWord{7, 10, 315},
+ dictWord{7, 10, 749},
+ dictWord{
+ 7,
+ 10,
+ 1900,
+ },
+ dictWord{9, 10, 78},
+ dictWord{9, 10, 508},
+ dictWord{10, 10, 611},
+ dictWord{10, 10, 811},
+ dictWord{11, 10, 510},
+ dictWord{11, 10, 728},
+ dictWord{
+ 13,
+ 10,
+ 36,
+ },
+ dictWord{14, 10, 39},
+ dictWord{16, 10, 83},
+ dictWord{17, 10, 124},
+ dictWord{148, 10, 30},
+ dictWord{8, 10, 570},
+ dictWord{9, 11, 477},
+ dictWord{
+ 141,
+ 11,
+ 78,
+ },
+ dictWord{4, 11, 639},
+ dictWord{10, 11, 4},
+ dictWord{10, 10, 322},
+ dictWord{10, 10, 719},
+ dictWord{11, 10, 407},
+ dictWord{11, 11, 638},
+ dictWord{
+ 12,
+ 11,
+ 177,
+ },
+ dictWord{148, 11, 57},
+ dictWord{7, 0, 1823},
+ dictWord{139, 0, 693},
+ dictWord{7, 0, 759},
+ dictWord{5, 11, 758},
+ dictWord{8, 10, 125},
+ dictWord{
+ 8,
+ 10,
+ 369,
+ },
+ dictWord{8, 10, 524},
+ dictWord{10, 10, 486},
+ dictWord{11, 10, 13},
+ dictWord{11, 10, 381},
+ dictWord{11, 10, 736},
+ dictWord{11, 10, 766},
+ dictWord{
+ 11,
+ 10,
+ 845,
+ },
+ dictWord{13, 10, 114},
+ dictWord{13, 10, 292},
+ dictWord{142, 10, 47},
+ dictWord{7, 0, 1932},
+ dictWord{6, 10, 1684},
+ dictWord{6, 10, 1731},
+ dictWord{7, 10, 356},
+ dictWord{8, 10, 54},
+ dictWord{8, 10, 221},
+ dictWord{9, 10, 225},
+ dictWord{9, 10, 356},
+ dictWord{10, 10, 77},
+ dictWord{10, 10, 446},
+ dictWord{
+ 10,
+ 10,
+ 731,
+ },
+ dictWord{12, 10, 404},
+ dictWord{141, 10, 491},
+ dictWord{135, 11, 552},
+ dictWord{135, 11, 1112},
+ dictWord{4, 0, 78},
+ dictWord{5, 0, 96},
+ dictWord{
+ 5,
+ 0,
+ 182,
+ },
+ dictWord{6, 0, 1257},
+ dictWord{7, 0, 1724},
+ dictWord{7, 0, 1825},
+ dictWord{10, 0, 394},
+ dictWord{10, 0, 471},
+ dictWord{11, 0, 532},
+ dictWord{
+ 14,
+ 0,
+ 340,
+ },
+ dictWord{145, 0, 88},
+ dictWord{139, 11, 328},
+ dictWord{135, 0, 1964},
+ dictWord{132, 10, 411},
+ dictWord{4, 10, 80},
+ dictWord{5, 10, 44},
+ dictWord{
+ 137,
+ 11,
+ 133,
+ },
+ dictWord{5, 11, 110},
+ dictWord{6, 11, 169},
+ dictWord{6, 11, 1702},
+ dictWord{7, 11, 400},
+ dictWord{8, 11, 538},
+ dictWord{9, 11, 184},
+ dictWord{
+ 9,
+ 11,
+ 524,
+ },
+ dictWord{140, 11, 218},
+ dictWord{4, 0, 521},
+ dictWord{5, 10, 299},
+ dictWord{7, 10, 1083},
+ dictWord{140, 11, 554},
+ dictWord{6, 11, 133},
+ dictWord{
+ 9,
+ 11,
+ 353,
+ },
+ dictWord{12, 11, 628},
+ dictWord{146, 11, 79},
+ dictWord{6, 0, 215},
+ dictWord{7, 0, 584},
+ dictWord{7, 0, 1028},
+ dictWord{7, 0, 1473},
+ dictWord{
+ 7,
+ 0,
+ 1721,
+ },
+ dictWord{9, 0, 424},
+ dictWord{138, 0, 779},
+ dictWord{7, 0, 857},
+ dictWord{7, 0, 1209},
+ dictWord{7, 10, 1713},
+ dictWord{9, 10, 537},
+ dictWord{
+ 10,
+ 10,
+ 165,
+ },
+ dictWord{12, 10, 219},
+ dictWord{140, 10, 561},
+ dictWord{4, 10, 219},
+ dictWord{6, 11, 93},
+ dictWord{7, 11, 1422},
+ dictWord{7, 10, 1761},
+ dictWord{
+ 7,
+ 11,
+ 1851,
+ },
+ dictWord{8, 11, 673},
+ dictWord{9, 10, 86},
+ dictWord{9, 11, 529},
+ dictWord{140, 11, 43},
+ dictWord{137, 11, 371},
+ dictWord{136, 0, 671},
+ dictWord{
+ 5,
+ 0,
+ 328,
+ },
+ dictWord{135, 0, 918},
+ dictWord{132, 0, 529},
+ dictWord{9, 11, 25},
+ dictWord{10, 11, 467},
+ dictWord{138, 11, 559},
+ dictWord{4, 11, 335},
+ dictWord{
+ 135,
+ 11,
+ 942,
+ },
+ dictWord{134, 0, 716},
+ dictWord{134, 0, 1509},
+ dictWord{6, 0, 67},
+ dictWord{7, 0, 258},
+ dictWord{7, 0, 1630},
+ dictWord{9, 0, 354},
+ dictWord{
+ 9,
+ 0,
+ 675,
+ },
+ dictWord{10, 0, 830},
+ dictWord{14, 0, 80},
+ dictWord{17, 0, 80},
+ dictWord{140, 10, 428},
+ dictWord{134, 0, 1112},
+ dictWord{6, 0, 141},
+ dictWord{7, 0, 225},
+ dictWord{9, 0, 59},
+ dictWord{9, 0, 607},
+ dictWord{10, 0, 312},
+ dictWord{11, 0, 687},
+ dictWord{12, 0, 555},
+ dictWord{13, 0, 373},
+ dictWord{13, 0, 494},
+ dictWord{
+ 148,
+ 0,
+ 58,
+ },
+ dictWord{133, 10, 514},
+ dictWord{8, 11, 39},
+ dictWord{10, 11, 773},
+ dictWord{11, 11, 84},
+ dictWord{12, 11, 205},
+ dictWord{142, 11, 1},
+ dictWord{
+ 8,
+ 0,
+ 783,
+ },
+ dictWord{5, 11, 601},
+ dictWord{133, 11, 870},
+ dictWord{136, 11, 594},
+ dictWord{4, 10, 55},
+ dictWord{5, 10, 301},
+ dictWord{6, 10, 571},
+ dictWord{
+ 14,
+ 10,
+ 49,
+ },
+ dictWord{146, 10, 102},
+ dictWord{132, 11, 181},
+ dictWord{134, 11, 1652},
+ dictWord{133, 10, 364},
+ dictWord{4, 11, 97},
+ dictWord{5, 11, 147},
+ dictWord{6, 11, 286},
+ dictWord{7, 11, 1362},
+ dictWord{141, 11, 176},
+ dictWord{4, 10, 76},
+ dictWord{7, 10, 1550},
+ dictWord{9, 10, 306},
+ dictWord{9, 10, 430},
+ dictWord{9, 10, 663},
+ dictWord{10, 10, 683},
+ dictWord{11, 10, 427},
+ dictWord{11, 10, 753},
+ dictWord{12, 10, 334},
+ dictWord{12, 10, 442},
+ dictWord{
+ 14,
+ 10,
+ 258,
+ },
+ dictWord{14, 10, 366},
+ dictWord{143, 10, 131},
+ dictWord{137, 10, 52},
+ dictWord{6, 0, 955},
+ dictWord{134, 0, 1498},
+ dictWord{6, 11, 375},
+ dictWord{
+ 7,
+ 11,
+ 169,
+ },
+ dictWord{7, 11, 254},
+ dictWord{136, 11, 780},
+ dictWord{7, 0, 430},
+ dictWord{11, 0, 46},
+ dictWord{14, 0, 343},
+ dictWord{142, 11, 343},
+ dictWord{
+ 135,
+ 0,
+ 1183,
+ },
+ dictWord{5, 0, 602},
+ dictWord{7, 0, 2018},
+ dictWord{9, 0, 418},
+ dictWord{9, 0, 803},
+ dictWord{135, 11, 1447},
+ dictWord{8, 0, 677},
+ dictWord{
+ 135,
+ 11,
+ 1044,
+ },
+ dictWord{139, 11, 285},
+ dictWord{4, 10, 656},
+ dictWord{135, 10, 779},
+ dictWord{135, 10, 144},
+ dictWord{5, 11, 629},
+ dictWord{
+ 135,
+ 11,
+ 1549,
+ },
+ dictWord{135, 10, 1373},
+ dictWord{138, 11, 209},
+ dictWord{7, 10, 554},
+ dictWord{7, 10, 605},
+ dictWord{141, 10, 10},
+ dictWord{5, 10, 838},
+ dictWord{
+ 5,
+ 10,
+ 841,
+ },
+ dictWord{134, 10, 1649},
+ dictWord{133, 10, 1012},
+ dictWord{6, 0, 1357},
+ dictWord{134, 0, 1380},
+ dictWord{144, 0, 53},
+ dictWord{6, 0, 590},
+ dictWord{7, 10, 365},
+ dictWord{7, 10, 1357},
+ dictWord{7, 10, 1497},
+ dictWord{8, 10, 154},
+ dictWord{141, 10, 281},
+ dictWord{133, 10, 340},
+ dictWord{
+ 132,
+ 11,
+ 420,
+ },
+ dictWord{135, 0, 329},
+ dictWord{147, 11, 32},
+ dictWord{4, 0, 469},
+ dictWord{10, 11, 429},
+ dictWord{139, 10, 495},
+ dictWord{8, 10, 261},
+ dictWord{
+ 9,
+ 10,
+ 144,
+ },
+ dictWord{9, 10, 466},
+ dictWord{10, 10, 370},
+ dictWord{12, 10, 470},
+ dictWord{13, 10, 144},
+ dictWord{142, 10, 348},
+ dictWord{142, 0, 460},
+ dictWord{4, 11, 325},
+ dictWord{9, 10, 897},
+ dictWord{138, 11, 125},
+ dictWord{6, 0, 1743},
+ dictWord{6, 10, 248},
+ dictWord{9, 10, 546},
+ dictWord{10, 10, 535},
+ dictWord{11, 10, 681},
+ dictWord{141, 10, 135},
+ dictWord{4, 0, 990},
+ dictWord{5, 0, 929},
+ dictWord{6, 0, 340},
+ dictWord{8, 0, 376},
+ dictWord{8, 0, 807},
+ dictWord{
+ 8,
+ 0,
+ 963,
+ },
+ dictWord{8, 0, 980},
+ dictWord{138, 0, 1007},
+ dictWord{134, 0, 1603},
+ dictWord{140, 0, 250},
+ dictWord{4, 11, 714},
+ dictWord{133, 11, 469},
+ dictWord{134, 10, 567},
+ dictWord{136, 10, 445},
+ dictWord{5, 0, 218},
+ dictWord{7, 0, 1610},
+ dictWord{8, 0, 646},
+ dictWord{10, 0, 83},
+ dictWord{11, 11, 138},
+ dictWord{140, 11, 40},
+ dictWord{7, 0, 1512},
+ dictWord{135, 0, 1794},
+ dictWord{135, 11, 1216},
+ dictWord{11, 0, 0},
+ dictWord{16, 0, 78},
+ dictWord{132, 11, 718},
+ dictWord{133, 0, 571},
+ dictWord{132, 0, 455},
+ dictWord{134, 0, 1012},
+ dictWord{5, 11, 124},
+ dictWord{5, 11, 144},
+ dictWord{6, 11, 548},
+ dictWord{7, 11, 15},
+ dictWord{7, 11, 153},
+ dictWord{137, 11, 629},
+ dictWord{142, 11, 10},
+ dictWord{6, 11, 75},
+ dictWord{7, 11, 1531},
+ dictWord{8, 11, 416},
+ dictWord{9, 11, 240},
+ dictWord{9, 11, 275},
+ dictWord{10, 11, 100},
+ dictWord{11, 11, 658},
+ dictWord{11, 11, 979},
+ dictWord{12, 11, 86},
+ dictWord{13, 11, 468},
+ dictWord{14, 11, 66},
+ dictWord{14, 11, 207},
+ dictWord{15, 11, 20},
+ dictWord{15, 11, 25},
+ dictWord{144, 11, 58},
+ dictWord{132, 10, 577},
+ dictWord{5, 11, 141},
+ dictWord{
+ 5,
+ 11,
+ 915,
+ },
+ dictWord{6, 11, 1783},
+ dictWord{7, 11, 211},
+ dictWord{7, 11, 698},
+ dictWord{7, 11, 1353},
+ dictWord{9, 11, 83},
+ dictWord{9, 11, 281},
+ dictWord{
+ 10,
+ 11,
+ 376,
+ },
+ dictWord{10, 11, 431},
+ dictWord{11, 11, 543},
+ dictWord{12, 11, 664},
+ dictWord{13, 11, 280},
+ dictWord{13, 11, 428},
+ dictWord{14, 11, 61},
+ dictWord{
+ 14,
+ 11,
+ 128,
+ },
+ dictWord{17, 11, 52},
+ dictWord{145, 11, 81},
+ dictWord{6, 0, 161},
+ dictWord{7, 0, 372},
+ dictWord{137, 0, 597},
+ dictWord{132, 0, 349},
+ dictWord{
+ 10,
+ 11,
+ 702,
+ },
+ dictWord{139, 11, 245},
+ dictWord{134, 0, 524},
+ dictWord{134, 10, 174},
+ dictWord{6, 0, 432},
+ dictWord{9, 0, 751},
+ dictWord{139, 0, 322},
+ dictWord{147, 11, 94},
+ dictWord{4, 11, 338},
+ dictWord{133, 11, 400},
+ dictWord{5, 0, 468},
+ dictWord{10, 0, 325},
+ dictWord{11, 0, 856},
+ dictWord{12, 0, 345},
+ dictWord{143, 0, 104},
+ dictWord{133, 0, 223},
+ dictWord{132, 0, 566},
+ dictWord{4, 11, 221},
+ dictWord{5, 11, 659},
+ dictWord{5, 11, 989},
+ dictWord{7, 11, 697},
+ dictWord{7, 11, 1211},
+ dictWord{138, 11, 284},
+ dictWord{135, 11, 1070},
+ dictWord{4, 0, 59},
+ dictWord{135, 0, 1394},
+ dictWord{6, 0, 436},
+ dictWord{11, 0, 481},
+ dictWord{5, 10, 878},
+ dictWord{133, 10, 972},
+ dictWord{4, 0, 48},
+ dictWord{5, 0, 271},
+ dictWord{135, 0, 953},
+ dictWord{5, 0, 610},
+ dictWord{136, 0, 457},
+ dictWord{
+ 4,
+ 0,
+ 773,
+ },
+ dictWord{5, 0, 618},
+ dictWord{137, 0, 756},
+ dictWord{133, 0, 755},
+ dictWord{135, 0, 1217},
+ dictWord{138, 11, 507},
+ dictWord{132, 10, 351},
+ dictWord{132, 0, 197},
+ dictWord{143, 11, 78},
+ dictWord{4, 11, 188},
+ dictWord{7, 11, 805},
+ dictWord{11, 11, 276},
+ dictWord{142, 11, 293},
+ dictWord{
+ 5,
+ 11,
+ 884,
+ },
+ dictWord{139, 11, 991},
+ dictWord{132, 10, 286},
+ dictWord{10, 0, 259},
+ dictWord{10, 0, 428},
+ dictWord{7, 10, 438},
+ dictWord{7, 10, 627},
+ dictWord{
+ 7,
+ 10,
+ 1516,
+ },
+ dictWord{8, 10, 40},
+ dictWord{9, 10, 56},
+ dictWord{9, 10, 294},
+ dictWord{11, 10, 969},
+ dictWord{11, 10, 995},
+ dictWord{146, 10, 148},
+ dictWord{
+ 4,
+ 0,
+ 356,
+ },
+ dictWord{5, 0, 217},
+ dictWord{5, 0, 492},
+ dictWord{5, 0, 656},
+ dictWord{8, 0, 544},
+ dictWord{136, 11, 544},
+ dictWord{5, 0, 259},
+ dictWord{6, 0, 1230},
+ dictWord{7, 0, 414},
+ dictWord{7, 0, 854},
+ dictWord{142, 0, 107},
+ dictWord{132, 0, 1007},
+ dictWord{15, 0, 14},
+ dictWord{144, 0, 5},
+ dictWord{6, 0, 1580},
+ dictWord{
+ 132,
+ 10,
+ 738,
+ },
+ dictWord{132, 11, 596},
+ dictWord{132, 0, 673},
+ dictWord{133, 10, 866},
+ dictWord{6, 0, 1843},
+ dictWord{135, 11, 1847},
+ dictWord{4, 0, 165},
+ dictWord{7, 0, 1398},
+ dictWord{135, 0, 1829},
+ dictWord{135, 11, 1634},
+ dictWord{147, 11, 65},
+ dictWord{6, 0, 885},
+ dictWord{6, 0, 1009},
+ dictWord{
+ 137,
+ 0,
+ 809,
+ },
+ dictWord{133, 10, 116},
+ dictWord{132, 10, 457},
+ dictWord{136, 11, 770},
+ dictWord{9, 0, 498},
+ dictWord{12, 0, 181},
+ dictWord{10, 11, 361},
+ dictWord{142, 11, 316},
+ dictWord{134, 11, 595},
+ dictWord{5, 0, 9},
+ dictWord{7, 0, 297},
+ dictWord{7, 0, 966},
+ dictWord{140, 0, 306},
+ dictWord{4, 11, 89},
+ dictWord{
+ 5,
+ 11,
+ 489,
+ },
+ dictWord{6, 11, 315},
+ dictWord{7, 11, 553},
+ dictWord{7, 11, 1745},
+ dictWord{138, 11, 243},
+ dictWord{134, 0, 1487},
+ dictWord{132, 0, 437},
+ dictWord{
+ 5,
+ 0,
+ 146,
+ },
+ dictWord{6, 0, 411},
+ dictWord{138, 0, 721},
+ dictWord{5, 10, 527},
+ dictWord{6, 10, 189},
+ dictWord{135, 10, 859},
+ dictWord{11, 10, 104},
+ dictWord{
+ 11,
+ 10,
+ 554,
+ },
+ dictWord{15, 10, 60},
+ dictWord{143, 10, 125},
+ dictWord{6, 11, 1658},
+ dictWord{9, 11, 3},
+ dictWord{10, 11, 154},
+ dictWord{11, 11, 641},
+ dictWord{13, 11, 85},
+ dictWord{13, 11, 201},
+ dictWord{141, 11, 346},
+ dictWord{6, 0, 177},
+ dictWord{135, 0, 467},
+ dictWord{134, 0, 1377},
+ dictWord{
+ 134,
+ 10,
+ 116,
+ },
+ dictWord{136, 11, 645},
+ dictWord{4, 11, 166},
+ dictWord{5, 11, 505},
+ dictWord{6, 11, 1670},
+ dictWord{137, 11, 110},
+ dictWord{133, 10, 487},
+ dictWord{
+ 4,
+ 10,
+ 86,
+ },
+ dictWord{5, 10, 667},
+ dictWord{5, 10, 753},
+ dictWord{6, 10, 316},
+ dictWord{6, 10, 455},
+ dictWord{135, 10, 946},
+ dictWord{133, 0, 200},
+ dictWord{132, 0, 959},
+ dictWord{6, 0, 1928},
+ dictWord{134, 0, 1957},
+ dictWord{139, 11, 203},
+ dictWord{150, 10, 45},
+ dictWord{4, 10, 79},
+ dictWord{7, 10, 1773},
+ dictWord{10, 10, 450},
+ dictWord{11, 10, 589},
+ dictWord{13, 10, 332},
+ dictWord{13, 10, 493},
+ dictWord{14, 10, 183},
+ dictWord{14, 10, 334},
+ dictWord{
+ 14,
+ 10,
+ 362,
+ },
+ dictWord{14, 10, 368},
+ dictWord{14, 10, 376},
+ dictWord{14, 10, 379},
+ dictWord{19, 10, 90},
+ dictWord{19, 10, 103},
+ dictWord{19, 10, 127},
+ dictWord{148, 10, 90},
+ dictWord{6, 0, 1435},
+ dictWord{135, 11, 1275},
+ dictWord{134, 0, 481},
+ dictWord{7, 11, 445},
+ dictWord{8, 11, 307},
+ dictWord{8, 11, 704},
+ dictWord{10, 11, 41},
+ dictWord{10, 11, 439},
+ dictWord{11, 11, 237},
+ dictWord{11, 11, 622},
+ dictWord{140, 11, 201},
+ dictWord{135, 11, 869},
+ dictWord{
+ 4,
+ 0,
+ 84,
+ },
+ dictWord{7, 0, 1482},
+ dictWord{10, 0, 76},
+ dictWord{138, 0, 142},
+ dictWord{11, 11, 277},
+ dictWord{144, 11, 14},
+ dictWord{135, 11, 1977},
+ dictWord{
+ 4,
+ 11,
+ 189,
+ },
+ dictWord{5, 11, 713},
+ dictWord{136, 11, 57},
+ dictWord{133, 0, 1015},
+ dictWord{138, 11, 371},
+ dictWord{4, 0, 315},
+ dictWord{5, 0, 507},
+ dictWord{
+ 135,
+ 0,
+ 1370,
+ },
+ dictWord{4, 11, 552},
+ dictWord{142, 10, 381},
+ dictWord{9, 0, 759},
+ dictWord{16, 0, 31},
+ dictWord{16, 0, 39},
+ dictWord{16, 0, 75},
+ dictWord{18, 0, 24},
+ dictWord{20, 0, 42},
+ dictWord{152, 0, 1},
+ dictWord{134, 0, 712},
+ dictWord{134, 0, 1722},
+ dictWord{133, 10, 663},
+ dictWord{133, 10, 846},
+ dictWord{
+ 8,
+ 0,
+ 222,
+ },
+ dictWord{8, 0, 476},
+ dictWord{9, 0, 238},
+ dictWord{11, 0, 516},
+ dictWord{11, 0, 575},
+ dictWord{15, 0, 109},
+ dictWord{146, 0, 100},
+ dictWord{7, 0, 1402},
+ dictWord{7, 0, 1414},
+ dictWord{12, 0, 456},
+ dictWord{5, 10, 378},
+ dictWord{8, 10, 465},
+ dictWord{9, 10, 286},
+ dictWord{10, 10, 185},
+ dictWord{10, 10, 562},
+ dictWord{10, 10, 635},
+ dictWord{11, 10, 31},
+ dictWord{11, 10, 393},
+ dictWord{13, 10, 312},
+ dictWord{18, 10, 65},
+ dictWord{18, 10, 96},
+ dictWord{147, 10, 89},
+ dictWord{4, 0, 986},
+ dictWord{6, 0, 1958},
+ dictWord{6, 0, 2032},
+ dictWord{8, 0, 934},
+ dictWord{138, 0, 985},
+ dictWord{7, 10, 1880},
+ dictWord{9, 10, 680},
+ dictWord{139, 10, 798},
+ dictWord{134, 10, 1770},
+ dictWord{145, 11, 49},
+ dictWord{132, 11, 614},
+ dictWord{132, 10, 648},
+ dictWord{5, 10, 945},
+ dictWord{
+ 6,
+ 10,
+ 1656,
+ },
+ dictWord{6, 10, 1787},
+ dictWord{7, 10, 167},
+ dictWord{8, 10, 824},
+ dictWord{9, 10, 391},
+ dictWord{10, 10, 375},
+ dictWord{139, 10, 185},
+ dictWord{138, 11, 661},
+ dictWord{7, 0, 1273},
+ dictWord{135, 11, 1945},
+ dictWord{7, 0, 706},
+ dictWord{7, 0, 1058},
+ dictWord{138, 0, 538},
+ dictWord{7, 10, 1645},
+ dictWord{8, 10, 352},
+ dictWord{137, 10, 249},
+ dictWord{132, 10, 152},
+ dictWord{11, 0, 92},
+ dictWord{11, 0, 196},
+ dictWord{11, 0, 409},
+ dictWord{11, 0, 450},
+ dictWord{11, 0, 666},
+ dictWord{11, 0, 777},
+ dictWord{12, 0, 262},
+ dictWord{13, 0, 385},
+ dictWord{13, 0, 393},
+ dictWord{15, 0, 115},
+ dictWord{16, 0, 45},
+ dictWord{145, 0, 82},
+ dictWord{133, 10, 1006},
+ dictWord{6, 0, 40},
+ dictWord{135, 0, 1781},
+ dictWord{9, 11, 614},
+ dictWord{139, 11, 327},
+ dictWord{5, 10, 420},
+ dictWord{135, 10, 1449},
+ dictWord{135, 0, 431},
+ dictWord{10, 0, 97},
+ dictWord{135, 10, 832},
+ dictWord{6, 0, 423},
+ dictWord{7, 0, 665},
+ dictWord{
+ 135,
+ 0,
+ 1210,
+ },
+ dictWord{7, 0, 237},
+ dictWord{8, 0, 664},
+ dictWord{9, 0, 42},
+ dictWord{9, 0, 266},
+ dictWord{9, 0, 380},
+ dictWord{9, 0, 645},
+ dictWord{10, 0, 177},
+ dictWord{
+ 138,
+ 0,
+ 276,
+ },
+ dictWord{7, 0, 264},
+ dictWord{133, 10, 351},
+ dictWord{8, 0, 213},
+ dictWord{5, 10, 40},
+ dictWord{7, 10, 598},
+ dictWord{7, 10, 1638},
+ dictWord{
+ 9,
+ 10,
+ 166,
+ },
+ dictWord{9, 10, 640},
+ dictWord{9, 10, 685},
+ dictWord{9, 10, 773},
+ dictWord{11, 10, 215},
+ dictWord{13, 10, 65},
+ dictWord{14, 10, 172},
+ dictWord{
+ 14,
+ 10,
+ 317,
+ },
+ dictWord{145, 10, 6},
+ dictWord{5, 11, 84},
+ dictWord{134, 11, 163},
+ dictWord{8, 10, 60},
+ dictWord{9, 10, 343},
+ dictWord{139, 10, 769},
+ dictWord{
+ 137,
+ 0,
+ 455,
+ },
+ dictWord{133, 11, 410},
+ dictWord{8, 0, 906},
+ dictWord{12, 0, 700},
+ dictWord{12, 0, 706},
+ dictWord{140, 0, 729},
+ dictWord{21, 11, 33},
+ dictWord{
+ 150,
+ 11,
+ 40,
+ },
+ dictWord{7, 10, 1951},
+ dictWord{8, 10, 765},
+ dictWord{8, 10, 772},
+ dictWord{140, 10, 671},
+ dictWord{7, 10, 108},
+ dictWord{8, 10, 219},
+ dictWord{
+ 8,
+ 10,
+ 388,
+ },
+ dictWord{9, 10, 639},
+ dictWord{9, 10, 775},
+ dictWord{11, 10, 275},
+ dictWord{140, 10, 464},
+ dictWord{5, 11, 322},
+ dictWord{7, 11, 1941},
+ dictWord{
+ 8,
+ 11,
+ 186,
+ },
+ dictWord{9, 11, 262},
+ dictWord{10, 11, 187},
+ dictWord{14, 11, 208},
+ dictWord{146, 11, 130},
+ dictWord{139, 0, 624},
+ dictWord{8, 0, 574},
+ dictWord{
+ 5,
+ 11,
+ 227,
+ },
+ dictWord{140, 11, 29},
+ dictWord{7, 11, 1546},
+ dictWord{11, 11, 299},
+ dictWord{142, 11, 407},
+ dictWord{5, 10, 15},
+ dictWord{6, 10, 56},
+ dictWord{
+ 7,
+ 10,
+ 1758,
+ },
+ dictWord{8, 10, 500},
+ dictWord{9, 10, 730},
+ dictWord{11, 10, 331},
+ dictWord{13, 10, 150},
+ dictWord{142, 10, 282},
+ dictWord{7, 11, 1395},
+ dictWord{8, 11, 486},
+ dictWord{9, 11, 236},
+ dictWord{9, 11, 878},
+ dictWord{10, 11, 218},
+ dictWord{11, 11, 95},
+ dictWord{19, 11, 17},
+ dictWord{147, 11, 31},
+ dictWord{135, 11, 2043},
+ dictWord{4, 0, 354},
+ dictWord{146, 11, 4},
+ dictWord{140, 11, 80},
+ dictWord{135, 0, 1558},
+ dictWord{134, 10, 1886},
+ dictWord{
+ 5,
+ 10,
+ 205,
+ },
+ dictWord{6, 10, 438},
+ dictWord{137, 10, 711},
+ dictWord{133, 11, 522},
+ dictWord{133, 10, 534},
+ dictWord{7, 0, 235},
+ dictWord{7, 0, 1475},
+ dictWord{
+ 15,
+ 0,
+ 68,
+ },
+ dictWord{146, 0, 120},
+ dictWord{137, 10, 691},
+ dictWord{4, 0, 942},
+ dictWord{6, 0, 1813},
+ dictWord{8, 0, 917},
+ dictWord{10, 0, 884},
+ dictWord{
+ 12,
+ 0,
+ 696,
+ },
+ dictWord{12, 0, 717},
+ dictWord{12, 0, 723},
+ dictWord{12, 0, 738},
+ dictWord{12, 0, 749},
+ dictWord{12, 0, 780},
+ dictWord{16, 0, 97},
+ dictWord{146, 0, 169},
+ dictWord{6, 10, 443},
+ dictWord{8, 11, 562},
+ dictWord{9, 10, 237},
+ dictWord{9, 10, 571},
+ dictWord{9, 10, 695},
+ dictWord{10, 10, 139},
+ dictWord{11, 10, 715},
+ dictWord{12, 10, 417},
+ dictWord{141, 10, 421},
+ dictWord{135, 0, 957},
+ dictWord{133, 0, 830},
+ dictWord{134, 11, 1771},
+ dictWord{146, 0, 23},
+ dictWord{
+ 5,
+ 0,
+ 496,
+ },
+ dictWord{6, 0, 694},
+ dictWord{7, 0, 203},
+ dictWord{7, 11, 1190},
+ dictWord{137, 11, 620},
+ dictWord{137, 11, 132},
+ dictWord{6, 0, 547},
+ dictWord{
+ 134,
+ 0,
+ 1549,
+ },
+ dictWord{8, 11, 258},
+ dictWord{9, 11, 208},
+ dictWord{137, 11, 359},
+ dictWord{4, 0, 864},
+ dictWord{5, 0, 88},
+ dictWord{137, 0, 239},
+ dictWord{
+ 135,
+ 11,
+ 493,
+ },
+ dictWord{4, 11, 317},
+ dictWord{135, 11, 1279},
+ dictWord{132, 11, 477},
+ dictWord{4, 10, 578},
+ dictWord{5, 11, 63},
+ dictWord{133, 11, 509},
+ dictWord{
+ 7,
+ 0,
+ 650,
+ },
+ dictWord{135, 0, 1310},
+ dictWord{7, 0, 1076},
+ dictWord{9, 0, 80},
+ dictWord{11, 0, 78},
+ dictWord{11, 0, 421},
+ dictWord{11, 0, 534},
+ dictWord{
+ 140,
+ 0,
+ 545,
+ },
+ dictWord{132, 11, 288},
+ dictWord{12, 0, 553},
+ dictWord{14, 0, 118},
+ dictWord{133, 10, 923},
+ dictWord{7, 0, 274},
+ dictWord{11, 0, 479},
+ dictWord{
+ 139,
+ 0,
+ 507,
+ },
+ dictWord{8, 11, 89},
+ dictWord{8, 11, 620},
+ dictWord{9, 11, 49},
+ dictWord{10, 11, 774},
+ dictWord{11, 11, 628},
+ dictWord{12, 11, 322},
+ dictWord{
+ 143,
+ 11,
+ 124,
+ },
+ dictWord{4, 0, 497},
+ dictWord{135, 0, 1584},
+ dictWord{7, 0, 261},
+ dictWord{7, 0, 1115},
+ dictWord{7, 0, 1354},
+ dictWord{7, 0, 1404},
+ dictWord{
+ 7,
+ 0,
+ 1588,
+ },
+ dictWord{7, 0, 1705},
+ dictWord{7, 0, 1902},
+ dictWord{9, 0, 465},
+ dictWord{10, 0, 248},
+ dictWord{10, 0, 349},
+ dictWord{10, 0, 647},
+ dictWord{11, 0, 527},
+ dictWord{11, 0, 660},
+ dictWord{11, 0, 669},
+ dictWord{12, 0, 529},
+ dictWord{13, 0, 305},
+ dictWord{132, 10, 924},
+ dictWord{133, 10, 665},
+ dictWord{
+ 136,
+ 0,
+ 13,
+ },
+ dictWord{6, 0, 791},
+ dictWord{138, 11, 120},
+ dictWord{7, 0, 642},
+ dictWord{8, 0, 250},
+ dictWord{11, 0, 123},
+ dictWord{11, 0, 137},
+ dictWord{13, 0, 48},
+ dictWord{142, 0, 95},
+ dictWord{4, 10, 265},
+ dictWord{7, 10, 807},
+ dictWord{135, 10, 950},
+ dictWord{5, 10, 93},
+ dictWord{140, 10, 267},
+ dictWord{135, 0, 1429},
+ dictWord{4, 0, 949},
+ dictWord{10, 0, 885},
+ dictWord{10, 0, 891},
+ dictWord{10, 0, 900},
+ dictWord{10, 0, 939},
+ dictWord{12, 0, 760},
+ dictWord{142, 0, 449},
+ dictWord{139, 11, 366},
+ dictWord{132, 0, 818},
+ dictWord{134, 11, 85},
+ dictWord{135, 10, 994},
+ dictWord{7, 0, 330},
+ dictWord{5, 10, 233},
+ dictWord{5, 10, 320},
+ dictWord{6, 10, 140},
+ dictWord{136, 10, 295},
+ dictWord{4, 0, 1004},
+ dictWord{8, 0, 982},
+ dictWord{136, 0, 993},
+ dictWord{133, 10, 978},
+ dictWord{4, 10, 905},
+ dictWord{6, 10, 1701},
+ dictWord{137, 10, 843},
+ dictWord{10, 0, 545},
+ dictWord{140, 0, 301},
+ dictWord{6, 0, 947},
+ dictWord{134, 0, 1062},
+ dictWord{
+ 134,
+ 0,
+ 1188,
+ },
+ dictWord{4, 0, 904},
+ dictWord{5, 0, 794},
+ dictWord{152, 10, 6},
+ dictWord{134, 0, 1372},
+ dictWord{135, 11, 608},
+ dictWord{5, 11, 279},
+ dictWord{
+ 6,
+ 11,
+ 235,
+ },
+ dictWord{7, 11, 468},
+ dictWord{8, 11, 446},
+ dictWord{9, 11, 637},
+ dictWord{10, 11, 717},
+ dictWord{11, 11, 738},
+ dictWord{140, 11, 514},
+ dictWord{
+ 132,
+ 10,
+ 509,
+ },
+ dictWord{5, 11, 17},
+ dictWord{6, 11, 371},
+ dictWord{137, 11, 528},
+ dictWord{132, 0, 693},
+ dictWord{4, 11, 115},
+ dictWord{5, 11, 669},
+ dictWord{
+ 6,
+ 11,
+ 407,
+ },
+ dictWord{8, 11, 311},
+ dictWord{11, 11, 10},
+ dictWord{141, 11, 5},
+ dictWord{11, 0, 377},
+ dictWord{7, 10, 273},
+ dictWord{137, 11, 381},
+ dictWord{
+ 135,
+ 0,
+ 695,
+ },
+ dictWord{7, 0, 386},
+ dictWord{138, 0, 713},
+ dictWord{135, 10, 1041},
+ dictWord{134, 0, 1291},
+ dictWord{6, 0, 7},
+ dictWord{6, 0, 35},
+ dictWord{
+ 7,
+ 0,
+ 147,
+ },
+ dictWord{7, 0, 1069},
+ dictWord{7, 0, 1568},
+ dictWord{7, 0, 1575},
+ dictWord{7, 0, 1917},
+ dictWord{8, 0, 43},
+ dictWord{8, 0, 208},
+ dictWord{9, 0, 128},
+ dictWord{
+ 9,
+ 0,
+ 866,
+ },
+ dictWord{10, 0, 20},
+ dictWord{11, 0, 981},
+ dictWord{147, 0, 33},
+ dictWord{7, 0, 893},
+ dictWord{141, 0, 424},
+ dictWord{139, 10, 234},
+ dictWord{
+ 150,
+ 11,
+ 56,
+ },
+ dictWord{5, 11, 779},
+ dictWord{5, 11, 807},
+ dictWord{6, 11, 1655},
+ dictWord{134, 11, 1676},
+ dictWord{5, 10, 802},
+ dictWord{7, 10, 2021},
+ dictWord{136, 10, 805},
+ dictWord{4, 11, 196},
+ dictWord{5, 10, 167},
+ dictWord{5, 11, 558},
+ dictWord{5, 10, 899},
+ dictWord{5, 11, 949},
+ dictWord{6, 10, 410},
+ dictWord{137, 10, 777},
+ dictWord{137, 10, 789},
+ dictWord{134, 10, 1705},
+ dictWord{8, 0, 904},
+ dictWord{140, 0, 787},
+ dictWord{6, 0, 322},
+ dictWord{9, 0, 552},
+ dictWord{11, 0, 274},
+ dictWord{13, 0, 209},
+ dictWord{13, 0, 499},
+ dictWord{14, 0, 85},
+ dictWord{15, 0, 126},
+ dictWord{145, 0, 70},
+ dictWord{135, 10, 10},
+ dictWord{
+ 5,
+ 10,
+ 11,
+ },
+ dictWord{6, 10, 117},
+ dictWord{6, 10, 485},
+ dictWord{7, 10, 1133},
+ dictWord{9, 10, 582},
+ dictWord{9, 10, 594},
+ dictWord{11, 10, 21},
+ dictWord{
+ 11,
+ 10,
+ 818,
+ },
+ dictWord{12, 10, 535},
+ dictWord{141, 10, 86},
+ dictWord{4, 10, 264},
+ dictWord{7, 10, 1067},
+ dictWord{8, 10, 204},
+ dictWord{8, 10, 385},
+ dictWord{139, 10, 953},
+ dictWord{132, 11, 752},
+ dictWord{138, 10, 56},
+ dictWord{133, 10, 470},
+ dictWord{6, 0, 1808},
+ dictWord{8, 0, 83},
+ dictWord{8, 0, 742},
+ dictWord{8, 0, 817},
+ dictWord{9, 0, 28},
+ dictWord{9, 0, 29},
+ dictWord{9, 0, 885},
+ dictWord{10, 0, 387},
+ dictWord{11, 0, 633},
+ dictWord{11, 0, 740},
+ dictWord{13, 0, 235},
+ dictWord{13, 0, 254},
+ dictWord{15, 0, 143},
+ dictWord{143, 0, 146},
+ dictWord{140, 0, 49},
+ dictWord{134, 0, 1832},
+ dictWord{4, 11, 227},
+ dictWord{5, 11, 159},
+ dictWord{5, 11, 409},
+ dictWord{7, 11, 80},
+ dictWord{10, 11, 294},
+ dictWord{10, 11, 479},
+ dictWord{12, 11, 418},
+ dictWord{14, 11, 50},
+ dictWord{14, 11, 249},
+ dictWord{142, 11, 295},
+ dictWord{7, 11, 1470},
+ dictWord{8, 11, 66},
+ dictWord{8, 11, 137},
+ dictWord{8, 11, 761},
+ dictWord{9, 11, 638},
+ dictWord{11, 11, 80},
+ dictWord{11, 11, 212},
+ dictWord{11, 11, 368},
+ dictWord{11, 11, 418},
+ dictWord{12, 11, 8},
+ dictWord{13, 11, 15},
+ dictWord{16, 11, 61},
+ dictWord{17, 11, 59},
+ dictWord{19, 11, 28},
+ dictWord{148, 11, 84},
+ dictWord{139, 10, 1015},
+ dictWord{138, 11, 468},
+ dictWord{135, 0, 421},
+ dictWord{6, 0, 415},
+ dictWord{
+ 7,
+ 0,
+ 1049,
+ },
+ dictWord{137, 0, 442},
+ dictWord{6, 11, 38},
+ dictWord{7, 11, 1220},
+ dictWord{8, 11, 185},
+ dictWord{8, 11, 256},
+ dictWord{9, 11, 22},
+ dictWord{
+ 9,
+ 11,
+ 331,
+ },
+ dictWord{10, 11, 738},
+ dictWord{11, 11, 205},
+ dictWord{11, 11, 540},
+ dictWord{11, 11, 746},
+ dictWord{13, 11, 399},
+ dictWord{13, 11, 465},
+ dictWord{
+ 14,
+ 11,
+ 88,
+ },
+ dictWord{142, 11, 194},
+ dictWord{139, 0, 289},
+ dictWord{133, 10, 715},
+ dictWord{4, 0, 110},
+ dictWord{10, 0, 415},
+ dictWord{10, 0, 597},
+ dictWord{142, 0, 206},
+ dictWord{4, 11, 159},
+ dictWord{6, 11, 115},
+ dictWord{7, 11, 252},
+ dictWord{7, 11, 257},
+ dictWord{7, 11, 1928},
+ dictWord{8, 11, 69},
+ dictWord{
+ 9,
+ 11,
+ 384,
+ },
+ dictWord{10, 11, 91},
+ dictWord{10, 11, 615},
+ dictWord{12, 11, 375},
+ dictWord{14, 11, 235},
+ dictWord{18, 11, 117},
+ dictWord{147, 11, 123},
+ dictWord{5, 11, 911},
+ dictWord{136, 11, 278},
+ dictWord{7, 0, 205},
+ dictWord{7, 0, 2000},
+ dictWord{8, 10, 794},
+ dictWord{9, 10, 400},
+ dictWord{10, 10, 298},
+ dictWord{142, 10, 228},
+ dictWord{135, 11, 1774},
+ dictWord{4, 11, 151},
+ dictWord{7, 11, 1567},
+ dictWord{8, 11, 351},
+ dictWord{137, 11, 322},
+ dictWord{
+ 136,
+ 10,
+ 724,
+ },
+ dictWord{133, 11, 990},
+ dictWord{7, 0, 1539},
+ dictWord{11, 0, 512},
+ dictWord{13, 0, 205},
+ dictWord{19, 0, 30},
+ dictWord{22, 0, 36},
+ dictWord{23, 0, 19},
+ dictWord{135, 11, 1539},
+ dictWord{5, 11, 194},
+ dictWord{7, 11, 1662},
+ dictWord{9, 11, 90},
+ dictWord{140, 11, 180},
+ dictWord{6, 10, 190},
+ dictWord{
+ 7,
+ 10,
+ 768,
+ },
+ dictWord{135, 10, 1170},
+ dictWord{134, 0, 1340},
+ dictWord{4, 0, 283},
+ dictWord{135, 0, 1194},
+ dictWord{133, 11, 425},
+ dictWord{133, 11, 971},
+ dictWord{12, 0, 549},
+ dictWord{14, 10, 67},
+ dictWord{147, 10, 60},
+ dictWord{135, 10, 1023},
+ dictWord{134, 0, 1720},
+ dictWord{138, 11, 587},
+ dictWord{
+ 5,
+ 11,
+ 72,
+ },
+ dictWord{6, 11, 264},
+ dictWord{7, 11, 21},
+ dictWord{7, 11, 46},
+ dictWord{7, 11, 2013},
+ dictWord{8, 11, 215},
+ dictWord{8, 11, 513},
+ dictWord{10, 11, 266},
+ dictWord{139, 11, 22},
+ dictWord{5, 0, 319},
+ dictWord{135, 0, 534},
+ dictWord{6, 10, 137},
+ dictWord{9, 10, 75},
+ dictWord{9, 10, 253},
+ dictWord{10, 10, 194},
+ dictWord{138, 10, 444},
+ dictWord{7, 0, 1180},
+ dictWord{20, 0, 112},
+ dictWord{6, 11, 239},
+ dictWord{7, 11, 118},
+ dictWord{10, 11, 95},
+ dictWord{11, 11, 603},
+ dictWord{13, 11, 443},
+ dictWord{14, 11, 160},
+ dictWord{143, 11, 4},
+ dictWord{134, 11, 431},
+ dictWord{5, 11, 874},
+ dictWord{6, 11, 1677},
+ dictWord{
+ 11,
+ 10,
+ 643,
+ },
+ dictWord{12, 10, 115},
+ dictWord{143, 11, 0},
+ dictWord{134, 0, 967},
+ dictWord{6, 11, 65},
+ dictWord{7, 11, 939},
+ dictWord{7, 11, 1172},
+ dictWord{
+ 7,
+ 11,
+ 1671,
+ },
+ dictWord{9, 11, 540},
+ dictWord{10, 11, 696},
+ dictWord{11, 11, 265},
+ dictWord{11, 11, 732},
+ dictWord{11, 11, 928},
+ dictWord{11, 11, 937},
+ dictWord{
+ 12,
+ 11,
+ 399,
+ },
+ dictWord{13, 11, 438},
+ dictWord{149, 11, 19},
+ dictWord{137, 11, 200},
+ dictWord{135, 0, 1940},
+ dictWord{5, 10, 760},
+ dictWord{7, 10, 542},
+ dictWord{8, 10, 135},
+ dictWord{136, 10, 496},
+ dictWord{140, 11, 44},
+ dictWord{7, 11, 1655},
+ dictWord{136, 11, 305},
+ dictWord{7, 10, 319},
+ dictWord{
+ 7,
+ 10,
+ 355,
+ },
+ dictWord{7, 10, 763},
+ dictWord{10, 10, 389},
+ dictWord{145, 10, 43},
+ dictWord{136, 0, 735},
+ dictWord{138, 10, 786},
+ dictWord{137, 11, 19},
+ dictWord{132, 11, 696},
+ dictWord{5, 0, 132},
+ dictWord{9, 0, 486},
+ dictWord{9, 0, 715},
+ dictWord{10, 0, 458},
+ dictWord{11, 0, 373},
+ dictWord{11, 0, 668},
+ dictWord{
+ 11,
+ 0,
+ 795,
+ },
+ dictWord{11, 0, 897},
+ dictWord{12, 0, 272},
+ dictWord{12, 0, 424},
+ dictWord{12, 0, 539},
+ dictWord{12, 0, 558},
+ dictWord{14, 0, 245},
+ dictWord{
+ 14,
+ 0,
+ 263,
+ },
+ dictWord{14, 0, 264},
+ dictWord{14, 0, 393},
+ dictWord{142, 0, 403},
+ dictWord{10, 0, 38},
+ dictWord{139, 0, 784},
+ dictWord{132, 0, 838},
+ dictWord{
+ 4,
+ 11,
+ 302,
+ },
+ dictWord{135, 11, 1766},
+ dictWord{133, 0, 379},
+ dictWord{5, 0, 8},
+ dictWord{6, 0, 89},
+ dictWord{6, 0, 400},
+ dictWord{7, 0, 1569},
+ dictWord{7, 0, 1623},
+ dictWord{7, 0, 1850},
+ dictWord{8, 0, 218},
+ dictWord{8, 0, 422},
+ dictWord{9, 0, 570},
+ dictWord{10, 0, 626},
+ dictWord{4, 11, 726},
+ dictWord{133, 11, 630},
+ dictWord{
+ 4,
+ 0,
+ 1017,
+ },
+ dictWord{138, 0, 660},
+ dictWord{6, 0, 387},
+ dictWord{7, 0, 882},
+ dictWord{141, 0, 111},
+ dictWord{6, 0, 224},
+ dictWord{7, 0, 877},
+ dictWord{
+ 137,
+ 0,
+ 647,
+ },
+ dictWord{4, 10, 58},
+ dictWord{5, 10, 286},
+ dictWord{6, 10, 319},
+ dictWord{7, 10, 402},
+ dictWord{7, 10, 1254},
+ dictWord{7, 10, 1903},
+ dictWord{
+ 8,
+ 10,
+ 356,
+ },
+ dictWord{140, 10, 408},
+ dictWord{135, 0, 790},
+ dictWord{9, 0, 510},
+ dictWord{10, 0, 53},
+ dictWord{4, 10, 389},
+ dictWord{9, 10, 181},
+ dictWord{
+ 10,
+ 10,
+ 29,
+ },
+ dictWord{10, 10, 816},
+ dictWord{11, 10, 311},
+ dictWord{11, 10, 561},
+ dictWord{12, 10, 67},
+ dictWord{141, 10, 181},
+ dictWord{142, 0, 458},
+ dictWord{
+ 6,
+ 11,
+ 118,
+ },
+ dictWord{7, 11, 215},
+ dictWord{7, 11, 1521},
+ dictWord{140, 11, 11},
+ dictWord{134, 0, 954},
+ dictWord{135, 0, 394},
+ dictWord{134, 0, 1367},
+ dictWord{5, 11, 225},
+ dictWord{133, 10, 373},
+ dictWord{132, 0, 882},
+ dictWord{7, 0, 1409},
+ dictWord{135, 10, 1972},
+ dictWord{135, 10, 1793},
+ dictWord{
+ 4,
+ 11,
+ 370,
+ },
+ dictWord{5, 11, 756},
+ dictWord{135, 11, 1326},
+ dictWord{150, 11, 13},
+ dictWord{7, 11, 354},
+ dictWord{10, 11, 410},
+ dictWord{139, 11, 815},
+ dictWord{6, 11, 1662},
+ dictWord{7, 11, 48},
+ dictWord{8, 11, 771},
+ dictWord{10, 11, 116},
+ dictWord{13, 11, 104},
+ dictWord{14, 11, 105},
+ dictWord{14, 11, 184},
+ dictWord{15, 11, 168},
+ dictWord{19, 11, 92},
+ dictWord{148, 11, 68},
+ dictWord{7, 0, 124},
+ dictWord{136, 0, 38},
+ dictWord{5, 0, 261},
+ dictWord{7, 0, 78},
+ dictWord{
+ 7,
+ 0,
+ 199,
+ },
+ dictWord{8, 0, 815},
+ dictWord{9, 0, 126},
+ dictWord{10, 0, 342},
+ dictWord{140, 0, 647},
+ dictWord{4, 0, 628},
+ dictWord{140, 0, 724},
+ dictWord{7, 0, 266},
+ dictWord{8, 0, 804},
+ dictWord{7, 10, 1651},
+ dictWord{145, 10, 89},
+ dictWord{135, 0, 208},
+ dictWord{134, 0, 1178},
+ dictWord{6, 0, 79},
+ dictWord{135, 0, 1519},
+ dictWord{132, 10, 672},
+ dictWord{133, 10, 737},
+ dictWord{136, 0, 741},
+ dictWord{132, 11, 120},
+ dictWord{4, 0, 710},
+ dictWord{6, 0, 376},
+ dictWord{
+ 134,
+ 0,
+ 606,
+ },
+ dictWord{134, 0, 1347},
+ dictWord{134, 0, 1494},
+ dictWord{6, 0, 850},
+ dictWord{6, 0, 1553},
+ dictWord{137, 0, 821},
+ dictWord{5, 10, 145},
+ dictWord{
+ 134,
+ 11,
+ 593,
+ },
+ dictWord{7, 0, 1311},
+ dictWord{140, 0, 135},
+ dictWord{4, 0, 467},
+ dictWord{5, 0, 405},
+ dictWord{134, 0, 544},
+ dictWord{5, 11, 820},
+ dictWord{
+ 135,
+ 11,
+ 931,
+ },
+ dictWord{6, 0, 100},
+ dictWord{7, 0, 244},
+ dictWord{7, 0, 632},
+ dictWord{7, 0, 1609},
+ dictWord{8, 0, 178},
+ dictWord{8, 0, 638},
+ dictWord{141, 0, 58},
+ dictWord{4, 10, 387},
+ dictWord{135, 10, 1288},
+ dictWord{6, 11, 151},
+ dictWord{6, 11, 1675},
+ dictWord{7, 11, 383},
+ dictWord{151, 11, 10},
+ dictWord{
+ 132,
+ 0,
+ 481,
+ },
+ dictWord{135, 10, 550},
+ dictWord{134, 0, 1378},
+ dictWord{6, 11, 1624},
+ dictWord{11, 11, 11},
+ dictWord{12, 11, 422},
+ dictWord{13, 11, 262},
+ dictWord{142, 11, 360},
+ dictWord{133, 0, 791},
+ dictWord{4, 11, 43},
+ dictWord{5, 11, 344},
+ dictWord{133, 11, 357},
+ dictWord{7, 0, 1227},
+ dictWord{140, 0, 978},
+ dictWord{7, 0, 686},
+ dictWord{8, 0, 33},
+ dictWord{8, 0, 238},
+ dictWord{10, 0, 616},
+ dictWord{11, 0, 467},
+ dictWord{11, 0, 881},
+ dictWord{13, 0, 217},
+ dictWord{
+ 13,
+ 0,
+ 253,
+ },
+ dictWord{142, 0, 268},
+ dictWord{137, 0, 857},
+ dictWord{8, 0, 467},
+ dictWord{8, 0, 1006},
+ dictWord{7, 11, 148},
+ dictWord{8, 11, 284},
+ dictWord{
+ 141,
+ 11,
+ 63,
+ },
+ dictWord{4, 10, 576},
+ dictWord{135, 10, 1263},
+ dictWord{133, 11, 888},
+ dictWord{5, 10, 919},
+ dictWord{134, 10, 1673},
+ dictWord{20, 10, 37},
+ dictWord{148, 11, 37},
+ dictWord{132, 0, 447},
+ dictWord{132, 11, 711},
+ dictWord{4, 0, 128},
+ dictWord{5, 0, 415},
+ dictWord{6, 0, 462},
+ dictWord{7, 0, 294},
+ dictWord{
+ 7,
+ 0,
+ 578,
+ },
+ dictWord{10, 0, 710},
+ dictWord{139, 0, 86},
+ dictWord{4, 10, 82},
+ dictWord{5, 10, 333},
+ dictWord{5, 10, 904},
+ dictWord{6, 10, 207},
+ dictWord{7, 10, 325},
+ dictWord{7, 10, 1726},
+ dictWord{8, 10, 101},
+ dictWord{10, 10, 778},
+ dictWord{139, 10, 220},
+ dictWord{136, 0, 587},
+ dictWord{137, 11, 440},
+ dictWord{
+ 133,
+ 10,
+ 903,
+ },
+ dictWord{6, 0, 427},
+ dictWord{7, 0, 1018},
+ dictWord{138, 0, 692},
+ dictWord{4, 0, 195},
+ dictWord{135, 0, 802},
+ dictWord{140, 10, 147},
+ dictWord{
+ 134,
+ 0,
+ 1546,
+ },
+ dictWord{134, 0, 684},
+ dictWord{132, 10, 705},
+ dictWord{136, 0, 345},
+ dictWord{11, 11, 678},
+ dictWord{140, 11, 307},
+ dictWord{
+ 133,
+ 0,
+ 365,
+ },
+ dictWord{134, 0, 1683},
+ dictWord{4, 11, 65},
+ dictWord{5, 11, 479},
+ dictWord{5, 11, 1004},
+ dictWord{7, 11, 1913},
+ dictWord{8, 11, 317},
+ dictWord{
+ 9,
+ 11,
+ 302,
+ },
+ dictWord{10, 11, 612},
+ dictWord{141, 11, 22},
+ dictWord{138, 0, 472},
+ dictWord{4, 11, 261},
+ dictWord{135, 11, 510},
+ dictWord{134, 10, 90},
+ dictWord{142, 0, 433},
+ dictWord{151, 0, 28},
+ dictWord{4, 11, 291},
+ dictWord{7, 11, 101},
+ dictWord{9, 11, 515},
+ dictWord{12, 11, 152},
+ dictWord{12, 11, 443},
+ dictWord{13, 11, 392},
+ dictWord{142, 11, 357},
+ dictWord{140, 0, 997},
+ dictWord{5, 0, 3},
+ dictWord{8, 0, 578},
+ dictWord{9, 0, 118},
+ dictWord{10, 0, 705},
+ dictWord{
+ 141,
+ 0,
+ 279,
+ },
+ dictWord{135, 11, 1266},
+ dictWord{7, 10, 813},
+ dictWord{12, 10, 497},
+ dictWord{141, 10, 56},
+ dictWord{133, 0, 229},
+ dictWord{6, 10, 125},
+ dictWord{135, 10, 1277},
+ dictWord{8, 0, 102},
+ dictWord{10, 0, 578},
+ dictWord{10, 0, 672},
+ dictWord{12, 0, 496},
+ dictWord{13, 0, 408},
+ dictWord{14, 0, 121},
+ dictWord{17, 0, 106},
+ dictWord{151, 10, 12},
+ dictWord{6, 0, 866},
+ dictWord{134, 0, 1080},
+ dictWord{136, 0, 1022},
+ dictWord{4, 11, 130},
+ dictWord{135, 11, 843},
+ dictWord{5, 11, 42},
+ dictWord{5, 11, 879},
+ dictWord{7, 11, 245},
+ dictWord{7, 11, 324},
+ dictWord{7, 11, 1532},
+ dictWord{11, 11, 463},
+ dictWord{11, 11, 472},
+ dictWord{13, 11, 363},
+ dictWord{144, 11, 52},
+ dictWord{150, 0, 55},
+ dictWord{8, 0, 115},
+ dictWord{8, 0, 350},
+ dictWord{9, 0, 489},
+ dictWord{10, 0, 128},
+ dictWord{
+ 11,
+ 0,
+ 306,
+ },
+ dictWord{12, 0, 373},
+ dictWord{14, 0, 30},
+ dictWord{17, 0, 79},
+ dictWord{19, 0, 80},
+ dictWord{4, 11, 134},
+ dictWord{133, 11, 372},
+ dictWord{
+ 134,
+ 0,
+ 657,
+ },
+ dictWord{134, 0, 933},
+ dictWord{135, 11, 1147},
+ dictWord{4, 0, 230},
+ dictWord{133, 0, 702},
+ dictWord{134, 0, 1728},
+ dictWord{4, 0, 484},
+ dictWord{
+ 18,
+ 0,
+ 26,
+ },
+ dictWord{19, 0, 42},
+ dictWord{20, 0, 43},
+ dictWord{21, 0, 0},
+ dictWord{23, 0, 27},
+ dictWord{152, 0, 14},
+ dictWord{7, 0, 185},
+ dictWord{135, 0, 703},
+ dictWord{
+ 6,
+ 0,
+ 417,
+ },
+ dictWord{10, 0, 618},
+ dictWord{7, 10, 1106},
+ dictWord{9, 10, 770},
+ dictWord{11, 10, 112},
+ dictWord{140, 10, 413},
+ dictWord{134, 0, 803},
+ dictWord{132, 11, 644},
+ dictWord{134, 0, 1262},
+ dictWord{7, 11, 540},
+ dictWord{12, 10, 271},
+ dictWord{145, 10, 109},
+ dictWord{135, 11, 123},
+ dictWord{
+ 132,
+ 0,
+ 633,
+ },
+ dictWord{134, 11, 623},
+ dictWord{4, 11, 908},
+ dictWord{5, 11, 359},
+ dictWord{5, 11, 508},
+ dictWord{6, 11, 1723},
+ dictWord{7, 11, 343},
+ dictWord{
+ 7,
+ 11,
+ 1996,
+ },
+ dictWord{135, 11, 2026},
+ dictWord{135, 0, 479},
+ dictWord{10, 0, 262},
+ dictWord{7, 10, 304},
+ dictWord{9, 10, 646},
+ dictWord{9, 10, 862},
+ dictWord{
+ 11,
+ 10,
+ 696,
+ },
+ dictWord{12, 10, 208},
+ dictWord{15, 10, 79},
+ dictWord{147, 10, 108},
+ dictWord{4, 11, 341},
+ dictWord{135, 11, 480},
+ dictWord{134, 0, 830},
+ dictWord{5, 0, 70},
+ dictWord{5, 0, 622},
+ dictWord{6, 0, 334},
+ dictWord{7, 0, 1032},
+ dictWord{9, 0, 171},
+ dictWord{11, 0, 26},
+ dictWord{11, 0, 213},
+ dictWord{
+ 11,
+ 0,
+ 637,
+ },
+ dictWord{11, 0, 707},
+ dictWord{12, 0, 202},
+ dictWord{12, 0, 380},
+ dictWord{13, 0, 226},
+ dictWord{13, 0, 355},
+ dictWord{14, 0, 222},
+ dictWord{145, 0, 42},
+ dictWord{135, 10, 981},
+ dictWord{143, 0, 217},
+ dictWord{137, 11, 114},
+ dictWord{4, 0, 23},
+ dictWord{4, 0, 141},
+ dictWord{5, 0, 313},
+ dictWord{5, 0, 1014},
+ dictWord{6, 0, 50},
+ dictWord{6, 0, 51},
+ dictWord{7, 0, 142},
+ dictWord{7, 0, 384},
+ dictWord{7, 0, 559},
+ dictWord{8, 0, 640},
+ dictWord{9, 0, 460},
+ dictWord{9, 0, 783},
+ dictWord{11, 0, 741},
+ dictWord{12, 0, 183},
+ dictWord{141, 0, 488},
+ dictWord{141, 0, 360},
+ dictWord{7, 0, 1586},
+ dictWord{7, 11, 1995},
+ dictWord{8, 11, 299},
+ dictWord{11, 11, 890},
+ dictWord{140, 11, 674},
+ dictWord{132, 10, 434},
+ dictWord{7, 0, 652},
+ dictWord{134, 10, 550},
+ dictWord{7, 0, 766},
+ dictWord{5, 10, 553},
+ dictWord{138, 10, 824},
+ dictWord{7, 0, 737},
+ dictWord{8, 0, 298},
+ dictWord{136, 10, 452},
+ dictWord{4, 11, 238},
+ dictWord{5, 11, 503},
+ dictWord{6, 11, 179},
+ dictWord{7, 11, 2003},
+ dictWord{8, 11, 381},
+ dictWord{8, 11, 473},
+ dictWord{9, 11, 149},
+ dictWord{10, 11, 183},
+ dictWord{15, 11, 45},
+ dictWord{143, 11, 86},
+ dictWord{133, 10, 292},
+ dictWord{5, 0, 222},
+ dictWord{9, 0, 655},
+ dictWord{138, 0, 534},
+ dictWord{138, 10, 135},
+ dictWord{4, 11, 121},
+ dictWord{5, 11, 156},
+ dictWord{5, 11, 349},
+ dictWord{9, 11, 136},
+ dictWord{10, 11, 605},
+ dictWord{14, 11, 342},
+ dictWord{147, 11, 107},
+ dictWord{137, 0, 906},
+ dictWord{6, 0, 1013},
+ dictWord{134, 0, 1250},
+ dictWord{6, 0, 1956},
+ dictWord{6, 0, 2009},
+ dictWord{8, 0, 991},
+ dictWord{144, 0, 120},
+ dictWord{135, 11, 1192},
+ dictWord{
+ 138,
+ 0,
+ 503,
+ },
+ dictWord{5, 0, 154},
+ dictWord{7, 0, 1491},
+ dictWord{10, 0, 379},
+ dictWord{138, 0, 485},
+ dictWord{6, 0, 1867},
+ dictWord{6, 0, 1914},
+ dictWord{6, 0, 1925},
+ dictWord{9, 0, 917},
+ dictWord{9, 0, 925},
+ dictWord{9, 0, 932},
+ dictWord{9, 0, 951},
+ dictWord{9, 0, 1007},
+ dictWord{9, 0, 1013},
+ dictWord{12, 0, 806},
+ dictWord{
+ 12,
+ 0,
+ 810,
+ },
+ dictWord{12, 0, 814},
+ dictWord{12, 0, 816},
+ dictWord{12, 0, 824},
+ dictWord{12, 0, 832},
+ dictWord{12, 0, 837},
+ dictWord{12, 0, 863},
+ dictWord{
+ 12,
+ 0,
+ 868,
+ },
+ dictWord{12, 0, 870},
+ dictWord{12, 0, 889},
+ dictWord{12, 0, 892},
+ dictWord{12, 0, 900},
+ dictWord{12, 0, 902},
+ dictWord{12, 0, 908},
+ dictWord{12, 0, 933},
+ dictWord{12, 0, 942},
+ dictWord{12, 0, 949},
+ dictWord{12, 0, 954},
+ dictWord{15, 0, 175},
+ dictWord{15, 0, 203},
+ dictWord{15, 0, 213},
+ dictWord{15, 0, 218},
+ dictWord{15, 0, 225},
+ dictWord{15, 0, 231},
+ dictWord{15, 0, 239},
+ dictWord{15, 0, 248},
+ dictWord{15, 0, 252},
+ dictWord{18, 0, 190},
+ dictWord{18, 0, 204},
+ dictWord{
+ 18,
+ 0,
+ 215,
+ },
+ dictWord{18, 0, 216},
+ dictWord{18, 0, 222},
+ dictWord{18, 0, 225},
+ dictWord{18, 0, 230},
+ dictWord{18, 0, 239},
+ dictWord{18, 0, 241},
+ dictWord{
+ 21,
+ 0,
+ 42,
+ },
+ dictWord{21, 0, 43},
+ dictWord{21, 0, 44},
+ dictWord{21, 0, 45},
+ dictWord{21, 0, 46},
+ dictWord{21, 0, 53},
+ dictWord{24, 0, 27},
+ dictWord{152, 0, 31},
+ dictWord{
+ 133,
+ 0,
+ 716,
+ },
+ dictWord{135, 0, 844},
+ dictWord{4, 0, 91},
+ dictWord{5, 0, 388},
+ dictWord{5, 0, 845},
+ dictWord{6, 0, 206},
+ dictWord{6, 0, 252},
+ dictWord{6, 0, 365},
+ dictWord{
+ 7,
+ 0,
+ 136,
+ },
+ dictWord{7, 0, 531},
+ dictWord{136, 0, 621},
+ dictWord{7, 10, 393},
+ dictWord{10, 10, 603},
+ dictWord{139, 10, 206},
+ dictWord{6, 11, 80},
+ dictWord{
+ 6,
+ 11,
+ 1694,
+ },
+ dictWord{7, 11, 173},
+ dictWord{7, 11, 1974},
+ dictWord{9, 11, 547},
+ dictWord{10, 11, 730},
+ dictWord{14, 11, 18},
+ dictWord{150, 11, 39},
+ dictWord{137, 0, 748},
+ dictWord{4, 11, 923},
+ dictWord{134, 11, 1711},
+ dictWord{4, 10, 912},
+ dictWord{137, 10, 232},
+ dictWord{7, 10, 98},
+ dictWord{7, 10, 1973},
+ dictWord{136, 10, 716},
+ dictWord{14, 0, 103},
+ dictWord{133, 10, 733},
+ dictWord{132, 11, 595},
+ dictWord{12, 0, 158},
+ dictWord{18, 0, 8},
+ dictWord{19, 0, 62},
+ dictWord{20, 0, 6},
+ dictWord{22, 0, 4},
+ dictWord{23, 0, 2},
+ dictWord{23, 0, 9},
+ dictWord{5, 11, 240},
+ dictWord{6, 11, 459},
+ dictWord{7, 11, 12},
+ dictWord{7, 11, 114},
+ dictWord{7, 11, 502},
+ dictWord{7, 11, 1751},
+ dictWord{7, 11, 1753},
+ dictWord{7, 11, 1805},
+ dictWord{8, 11, 658},
+ dictWord{9, 11, 1},
+ dictWord{11, 11, 959},
+ dictWord{13, 11, 446},
+ dictWord{142, 11, 211},
+ dictWord{135, 0, 576},
+ dictWord{5, 0, 771},
+ dictWord{5, 0, 863},
+ dictWord{5, 0, 898},
+ dictWord{6, 0, 648},
+ dictWord{
+ 6,
+ 0,
+ 1632,
+ },
+ dictWord{6, 0, 1644},
+ dictWord{134, 0, 1780},
+ dictWord{133, 0, 331},
+ dictWord{7, 11, 633},
+ dictWord{7, 11, 905},
+ dictWord{7, 11, 909},
+ dictWord{
+ 7,
+ 11,
+ 1538,
+ },
+ dictWord{9, 11, 767},
+ dictWord{140, 11, 636},
+ dictWord{140, 0, 632},
+ dictWord{5, 0, 107},
+ dictWord{7, 0, 201},
+ dictWord{136, 0, 518},
+ dictWord{
+ 6,
+ 0,
+ 446,
+ },
+ dictWord{7, 0, 1817},
+ dictWord{134, 11, 490},
+ dictWord{9, 0, 851},
+ dictWord{141, 0, 510},
+ dictWord{7, 11, 250},
+ dictWord{8, 11, 506},
+ dictWord{
+ 136,
+ 11,
+ 507,
+ },
+ dictWord{4, 0, 504},
+ dictWord{137, 10, 72},
+ dictWord{132, 11, 158},
+ dictWord{4, 11, 140},
+ dictWord{7, 11, 362},
+ dictWord{8, 11, 209},
+ dictWord{
+ 9,
+ 11,
+ 10,
+ },
+ dictWord{9, 11, 160},
+ dictWord{9, 11, 503},
+ dictWord{10, 11, 689},
+ dictWord{11, 11, 350},
+ dictWord{11, 11, 553},
+ dictWord{11, 11, 725},
+ dictWord{
+ 12,
+ 11,
+ 252,
+ },
+ dictWord{12, 11, 583},
+ dictWord{13, 11, 192},
+ dictWord{13, 11, 352},
+ dictWord{14, 11, 269},
+ dictWord{14, 11, 356},
+ dictWord{148, 11, 50},
+ dictWord{6, 11, 597},
+ dictWord{135, 11, 1318},
+ dictWord{135, 10, 1454},
+ dictWord{5, 0, 883},
+ dictWord{5, 0, 975},
+ dictWord{8, 0, 392},
+ dictWord{148, 0, 7},
+ dictWord{6, 11, 228},
+ dictWord{7, 11, 1341},
+ dictWord{9, 11, 408},
+ dictWord{138, 11, 343},
+ dictWord{11, 11, 348},
+ dictWord{11, 10, 600},
+ dictWord{12, 11, 99},
+ dictWord{13, 10, 245},
+ dictWord{18, 11, 1},
+ dictWord{18, 11, 11},
+ dictWord{147, 11, 4},
+ dictWord{134, 11, 296},
+ dictWord{5, 0, 922},
+ dictWord{134, 0, 1707},
+ dictWord{132, 11, 557},
+ dictWord{4, 11, 548},
+ dictWord{7, 10, 164},
+ dictWord{7, 10, 1571},
+ dictWord{9, 10, 107},
+ dictWord{140, 10, 225},
+ dictWord{
+ 7,
+ 11,
+ 197,
+ },
+ dictWord{8, 11, 142},
+ dictWord{8, 11, 325},
+ dictWord{9, 11, 150},
+ dictWord{9, 11, 596},
+ dictWord{10, 11, 350},
+ dictWord{10, 11, 353},
+ dictWord{
+ 11,
+ 11,
+ 74,
+ },
+ dictWord{11, 11, 315},
+ dictWord{14, 11, 423},
+ dictWord{143, 11, 141},
+ dictWord{5, 0, 993},
+ dictWord{7, 0, 515},
+ dictWord{137, 0, 91},
+ dictWord{4, 0, 131},
+ dictWord{8, 0, 200},
+ dictWord{5, 10, 484},
+ dictWord{5, 10, 510},
+ dictWord{6, 10, 434},
+ dictWord{7, 10, 1000},
+ dictWord{7, 10, 1098},
+ dictWord{136, 10, 2},
+ dictWord{152, 0, 10},
+ dictWord{4, 11, 62},
+ dictWord{5, 11, 83},
+ dictWord{6, 11, 399},
+ dictWord{6, 11, 579},
+ dictWord{7, 11, 692},
+ dictWord{7, 11, 846},
+ dictWord{
+ 7,
+ 11,
+ 1015,
+ },
+ dictWord{7, 11, 1799},
+ dictWord{8, 11, 403},
+ dictWord{9, 11, 394},
+ dictWord{10, 11, 133},
+ dictWord{12, 11, 4},
+ dictWord{12, 11, 297},
+ dictWord{
+ 12,
+ 11,
+ 452,
+ },
+ dictWord{16, 11, 81},
+ dictWord{18, 11, 19},
+ dictWord{18, 11, 25},
+ dictWord{21, 11, 14},
+ dictWord{22, 11, 12},
+ dictWord{151, 11, 18},
+ dictWord{
+ 140,
+ 11,
+ 459,
+ },
+ dictWord{132, 11, 177},
+ dictWord{7, 0, 1433},
+ dictWord{9, 0, 365},
+ dictWord{137, 11, 365},
+ dictWord{132, 10, 460},
+ dictWord{5, 0, 103},
+ dictWord{
+ 6,
+ 0,
+ 2004,
+ },
+ dictWord{7, 0, 921},
+ dictWord{8, 0, 580},
+ dictWord{8, 0, 593},
+ dictWord{8, 0, 630},
+ dictWord{10, 0, 28},
+ dictWord{5, 11, 411},
+ dictWord{
+ 135,
+ 11,
+ 653,
+ },
+ dictWord{4, 10, 932},
+ dictWord{133, 10, 891},
+ dictWord{4, 0, 911},
+ dictWord{5, 0, 867},
+ dictWord{5, 0, 1013},
+ dictWord{7, 0, 2034},
+ dictWord{8, 0, 798},
+ dictWord{136, 0, 813},
+ dictWord{7, 11, 439},
+ dictWord{10, 11, 727},
+ dictWord{11, 11, 260},
+ dictWord{139, 11, 684},
+ dictWord{136, 10, 625},
+ dictWord{
+ 5,
+ 11,
+ 208,
+ },
+ dictWord{7, 11, 753},
+ dictWord{135, 11, 1528},
+ dictWord{5, 0, 461},
+ dictWord{7, 0, 1925},
+ dictWord{12, 0, 39},
+ dictWord{13, 0, 265},
+ dictWord{
+ 13,
+ 0,
+ 439,
+ },
+ dictWord{134, 10, 76},
+ dictWord{6, 0, 853},
+ dictWord{8, 10, 92},
+ dictWord{137, 10, 221},
+ dictWord{5, 0, 135},
+ dictWord{6, 0, 519},
+ dictWord{7, 0, 1722},
+ dictWord{10, 0, 271},
+ dictWord{11, 0, 261},
+ dictWord{145, 0, 54},
+ dictWord{139, 11, 814},
+ dictWord{14, 0, 338},
+ dictWord{148, 0, 81},
+ dictWord{4, 0, 300},
+ dictWord{133, 0, 436},
+ dictWord{5, 0, 419},
+ dictWord{5, 0, 687},
+ dictWord{7, 0, 864},
+ dictWord{9, 0, 470},
+ dictWord{135, 11, 864},
+ dictWord{9, 0, 836},
+ dictWord{
+ 133,
+ 11,
+ 242,
+ },
+ dictWord{134, 0, 1937},
+ dictWord{4, 10, 763},
+ dictWord{133, 11, 953},
+ dictWord{132, 10, 622},
+ dictWord{132, 0, 393},
+ dictWord{
+ 133,
+ 10,
+ 253,
+ },
+ dictWord{8, 0, 357},
+ dictWord{10, 0, 745},
+ dictWord{14, 0, 426},
+ dictWord{17, 0, 94},
+ dictWord{19, 0, 57},
+ dictWord{135, 10, 546},
+ dictWord{5, 11, 615},
+ dictWord{146, 11, 37},
+ dictWord{9, 10, 73},
+ dictWord{10, 10, 110},
+ dictWord{14, 10, 185},
+ dictWord{145, 10, 119},
+ dictWord{11, 0, 703},
+ dictWord{7, 10, 624},
+ dictWord{7, 10, 916},
+ dictWord{10, 10, 256},
+ dictWord{139, 10, 87},
+ dictWord{133, 11, 290},
+ dictWord{5, 10, 212},
+ dictWord{12, 10, 35},
+ dictWord{
+ 141,
+ 10,
+ 382,
+ },
+ dictWord{132, 11, 380},
+ dictWord{5, 11, 52},
+ dictWord{7, 11, 277},
+ dictWord{9, 11, 368},
+ dictWord{139, 11, 791},
+ dictWord{133, 0, 387},
+ dictWord{
+ 10,
+ 11,
+ 138,
+ },
+ dictWord{139, 11, 476},
+ dictWord{4, 0, 6},
+ dictWord{5, 0, 708},
+ dictWord{136, 0, 75},
+ dictWord{7, 0, 1351},
+ dictWord{9, 0, 581},
+ dictWord{10, 0, 639},
+ dictWord{11, 0, 453},
+ dictWord{140, 0, 584},
+ dictWord{132, 0, 303},
+ dictWord{138, 0, 772},
+ dictWord{135, 10, 1175},
+ dictWord{4, 0, 749},
+ dictWord{
+ 5,
+ 10,
+ 816,
+ },
+ dictWord{6, 11, 256},
+ dictWord{7, 11, 307},
+ dictWord{7, 11, 999},
+ dictWord{7, 11, 1481},
+ dictWord{7, 11, 1732},
+ dictWord{7, 11, 1738},
+ dictWord{
+ 8,
+ 11,
+ 265,
+ },
+ dictWord{9, 11, 414},
+ dictWord{11, 11, 316},
+ dictWord{12, 11, 52},
+ dictWord{13, 11, 420},
+ dictWord{147, 11, 100},
+ dictWord{135, 11, 1296},
+ dictWord{
+ 6,
+ 0,
+ 1065,
+ },
+ dictWord{5, 10, 869},
+ dictWord{5, 10, 968},
+ dictWord{6, 10, 1626},
+ dictWord{8, 10, 734},
+ dictWord{136, 10, 784},
+ dictWord{4, 10, 542},
+ dictWord{
+ 6,
+ 10,
+ 1716,
+ },
+ dictWord{6, 10, 1727},
+ dictWord{7, 10, 1082},
+ dictWord{7, 10, 1545},
+ dictWord{8, 10, 56},
+ dictWord{8, 10, 118},
+ dictWord{8, 10, 412},
+ dictWord{
+ 8,
+ 10,
+ 564,
+ },
+ dictWord{9, 10, 888},
+ dictWord{9, 10, 908},
+ dictWord{10, 10, 50},
+ dictWord{10, 10, 423},
+ dictWord{11, 10, 685},
+ dictWord{11, 10, 697},
+ dictWord{11, 10, 933},
+ dictWord{12, 10, 299},
+ dictWord{13, 10, 126},
+ dictWord{13, 10, 136},
+ dictWord{13, 10, 170},
+ dictWord{141, 10, 190},
+ dictWord{
+ 134,
+ 0,
+ 226,
+ },
+ dictWord{4, 0, 106},
+ dictWord{7, 0, 310},
+ dictWord{11, 0, 717},
+ dictWord{133, 11, 723},
+ dictWord{5, 0, 890},
+ dictWord{5, 0, 988},
+ dictWord{4, 10, 232},
+ dictWord{9, 10, 202},
+ dictWord{10, 10, 474},
+ dictWord{140, 10, 433},
+ dictWord{6, 0, 626},
+ dictWord{142, 0, 431},
+ dictWord{10, 0, 706},
+ dictWord{150, 0, 44},
+ dictWord{13, 0, 51},
+ dictWord{6, 10, 108},
+ dictWord{7, 10, 1003},
+ dictWord{7, 10, 1181},
+ dictWord{8, 10, 111},
+ dictWord{136, 10, 343},
+ dictWord{132, 0, 698},
+ dictWord{5, 11, 109},
+ dictWord{6, 11, 1784},
+ dictWord{7, 11, 1895},
+ dictWord{12, 11, 296},
+ dictWord{140, 11, 302},
+ dictWord{134, 0, 828},
+ dictWord{
+ 134,
+ 10,
+ 1712,
+ },
+ dictWord{138, 0, 17},
+ dictWord{7, 0, 1929},
+ dictWord{4, 10, 133},
+ dictWord{5, 11, 216},
+ dictWord{7, 10, 711},
+ dictWord{7, 10, 1298},
+ dictWord{
+ 7,
+ 10,
+ 1585,
+ },
+ dictWord{7, 11, 1879},
+ dictWord{9, 11, 141},
+ dictWord{9, 11, 270},
+ dictWord{9, 11, 679},
+ dictWord{10, 11, 159},
+ dictWord{10, 11, 553},
+ dictWord{
+ 11,
+ 11,
+ 197,
+ },
+ dictWord{11, 11, 438},
+ dictWord{12, 11, 538},
+ dictWord{12, 11, 559},
+ dictWord{13, 11, 193},
+ dictWord{13, 11, 423},
+ dictWord{14, 11, 144},
+ dictWord{14, 11, 166},
+ dictWord{14, 11, 167},
+ dictWord{15, 11, 67},
+ dictWord{147, 11, 84},
+ dictWord{141, 11, 127},
+ dictWord{7, 11, 1872},
+ dictWord{
+ 137,
+ 11,
+ 81,
+ },
+ dictWord{6, 10, 99},
+ dictWord{7, 10, 1808},
+ dictWord{145, 10, 57},
+ dictWord{134, 11, 391},
+ dictWord{5, 0, 689},
+ dictWord{6, 0, 84},
+ dictWord{7, 0, 1250},
+ dictWord{6, 10, 574},
+ dictWord{7, 10, 428},
+ dictWord{10, 10, 669},
+ dictWord{11, 10, 485},
+ dictWord{11, 10, 840},
+ dictWord{12, 10, 300},
+ dictWord{
+ 142,
+ 10,
+ 250,
+ },
+ dictWord{7, 11, 322},
+ dictWord{136, 11, 249},
+ dictWord{7, 11, 432},
+ dictWord{135, 11, 1649},
+ dictWord{135, 10, 1871},
+ dictWord{137, 10, 252},
+ dictWord{6, 11, 155},
+ dictWord{140, 11, 234},
+ dictWord{7, 0, 871},
+ dictWord{19, 0, 27},
+ dictWord{147, 11, 27},
+ dictWord{140, 0, 498},
+ dictWord{5, 0, 986},
+ dictWord{6, 0, 130},
+ dictWord{138, 0, 823},
+ dictWord{6, 0, 1793},
+ dictWord{7, 0, 1582},
+ dictWord{8, 0, 458},
+ dictWord{10, 0, 101},
+ dictWord{10, 0, 318},
+ dictWord{
+ 10,
+ 0,
+ 945,
+ },
+ dictWord{12, 0, 734},
+ dictWord{16, 0, 104},
+ dictWord{18, 0, 177},
+ dictWord{6, 10, 323},
+ dictWord{135, 10, 1564},
+ dictWord{5, 11, 632},
+ dictWord{
+ 138,
+ 11,
+ 526,
+ },
+ dictWord{10, 0, 435},
+ dictWord{7, 10, 461},
+ dictWord{136, 10, 775},
+ dictWord{6, 11, 144},
+ dictWord{7, 11, 948},
+ dictWord{7, 11, 1042},
+ dictWord{
+ 7,
+ 11,
+ 1857,
+ },
+ dictWord{8, 11, 235},
+ dictWord{8, 11, 461},
+ dictWord{9, 11, 453},
+ dictWord{9, 11, 530},
+ dictWord{10, 11, 354},
+ dictWord{17, 11, 77},
+ dictWord{
+ 19,
+ 11,
+ 99,
+ },
+ dictWord{148, 11, 79},
+ dictWord{138, 0, 966},
+ dictWord{7, 0, 1644},
+ dictWord{137, 0, 129},
+ dictWord{135, 0, 997},
+ dictWord{136, 0, 502},
+ dictWord{
+ 5,
+ 11,
+ 196,
+ },
+ dictWord{6, 11, 486},
+ dictWord{7, 11, 212},
+ dictWord{8, 11, 309},
+ dictWord{136, 11, 346},
+ dictWord{7, 10, 727},
+ dictWord{146, 10, 73},
+ dictWord{132, 0, 823},
+ dictWord{132, 11, 686},
+ dictWord{135, 0, 1927},
+ dictWord{4, 0, 762},
+ dictWord{7, 0, 1756},
+ dictWord{137, 0, 98},
+ dictWord{136, 10, 577},
+ dictWord{24, 0, 8},
+ dictWord{4, 11, 30},
+ dictWord{5, 11, 43},
+ dictWord{152, 11, 8},
+ dictWord{7, 0, 1046},
+ dictWord{139, 0, 160},
+ dictWord{7, 0, 492},
+ dictWord{
+ 4,
+ 10,
+ 413,
+ },
+ dictWord{5, 10, 677},
+ dictWord{7, 11, 492},
+ dictWord{8, 10, 432},
+ dictWord{140, 10, 280},
+ dictWord{6, 0, 45},
+ dictWord{7, 0, 433},
+ dictWord{8, 0, 129},
+ dictWord{9, 0, 21},
+ dictWord{10, 0, 392},
+ dictWord{11, 0, 79},
+ dictWord{12, 0, 499},
+ dictWord{13, 0, 199},
+ dictWord{141, 0, 451},
+ dictWord{7, 0, 558},
+ dictWord{
+ 136,
+ 0,
+ 353,
+ },
+ dictWord{4, 11, 220},
+ dictWord{7, 11, 1535},
+ dictWord{9, 11, 93},
+ dictWord{139, 11, 474},
+ dictWord{7, 10, 646},
+ dictWord{7, 10, 1730},
+ dictWord{
+ 11,
+ 10,
+ 446,
+ },
+ dictWord{141, 10, 178},
+ dictWord{133, 0, 785},
+ dictWord{134, 0, 1145},
+ dictWord{8, 0, 81},
+ dictWord{9, 0, 189},
+ dictWord{9, 0, 201},
+ dictWord{
+ 11,
+ 0,
+ 478,
+ },
+ dictWord{11, 0, 712},
+ dictWord{141, 0, 338},
+ dictWord{5, 0, 353},
+ dictWord{151, 0, 26},
+ dictWord{11, 0, 762},
+ dictWord{132, 10, 395},
+ dictWord{
+ 134,
+ 0,
+ 2024,
+ },
+ dictWord{4, 0, 611},
+ dictWord{133, 0, 606},
+ dictWord{9, 10, 174},
+ dictWord{10, 10, 164},
+ dictWord{11, 10, 440},
+ dictWord{11, 10, 841},
+ dictWord{
+ 143,
+ 10,
+ 98,
+ },
+ dictWord{134, 10, 426},
+ dictWord{10, 10, 608},
+ dictWord{139, 10, 1002},
+ dictWord{138, 10, 250},
+ dictWord{6, 0, 25},
+ dictWord{7, 0, 855},
+ dictWord{7, 0, 1258},
+ dictWord{144, 0, 32},
+ dictWord{7, 11, 1725},
+ dictWord{138, 11, 393},
+ dictWord{5, 11, 263},
+ dictWord{134, 11, 414},
+ dictWord{6, 0, 2011},
+ dictWord{133, 10, 476},
+ dictWord{4, 0, 4},
+ dictWord{7, 0, 1118},
+ dictWord{7, 0, 1320},
+ dictWord{7, 0, 1706},
+ dictWord{8, 0, 277},
+ dictWord{9, 0, 622},
+ dictWord{
+ 10,
+ 0,
+ 9,
+ },
+ dictWord{11, 0, 724},
+ dictWord{12, 0, 350},
+ dictWord{12, 0, 397},
+ dictWord{13, 0, 28},
+ dictWord{13, 0, 159},
+ dictWord{15, 0, 89},
+ dictWord{18, 0, 5},
+ dictWord{
+ 19,
+ 0,
+ 9,
+ },
+ dictWord{20, 0, 34},
+ dictWord{22, 0, 47},
+ dictWord{6, 11, 178},
+ dictWord{6, 11, 1750},
+ dictWord{8, 11, 251},
+ dictWord{9, 11, 690},
+ dictWord{
+ 10,
+ 11,
+ 155,
+ },
+ dictWord{10, 11, 196},
+ dictWord{10, 11, 373},
+ dictWord{11, 11, 698},
+ dictWord{13, 11, 155},
+ dictWord{148, 11, 93},
+ dictWord{5, 11, 97},
+ dictWord{
+ 137,
+ 11,
+ 393,
+ },
+ dictWord{7, 0, 764},
+ dictWord{11, 0, 461},
+ dictWord{12, 0, 172},
+ dictWord{5, 10, 76},
+ dictWord{6, 10, 458},
+ dictWord{6, 10, 497},
+ dictWord{
+ 7,
+ 10,
+ 868,
+ },
+ dictWord{9, 10, 658},
+ dictWord{10, 10, 594},
+ dictWord{11, 10, 566},
+ dictWord{12, 10, 338},
+ dictWord{141, 10, 200},
+ dictWord{134, 0, 1449},
+ dictWord{138, 11, 40},
+ dictWord{134, 11, 1639},
+ dictWord{134, 0, 1445},
+ dictWord{6, 0, 1168},
+ dictWord{4, 10, 526},
+ dictWord{7, 10, 1029},
+ dictWord{
+ 135,
+ 10,
+ 1054,
+ },
+ dictWord{4, 11, 191},
+ dictWord{7, 11, 934},
+ dictWord{8, 11, 647},
+ dictWord{145, 11, 97},
+ dictWord{132, 10, 636},
+ dictWord{6, 0, 233},
+ dictWord{
+ 7,
+ 10,
+ 660,
+ },
+ dictWord{7, 10, 1124},
+ dictWord{17, 10, 31},
+ dictWord{19, 10, 22},
+ dictWord{151, 10, 14},
+ dictWord{6, 10, 1699},
+ dictWord{136, 11, 110},
+ dictWord{
+ 12,
+ 11,
+ 246,
+ },
+ dictWord{15, 11, 162},
+ dictWord{19, 11, 64},
+ dictWord{20, 11, 8},
+ dictWord{20, 11, 95},
+ dictWord{22, 11, 24},
+ dictWord{152, 11, 17},
+ dictWord{
+ 5,
+ 11,
+ 165,
+ },
+ dictWord{9, 11, 346},
+ dictWord{138, 11, 655},
+ dictWord{5, 11, 319},
+ dictWord{135, 11, 534},
+ dictWord{134, 0, 255},
+ dictWord{9, 0, 216},
+ dictWord{
+ 8,
+ 11,
+ 128,
+ },
+ dictWord{139, 11, 179},
+ dictWord{9, 0, 183},
+ dictWord{139, 0, 286},
+ dictWord{11, 0, 956},
+ dictWord{151, 0, 3},
+ dictWord{4, 0, 536},
+ dictWord{
+ 7,
+ 0,
+ 1141,
+ },
+ dictWord{10, 0, 723},
+ dictWord{139, 0, 371},
+ dictWord{4, 10, 279},
+ dictWord{7, 10, 301},
+ dictWord{137, 10, 362},
+ dictWord{7, 0, 285},
+ dictWord{
+ 5,
+ 11,
+ 57,
+ },
+ dictWord{6, 11, 101},
+ dictWord{6, 11, 1663},
+ dictWord{7, 11, 132},
+ dictWord{7, 11, 1048},
+ dictWord{7, 11, 1154},
+ dictWord{7, 11, 1415},
+ dictWord{
+ 7,
+ 11,
+ 1507,
+ },
+ dictWord{12, 11, 493},
+ dictWord{15, 11, 105},
+ dictWord{151, 11, 15},
+ dictWord{5, 11, 459},
+ dictWord{7, 11, 1073},
+ dictWord{7, 10, 1743},
+ dictWord{
+ 8,
+ 11,
+ 241,
+ },
+ dictWord{136, 11, 334},
+ dictWord{4, 10, 178},
+ dictWord{133, 10, 399},
+ dictWord{135, 0, 560},
+ dictWord{132, 0, 690},
+ dictWord{135, 0, 1246},
+ dictWord{18, 0, 157},
+ dictWord{147, 0, 63},
+ dictWord{10, 0, 599},
+ dictWord{11, 0, 33},
+ dictWord{12, 0, 571},
+ dictWord{149, 0, 1},
+ dictWord{6, 11, 324},
+ dictWord{
+ 6,
+ 11,
+ 520,
+ },
+ dictWord{7, 11, 338},
+ dictWord{7, 11, 1616},
+ dictWord{7, 11, 1729},
+ dictWord{8, 11, 228},
+ dictWord{9, 11, 69},
+ dictWord{139, 11, 750},
+ dictWord{
+ 7,
+ 0,
+ 1862,
+ },
+ dictWord{12, 0, 491},
+ dictWord{12, 0, 520},
+ dictWord{13, 0, 383},
+ dictWord{142, 0, 244},
+ dictWord{135, 11, 734},
+ dictWord{134, 10, 1692},
+ dictWord{10, 0, 448},
+ dictWord{11, 0, 630},
+ dictWord{17, 0, 117},
+ dictWord{6, 10, 202},
+ dictWord{7, 11, 705},
+ dictWord{12, 10, 360},
+ dictWord{17, 10, 118},
+ dictWord{18, 10, 27},
+ dictWord{148, 10, 67},
+ dictWord{4, 11, 73},
+ dictWord{6, 11, 612},
+ dictWord{7, 11, 927},
+ dictWord{7, 11, 1822},
+ dictWord{8, 11, 217},
+ dictWord{
+ 9,
+ 11,
+ 472,
+ },
+ dictWord{9, 11, 765},
+ dictWord{9, 11, 766},
+ dictWord{10, 11, 408},
+ dictWord{11, 11, 51},
+ dictWord{11, 11, 793},
+ dictWord{12, 11, 266},
+ dictWord{
+ 15,
+ 11,
+ 158,
+ },
+ dictWord{20, 11, 89},
+ dictWord{150, 11, 32},
+ dictWord{4, 0, 190},
+ dictWord{133, 0, 554},
+ dictWord{133, 0, 1001},
+ dictWord{5, 11, 389},
+ dictWord{
+ 8,
+ 11,
+ 636,
+ },
+ dictWord{137, 11, 229},
+ dictWord{5, 0, 446},
+ dictWord{7, 10, 872},
+ dictWord{10, 10, 516},
+ dictWord{139, 10, 167},
+ dictWord{137, 10, 313},
+ dictWord{132, 10, 224},
+ dictWord{134, 0, 1313},
+ dictWord{5, 10, 546},
+ dictWord{7, 10, 35},
+ dictWord{8, 10, 11},
+ dictWord{8, 10, 12},
+ dictWord{9, 10, 315},
+ dictWord{9, 10, 533},
+ dictWord{10, 10, 802},
+ dictWord{11, 10, 166},
+ dictWord{12, 10, 525},
+ dictWord{142, 10, 243},
+ dictWord{6, 0, 636},
+ dictWord{137, 0, 837},
+ dictWord{5, 10, 241},
+ dictWord{8, 10, 242},
+ dictWord{9, 10, 451},
+ dictWord{10, 10, 667},
+ dictWord{11, 10, 598},
+ dictWord{140, 10, 429},
+ dictWord{22, 10, 46},
+ dictWord{150, 11, 46},
+ dictWord{136, 11, 472},
+ dictWord{11, 0, 278},
+ dictWord{142, 0, 73},
+ dictWord{141, 11, 185},
+ dictWord{132, 0, 868},
+ dictWord{
+ 134,
+ 0,
+ 972,
+ },
+ dictWord{4, 10, 366},
+ dictWord{137, 10, 516},
+ dictWord{138, 0, 1010},
+ dictWord{5, 11, 189},
+ dictWord{6, 10, 1736},
+ dictWord{7, 11, 442},
+ dictWord{
+ 7,
+ 11,
+ 443,
+ },
+ dictWord{8, 11, 281},
+ dictWord{12, 11, 174},
+ dictWord{13, 11, 83},
+ dictWord{141, 11, 261},
+ dictWord{139, 11, 384},
+ dictWord{6, 11, 2},
+ dictWord{
+ 7,
+ 11,
+ 191,
+ },
+ dictWord{7, 11, 446},
+ dictWord{7, 11, 758},
+ dictWord{7, 11, 1262},
+ dictWord{7, 11, 1737},
+ dictWord{8, 11, 22},
+ dictWord{8, 11, 270},
+ dictWord{
+ 8,
+ 11,
+ 612,
+ },
+ dictWord{9, 11, 4},
+ dictWord{9, 11, 167},
+ dictWord{9, 11, 312},
+ dictWord{9, 11, 436},
+ dictWord{10, 11, 156},
+ dictWord{10, 11, 216},
+ dictWord{
+ 10,
+ 11,
+ 311,
+ },
+ dictWord{10, 11, 623},
+ dictWord{11, 11, 72},
+ dictWord{11, 11, 330},
+ dictWord{11, 11, 455},
+ dictWord{12, 11, 101},
+ dictWord{12, 11, 321},
+ dictWord{
+ 12,
+ 11,
+ 504,
+ },
+ dictWord{12, 11, 530},
+ dictWord{12, 11, 543},
+ dictWord{13, 11, 17},
+ dictWord{13, 11, 156},
+ dictWord{13, 11, 334},
+ dictWord{14, 11, 48},
+ dictWord{15, 11, 70},
+ dictWord{17, 11, 60},
+ dictWord{148, 11, 64},
+ dictWord{6, 10, 331},
+ dictWord{136, 10, 623},
+ dictWord{135, 0, 1231},
+ dictWord{132, 0, 304},
+ dictWord{6, 11, 60},
+ dictWord{7, 11, 670},
+ dictWord{7, 11, 1327},
+ dictWord{8, 11, 411},
+ dictWord{8, 11, 435},
+ dictWord{9, 11, 653},
+ dictWord{9, 11, 740},
+ dictWord{10, 11, 385},
+ dictWord{11, 11, 222},
+ dictWord{11, 11, 324},
+ dictWord{11, 11, 829},
+ dictWord{140, 11, 611},
+ dictWord{7, 0, 506},
+ dictWord{6, 11, 166},
+ dictWord{7, 11, 374},
+ dictWord{135, 11, 1174},
+ dictWord{14, 11, 43},
+ dictWord{146, 11, 21},
+ dictWord{135, 11, 1694},
+ dictWord{135, 10, 1888},
+ dictWord{
+ 5,
+ 11,
+ 206,
+ },
+ dictWord{134, 11, 398},
+ dictWord{135, 11, 50},
+ dictWord{150, 0, 26},
+ dictWord{6, 0, 53},
+ dictWord{6, 0, 199},
+ dictWord{7, 0, 1408},
+ dictWord{
+ 8,
+ 0,
+ 32,
+ },
+ dictWord{8, 0, 93},
+ dictWord{10, 0, 397},
+ dictWord{10, 0, 629},
+ dictWord{11, 0, 593},
+ dictWord{11, 0, 763},
+ dictWord{13, 0, 326},
+ dictWord{145, 0, 35},
+ dictWord{134, 0, 105},
+ dictWord{132, 10, 394},
+ dictWord{4, 0, 843},
+ dictWord{138, 0, 794},
+ dictWord{11, 0, 704},
+ dictWord{141, 0, 396},
+ dictWord{5, 0, 114},
+ dictWord{5, 0, 255},
+ dictWord{141, 0, 285},
+ dictWord{6, 0, 619},
+ dictWord{7, 0, 898},
+ dictWord{7, 0, 1092},
+ dictWord{8, 0, 485},
+ dictWord{18, 0, 28},
+ dictWord{
+ 19,
+ 0,
+ 116,
+ },
+ dictWord{135, 10, 1931},
+ dictWord{9, 0, 145},
+ dictWord{7, 10, 574},
+ dictWord{135, 10, 1719},
+ dictWord{7, 0, 2035},
+ dictWord{8, 0, 19},
+ dictWord{
+ 9,
+ 0,
+ 89,
+ },
+ dictWord{138, 0, 831},
+ dictWord{132, 10, 658},
+ dictWord{6, 11, 517},
+ dictWord{7, 11, 1159},
+ dictWord{10, 11, 621},
+ dictWord{139, 11, 192},
+ dictWord{
+ 7,
+ 0,
+ 1933,
+ },
+ dictWord{7, 11, 1933},
+ dictWord{9, 10, 781},
+ dictWord{10, 10, 144},
+ dictWord{11, 10, 385},
+ dictWord{13, 10, 161},
+ dictWord{13, 10, 228},
+ dictWord{13, 10, 268},
+ dictWord{148, 10, 107},
+ dictWord{136, 10, 374},
+ dictWord{10, 11, 223},
+ dictWord{139, 11, 645},
+ dictWord{135, 0, 1728},
+ dictWord{
+ 7,
+ 11,
+ 64,
+ },
+ dictWord{7, 11, 289},
+ dictWord{136, 11, 245},
+ dictWord{4, 10, 344},
+ dictWord{6, 10, 498},
+ dictWord{139, 10, 323},
+ dictWord{136, 0, 746},
+ dictWord{
+ 135,
+ 10,
+ 1063,
+ },
+ dictWord{137, 10, 155},
+ dictWord{4, 0, 987},
+ dictWord{6, 0, 1964},
+ dictWord{6, 0, 1974},
+ dictWord{6, 0, 1990},
+ dictWord{136, 0, 995},
+ dictWord{133, 11, 609},
+ dictWord{133, 10, 906},
+ dictWord{134, 0, 1550},
+ dictWord{134, 0, 874},
+ dictWord{5, 11, 129},
+ dictWord{6, 11, 61},
+ dictWord{
+ 135,
+ 11,
+ 947,
+ },
+ dictWord{4, 0, 1018},
+ dictWord{6, 0, 1938},
+ dictWord{6, 0, 2021},
+ dictWord{134, 0, 2039},
+ dictWord{132, 0, 814},
+ dictWord{11, 0, 126},
+ dictWord{
+ 139,
+ 0,
+ 287,
+ },
+ dictWord{134, 0, 1264},
+ dictWord{5, 0, 955},
+ dictWord{136, 0, 814},
+ dictWord{141, 11, 506},
+ dictWord{132, 11, 314},
+ dictWord{6, 0, 981},
+ dictWord{139, 11, 1000},
+ dictWord{5, 0, 56},
+ dictWord{8, 0, 892},
+ dictWord{8, 0, 915},
+ dictWord{140, 0, 776},
+ dictWord{148, 0, 100},
+ dictWord{10, 0, 4},
+ dictWord{
+ 10,
+ 0,
+ 13,
+ },
+ dictWord{11, 0, 638},
+ dictWord{148, 0, 57},
+ dictWord{148, 11, 74},
+ dictWord{5, 0, 738},
+ dictWord{132, 10, 616},
+ dictWord{133, 11, 637},
+ dictWord{
+ 136,
+ 10,
+ 692,
+ },
+ dictWord{133, 0, 758},
+ dictWord{132, 10, 305},
+ dictWord{137, 11, 590},
+ dictWord{5, 11, 280},
+ dictWord{135, 11, 1226},
+ dictWord{
+ 134,
+ 11,
+ 494,
+ },
+ dictWord{135, 0, 1112},
+ dictWord{133, 11, 281},
+ dictWord{13, 0, 44},
+ dictWord{14, 0, 214},
+ dictWord{5, 10, 214},
+ dictWord{7, 10, 603},
+ dictWord{
+ 8,
+ 10,
+ 611,
+ },
+ dictWord{9, 10, 686},
+ dictWord{10, 10, 88},
+ dictWord{11, 10, 459},
+ dictWord{11, 10, 496},
+ dictWord{12, 10, 463},
+ dictWord{140, 10, 590},
+ dictWord{
+ 139,
+ 0,
+ 328,
+ },
+ dictWord{135, 11, 1064},
+ dictWord{137, 0, 133},
+ dictWord{7, 0, 168},
+ dictWord{13, 0, 196},
+ dictWord{141, 0, 237},
+ dictWord{134, 10, 1703},
+ dictWord{134, 0, 1152},
+ dictWord{135, 0, 1245},
+ dictWord{5, 0, 110},
+ dictWord{6, 0, 169},
+ dictWord{6, 0, 1702},
+ dictWord{7, 0, 400},
+ dictWord{8, 0, 538},
+ dictWord{
+ 9,
+ 0,
+ 184,
+ },
+ dictWord{9, 0, 524},
+ dictWord{140, 0, 218},
+ dictWord{6, 0, 1816},
+ dictWord{10, 0, 871},
+ dictWord{12, 0, 769},
+ dictWord{140, 0, 785},
+ dictWord{
+ 132,
+ 11,
+ 630,
+ },
+ dictWord{7, 11, 33},
+ dictWord{7, 11, 120},
+ dictWord{8, 11, 489},
+ dictWord{9, 11, 319},
+ dictWord{10, 11, 820},
+ dictWord{11, 11, 1004},
+ dictWord{
+ 12,
+ 11,
+ 379,
+ },
+ dictWord{13, 11, 117},
+ dictWord{13, 11, 412},
+ dictWord{14, 11, 25},
+ dictWord{15, 11, 52},
+ dictWord{15, 11, 161},
+ dictWord{16, 11, 47},
+ dictWord{149, 11, 2},
+ dictWord{6, 0, 133},
+ dictWord{8, 0, 413},
+ dictWord{9, 0, 353},
+ dictWord{139, 0, 993},
+ dictWord{145, 10, 19},
+ dictWord{4, 11, 937},
+ dictWord{
+ 133,
+ 11,
+ 801,
+ },
+ dictWord{134, 0, 978},
+ dictWord{6, 0, 93},
+ dictWord{6, 0, 1508},
+ dictWord{7, 0, 1422},
+ dictWord{7, 0, 1851},
+ dictWord{8, 0, 673},
+ dictWord{9, 0, 529},
+ dictWord{140, 0, 43},
+ dictWord{6, 0, 317},
+ dictWord{10, 0, 512},
+ dictWord{4, 10, 737},
+ dictWord{11, 10, 294},
+ dictWord{12, 10, 60},
+ dictWord{12, 10, 437},
+ dictWord{13, 10, 64},
+ dictWord{13, 10, 380},
+ dictWord{142, 10, 430},
+ dictWord{9, 0, 371},
+ dictWord{7, 11, 1591},
+ dictWord{144, 11, 43},
+ dictWord{6, 10, 1758},
+ dictWord{8, 10, 520},
+ dictWord{9, 10, 345},
+ dictWord{9, 10, 403},
+ dictWord{142, 10, 350},
+ dictWord{5, 0, 526},
+ dictWord{10, 10, 242},
+ dictWord{
+ 138,
+ 10,
+ 579,
+ },
+ dictWord{9, 0, 25},
+ dictWord{10, 0, 467},
+ dictWord{138, 0, 559},
+ dictWord{5, 10, 139},
+ dictWord{7, 10, 1168},
+ dictWord{138, 10, 539},
+ dictWord{
+ 4,
+ 0,
+ 335,
+ },
+ dictWord{135, 0, 942},
+ dictWord{140, 0, 754},
+ dictWord{132, 11, 365},
+ dictWord{11, 0, 182},
+ dictWord{142, 0, 195},
+ dictWord{142, 11, 29},
+ dictWord{
+ 5,
+ 11,
+ 7,
+ },
+ dictWord{139, 11, 774},
+ dictWord{4, 11, 746},
+ dictWord{135, 11, 1090},
+ dictWord{8, 0, 39},
+ dictWord{10, 0, 773},
+ dictWord{11, 0, 84},
+ dictWord{
+ 12,
+ 0,
+ 205,
+ },
+ dictWord{142, 0, 1},
+ dictWord{5, 0, 601},
+ dictWord{5, 0, 870},
+ dictWord{5, 11, 360},
+ dictWord{136, 11, 237},
+ dictWord{132, 0, 181},
+ dictWord{
+ 136,
+ 0,
+ 370,
+ },
+ dictWord{134, 0, 1652},
+ dictWord{8, 0, 358},
+ dictWord{4, 10, 107},
+ dictWord{7, 10, 613},
+ dictWord{8, 10, 439},
+ dictWord{8, 10, 504},
+ dictWord{
+ 9,
+ 10,
+ 501,
+ },
+ dictWord{10, 10, 383},
+ dictWord{139, 10, 477},
+ dictWord{132, 10, 229},
+ dictWord{137, 11, 785},
+ dictWord{4, 0, 97},
+ dictWord{5, 0, 147},
+ dictWord{
+ 6,
+ 0,
+ 286,
+ },
+ dictWord{7, 0, 1362},
+ dictWord{141, 0, 176},
+ dictWord{6, 0, 537},
+ dictWord{7, 0, 788},
+ dictWord{7, 0, 1816},
+ dictWord{132, 10, 903},
+ dictWord{
+ 140,
+ 10,
+ 71,
+ },
+ dictWord{6, 0, 743},
+ dictWord{134, 0, 1223},
+ dictWord{6, 0, 375},
+ dictWord{7, 0, 169},
+ dictWord{7, 0, 254},
+ dictWord{8, 0, 780},
+ dictWord{135, 11, 1493},
+ dictWord{7, 0, 1714},
+ dictWord{4, 10, 47},
+ dictWord{6, 10, 373},
+ dictWord{7, 10, 452},
+ dictWord{7, 10, 543},
+ dictWord{7, 10, 1856},
+ dictWord{9, 10, 6},
+ dictWord{
+ 11,
+ 10,
+ 257,
+ },
+ dictWord{139, 10, 391},
+ dictWord{6, 0, 896},
+ dictWord{136, 0, 1003},
+ dictWord{135, 0, 1447},
+ dictWord{137, 11, 341},
+ dictWord{5, 10, 980},
+ dictWord{134, 10, 1754},
+ dictWord{145, 11, 22},
+ dictWord{4, 11, 277},
+ dictWord{5, 11, 608},
+ dictWord{6, 11, 493},
+ dictWord{7, 11, 457},
+ dictWord{
+ 140,
+ 11,
+ 384,
+ },
+ dictWord{7, 10, 536},
+ dictWord{7, 10, 1331},
+ dictWord{136, 10, 143},
+ dictWord{140, 0, 744},
+ dictWord{7, 11, 27},
+ dictWord{135, 11, 316},
+ dictWord{
+ 18,
+ 0,
+ 126,
+ },
+ dictWord{5, 10, 19},
+ dictWord{134, 10, 533},
+ dictWord{4, 0, 788},
+ dictWord{11, 0, 41},
+ dictWord{5, 11, 552},
+ dictWord{5, 11, 586},
+ dictWord{
+ 5,
+ 11,
+ 676,
+ },
+ dictWord{6, 11, 448},
+ dictWord{8, 11, 244},
+ dictWord{11, 11, 1},
+ dictWord{11, 11, 41},
+ dictWord{13, 11, 3},
+ dictWord{16, 11, 54},
+ dictWord{17, 11, 4},
+ dictWord{146, 11, 13},
+ dictWord{4, 0, 985},
+ dictWord{6, 0, 1801},
+ dictWord{4, 11, 401},
+ dictWord{137, 11, 264},
+ dictWord{5, 10, 395},
+ dictWord{5, 10, 951},
+ dictWord{134, 10, 1776},
+ dictWord{5, 0, 629},
+ dictWord{135, 0, 1549},
+ dictWord{11, 10, 663},
+ dictWord{12, 10, 210},
+ dictWord{13, 10, 166},
+ dictWord{
+ 13,
+ 10,
+ 310,
+ },
+ dictWord{14, 10, 373},
+ dictWord{147, 10, 43},
+ dictWord{9, 11, 543},
+ dictWord{10, 11, 524},
+ dictWord{11, 11, 30},
+ dictWord{12, 11, 524},
+ dictWord{
+ 14,
+ 11,
+ 315,
+ },
+ dictWord{16, 11, 18},
+ dictWord{20, 11, 26},
+ dictWord{148, 11, 65},
+ dictWord{4, 11, 205},
+ dictWord{5, 11, 623},
+ dictWord{7, 11, 104},
+ dictWord{
+ 136,
+ 11,
+ 519,
+ },
+ dictWord{5, 0, 293},
+ dictWord{134, 0, 601},
+ dictWord{7, 11, 579},
+ dictWord{9, 11, 41},
+ dictWord{9, 11, 244},
+ dictWord{9, 11, 669},
+ dictWord{
+ 10,
+ 11,
+ 5,
+ },
+ dictWord{11, 11, 861},
+ dictWord{11, 11, 951},
+ dictWord{139, 11, 980},
+ dictWord{132, 11, 717},
+ dictWord{132, 10, 695},
+ dictWord{7, 10, 497},
+ dictWord{
+ 9,
+ 10,
+ 387,
+ },
+ dictWord{147, 10, 81},
+ dictWord{132, 0, 420},
+ dictWord{142, 0, 37},
+ dictWord{6, 0, 1134},
+ dictWord{6, 0, 1900},
+ dictWord{12, 0, 830},
+ dictWord{
+ 12,
+ 0,
+ 878,
+ },
+ dictWord{12, 0, 894},
+ dictWord{15, 0, 221},
+ dictWord{143, 0, 245},
+ dictWord{132, 11, 489},
+ dictWord{7, 0, 1570},
+ dictWord{140, 0, 542},
+ dictWord{
+ 8,
+ 0,
+ 933,
+ },
+ dictWord{136, 0, 957},
+ dictWord{6, 0, 1371},
+ dictWord{7, 0, 31},
+ dictWord{8, 0, 373},
+ dictWord{5, 10, 284},
+ dictWord{6, 10, 49},
+ dictWord{6, 10, 350},
+ dictWord{7, 10, 377},
+ dictWord{7, 10, 1693},
+ dictWord{8, 10, 678},
+ dictWord{9, 10, 161},
+ dictWord{9, 10, 585},
+ dictWord{9, 10, 671},
+ dictWord{9, 10, 839},
+ dictWord{11, 10, 912},
+ dictWord{141, 10, 427},
+ dictWord{135, 11, 892},
+ dictWord{4, 0, 325},
+ dictWord{138, 0, 125},
+ dictWord{139, 11, 47},
+ dictWord{
+ 132,
+ 10,
+ 597,
+ },
+ dictWord{138, 0, 323},
+ dictWord{6, 0, 1547},
+ dictWord{7, 11, 1605},
+ dictWord{9, 11, 473},
+ dictWord{11, 11, 962},
+ dictWord{146, 11, 139},
+ dictWord{
+ 139,
+ 10,
+ 908,
+ },
+ dictWord{7, 11, 819},
+ dictWord{9, 11, 26},
+ dictWord{9, 11, 392},
+ dictWord{10, 11, 152},
+ dictWord{10, 11, 226},
+ dictWord{11, 11, 19},
+ dictWord{
+ 12,
+ 11,
+ 276,
+ },
+ dictWord{12, 11, 426},
+ dictWord{12, 11, 589},
+ dictWord{13, 11, 460},
+ dictWord{15, 11, 97},
+ dictWord{19, 11, 48},
+ dictWord{148, 11, 104},
+ dictWord{135, 11, 51},
+ dictWord{4, 0, 718},
+ dictWord{135, 0, 1216},
+ dictWord{6, 0, 1896},
+ dictWord{6, 0, 1905},
+ dictWord{6, 0, 1912},
+ dictWord{9, 0, 947},
+ dictWord{
+ 9,
+ 0,
+ 974,
+ },
+ dictWord{12, 0, 809},
+ dictWord{12, 0, 850},
+ dictWord{12, 0, 858},
+ dictWord{12, 0, 874},
+ dictWord{12, 0, 887},
+ dictWord{12, 0, 904},
+ dictWord{
+ 12,
+ 0,
+ 929,
+ },
+ dictWord{12, 0, 948},
+ dictWord{12, 0, 952},
+ dictWord{15, 0, 198},
+ dictWord{15, 0, 206},
+ dictWord{15, 0, 220},
+ dictWord{15, 0, 227},
+ dictWord{15, 0, 247},
+ dictWord{18, 0, 188},
+ dictWord{21, 0, 48},
+ dictWord{21, 0, 50},
+ dictWord{24, 0, 25},
+ dictWord{24, 0, 29},
+ dictWord{7, 11, 761},
+ dictWord{7, 11, 1051},
+ dictWord{
+ 137,
+ 11,
+ 545,
+ },
+ dictWord{5, 0, 124},
+ dictWord{5, 0, 144},
+ dictWord{6, 0, 548},
+ dictWord{7, 0, 15},
+ dictWord{7, 0, 153},
+ dictWord{137, 0, 629},
+ dictWord{
+ 135,
+ 11,
+ 606,
+ },
+ dictWord{135, 10, 2014},
+ dictWord{7, 10, 2007},
+ dictWord{9, 11, 46},
+ dictWord{9, 10, 101},
+ dictWord{9, 10, 450},
+ dictWord{10, 10, 66},
+ dictWord{
+ 10,
+ 10,
+ 842,
+ },
+ dictWord{11, 10, 536},
+ dictWord{140, 10, 587},
+ dictWord{6, 0, 75},
+ dictWord{7, 0, 1531},
+ dictWord{8, 0, 416},
+ dictWord{9, 0, 240},
+ dictWord{9, 0, 275},
+ dictWord{10, 0, 100},
+ dictWord{11, 0, 658},
+ dictWord{11, 0, 979},
+ dictWord{12, 0, 86},
+ dictWord{14, 0, 207},
+ dictWord{15, 0, 20},
+ dictWord{143, 0, 25},
+ dictWord{
+ 5,
+ 0,
+ 141,
+ },
+ dictWord{5, 0, 915},
+ dictWord{6, 0, 1783},
+ dictWord{7, 0, 211},
+ dictWord{7, 0, 698},
+ dictWord{7, 0, 1353},
+ dictWord{9, 0, 83},
+ dictWord{9, 0, 281},
+ dictWord{
+ 10,
+ 0,
+ 376,
+ },
+ dictWord{10, 0, 431},
+ dictWord{11, 0, 543},
+ dictWord{12, 0, 664},
+ dictWord{13, 0, 280},
+ dictWord{13, 0, 428},
+ dictWord{14, 0, 61},
+ dictWord{
+ 14,
+ 0,
+ 128,
+ },
+ dictWord{17, 0, 52},
+ dictWord{145, 0, 81},
+ dictWord{132, 11, 674},
+ dictWord{135, 0, 533},
+ dictWord{149, 0, 6},
+ dictWord{132, 11, 770},
+ dictWord{
+ 133,
+ 0,
+ 538,
+ },
+ dictWord{5, 11, 79},
+ dictWord{7, 11, 1027},
+ dictWord{7, 11, 1477},
+ dictWord{139, 11, 52},
+ dictWord{139, 10, 62},
+ dictWord{4, 0, 338},
+ dictWord{
+ 133,
+ 0,
+ 400,
+ },
+ dictWord{5, 11, 789},
+ dictWord{134, 11, 195},
+ dictWord{4, 11, 251},
+ dictWord{4, 11, 688},
+ dictWord{7, 11, 513},
+ dictWord{7, 11, 1284},
+ dictWord{
+ 9,
+ 11,
+ 87,
+ },
+ dictWord{138, 11, 365},
+ dictWord{134, 10, 1766},
+ dictWord{6, 0, 0},
+ dictWord{7, 0, 84},
+ dictWord{11, 0, 895},
+ dictWord{145, 0, 11},
+ dictWord{
+ 139,
+ 0,
+ 892,
+ },
+ dictWord{4, 0, 221},
+ dictWord{5, 0, 659},
+ dictWord{7, 0, 697},
+ dictWord{7, 0, 1211},
+ dictWord{138, 0, 284},
+ dictWord{133, 0, 989},
+ dictWord{
+ 133,
+ 11,
+ 889,
+ },
+ dictWord{4, 11, 160},
+ dictWord{5, 11, 330},
+ dictWord{7, 11, 1434},
+ dictWord{136, 11, 174},
+ dictWord{6, 10, 1665},
+ dictWord{7, 10, 256},
+ dictWord{
+ 7,
+ 10,
+ 1388,
+ },
+ dictWord{10, 10, 499},
+ dictWord{139, 10, 670},
+ dictWord{7, 0, 848},
+ dictWord{4, 10, 22},
+ dictWord{5, 10, 10},
+ dictWord{136, 10, 97},
+ dictWord{
+ 138,
+ 0,
+ 507,
+ },
+ dictWord{133, 10, 481},
+ dictWord{4, 0, 188},
+ dictWord{135, 0, 805},
+ dictWord{5, 0, 884},
+ dictWord{6, 0, 732},
+ dictWord{139, 0, 991},
+ dictWord{
+ 135,
+ 11,
+ 968,
+ },
+ dictWord{11, 11, 636},
+ dictWord{15, 11, 145},
+ dictWord{17, 11, 34},
+ dictWord{19, 11, 50},
+ dictWord{151, 11, 20},
+ dictWord{7, 0, 959},
+ dictWord{
+ 16,
+ 0,
+ 60,
+ },
+ dictWord{6, 10, 134},
+ dictWord{7, 10, 437},
+ dictWord{9, 10, 37},
+ dictWord{14, 10, 285},
+ dictWord{142, 10, 371},
+ dictWord{7, 10, 486},
+ dictWord{
+ 8,
+ 10,
+ 155,
+ },
+ dictWord{11, 10, 93},
+ dictWord{140, 10, 164},
+ dictWord{134, 0, 1653},
+ dictWord{7, 0, 337},
+ dictWord{133, 10, 591},
+ dictWord{6, 0, 1989},
+ dictWord{
+ 8,
+ 0,
+ 922,
+ },
+ dictWord{8, 0, 978},
+ dictWord{133, 11, 374},
+ dictWord{132, 0, 638},
+ dictWord{138, 0, 500},
+ dictWord{133, 11, 731},
+ dictWord{5, 10, 380},
+ dictWord{
+ 5,
+ 10,
+ 650,
+ },
+ dictWord{136, 10, 310},
+ dictWord{138, 11, 381},
+ dictWord{4, 10, 364},
+ dictWord{7, 10, 1156},
+ dictWord{7, 10, 1187},
+ dictWord{137, 10, 409},
+ dictWord{137, 11, 224},
+ dictWord{140, 0, 166},
+ dictWord{134, 10, 482},
+ dictWord{4, 11, 626},
+ dictWord{5, 11, 642},
+ dictWord{6, 11, 425},
+ dictWord{
+ 10,
+ 11,
+ 202,
+ },
+ dictWord{139, 11, 141},
+ dictWord{4, 10, 781},
+ dictWord{6, 10, 487},
+ dictWord{7, 10, 926},
+ dictWord{8, 10, 263},
+ dictWord{139, 10, 500},
+ dictWord{
+ 135,
+ 0,
+ 418,
+ },
+ dictWord{4, 10, 94},
+ dictWord{135, 10, 1265},
+ dictWord{136, 0, 760},
+ dictWord{132, 10, 417},
+ dictWord{136, 11, 835},
+ dictWord{5, 10, 348},
+ dictWord{134, 10, 522},
+ dictWord{6, 0, 1277},
+ dictWord{134, 0, 1538},
+ dictWord{139, 11, 541},
+ dictWord{135, 11, 1597},
+ dictWord{5, 11, 384},
+ dictWord{
+ 8,
+ 11,
+ 455,
+ },
+ dictWord{140, 11, 48},
+ dictWord{136, 0, 770},
+ dictWord{5, 11, 264},
+ dictWord{134, 11, 184},
+ dictWord{4, 0, 89},
+ dictWord{5, 0, 489},
+ dictWord{
+ 6,
+ 0,
+ 315,
+ },
+ dictWord{7, 0, 553},
+ dictWord{7, 0, 1745},
+ dictWord{138, 0, 243},
+ dictWord{4, 10, 408},
+ dictWord{4, 10, 741},
+ dictWord{135, 10, 500},
+ dictWord{
+ 134,
+ 0,
+ 1396,
+ },
+ dictWord{133, 0, 560},
+ dictWord{6, 0, 1658},
+ dictWord{9, 0, 3},
+ dictWord{10, 0, 154},
+ dictWord{11, 0, 641},
+ dictWord{13, 0, 85},
+ dictWord{13, 0, 201},
+ dictWord{141, 0, 346},
+ dictWord{135, 11, 1595},
+ dictWord{5, 11, 633},
+ dictWord{6, 11, 28},
+ dictWord{7, 11, 219},
+ dictWord{135, 11, 1323},
+ dictWord{
+ 9,
+ 11,
+ 769,
+ },
+ dictWord{140, 11, 185},
+ dictWord{135, 11, 785},
+ dictWord{7, 11, 359},
+ dictWord{8, 11, 243},
+ dictWord{140, 11, 175},
+ dictWord{138, 0, 586},
+ dictWord{
+ 7,
+ 0,
+ 1271,
+ },
+ dictWord{134, 10, 73},
+ dictWord{132, 11, 105},
+ dictWord{4, 0, 166},
+ dictWord{5, 0, 505},
+ dictWord{134, 0, 1670},
+ dictWord{133, 10, 576},
+ dictWord{4, 11, 324},
+ dictWord{138, 11, 104},
+ dictWord{142, 10, 231},
+ dictWord{6, 0, 637},
+ dictWord{7, 10, 1264},
+ dictWord{7, 10, 1678},
+ dictWord{
+ 11,
+ 10,
+ 945,
+ },
+ dictWord{12, 10, 341},
+ dictWord{12, 10, 471},
+ dictWord{12, 10, 569},
+ dictWord{23, 11, 21},
+ dictWord{151, 11, 23},
+ dictWord{8, 11, 559},
+ dictWord{
+ 141,
+ 11,
+ 109,
+ },
+ dictWord{134, 0, 1947},
+ dictWord{7, 0, 445},
+ dictWord{8, 0, 307},
+ dictWord{8, 0, 704},
+ dictWord{10, 0, 41},
+ dictWord{10, 0, 439},
+ dictWord{
+ 11,
+ 0,
+ 237,
+ },
+ dictWord{11, 0, 622},
+ dictWord{140, 0, 201},
+ dictWord{135, 11, 963},
+ dictWord{135, 0, 1977},
+ dictWord{4, 0, 189},
+ dictWord{5, 0, 713},
+ dictWord{
+ 136,
+ 0,
+ 57,
+ },
+ dictWord{138, 0, 371},
+ dictWord{135, 10, 538},
+ dictWord{132, 0, 552},
+ dictWord{6, 0, 883},
+ dictWord{133, 10, 413},
+ dictWord{6, 0, 923},
+ dictWord{
+ 132,
+ 11,
+ 758,
+ },
+ dictWord{138, 11, 215},
+ dictWord{136, 10, 495},
+ dictWord{7, 10, 54},
+ dictWord{8, 10, 312},
+ dictWord{10, 10, 191},
+ dictWord{10, 10, 614},
+ dictWord{140, 10, 567},
+ dictWord{7, 11, 351},
+ dictWord{139, 11, 128},
+ dictWord{7, 0, 875},
+ dictWord{6, 10, 468},
+ dictWord{7, 10, 1478},
+ dictWord{8, 10, 530},
+ dictWord{142, 10, 290},
+ dictWord{135, 0, 1788},
+ dictWord{17, 0, 49},
+ dictWord{133, 11, 918},
+ dictWord{12, 11, 398},
+ dictWord{20, 11, 39},
+ dictWord{
+ 21,
+ 11,
+ 11,
+ },
+ dictWord{150, 11, 41},
+ dictWord{10, 0, 661},
+ dictWord{6, 10, 484},
+ dictWord{135, 10, 822},
+ dictWord{135, 0, 1945},
+ dictWord{134, 0, 794},
+ dictWord{
+ 137,
+ 10,
+ 900,
+ },
+ dictWord{135, 10, 1335},
+ dictWord{6, 10, 1724},
+ dictWord{135, 10, 2022},
+ dictWord{132, 11, 340},
+ dictWord{134, 0, 1135},
+ dictWord{
+ 4,
+ 0,
+ 784,
+ },
+ dictWord{133, 0, 745},
+ dictWord{5, 0, 84},
+ dictWord{134, 0, 163},
+ dictWord{133, 0, 410},
+ dictWord{4, 0, 976},
+ dictWord{5, 11, 985},
+ dictWord{7, 11, 509},
+ dictWord{7, 11, 529},
+ dictWord{145, 11, 96},
+ dictWord{132, 10, 474},
+ dictWord{134, 0, 703},
+ dictWord{135, 11, 1919},
+ dictWord{5, 0, 322},
+ dictWord{
+ 8,
+ 0,
+ 186,
+ },
+ dictWord{9, 0, 262},
+ dictWord{10, 0, 187},
+ dictWord{142, 0, 208},
+ dictWord{135, 10, 1504},
+ dictWord{133, 0, 227},
+ dictWord{9, 0, 560},
+ dictWord{
+ 13,
+ 0,
+ 208,
+ },
+ dictWord{133, 10, 305},
+ dictWord{132, 11, 247},
+ dictWord{7, 0, 1395},
+ dictWord{8, 0, 486},
+ dictWord{9, 0, 236},
+ dictWord{9, 0, 878},
+ dictWord{
+ 10,
+ 0,
+ 218,
+ },
+ dictWord{11, 0, 95},
+ dictWord{19, 0, 17},
+ dictWord{147, 0, 31},
+ dictWord{7, 0, 2043},
+ dictWord{8, 0, 672},
+ dictWord{141, 0, 448},
+ dictWord{4, 11, 184},
+ dictWord{5, 11, 390},
+ dictWord{6, 11, 337},
+ dictWord{7, 11, 23},
+ dictWord{7, 11, 494},
+ dictWord{7, 11, 618},
+ dictWord{7, 11, 1456},
+ dictWord{8, 11, 27},
+ dictWord{
+ 8,
+ 11,
+ 599,
+ },
+ dictWord{10, 11, 153},
+ dictWord{139, 11, 710},
+ dictWord{135, 0, 466},
+ dictWord{135, 10, 1236},
+ dictWord{6, 0, 167},
+ dictWord{7, 0, 186},
+ dictWord{7, 0, 656},
+ dictWord{10, 0, 643},
+ dictWord{4, 10, 480},
+ dictWord{6, 10, 302},
+ dictWord{6, 10, 1642},
+ dictWord{7, 10, 837},
+ dictWord{7, 10, 1547},
+ dictWord{
+ 7,
+ 10,
+ 1657,
+ },
+ dictWord{8, 10, 429},
+ dictWord{9, 10, 228},
+ dictWord{13, 10, 289},
+ dictWord{13, 10, 343},
+ dictWord{147, 10, 101},
+ dictWord{134, 0, 1428},
+ dictWord{134, 0, 1440},
+ dictWord{5, 0, 412},
+ dictWord{7, 10, 278},
+ dictWord{10, 10, 739},
+ dictWord{11, 10, 708},
+ dictWord{141, 10, 348},
+ dictWord{
+ 134,
+ 0,
+ 1118,
+ },
+ dictWord{136, 0, 562},
+ dictWord{148, 11, 46},
+ dictWord{9, 0, 316},
+ dictWord{139, 0, 256},
+ dictWord{134, 0, 1771},
+ dictWord{135, 0, 1190},
+ dictWord{137, 0, 132},
+ dictWord{10, 11, 227},
+ dictWord{11, 11, 497},
+ dictWord{11, 11, 709},
+ dictWord{140, 11, 415},
+ dictWord{143, 0, 66},
+ dictWord{6, 11, 360},
+ dictWord{7, 11, 1664},
+ dictWord{136, 11, 478},
+ dictWord{144, 10, 28},
+ dictWord{4, 0, 317},
+ dictWord{135, 0, 1279},
+ dictWord{5, 0, 63},
+ dictWord{
+ 133,
+ 0,
+ 509,
+ },
+ dictWord{136, 11, 699},
+ dictWord{145, 10, 36},
+ dictWord{134, 0, 1475},
+ dictWord{11, 11, 343},
+ dictWord{142, 11, 127},
+ dictWord{132, 11, 739},
+ dictWord{132, 0, 288},
+ dictWord{135, 11, 1757},
+ dictWord{8, 0, 89},
+ dictWord{8, 0, 620},
+ dictWord{9, 0, 608},
+ dictWord{11, 0, 628},
+ dictWord{12, 0, 322},
+ dictWord{143, 0, 124},
+ dictWord{134, 0, 1225},
+ dictWord{7, 0, 1189},
+ dictWord{4, 11, 67},
+ dictWord{5, 11, 422},
+ dictWord{6, 10, 363},
+ dictWord{7, 11, 1037},
+ dictWord{7, 11, 1289},
+ dictWord{7, 11, 1555},
+ dictWord{7, 10, 1955},
+ dictWord{8, 10, 725},
+ dictWord{9, 11, 741},
+ dictWord{145, 11, 108},
+ dictWord{
+ 134,
+ 0,
+ 1468,
+ },
+ dictWord{6, 0, 689},
+ dictWord{134, 0, 1451},
+ dictWord{138, 0, 120},
+ dictWord{151, 0, 1},
+ dictWord{137, 10, 805},
+ dictWord{142, 0, 329},
+ dictWord{
+ 5,
+ 10,
+ 813,
+ },
+ dictWord{135, 10, 2046},
+ dictWord{135, 0, 226},
+ dictWord{138, 11, 96},
+ dictWord{7, 0, 1855},
+ dictWord{5, 10, 712},
+ dictWord{11, 10, 17},
+ dictWord{13, 10, 321},
+ dictWord{144, 10, 67},
+ dictWord{9, 0, 461},
+ dictWord{6, 10, 320},
+ dictWord{7, 10, 781},
+ dictWord{7, 10, 1921},
+ dictWord{9, 10, 55},
+ dictWord{
+ 10,
+ 10,
+ 186,
+ },
+ dictWord{10, 10, 273},
+ dictWord{10, 10, 664},
+ dictWord{10, 10, 801},
+ dictWord{11, 10, 996},
+ dictWord{11, 10, 997},
+ dictWord{13, 10, 157},
+ dictWord{142, 10, 170},
+ dictWord{8, 11, 203},
+ dictWord{8, 10, 271},
+ dictWord{11, 11, 823},
+ dictWord{11, 11, 846},
+ dictWord{12, 11, 482},
+ dictWord{
+ 13,
+ 11,
+ 133,
+ },
+ dictWord{13, 11, 277},
+ dictWord{13, 11, 302},
+ dictWord{13, 11, 464},
+ dictWord{14, 11, 205},
+ dictWord{142, 11, 221},
+ dictWord{135, 0, 1346},
+ dictWord{4, 11, 449},
+ dictWord{133, 11, 718},
+ dictWord{134, 0, 85},
+ dictWord{14, 0, 299},
+ dictWord{7, 10, 103},
+ dictWord{7, 10, 863},
+ dictWord{11, 10, 184},
+ dictWord{145, 10, 62},
+ dictWord{4, 11, 355},
+ dictWord{6, 11, 311},
+ dictWord{9, 11, 256},
+ dictWord{138, 11, 404},
+ dictWord{137, 10, 659},
+ dictWord{
+ 138,
+ 11,
+ 758,
+ },
+ dictWord{133, 11, 827},
+ dictWord{5, 11, 64},
+ dictWord{140, 11, 581},
+ dictWord{134, 0, 1171},
+ dictWord{4, 11, 442},
+ dictWord{7, 11, 1047},
+ dictWord{
+ 7,
+ 11,
+ 1352,
+ },
+ dictWord{135, 11, 1643},
+ dictWord{132, 0, 980},
+ dictWord{5, 11, 977},
+ dictWord{6, 11, 288},
+ dictWord{7, 11, 528},
+ dictWord{135, 11, 1065},
+ dictWord{5, 0, 279},
+ dictWord{6, 0, 235},
+ dictWord{7, 0, 468},
+ dictWord{8, 0, 446},
+ dictWord{9, 0, 637},
+ dictWord{10, 0, 717},
+ dictWord{11, 0, 738},
+ dictWord{
+ 140,
+ 0,
+ 514,
+ },
+ dictWord{132, 0, 293},
+ dictWord{11, 10, 337},
+ dictWord{142, 10, 303},
+ dictWord{136, 11, 285},
+ dictWord{5, 0, 17},
+ dictWord{6, 0, 371},
+ dictWord{
+ 9,
+ 0,
+ 528,
+ },
+ dictWord{12, 0, 364},
+ dictWord{132, 11, 254},
+ dictWord{5, 10, 77},
+ dictWord{7, 10, 1455},
+ dictWord{10, 10, 843},
+ dictWord{147, 10, 73},
+ dictWord{
+ 150,
+ 0,
+ 5,
+ },
+ dictWord{132, 10, 458},
+ dictWord{6, 11, 12},
+ dictWord{7, 11, 1219},
+ dictWord{145, 11, 73},
+ dictWord{135, 10, 1420},
+ dictWord{6, 10, 109},
+ dictWord{138, 10, 382},
+ dictWord{135, 11, 125},
+ dictWord{6, 10, 330},
+ dictWord{7, 10, 1084},
+ dictWord{139, 10, 142},
+ dictWord{6, 11, 369},
+ dictWord{
+ 6,
+ 11,
+ 502,
+ },
+ dictWord{7, 11, 1036},
+ dictWord{8, 11, 348},
+ dictWord{9, 11, 452},
+ dictWord{10, 11, 26},
+ dictWord{11, 11, 224},
+ dictWord{11, 11, 387},
+ dictWord{
+ 11,
+ 11,
+ 772,
+ },
+ dictWord{12, 11, 95},
+ dictWord{12, 11, 629},
+ dictWord{13, 11, 195},
+ dictWord{13, 11, 207},
+ dictWord{13, 11, 241},
+ dictWord{14, 11, 260},
+ dictWord{
+ 14,
+ 11,
+ 270,
+ },
+ dictWord{143, 11, 140},
+ dictWord{132, 11, 269},
+ dictWord{5, 11, 480},
+ dictWord{7, 11, 532},
+ dictWord{7, 11, 1197},
+ dictWord{7, 11, 1358},
+ dictWord{8, 11, 291},
+ dictWord{11, 11, 349},
+ dictWord{142, 11, 396},
+ dictWord{150, 0, 48},
+ dictWord{10, 0, 601},
+ dictWord{13, 0, 353},
+ dictWord{141, 0, 376},
+ dictWord{5, 0, 779},
+ dictWord{5, 0, 807},
+ dictWord{6, 0, 1655},
+ dictWord{134, 0, 1676},
+ dictWord{142, 11, 223},
+ dictWord{4, 0, 196},
+ dictWord{5, 0, 558},
+ dictWord{133, 0, 949},
+ dictWord{148, 11, 15},
+ dictWord{135, 11, 1764},
+ dictWord{134, 0, 1322},
+ dictWord{132, 0, 752},
+ dictWord{139, 0, 737},
+ dictWord{
+ 135,
+ 11,
+ 657,
+ },
+ dictWord{136, 11, 533},
+ dictWord{135, 0, 412},
+ dictWord{4, 0, 227},
+ dictWord{5, 0, 159},
+ dictWord{5, 0, 409},
+ dictWord{7, 0, 80},
+ dictWord{8, 0, 556},
+ dictWord{10, 0, 479},
+ dictWord{12, 0, 418},
+ dictWord{14, 0, 50},
+ dictWord{14, 0, 123},
+ dictWord{14, 0, 192},
+ dictWord{14, 0, 249},
+ dictWord{14, 0, 295},
+ dictWord{143, 0, 27},
+ dictWord{7, 0, 1470},
+ dictWord{8, 0, 66},
+ dictWord{8, 0, 137},
+ dictWord{8, 0, 761},
+ dictWord{9, 0, 638},
+ dictWord{11, 0, 80},
+ dictWord{11, 0, 212},
+ dictWord{11, 0, 368},
+ dictWord{11, 0, 418},
+ dictWord{12, 0, 8},
+ dictWord{13, 0, 15},
+ dictWord{16, 0, 61},
+ dictWord{17, 0, 59},
+ dictWord{19, 0, 28},
+ dictWord{
+ 148,
+ 0,
+ 84,
+ },
+ dictWord{135, 10, 1985},
+ dictWord{4, 11, 211},
+ dictWord{4, 11, 332},
+ dictWord{5, 11, 335},
+ dictWord{6, 11, 238},
+ dictWord{7, 11, 269},
+ dictWord{
+ 7,
+ 11,
+ 811,
+ },
+ dictWord{7, 11, 1797},
+ dictWord{8, 10, 122},
+ dictWord{8, 11, 836},
+ dictWord{9, 11, 507},
+ dictWord{141, 11, 242},
+ dictWord{6, 0, 683},
+ dictWord{
+ 134,
+ 0,
+ 1252,
+ },
+ dictWord{4, 0, 873},
+ dictWord{132, 10, 234},
+ dictWord{134, 0, 835},
+ dictWord{6, 0, 38},
+ dictWord{7, 0, 1220},
+ dictWord{8, 0, 185},
+ dictWord{8, 0, 256},
+ dictWord{9, 0, 22},
+ dictWord{9, 0, 331},
+ dictWord{10, 0, 738},
+ dictWord{11, 0, 205},
+ dictWord{11, 0, 540},
+ dictWord{11, 0, 746},
+ dictWord{13, 0, 465},
+ dictWord{
+ 14,
+ 0,
+ 88,
+ },
+ dictWord{142, 0, 194},
+ dictWord{138, 0, 986},
+ dictWord{5, 11, 1009},
+ dictWord{12, 11, 582},
+ dictWord{146, 11, 131},
+ dictWord{4, 0, 159},
+ dictWord{
+ 6,
+ 0,
+ 115,
+ },
+ dictWord{7, 0, 252},
+ dictWord{7, 0, 257},
+ dictWord{7, 0, 1928},
+ dictWord{8, 0, 69},
+ dictWord{9, 0, 384},
+ dictWord{10, 0, 91},
+ dictWord{10, 0, 615},
+ dictWord{
+ 12,
+ 0,
+ 375,
+ },
+ dictWord{14, 0, 235},
+ dictWord{18, 0, 117},
+ dictWord{147, 0, 123},
+ dictWord{133, 0, 911},
+ dictWord{136, 0, 278},
+ dictWord{5, 10, 430},
+ dictWord{
+ 5,
+ 10,
+ 932,
+ },
+ dictWord{6, 10, 131},
+ dictWord{7, 10, 417},
+ dictWord{9, 10, 522},
+ dictWord{11, 10, 314},
+ dictWord{141, 10, 390},
+ dictWord{14, 10, 149},
+ dictWord{14, 10, 399},
+ dictWord{143, 10, 57},
+ dictWord{4, 0, 151},
+ dictWord{7, 0, 1567},
+ dictWord{136, 0, 749},
+ dictWord{5, 11, 228},
+ dictWord{6, 11, 203},
+ dictWord{
+ 7,
+ 11,
+ 156,
+ },
+ dictWord{8, 11, 347},
+ dictWord{137, 11, 265},
+ dictWord{132, 10, 507},
+ dictWord{10, 0, 989},
+ dictWord{140, 0, 956},
+ dictWord{133, 0, 990},
+ dictWord{5, 0, 194},
+ dictWord{6, 0, 927},
+ dictWord{7, 0, 1662},
+ dictWord{9, 0, 90},
+ dictWord{140, 0, 564},
+ dictWord{4, 10, 343},
+ dictWord{133, 10, 511},
+ dictWord{133, 0, 425},
+ dictWord{7, 10, 455},
+ dictWord{138, 10, 591},
+ dictWord{4, 0, 774},
+ dictWord{7, 11, 476},
+ dictWord{7, 11, 1592},
+ dictWord{138, 11, 87},
+ dictWord{5, 0, 971},
+ dictWord{135, 10, 1381},
+ dictWord{5, 11, 318},
+ dictWord{147, 11, 121},
+ dictWord{5, 11, 291},
+ dictWord{7, 11, 765},
+ dictWord{9, 11, 389},
+ dictWord{140, 11, 548},
+ dictWord{134, 10, 575},
+ dictWord{4, 0, 827},
+ dictWord{12, 0, 646},
+ dictWord{12, 0, 705},
+ dictWord{12, 0, 712},
+ dictWord{140, 0, 714},
+ dictWord{139, 0, 752},
+ dictWord{137, 0, 662},
+ dictWord{5, 0, 72},
+ dictWord{6, 0, 264},
+ dictWord{7, 0, 21},
+ dictWord{7, 0, 46},
+ dictWord{7, 0, 2013},
+ dictWord{
+ 8,
+ 0,
+ 215,
+ },
+ dictWord{8, 0, 513},
+ dictWord{10, 0, 266},
+ dictWord{139, 0, 22},
+ dictWord{139, 11, 522},
+ dictWord{6, 0, 239},
+ dictWord{7, 0, 118},
+ dictWord{10, 0, 95},
+ dictWord{11, 0, 603},
+ dictWord{13, 0, 443},
+ dictWord{14, 0, 160},
+ dictWord{143, 0, 4},
+ dictWord{6, 0, 431},
+ dictWord{134, 0, 669},
+ dictWord{7, 10, 1127},
+ dictWord{
+ 7,
+ 10,
+ 1572,
+ },
+ dictWord{10, 10, 297},
+ dictWord{10, 10, 422},
+ dictWord{11, 10, 764},
+ dictWord{11, 10, 810},
+ dictWord{12, 10, 264},
+ dictWord{13, 10, 102},
+ dictWord{13, 10, 300},
+ dictWord{13, 10, 484},
+ dictWord{14, 10, 147},
+ dictWord{14, 10, 229},
+ dictWord{17, 10, 71},
+ dictWord{18, 10, 118},
+ dictWord{
+ 147,
+ 10,
+ 120,
+ },
+ dictWord{5, 0, 874},
+ dictWord{6, 0, 1677},
+ dictWord{15, 0, 0},
+ dictWord{10, 11, 525},
+ dictWord{139, 11, 82},
+ dictWord{6, 0, 65},
+ dictWord{7, 0, 939},
+ dictWord{
+ 7,
+ 0,
+ 1172,
+ },
+ dictWord{7, 0, 1671},
+ dictWord{9, 0, 540},
+ dictWord{10, 0, 696},
+ dictWord{11, 0, 265},
+ dictWord{11, 0, 732},
+ dictWord{11, 0, 928},
+ dictWord{
+ 11,
+ 0,
+ 937,
+ },
+ dictWord{141, 0, 438},
+ dictWord{134, 0, 1350},
+ dictWord{136, 11, 547},
+ dictWord{132, 11, 422},
+ dictWord{5, 11, 355},
+ dictWord{145, 11, 0},
+ dictWord{137, 11, 905},
+ dictWord{5, 0, 682},
+ dictWord{135, 0, 1887},
+ dictWord{132, 0, 809},
+ dictWord{4, 0, 696},
+ dictWord{133, 11, 865},
+ dictWord{6, 0, 1074},
+ dictWord{6, 0, 1472},
+ dictWord{14, 10, 35},
+ dictWord{142, 10, 191},
+ dictWord{5, 11, 914},
+ dictWord{134, 11, 1625},
+ dictWord{133, 11, 234},
+ dictWord{
+ 135,
+ 11,
+ 1383,
+ },
+ dictWord{137, 11, 780},
+ dictWord{132, 10, 125},
+ dictWord{4, 0, 726},
+ dictWord{133, 0, 630},
+ dictWord{8, 0, 802},
+ dictWord{136, 0, 838},
+ dictWord{132, 10, 721},
+ dictWord{6, 0, 1337},
+ dictWord{7, 0, 776},
+ dictWord{19, 0, 56},
+ dictWord{136, 10, 145},
+ dictWord{132, 0, 970},
+ dictWord{7, 10, 792},
+ dictWord{8, 10, 147},
+ dictWord{10, 10, 821},
+ dictWord{139, 10, 1021},
+ dictWord{139, 10, 970},
+ dictWord{8, 0, 940},
+ dictWord{137, 0, 797},
+ dictWord{
+ 135,
+ 11,
+ 1312,
+ },
+ dictWord{9, 0, 248},
+ dictWord{10, 0, 400},
+ dictWord{7, 11, 816},
+ dictWord{7, 11, 1241},
+ dictWord{7, 10, 1999},
+ dictWord{9, 11, 283},
+ dictWord{
+ 9,
+ 11,
+ 520,
+ },
+ dictWord{10, 11, 213},
+ dictWord{10, 11, 307},
+ dictWord{10, 11, 463},
+ dictWord{10, 11, 671},
+ dictWord{10, 11, 746},
+ dictWord{11, 11, 401},
+ dictWord{
+ 11,
+ 11,
+ 794,
+ },
+ dictWord{12, 11, 517},
+ dictWord{18, 11, 107},
+ dictWord{147, 11, 115},
+ dictWord{6, 0, 1951},
+ dictWord{134, 0, 2040},
+ dictWord{
+ 135,
+ 11,
+ 339,
+ },
+ dictWord{13, 0, 41},
+ dictWord{15, 0, 93},
+ dictWord{5, 10, 168},
+ dictWord{5, 10, 930},
+ dictWord{8, 10, 74},
+ dictWord{9, 10, 623},
+ dictWord{12, 10, 500},
+ dictWord{140, 10, 579},
+ dictWord{6, 0, 118},
+ dictWord{7, 0, 215},
+ dictWord{7, 0, 1521},
+ dictWord{140, 0, 11},
+ dictWord{6, 10, 220},
+ dictWord{7, 10, 1101},
+ dictWord{141, 10, 105},
+ dictWord{6, 11, 421},
+ dictWord{7, 11, 61},
+ dictWord{7, 11, 1540},
+ dictWord{10, 11, 11},
+ dictWord{138, 11, 501},
+ dictWord{7, 0, 615},
+ dictWord{138, 0, 251},
+ dictWord{140, 11, 631},
+ dictWord{135, 0, 1044},
+ dictWord{6, 10, 19},
+ dictWord{7, 10, 1413},
+ dictWord{139, 10, 428},
+ dictWord{
+ 133,
+ 0,
+ 225,
+ },
+ dictWord{7, 10, 96},
+ dictWord{8, 10, 401},
+ dictWord{8, 10, 703},
+ dictWord{137, 10, 896},
+ dictWord{145, 10, 116},
+ dictWord{6, 11, 102},
+ dictWord{
+ 7,
+ 11,
+ 72,
+ },
+ dictWord{15, 11, 142},
+ dictWord{147, 11, 67},
+ dictWord{7, 10, 1961},
+ dictWord{7, 10, 1965},
+ dictWord{8, 10, 702},
+ dictWord{136, 10, 750},
+ dictWord{
+ 7,
+ 10,
+ 2030,
+ },
+ dictWord{8, 10, 150},
+ dictWord{8, 10, 737},
+ dictWord{12, 10, 366},
+ dictWord{151, 11, 30},
+ dictWord{4, 0, 370},
+ dictWord{5, 0, 756},
+ dictWord{
+ 7,
+ 0,
+ 1326,
+ },
+ dictWord{135, 11, 823},
+ dictWord{8, 10, 800},
+ dictWord{9, 10, 148},
+ dictWord{9, 10, 872},
+ dictWord{9, 10, 890},
+ dictWord{11, 10, 309},
+ dictWord{
+ 11,
+ 10,
+ 1001,
+ },
+ dictWord{13, 10, 267},
+ dictWord{141, 10, 323},
+ dictWord{6, 0, 1662},
+ dictWord{7, 0, 48},
+ dictWord{8, 0, 771},
+ dictWord{10, 0, 116},
+ dictWord{
+ 13,
+ 0,
+ 104,
+ },
+ dictWord{14, 0, 105},
+ dictWord{14, 0, 184},
+ dictWord{15, 0, 168},
+ dictWord{19, 0, 92},
+ dictWord{148, 0, 68},
+ dictWord{10, 0, 209},
+ dictWord{
+ 135,
+ 11,
+ 1870,
+ },
+ dictWord{7, 11, 68},
+ dictWord{8, 11, 48},
+ dictWord{8, 11, 88},
+ dictWord{8, 11, 582},
+ dictWord{8, 11, 681},
+ dictWord{9, 11, 373},
+ dictWord{9, 11, 864},
+ dictWord{11, 11, 157},
+ dictWord{11, 11, 336},
+ dictWord{11, 11, 843},
+ dictWord{148, 11, 27},
+ dictWord{134, 0, 930},
+ dictWord{4, 11, 88},
+ dictWord{5, 11, 137},
+ dictWord{5, 11, 174},
+ dictWord{5, 11, 777},
+ dictWord{6, 11, 1664},
+ dictWord{6, 11, 1725},
+ dictWord{7, 11, 77},
+ dictWord{7, 11, 426},
+ dictWord{7, 11, 1317},
+ dictWord{7, 11, 1355},
+ dictWord{8, 11, 126},
+ dictWord{8, 11, 563},
+ dictWord{9, 11, 523},
+ dictWord{9, 11, 750},
+ dictWord{10, 11, 310},
+ dictWord{10, 11, 836},
+ dictWord{11, 11, 42},
+ dictWord{11, 11, 318},
+ dictWord{11, 11, 731},
+ dictWord{12, 11, 68},
+ dictWord{12, 11, 92},
+ dictWord{12, 11, 507},
+ dictWord{12, 11, 692},
+ dictWord{13, 11, 81},
+ dictWord{13, 11, 238},
+ dictWord{13, 11, 374},
+ dictWord{18, 11, 138},
+ dictWord{19, 11, 78},
+ dictWord{19, 11, 111},
+ dictWord{20, 11, 55},
+ dictWord{20, 11, 77},
+ dictWord{148, 11, 92},
+ dictWord{4, 11, 938},
+ dictWord{135, 11, 1831},
+ dictWord{5, 10, 547},
+ dictWord{7, 10, 424},
+ dictWord{
+ 8,
+ 11,
+ 617,
+ },
+ dictWord{138, 11, 351},
+ dictWord{6, 0, 1286},
+ dictWord{6, 11, 1668},
+ dictWord{7, 11, 1499},
+ dictWord{8, 11, 117},
+ dictWord{9, 11, 314},
+ dictWord{
+ 138,
+ 11,
+ 174,
+ },
+ dictWord{6, 0, 759},
+ dictWord{6, 0, 894},
+ dictWord{7, 11, 707},
+ dictWord{139, 11, 563},
+ dictWord{4, 0, 120},
+ dictWord{135, 0, 1894},
+ dictWord{
+ 9,
+ 0,
+ 385,
+ },
+ dictWord{149, 0, 17},
+ dictWord{138, 0, 429},
+ dictWord{133, 11, 403},
+ dictWord{5, 0, 820},
+ dictWord{135, 0, 931},
+ dictWord{10, 0, 199},
+ dictWord{
+ 133,
+ 10,
+ 133,
+ },
+ dictWord{6, 0, 151},
+ dictWord{6, 0, 1675},
+ dictWord{7, 0, 383},
+ dictWord{151, 0, 10},
+ dictWord{6, 0, 761},
+ dictWord{136, 10, 187},
+ dictWord{
+ 8,
+ 0,
+ 365,
+ },
+ dictWord{10, 10, 0},
+ dictWord{10, 10, 818},
+ dictWord{139, 10, 988},
+ dictWord{4, 11, 44},
+ dictWord{5, 11, 311},
+ dictWord{6, 11, 156},
+ dictWord{
+ 7,
+ 11,
+ 639,
+ },
+ dictWord{7, 11, 762},
+ dictWord{7, 11, 1827},
+ dictWord{9, 11, 8},
+ dictWord{9, 11, 462},
+ dictWord{148, 11, 83},
+ dictWord{4, 11, 346},
+ dictWord{7, 11, 115},
+ dictWord{9, 11, 180},
+ dictWord{9, 11, 456},
+ dictWord{138, 11, 363},
+ dictWord{136, 10, 685},
+ dictWord{7, 0, 1086},
+ dictWord{145, 0, 46},
+ dictWord{
+ 6,
+ 0,
+ 1624,
+ },
+ dictWord{11, 0, 11},
+ dictWord{12, 0, 422},
+ dictWord{13, 0, 444},
+ dictWord{142, 0, 360},
+ dictWord{6, 0, 1020},
+ dictWord{6, 0, 1260},
+ dictWord{
+ 134,
+ 0,
+ 1589,
+ },
+ dictWord{4, 0, 43},
+ dictWord{5, 0, 344},
+ dictWord{5, 0, 357},
+ dictWord{14, 0, 472},
+ dictWord{150, 0, 58},
+ dictWord{6, 0, 1864},
+ dictWord{6, 0, 1866},
+ dictWord{6, 0, 1868},
+ dictWord{6, 0, 1869},
+ dictWord{6, 0, 1874},
+ dictWord{6, 0, 1877},
+ dictWord{6, 0, 1903},
+ dictWord{6, 0, 1911},
+ dictWord{9, 0, 920},
+ dictWord{
+ 9,
+ 0,
+ 921,
+ },
+ dictWord{9, 0, 924},
+ dictWord{9, 0, 946},
+ dictWord{9, 0, 959},
+ dictWord{9, 0, 963},
+ dictWord{9, 0, 970},
+ dictWord{9, 0, 997},
+ dictWord{9, 0, 1008},
+ dictWord{
+ 9,
+ 0,
+ 1017,
+ },
+ dictWord{12, 0, 795},
+ dictWord{12, 0, 797},
+ dictWord{12, 0, 798},
+ dictWord{12, 0, 800},
+ dictWord{12, 0, 803},
+ dictWord{12, 0, 811},
+ dictWord{
+ 12,
+ 0,
+ 820,
+ },
+ dictWord{12, 0, 821},
+ dictWord{12, 0, 839},
+ dictWord{12, 0, 841},
+ dictWord{12, 0, 848},
+ dictWord{12, 0, 911},
+ dictWord{12, 0, 921},
+ dictWord{12, 0, 922},
+ dictWord{12, 0, 925},
+ dictWord{12, 0, 937},
+ dictWord{12, 0, 944},
+ dictWord{12, 0, 945},
+ dictWord{12, 0, 953},
+ dictWord{15, 0, 184},
+ dictWord{15, 0, 191},
+ dictWord{15, 0, 199},
+ dictWord{15, 0, 237},
+ dictWord{15, 0, 240},
+ dictWord{15, 0, 243},
+ dictWord{15, 0, 246},
+ dictWord{18, 0, 203},
+ dictWord{21, 0, 40},
+ dictWord{
+ 21,
+ 0,
+ 52,
+ },
+ dictWord{21, 0, 57},
+ dictWord{24, 0, 23},
+ dictWord{24, 0, 28},
+ dictWord{152, 0, 30},
+ dictWord{134, 0, 725},
+ dictWord{145, 11, 58},
+ dictWord{133, 0, 888},
+ dictWord{137, 10, 874},
+ dictWord{4, 0, 711},
+ dictWord{8, 10, 774},
+ dictWord{10, 10, 670},
+ dictWord{140, 10, 51},
+ dictWord{144, 11, 40},
+ dictWord{
+ 6,
+ 11,
+ 185,
+ },
+ dictWord{7, 11, 1899},
+ dictWord{139, 11, 673},
+ dictWord{137, 10, 701},
+ dictWord{137, 0, 440},
+ dictWord{4, 11, 327},
+ dictWord{5, 11, 478},
+ dictWord{
+ 7,
+ 11,
+ 1332,
+ },
+ dictWord{8, 11, 753},
+ dictWord{140, 11, 227},
+ dictWord{4, 10, 127},
+ dictWord{5, 10, 350},
+ dictWord{6, 10, 356},
+ dictWord{8, 10, 426},
+ dictWord{
+ 9,
+ 10,
+ 572,
+ },
+ dictWord{10, 10, 247},
+ dictWord{139, 10, 312},
+ dictWord{5, 11, 1020},
+ dictWord{133, 11, 1022},
+ dictWord{4, 11, 103},
+ dictWord{
+ 133,
+ 11,
+ 401,
+ },
+ dictWord{6, 0, 1913},
+ dictWord{6, 0, 1926},
+ dictWord{6, 0, 1959},
+ dictWord{9, 0, 914},
+ dictWord{9, 0, 939},
+ dictWord{9, 0, 952},
+ dictWord{9, 0, 979},
+ dictWord{
+ 9,
+ 0,
+ 990,
+ },
+ dictWord{9, 0, 998},
+ dictWord{9, 0, 1003},
+ dictWord{9, 0, 1023},
+ dictWord{12, 0, 827},
+ dictWord{12, 0, 834},
+ dictWord{12, 0, 845},
+ dictWord{
+ 12,
+ 0,
+ 912,
+ },
+ dictWord{12, 0, 935},
+ dictWord{12, 0, 951},
+ dictWord{15, 0, 172},
+ dictWord{15, 0, 174},
+ dictWord{18, 0, 198},
+ dictWord{149, 0, 63},
+ dictWord{5, 0, 958},
+ dictWord{5, 0, 987},
+ dictWord{4, 11, 499},
+ dictWord{135, 11, 1421},
+ dictWord{7, 0, 885},
+ dictWord{6, 10, 59},
+ dictWord{6, 10, 1762},
+ dictWord{9, 10, 603},
+ dictWord{141, 10, 397},
+ dictWord{10, 11, 62},
+ dictWord{141, 11, 164},
+ dictWord{4, 0, 847},
+ dictWord{135, 0, 326},
+ dictWord{11, 0, 276},
+ dictWord{142, 0, 293},
+ dictWord{4, 0, 65},
+ dictWord{5, 0, 479},
+ dictWord{5, 0, 1004},
+ dictWord{7, 0, 1913},
+ dictWord{8, 0, 317},
+ dictWord{9, 0, 302},
+ dictWord{10, 0, 612},
+ dictWord{
+ 13,
+ 0,
+ 22,
+ },
+ dictWord{132, 11, 96},
+ dictWord{4, 0, 261},
+ dictWord{135, 0, 510},
+ dictWord{135, 0, 1514},
+ dictWord{6, 10, 111},
+ dictWord{7, 10, 4},
+ dictWord{8, 10, 163},
+ dictWord{8, 10, 776},
+ dictWord{138, 10, 566},
+ dictWord{4, 0, 291},
+ dictWord{9, 0, 515},
+ dictWord{12, 0, 152},
+ dictWord{12, 0, 443},
+ dictWord{13, 0, 392},
+ dictWord{142, 0, 357},
+ dictWord{7, 11, 399},
+ dictWord{135, 11, 1492},
+ dictWord{4, 0, 589},
+ dictWord{139, 0, 282},
+ dictWord{6, 11, 563},
+ dictWord{
+ 135,
+ 10,
+ 1994,
+ },
+ dictWord{5, 10, 297},
+ dictWord{135, 10, 1038},
+ dictWord{4, 0, 130},
+ dictWord{7, 0, 843},
+ dictWord{135, 0, 1562},
+ dictWord{5, 0, 42},
+ dictWord{
+ 5,
+ 0,
+ 879,
+ },
+ dictWord{7, 0, 245},
+ dictWord{7, 0, 324},
+ dictWord{7, 0, 1532},
+ dictWord{11, 0, 463},
+ dictWord{11, 0, 472},
+ dictWord{13, 0, 363},
+ dictWord{144, 0, 52},
+ dictWord{4, 0, 134},
+ dictWord{133, 0, 372},
+ dictWord{133, 0, 680},
+ dictWord{136, 10, 363},
+ dictWord{6, 0, 1997},
+ dictWord{8, 0, 935},
+ dictWord{136, 0, 977},
+ dictWord{4, 0, 810},
+ dictWord{135, 0, 1634},
+ dictWord{135, 10, 1675},
+ dictWord{7, 0, 1390},
+ dictWord{4, 11, 910},
+ dictWord{133, 11, 832},
+ dictWord{
+ 7,
+ 10,
+ 808,
+ },
+ dictWord{8, 11, 266},
+ dictWord{139, 11, 578},
+ dictWord{132, 0, 644},
+ dictWord{4, 0, 982},
+ dictWord{138, 0, 867},
+ dictWord{132, 10, 280},
+ dictWord{
+ 135,
+ 0,
+ 540,
+ },
+ dictWord{140, 10, 54},
+ dictWord{135, 0, 123},
+ dictWord{134, 0, 1978},
+ dictWord{4, 10, 421},
+ dictWord{133, 10, 548},
+ dictWord{6, 0, 623},
+ dictWord{136, 0, 789},
+ dictWord{4, 0, 908},
+ dictWord{5, 0, 359},
+ dictWord{5, 0, 508},
+ dictWord{6, 0, 1723},
+ dictWord{7, 0, 343},
+ dictWord{7, 0, 1996},
+ dictWord{
+ 135,
+ 0,
+ 2026,
+ },
+ dictWord{134, 0, 1220},
+ dictWord{4, 0, 341},
+ dictWord{135, 0, 480},
+ dictWord{6, 10, 254},
+ dictWord{9, 10, 109},
+ dictWord{138, 10, 103},
+ dictWord{
+ 134,
+ 0,
+ 888,
+ },
+ dictWord{8, 11, 528},
+ dictWord{137, 11, 348},
+ dictWord{7, 0, 1995},
+ dictWord{8, 0, 299},
+ dictWord{11, 0, 890},
+ dictWord{12, 0, 674},
+ dictWord{
+ 4,
+ 11,
+ 20,
+ },
+ dictWord{133, 11, 616},
+ dictWord{135, 11, 1094},
+ dictWord{134, 10, 1630},
+ dictWord{4, 0, 238},
+ dictWord{5, 0, 503},
+ dictWord{6, 0, 179},
+ dictWord{
+ 7,
+ 0,
+ 2003,
+ },
+ dictWord{8, 0, 381},
+ dictWord{8, 0, 473},
+ dictWord{9, 0, 149},
+ dictWord{10, 0, 788},
+ dictWord{15, 0, 45},
+ dictWord{15, 0, 86},
+ dictWord{20, 0, 110},
+ dictWord{150, 0, 57},
+ dictWord{133, 10, 671},
+ dictWord{4, 11, 26},
+ dictWord{5, 11, 429},
+ dictWord{6, 11, 245},
+ dictWord{7, 11, 704},
+ dictWord{7, 11, 1379},
+ dictWord{135, 11, 1474},
+ dictWord{4, 0, 121},
+ dictWord{5, 0, 156},
+ dictWord{5, 0, 349},
+ dictWord{9, 0, 431},
+ dictWord{10, 0, 605},
+ dictWord{142, 0, 342},
+ dictWord{
+ 7,
+ 11,
+ 943,
+ },
+ dictWord{139, 11, 614},
+ dictWord{132, 10, 889},
+ dictWord{132, 11, 621},
+ dictWord{7, 10, 1382},
+ dictWord{7, 11, 1382},
+ dictWord{
+ 135,
+ 10,
+ 1910,
+ },
+ dictWord{132, 10, 627},
+ dictWord{133, 10, 775},
+ dictWord{133, 11, 542},
+ dictWord{133, 11, 868},
+ dictWord{136, 11, 433},
+ dictWord{6, 0, 1373},
+ dictWord{7, 0, 1011},
+ dictWord{11, 10, 362},
+ dictWord{11, 10, 948},
+ dictWord{140, 10, 388},
+ dictWord{6, 0, 80},
+ dictWord{7, 0, 173},
+ dictWord{9, 0, 547},
+ dictWord{10, 0, 730},
+ dictWord{14, 0, 18},
+ dictWord{22, 0, 39},
+ dictWord{135, 11, 1495},
+ dictWord{6, 0, 1694},
+ dictWord{135, 0, 1974},
+ dictWord{140, 0, 196},
+ dictWord{4, 0, 923},
+ dictWord{6, 0, 507},
+ dictWord{6, 0, 1711},
+ dictWord{7, 10, 451},
+ dictWord{8, 10, 389},
+ dictWord{12, 10, 490},
+ dictWord{13, 10, 16},
+ dictWord{
+ 13,
+ 10,
+ 215,
+ },
+ dictWord{13, 10, 351},
+ dictWord{18, 10, 132},
+ dictWord{147, 10, 125},
+ dictWord{6, 0, 646},
+ dictWord{134, 0, 1047},
+ dictWord{135, 10, 841},
+ dictWord{136, 10, 566},
+ dictWord{6, 0, 1611},
+ dictWord{135, 0, 1214},
+ dictWord{139, 0, 926},
+ dictWord{132, 11, 525},
+ dictWord{132, 0, 595},
+ dictWord{
+ 5,
+ 0,
+ 240,
+ },
+ dictWord{6, 0, 459},
+ dictWord{7, 0, 12},
+ dictWord{7, 0, 114},
+ dictWord{7, 0, 949},
+ dictWord{7, 0, 1753},
+ dictWord{7, 0, 1805},
+ dictWord{8, 0, 658},
+ dictWord{
+ 9,
+ 0,
+ 1,
+ },
+ dictWord{11, 0, 959},
+ dictWord{141, 0, 446},
+ dictWord{5, 10, 912},
+ dictWord{134, 10, 1695},
+ dictWord{132, 0, 446},
+ dictWord{7, 11, 62},
+ dictWord{
+ 12,
+ 11,
+ 45,
+ },
+ dictWord{147, 11, 112},
+ dictWord{5, 10, 236},
+ dictWord{6, 10, 572},
+ dictWord{8, 10, 492},
+ dictWord{11, 10, 618},
+ dictWord{144, 10, 56},
+ dictWord{
+ 5,
+ 10,
+ 190,
+ },
+ dictWord{136, 10, 318},
+ dictWord{135, 10, 1376},
+ dictWord{4, 11, 223},
+ dictWord{6, 11, 359},
+ dictWord{11, 11, 3},
+ dictWord{13, 11, 108},
+ dictWord{
+ 14,
+ 11,
+ 89,
+ },
+ dictWord{144, 11, 22},
+ dictWord{132, 11, 647},
+ dictWord{134, 0, 490},
+ dictWord{134, 0, 491},
+ dictWord{134, 0, 1584},
+ dictWord{
+ 135,
+ 11,
+ 685,
+ },
+ dictWord{138, 11, 220},
+ dictWord{7, 0, 250},
+ dictWord{136, 0, 507},
+ dictWord{132, 0, 158},
+ dictWord{4, 0, 140},
+ dictWord{7, 0, 362},
+ dictWord{8, 0, 209},
+ dictWord{9, 0, 10},
+ dictWord{9, 0, 160},
+ dictWord{9, 0, 503},
+ dictWord{9, 0, 614},
+ dictWord{10, 0, 689},
+ dictWord{11, 0, 327},
+ dictWord{11, 0, 553},
+ dictWord{
+ 11,
+ 0,
+ 725,
+ },
+ dictWord{11, 0, 767},
+ dictWord{12, 0, 252},
+ dictWord{12, 0, 583},
+ dictWord{13, 0, 192},
+ dictWord{14, 0, 269},
+ dictWord{14, 0, 356},
+ dictWord{148, 0, 50},
+ dictWord{19, 0, 1},
+ dictWord{19, 0, 26},
+ dictWord{150, 0, 9},
+ dictWord{132, 11, 109},
+ dictWord{6, 0, 228},
+ dictWord{7, 0, 1341},
+ dictWord{9, 0, 408},
+ dictWord{
+ 138,
+ 0,
+ 343,
+ },
+ dictWord{4, 0, 373},
+ dictWord{5, 0, 283},
+ dictWord{6, 0, 480},
+ dictWord{7, 0, 609},
+ dictWord{10, 0, 860},
+ dictWord{138, 0, 878},
+ dictWord{6, 0, 779},
+ dictWord{134, 0, 1209},
+ dictWord{4, 0, 557},
+ dictWord{7, 11, 263},
+ dictWord{7, 11, 628},
+ dictWord{136, 11, 349},
+ dictWord{132, 0, 548},
+ dictWord{7, 0, 197},
+ dictWord{8, 0, 142},
+ dictWord{8, 0, 325},
+ dictWord{9, 0, 150},
+ dictWord{9, 0, 596},
+ dictWord{10, 0, 350},
+ dictWord{10, 0, 353},
+ dictWord{11, 0, 74},
+ dictWord{
+ 11,
+ 0,
+ 315,
+ },
+ dictWord{12, 0, 662},
+ dictWord{12, 0, 681},
+ dictWord{14, 0, 423},
+ dictWord{143, 0, 141},
+ dictWord{4, 11, 40},
+ dictWord{10, 11, 67},
+ dictWord{
+ 11,
+ 11,
+ 117,
+ },
+ dictWord{11, 11, 768},
+ dictWord{139, 11, 935},
+ dictWord{7, 11, 992},
+ dictWord{8, 11, 301},
+ dictWord{9, 11, 722},
+ dictWord{12, 11, 63},
+ dictWord{
+ 13,
+ 11,
+ 29,
+ },
+ dictWord{14, 11, 161},
+ dictWord{143, 11, 18},
+ dictWord{6, 0, 1490},
+ dictWord{138, 11, 532},
+ dictWord{5, 0, 580},
+ dictWord{7, 0, 378},
+ dictWord{
+ 7,
+ 0,
+ 674,
+ },
+ dictWord{7, 0, 1424},
+ dictWord{15, 0, 83},
+ dictWord{16, 0, 11},
+ dictWord{15, 11, 83},
+ dictWord{144, 11, 11},
+ dictWord{6, 0, 1057},
+ dictWord{6, 0, 1335},
+ dictWord{10, 0, 316},
+ dictWord{7, 10, 85},
+ dictWord{7, 10, 247},
+ dictWord{8, 10, 585},
+ dictWord{138, 10, 163},
+ dictWord{4, 0, 169},
+ dictWord{5, 0, 83},
+ dictWord{
+ 6,
+ 0,
+ 399,
+ },
+ dictWord{6, 0, 579},
+ dictWord{6, 0, 1513},
+ dictWord{7, 0, 692},
+ dictWord{7, 0, 846},
+ dictWord{7, 0, 1015},
+ dictWord{7, 0, 1799},
+ dictWord{8, 0, 403},
+ dictWord{9, 0, 394},
+ dictWord{10, 0, 133},
+ dictWord{12, 0, 4},
+ dictWord{12, 0, 297},
+ dictWord{12, 0, 452},
+ dictWord{16, 0, 81},
+ dictWord{18, 0, 25},
+ dictWord{21, 0, 14},
+ dictWord{22, 0, 12},
+ dictWord{151, 0, 18},
+ dictWord{134, 0, 1106},
+ dictWord{7, 0, 1546},
+ dictWord{11, 0, 299},
+ dictWord{142, 0, 407},
+ dictWord{134, 0, 1192},
+ dictWord{132, 0, 177},
+ dictWord{5, 0, 411},
+ dictWord{135, 0, 653},
+ dictWord{7, 0, 439},
+ dictWord{10, 0, 727},
+ dictWord{11, 0, 260},
+ dictWord{139, 0, 684},
+ dictWord{138, 10, 145},
+ dictWord{147, 10, 83},
+ dictWord{5, 0, 208},
+ dictWord{7, 0, 753},
+ dictWord{135, 0, 1528},
+ dictWord{137, 11, 617},
+ dictWord{
+ 135,
+ 10,
+ 1922,
+ },
+ dictWord{135, 11, 825},
+ dictWord{11, 0, 422},
+ dictWord{13, 0, 389},
+ dictWord{4, 10, 124},
+ dictWord{10, 10, 457},
+ dictWord{11, 10, 121},
+ dictWord{
+ 11,
+ 10,
+ 169,
+ },
+ dictWord{11, 10, 870},
+ dictWord{12, 10, 214},
+ dictWord{14, 10, 187},
+ dictWord{143, 10, 77},
+ dictWord{11, 0, 615},
+ dictWord{15, 0, 58},
+ dictWord{
+ 11,
+ 11,
+ 615,
+ },
+ dictWord{143, 11, 58},
+ dictWord{9, 0, 618},
+ dictWord{138, 0, 482},
+ dictWord{6, 0, 1952},
+ dictWord{6, 0, 1970},
+ dictWord{142, 0, 505},
+ dictWord{
+ 7,
+ 10,
+ 1193,
+ },
+ dictWord{135, 11, 1838},
+ dictWord{133, 0, 242},
+ dictWord{135, 10, 1333},
+ dictWord{6, 10, 107},
+ dictWord{7, 10, 638},
+ dictWord{
+ 7,
+ 10,
+ 1632,
+ },
+ dictWord{137, 10, 396},
+ dictWord{133, 0, 953},
+ dictWord{5, 10, 370},
+ dictWord{134, 10, 1756},
+ dictWord{5, 11, 28},
+ dictWord{6, 11, 204},
+ dictWord{
+ 10,
+ 11,
+ 320,
+ },
+ dictWord{10, 11, 583},
+ dictWord{13, 11, 502},
+ dictWord{14, 11, 72},
+ dictWord{14, 11, 274},
+ dictWord{14, 11, 312},
+ dictWord{14, 11, 344},
+ dictWord{15, 11, 159},
+ dictWord{16, 11, 62},
+ dictWord{16, 11, 69},
+ dictWord{17, 11, 30},
+ dictWord{18, 11, 42},
+ dictWord{18, 11, 53},
+ dictWord{18, 11, 84},
+ dictWord{18, 11, 140},
+ dictWord{19, 11, 68},
+ dictWord{19, 11, 85},
+ dictWord{20, 11, 5},
+ dictWord{20, 11, 45},
+ dictWord{20, 11, 101},
+ dictWord{22, 11, 7},
+ dictWord{
+ 150,
+ 11,
+ 20,
+ },
+ dictWord{4, 11, 558},
+ dictWord{6, 11, 390},
+ dictWord{7, 11, 162},
+ dictWord{7, 11, 689},
+ dictWord{9, 11, 360},
+ dictWord{138, 11, 653},
+ dictWord{
+ 11,
+ 0,
+ 802,
+ },
+ dictWord{141, 0, 67},
+ dictWord{133, 10, 204},
+ dictWord{133, 0, 290},
+ dictWord{5, 10, 970},
+ dictWord{134, 10, 1706},
+ dictWord{132, 0, 380},
+ dictWord{5, 0, 52},
+ dictWord{7, 0, 277},
+ dictWord{9, 0, 368},
+ dictWord{139, 0, 791},
+ dictWord{5, 11, 856},
+ dictWord{6, 11, 1672},
+ dictWord{6, 11, 1757},
+ dictWord{
+ 6,
+ 11,
+ 1781,
+ },
+ dictWord{7, 11, 1150},
+ dictWord{7, 11, 1425},
+ dictWord{7, 11, 1453},
+ dictWord{140, 11, 513},
+ dictWord{5, 11, 92},
+ dictWord{7, 10, 3},
+ dictWord{
+ 10,
+ 11,
+ 736,
+ },
+ dictWord{140, 11, 102},
+ dictWord{4, 0, 112},
+ dictWord{5, 0, 653},
+ dictWord{5, 10, 483},
+ dictWord{5, 10, 685},
+ dictWord{6, 10, 489},
+ dictWord{
+ 7,
+ 10,
+ 1204,
+ },
+ dictWord{136, 10, 394},
+ dictWord{132, 10, 921},
+ dictWord{6, 0, 1028},
+ dictWord{133, 10, 1007},
+ dictWord{5, 11, 590},
+ dictWord{9, 11, 213},
+ dictWord{145, 11, 91},
+ dictWord{135, 10, 1696},
+ dictWord{10, 0, 138},
+ dictWord{139, 0, 476},
+ dictWord{5, 0, 725},
+ dictWord{5, 0, 727},
+ dictWord{135, 0, 1811},
+ dictWord{4, 0, 979},
+ dictWord{6, 0, 1821},
+ dictWord{6, 0, 1838},
+ dictWord{8, 0, 876},
+ dictWord{8, 0, 883},
+ dictWord{8, 0, 889},
+ dictWord{8, 0, 893},
+ dictWord{
+ 8,
+ 0,
+ 895,
+ },
+ dictWord{10, 0, 934},
+ dictWord{12, 0, 720},
+ dictWord{14, 0, 459},
+ dictWord{148, 0, 123},
+ dictWord{135, 11, 551},
+ dictWord{4, 0, 38},
+ dictWord{6, 0, 435},
+ dictWord{7, 0, 307},
+ dictWord{7, 0, 999},
+ dictWord{7, 0, 1481},
+ dictWord{7, 0, 1732},
+ dictWord{7, 0, 1738},
+ dictWord{8, 0, 371},
+ dictWord{9, 0, 414},
+ dictWord{
+ 11,
+ 0,
+ 316,
+ },
+ dictWord{12, 0, 52},
+ dictWord{13, 0, 420},
+ dictWord{147, 0, 100},
+ dictWord{135, 0, 1296},
+ dictWord{132, 10, 712},
+ dictWord{134, 10, 1629},
+ dictWord{133, 0, 723},
+ dictWord{134, 0, 651},
+ dictWord{136, 11, 191},
+ dictWord{9, 11, 791},
+ dictWord{10, 11, 93},
+ dictWord{11, 11, 301},
+ dictWord{16, 11, 13},
+ dictWord{17, 11, 23},
+ dictWord{18, 11, 135},
+ dictWord{19, 11, 12},
+ dictWord{20, 11, 1},
+ dictWord{20, 11, 12},
+ dictWord{148, 11, 14},
+ dictWord{136, 11, 503},
+ dictWord{6, 11, 466},
+ dictWord{135, 11, 671},
+ dictWord{6, 0, 1200},
+ dictWord{134, 0, 1330},
+ dictWord{135, 0, 1255},
+ dictWord{134, 0, 986},
+ dictWord{
+ 5,
+ 0,
+ 109,
+ },
+ dictWord{6, 0, 1784},
+ dictWord{7, 0, 1895},
+ dictWord{12, 0, 296},
+ dictWord{140, 0, 302},
+ dictWord{135, 11, 983},
+ dictWord{133, 10, 485},
+ dictWord{
+ 134,
+ 0,
+ 660,
+ },
+ dictWord{134, 0, 800},
+ dictWord{5, 0, 216},
+ dictWord{5, 0, 294},
+ dictWord{6, 0, 591},
+ dictWord{7, 0, 1879},
+ dictWord{9, 0, 141},
+ dictWord{9, 0, 270},
+ dictWord{9, 0, 679},
+ dictWord{10, 0, 159},
+ dictWord{11, 0, 197},
+ dictWord{11, 0, 438},
+ dictWord{12, 0, 538},
+ dictWord{12, 0, 559},
+ dictWord{14, 0, 144},
+ dictWord{
+ 14,
+ 0,
+ 167,
+ },
+ dictWord{15, 0, 67},
+ dictWord{4, 10, 285},
+ dictWord{5, 10, 317},
+ dictWord{6, 10, 301},
+ dictWord{7, 10, 7},
+ dictWord{8, 10, 153},
+ dictWord{
+ 10,
+ 10,
+ 766,
+ },
+ dictWord{11, 10, 468},
+ dictWord{12, 10, 467},
+ dictWord{141, 10, 143},
+ dictWord{136, 0, 945},
+ dictWord{134, 0, 1090},
+ dictWord{137, 0, 81},
+ dictWord{12, 11, 468},
+ dictWord{19, 11, 96},
+ dictWord{148, 11, 24},
+ dictWord{134, 0, 391},
+ dictWord{138, 11, 241},
+ dictWord{7, 0, 322},
+ dictWord{136, 0, 249},
+ dictWord{134, 0, 1412},
+ dictWord{135, 11, 795},
+ dictWord{5, 0, 632},
+ dictWord{138, 0, 526},
+ dictWord{136, 10, 819},
+ dictWord{6, 0, 144},
+ dictWord{7, 0, 948},
+ dictWord{7, 0, 1042},
+ dictWord{8, 0, 235},
+ dictWord{8, 0, 461},
+ dictWord{9, 0, 453},
+ dictWord{9, 0, 796},
+ dictWord{10, 0, 354},
+ dictWord{17, 0, 77},
+ dictWord{
+ 135,
+ 11,
+ 954,
+ },
+ dictWord{139, 10, 917},
+ dictWord{6, 0, 940},
+ dictWord{134, 0, 1228},
+ dictWord{4, 0, 362},
+ dictWord{7, 0, 52},
+ dictWord{135, 0, 303},
+ dictWord{
+ 6,
+ 11,
+ 549,
+ },
+ dictWord{8, 11, 34},
+ dictWord{8, 11, 283},
+ dictWord{9, 11, 165},
+ dictWord{138, 11, 475},
+ dictWord{7, 11, 370},
+ dictWord{7, 11, 1007},
+ dictWord{
+ 7,
+ 11,
+ 1177,
+ },
+ dictWord{135, 11, 1565},
+ dictWord{5, 11, 652},
+ dictWord{5, 11, 701},
+ dictWord{135, 11, 449},
+ dictWord{5, 0, 196},
+ dictWord{6, 0, 486},
+ dictWord{
+ 7,
+ 0,
+ 212,
+ },
+ dictWord{8, 0, 309},
+ dictWord{136, 0, 346},
+ dictWord{6, 10, 1719},
+ dictWord{6, 10, 1735},
+ dictWord{7, 10, 2016},
+ dictWord{7, 10, 2020},
+ dictWord{
+ 8,
+ 10,
+ 837,
+ },
+ dictWord{137, 10, 852},
+ dictWord{6, 11, 159},
+ dictWord{6, 11, 364},
+ dictWord{7, 11, 516},
+ dictWord{7, 11, 1439},
+ dictWord{137, 11, 518},
+ dictWord{135, 0, 1912},
+ dictWord{135, 0, 1290},
+ dictWord{132, 0, 686},
+ dictWord{141, 11, 151},
+ dictWord{138, 0, 625},
+ dictWord{136, 0, 706},
+ dictWord{
+ 138,
+ 10,
+ 568,
+ },
+ dictWord{139, 0, 412},
+ dictWord{4, 0, 30},
+ dictWord{133, 0, 43},
+ dictWord{8, 10, 67},
+ dictWord{138, 10, 419},
+ dictWord{7, 0, 967},
+ dictWord{
+ 141,
+ 0,
+ 11,
+ },
+ dictWord{12, 0, 758},
+ dictWord{14, 0, 441},
+ dictWord{142, 0, 462},
+ dictWord{10, 10, 657},
+ dictWord{14, 10, 297},
+ dictWord{142, 10, 361},
+ dictWord{
+ 139,
+ 10,
+ 729,
+ },
+ dictWord{4, 0, 220},
+ dictWord{135, 0, 1535},
+ dictWord{7, 11, 501},
+ dictWord{9, 11, 111},
+ dictWord{10, 11, 141},
+ dictWord{11, 11, 332},
+ dictWord{
+ 13,
+ 11,
+ 43,
+ },
+ dictWord{13, 11, 429},
+ dictWord{14, 11, 130},
+ dictWord{14, 11, 415},
+ dictWord{145, 11, 102},
+ dictWord{4, 0, 950},
+ dictWord{6, 0, 1859},
+ dictWord{
+ 7,
+ 0,
+ 11,
+ },
+ dictWord{8, 0, 873},
+ dictWord{12, 0, 710},
+ dictWord{12, 0, 718},
+ dictWord{12, 0, 748},
+ dictWord{12, 0, 765},
+ dictWord{148, 0, 124},
+ dictWord{
+ 5,
+ 11,
+ 149,
+ },
+ dictWord{5, 11, 935},
+ dictWord{136, 11, 233},
+ dictWord{142, 11, 291},
+ dictWord{134, 0, 1579},
+ dictWord{7, 0, 890},
+ dictWord{8, 10, 51},
+ dictWord{
+ 9,
+ 10,
+ 868,
+ },
+ dictWord{10, 10, 833},
+ dictWord{12, 10, 481},
+ dictWord{12, 10, 570},
+ dictWord{148, 10, 106},
+ dictWord{141, 0, 2},
+ dictWord{132, 10, 445},
+ dictWord{136, 11, 801},
+ dictWord{135, 0, 1774},
+ dictWord{7, 0, 1725},
+ dictWord{138, 0, 393},
+ dictWord{5, 0, 263},
+ dictWord{134, 0, 414},
+ dictWord{
+ 132,
+ 11,
+ 322,
+ },
+ dictWord{133, 10, 239},
+ dictWord{7, 0, 456},
+ dictWord{7, 10, 1990},
+ dictWord{8, 10, 130},
+ dictWord{139, 10, 720},
+ dictWord{137, 0, 818},
+ dictWord{
+ 5,
+ 10,
+ 123,
+ },
+ dictWord{6, 10, 530},
+ dictWord{7, 10, 348},
+ dictWord{135, 10, 1419},
+ dictWord{135, 10, 2024},
+ dictWord{6, 0, 178},
+ dictWord{6, 0, 1750},
+ dictWord{8, 0, 251},
+ dictWord{9, 0, 690},
+ dictWord{10, 0, 155},
+ dictWord{10, 0, 196},
+ dictWord{10, 0, 373},
+ dictWord{11, 0, 698},
+ dictWord{13, 0, 155},
+ dictWord{
+ 148,
+ 0,
+ 93,
+ },
+ dictWord{5, 0, 97},
+ dictWord{137, 0, 393},
+ dictWord{134, 0, 674},
+ dictWord{11, 0, 223},
+ dictWord{140, 0, 168},
+ dictWord{132, 10, 210},
+ dictWord{
+ 139,
+ 11,
+ 464,
+ },
+ dictWord{6, 0, 1639},
+ dictWord{146, 0, 159},
+ dictWord{139, 11, 2},
+ dictWord{7, 0, 934},
+ dictWord{8, 0, 647},
+ dictWord{17, 0, 97},
+ dictWord{19, 0, 59},
+ dictWord{150, 0, 2},
+ dictWord{132, 0, 191},
+ dictWord{5, 0, 165},
+ dictWord{9, 0, 346},
+ dictWord{10, 0, 655},
+ dictWord{11, 0, 885},
+ dictWord{4, 10, 430},
+ dictWord{135, 11, 357},
+ dictWord{133, 0, 877},
+ dictWord{5, 10, 213},
+ dictWord{133, 11, 406},
+ dictWord{8, 0, 128},
+ dictWord{139, 0, 179},
+ dictWord{6, 11, 69},
+ dictWord{135, 11, 117},
+ dictWord{135, 0, 1297},
+ dictWord{11, 11, 43},
+ dictWord{13, 11, 72},
+ dictWord{141, 11, 142},
+ dictWord{135, 11, 1830},
+ dictWord{
+ 142,
+ 0,
+ 164,
+ },
+ dictWord{5, 0, 57},
+ dictWord{6, 0, 101},
+ dictWord{6, 0, 586},
+ dictWord{6, 0, 1663},
+ dictWord{7, 0, 132},
+ dictWord{7, 0, 1154},
+ dictWord{7, 0, 1415},
+ dictWord{7, 0, 1507},
+ dictWord{12, 0, 493},
+ dictWord{15, 0, 105},
+ dictWord{151, 0, 15},
+ dictWord{5, 0, 459},
+ dictWord{7, 0, 1073},
+ dictWord{8, 0, 241},
+ dictWord{
+ 136,
+ 0,
+ 334,
+ },
+ dictWord{133, 11, 826},
+ dictWord{133, 10, 108},
+ dictWord{5, 10, 219},
+ dictWord{10, 11, 132},
+ dictWord{11, 11, 191},
+ dictWord{11, 11, 358},
+ dictWord{139, 11, 460},
+ dictWord{6, 0, 324},
+ dictWord{6, 0, 520},
+ dictWord{7, 0, 338},
+ dictWord{7, 0, 1729},
+ dictWord{8, 0, 228},
+ dictWord{139, 0, 750},
+ dictWord{
+ 21,
+ 0,
+ 30,
+ },
+ dictWord{22, 0, 53},
+ dictWord{4, 10, 193},
+ dictWord{5, 10, 916},
+ dictWord{7, 10, 364},
+ dictWord{10, 10, 398},
+ dictWord{10, 10, 726},
+ dictWord{
+ 11,
+ 10,
+ 317,
+ },
+ dictWord{11, 10, 626},
+ dictWord{12, 10, 142},
+ dictWord{12, 10, 288},
+ dictWord{12, 10, 678},
+ dictWord{13, 10, 313},
+ dictWord{15, 10, 113},
+ dictWord{146, 10, 114},
+ dictWord{6, 11, 110},
+ dictWord{135, 11, 1681},
+ dictWord{135, 0, 910},
+ dictWord{6, 10, 241},
+ dictWord{7, 10, 907},
+ dictWord{8, 10, 832},
+ dictWord{9, 10, 342},
+ dictWord{10, 10, 729},
+ dictWord{11, 10, 284},
+ dictWord{11, 10, 445},
+ dictWord{11, 10, 651},
+ dictWord{11, 10, 863},
+ dictWord{
+ 13,
+ 10,
+ 398,
+ },
+ dictWord{146, 10, 99},
+ dictWord{7, 0, 705},
+ dictWord{9, 0, 734},
+ dictWord{5, 11, 1000},
+ dictWord{7, 11, 733},
+ dictWord{137, 11, 583},
+ dictWord{4, 0, 73},
+ dictWord{6, 0, 612},
+ dictWord{7, 0, 927},
+ dictWord{7, 0, 1822},
+ dictWord{8, 0, 217},
+ dictWord{9, 0, 765},
+ dictWord{9, 0, 766},
+ dictWord{10, 0, 408},
+ dictWord{
+ 11,
+ 0,
+ 51,
+ },
+ dictWord{11, 0, 793},
+ dictWord{12, 0, 266},
+ dictWord{15, 0, 158},
+ dictWord{20, 0, 89},
+ dictWord{150, 0, 32},
+ dictWord{7, 0, 1330},
+ dictWord{4, 11, 297},
+ dictWord{6, 11, 529},
+ dictWord{7, 11, 152},
+ dictWord{7, 11, 713},
+ dictWord{7, 11, 1845},
+ dictWord{8, 11, 710},
+ dictWord{8, 11, 717},
+ dictWord{140, 11, 639},
+ dictWord{5, 0, 389},
+ dictWord{136, 0, 636},
+ dictWord{134, 0, 1409},
+ dictWord{4, 10, 562},
+ dictWord{9, 10, 254},
+ dictWord{139, 10, 879},
+ dictWord{134, 0, 893},
+ dictWord{132, 10, 786},
+ dictWord{4, 11, 520},
+ dictWord{135, 11, 575},
+ dictWord{136, 0, 21},
+ dictWord{140, 0, 721},
+ dictWord{136, 0, 959},
+ dictWord{
+ 7,
+ 11,
+ 1428,
+ },
+ dictWord{7, 11, 1640},
+ dictWord{9, 11, 169},
+ dictWord{9, 11, 182},
+ dictWord{9, 11, 367},
+ dictWord{9, 11, 478},
+ dictWord{9, 11, 506},
+ dictWord{
+ 9,
+ 11,
+ 551,
+ },
+ dictWord{9, 11, 648},
+ dictWord{9, 11, 651},
+ dictWord{9, 11, 697},
+ dictWord{9, 11, 705},
+ dictWord{9, 11, 725},
+ dictWord{9, 11, 787},
+ dictWord{9, 11, 794},
+ dictWord{10, 11, 198},
+ dictWord{10, 11, 214},
+ dictWord{10, 11, 267},
+ dictWord{10, 11, 275},
+ dictWord{10, 11, 456},
+ dictWord{10, 11, 551},
+ dictWord{
+ 10,
+ 11,
+ 561,
+ },
+ dictWord{10, 11, 613},
+ dictWord{10, 11, 627},
+ dictWord{10, 11, 668},
+ dictWord{10, 11, 675},
+ dictWord{10, 11, 691},
+ dictWord{10, 11, 695},
+ dictWord{10, 11, 707},
+ dictWord{10, 11, 715},
+ dictWord{11, 11, 183},
+ dictWord{11, 11, 201},
+ dictWord{11, 11, 244},
+ dictWord{11, 11, 262},
+ dictWord{
+ 11,
+ 11,
+ 352,
+ },
+ dictWord{11, 11, 439},
+ dictWord{11, 11, 493},
+ dictWord{11, 11, 572},
+ dictWord{11, 11, 591},
+ dictWord{11, 11, 608},
+ dictWord{11, 11, 611},
+ dictWord{
+ 11,
+ 11,
+ 646,
+ },
+ dictWord{11, 11, 674},
+ dictWord{11, 11, 711},
+ dictWord{11, 11, 751},
+ dictWord{11, 11, 761},
+ dictWord{11, 11, 776},
+ dictWord{11, 11, 785},
+ dictWord{11, 11, 850},
+ dictWord{11, 11, 853},
+ dictWord{11, 11, 862},
+ dictWord{11, 11, 865},
+ dictWord{11, 11, 868},
+ dictWord{11, 11, 898},
+ dictWord{
+ 11,
+ 11,
+ 902,
+ },
+ dictWord{11, 11, 903},
+ dictWord{11, 11, 910},
+ dictWord{11, 11, 932},
+ dictWord{11, 11, 942},
+ dictWord{11, 11, 957},
+ dictWord{11, 11, 967},
+ dictWord{
+ 11,
+ 11,
+ 972,
+ },
+ dictWord{12, 11, 148},
+ dictWord{12, 11, 195},
+ dictWord{12, 11, 220},
+ dictWord{12, 11, 237},
+ dictWord{12, 11, 318},
+ dictWord{12, 11, 339},
+ dictWord{12, 11, 393},
+ dictWord{12, 11, 445},
+ dictWord{12, 11, 450},
+ dictWord{12, 11, 474},
+ dictWord{12, 11, 509},
+ dictWord{12, 11, 533},
+ dictWord{
+ 12,
+ 11,
+ 591,
+ },
+ dictWord{12, 11, 594},
+ dictWord{12, 11, 597},
+ dictWord{12, 11, 621},
+ dictWord{12, 11, 633},
+ dictWord{12, 11, 642},
+ dictWord{13, 11, 59},
+ dictWord{
+ 13,
+ 11,
+ 60,
+ },
+ dictWord{13, 11, 145},
+ dictWord{13, 11, 239},
+ dictWord{13, 11, 250},
+ dictWord{13, 11, 273},
+ dictWord{13, 11, 329},
+ dictWord{13, 11, 344},
+ dictWord{13, 11, 365},
+ dictWord{13, 11, 372},
+ dictWord{13, 11, 387},
+ dictWord{13, 11, 403},
+ dictWord{13, 11, 414},
+ dictWord{13, 11, 456},
+ dictWord{
+ 13,
+ 11,
+ 478,
+ },
+ dictWord{13, 11, 483},
+ dictWord{13, 11, 489},
+ dictWord{14, 11, 55},
+ dictWord{14, 11, 57},
+ dictWord{14, 11, 81},
+ dictWord{14, 11, 90},
+ dictWord{
+ 14,
+ 11,
+ 148,
+ },
+ dictWord{14, 11, 239},
+ dictWord{14, 11, 266},
+ dictWord{14, 11, 321},
+ dictWord{14, 11, 326},
+ dictWord{14, 11, 327},
+ dictWord{14, 11, 330},
+ dictWord{
+ 14,
+ 11,
+ 347,
+ },
+ dictWord{14, 11, 355},
+ dictWord{14, 11, 401},
+ dictWord{14, 11, 411},
+ dictWord{14, 11, 414},
+ dictWord{14, 11, 416},
+ dictWord{14, 11, 420},
+ dictWord{15, 11, 61},
+ dictWord{15, 11, 74},
+ dictWord{15, 11, 87},
+ dictWord{15, 11, 88},
+ dictWord{15, 11, 94},
+ dictWord{15, 11, 96},
+ dictWord{15, 11, 116},
+ dictWord{15, 11, 149},
+ dictWord{15, 11, 154},
+ dictWord{16, 11, 50},
+ dictWord{16, 11, 63},
+ dictWord{16, 11, 73},
+ dictWord{17, 11, 2},
+ dictWord{17, 11, 66},
+ dictWord{
+ 17,
+ 11,
+ 92,
+ },
+ dictWord{17, 11, 103},
+ dictWord{17, 11, 112},
+ dictWord{18, 11, 50},
+ dictWord{18, 11, 54},
+ dictWord{18, 11, 82},
+ dictWord{18, 11, 86},
+ dictWord{
+ 18,
+ 11,
+ 90,
+ },
+ dictWord{18, 11, 111},
+ dictWord{18, 11, 115},
+ dictWord{18, 11, 156},
+ dictWord{19, 11, 40},
+ dictWord{19, 11, 79},
+ dictWord{20, 11, 78},
+ dictWord{
+ 149,
+ 11,
+ 22,
+ },
+ dictWord{137, 11, 170},
+ dictWord{134, 0, 1433},
+ dictWord{135, 11, 1307},
+ dictWord{139, 11, 411},
+ dictWord{5, 0, 189},
+ dictWord{7, 0, 442},
+ dictWord{7, 0, 443},
+ dictWord{8, 0, 281},
+ dictWord{12, 0, 174},
+ dictWord{141, 0, 261},
+ dictWord{6, 10, 216},
+ dictWord{7, 10, 901},
+ dictWord{7, 10, 1343},
+ dictWord{136, 10, 493},
+ dictWord{5, 11, 397},
+ dictWord{6, 11, 154},
+ dictWord{7, 10, 341},
+ dictWord{7, 11, 676},
+ dictWord{8, 11, 443},
+ dictWord{8, 11, 609},
+ dictWord{
+ 9,
+ 11,
+ 24,
+ },
+ dictWord{9, 11, 325},
+ dictWord{10, 11, 35},
+ dictWord{11, 10, 219},
+ dictWord{11, 11, 535},
+ dictWord{11, 11, 672},
+ dictWord{11, 11, 1018},
+ dictWord{12, 11, 637},
+ dictWord{144, 11, 30},
+ dictWord{6, 0, 2},
+ dictWord{7, 0, 191},
+ dictWord{7, 0, 446},
+ dictWord{7, 0, 1262},
+ dictWord{7, 0, 1737},
+ dictWord{8, 0, 22},
+ dictWord{8, 0, 270},
+ dictWord{8, 0, 612},
+ dictWord{9, 0, 4},
+ dictWord{9, 0, 312},
+ dictWord{9, 0, 436},
+ dictWord{9, 0, 626},
+ dictWord{10, 0, 216},
+ dictWord{10, 0, 311},
+ dictWord{10, 0, 521},
+ dictWord{10, 0, 623},
+ dictWord{11, 0, 72},
+ dictWord{11, 0, 330},
+ dictWord{11, 0, 455},
+ dictWord{12, 0, 321},
+ dictWord{12, 0, 504},
+ dictWord{12, 0, 530},
+ dictWord{12, 0, 543},
+ dictWord{13, 0, 17},
+ dictWord{13, 0, 156},
+ dictWord{13, 0, 334},
+ dictWord{14, 0, 131},
+ dictWord{17, 0, 60},
+ dictWord{
+ 148,
+ 0,
+ 64,
+ },
+ dictWord{7, 0, 354},
+ dictWord{10, 0, 410},
+ dictWord{139, 0, 815},
+ dictWord{139, 10, 130},
+ dictWord{7, 10, 1734},
+ dictWord{137, 11, 631},
+ dictWord{
+ 12,
+ 0,
+ 425,
+ },
+ dictWord{15, 0, 112},
+ dictWord{10, 10, 115},
+ dictWord{11, 10, 420},
+ dictWord{13, 10, 404},
+ dictWord{14, 10, 346},
+ dictWord{143, 10, 54},
+ dictWord{
+ 6,
+ 0,
+ 60,
+ },
+ dictWord{6, 0, 166},
+ dictWord{7, 0, 374},
+ dictWord{7, 0, 670},
+ dictWord{7, 0, 1327},
+ dictWord{8, 0, 411},
+ dictWord{8, 0, 435},
+ dictWord{9, 0, 653},
+ dictWord{
+ 9,
+ 0,
+ 740,
+ },
+ dictWord{10, 0, 385},
+ dictWord{11, 0, 222},
+ dictWord{11, 0, 324},
+ dictWord{11, 0, 829},
+ dictWord{140, 0, 611},
+ dictWord{7, 0, 1611},
+ dictWord{
+ 13,
+ 0,
+ 14,
+ },
+ dictWord{15, 0, 44},
+ dictWord{19, 0, 13},
+ dictWord{148, 0, 76},
+ dictWord{133, 11, 981},
+ dictWord{4, 11, 56},
+ dictWord{7, 11, 1791},
+ dictWord{8, 11, 607},
+ dictWord{8, 11, 651},
+ dictWord{11, 11, 465},
+ dictWord{11, 11, 835},
+ dictWord{12, 11, 337},
+ dictWord{141, 11, 480},
+ dictWord{6, 0, 1478},
+ dictWord{
+ 5,
+ 10,
+ 1011,
+ },
+ dictWord{136, 10, 701},
+ dictWord{139, 0, 596},
+ dictWord{5, 0, 206},
+ dictWord{134, 0, 398},
+ dictWord{4, 10, 54},
+ dictWord{5, 10, 666},
+ dictWord{
+ 7,
+ 10,
+ 1039,
+ },
+ dictWord{7, 10, 1130},
+ dictWord{9, 10, 195},
+ dictWord{138, 10, 302},
+ dictWord{7, 0, 50},
+ dictWord{9, 11, 158},
+ dictWord{138, 11, 411},
+ dictWord{
+ 135,
+ 11,
+ 1120,
+ },
+ dictWord{6, 0, 517},
+ dictWord{7, 0, 1159},
+ dictWord{10, 0, 621},
+ dictWord{11, 0, 192},
+ dictWord{134, 10, 1669},
+ dictWord{4, 0, 592},
+ dictWord{
+ 6,
+ 0,
+ 600,
+ },
+ dictWord{135, 0, 1653},
+ dictWord{10, 0, 223},
+ dictWord{139, 0, 645},
+ dictWord{136, 11, 139},
+ dictWord{7, 0, 64},
+ dictWord{136, 0, 245},
+ dictWord{
+ 142,
+ 0,
+ 278,
+ },
+ dictWord{6, 11, 622},
+ dictWord{135, 11, 1030},
+ dictWord{136, 0, 604},
+ dictWord{134, 0, 1502},
+ dictWord{138, 0, 265},
+ dictWord{
+ 141,
+ 11,
+ 168,
+ },
+ dictWord{7, 0, 1763},
+ dictWord{140, 0, 310},
+ dictWord{7, 10, 798},
+ dictWord{139, 11, 719},
+ dictWord{7, 11, 160},
+ dictWord{10, 11, 624},
+ dictWord{
+ 142,
+ 11,
+ 279,
+ },
+ dictWord{132, 11, 363},
+ dictWord{7, 10, 122},
+ dictWord{9, 10, 259},
+ dictWord{10, 10, 84},
+ dictWord{11, 10, 470},
+ dictWord{12, 10, 541},
+ dictWord{141, 10, 379},
+ dictWord{5, 0, 129},
+ dictWord{6, 0, 61},
+ dictWord{135, 0, 947},
+ dictWord{134, 0, 1356},
+ dictWord{135, 11, 1191},
+ dictWord{13, 0, 505},
+ dictWord{141, 0, 506},
+ dictWord{11, 0, 1000},
+ dictWord{5, 10, 82},
+ dictWord{5, 10, 131},
+ dictWord{7, 10, 1755},
+ dictWord{8, 10, 31},
+ dictWord{9, 10, 168},
+ dictWord{9, 10, 764},
+ dictWord{139, 10, 869},
+ dictWord{134, 0, 966},
+ dictWord{134, 10, 605},
+ dictWord{134, 11, 292},
+ dictWord{5, 11, 177},
+ dictWord{
+ 6,
+ 11,
+ 616,
+ },
+ dictWord{7, 11, 827},
+ dictWord{9, 11, 525},
+ dictWord{138, 11, 656},
+ dictWord{135, 11, 1486},
+ dictWord{138, 11, 31},
+ dictWord{5, 10, 278},
+ dictWord{137, 10, 68},
+ dictWord{4, 10, 163},
+ dictWord{5, 10, 201},
+ dictWord{5, 10, 307},
+ dictWord{5, 10, 310},
+ dictWord{6, 10, 335},
+ dictWord{7, 10, 284},
+ dictWord{136, 10, 165},
+ dictWord{6, 0, 839},
+ dictWord{135, 10, 1660},
+ dictWord{136, 10, 781},
+ dictWord{6, 10, 33},
+ dictWord{135, 10, 1244},
+ dictWord{
+ 133,
+ 0,
+ 637,
+ },
+ dictWord{4, 11, 161},
+ dictWord{133, 11, 631},
+ dictWord{137, 0, 590},
+ dictWord{7, 10, 1953},
+ dictWord{136, 10, 720},
+ dictWord{5, 0, 280},
+ dictWord{
+ 7,
+ 0,
+ 1226,
+ },
+ dictWord{138, 10, 203},
+ dictWord{134, 0, 1386},
+ dictWord{5, 0, 281},
+ dictWord{6, 0, 1026},
+ dictWord{6, 10, 326},
+ dictWord{7, 10, 677},
+ dictWord{
+ 137,
+ 10,
+ 425,
+ },
+ dictWord{7, 11, 1557},
+ dictWord{135, 11, 1684},
+ dictWord{135, 0, 1064},
+ dictWord{9, 11, 469},
+ dictWord{9, 11, 709},
+ dictWord{12, 11, 512},
+ dictWord{14, 11, 65},
+ dictWord{145, 11, 12},
+ dictWord{134, 0, 917},
+ dictWord{10, 11, 229},
+ dictWord{11, 11, 73},
+ dictWord{11, 11, 376},
+ dictWord{
+ 139,
+ 11,
+ 433,
+ },
+ dictWord{7, 0, 555},
+ dictWord{9, 0, 192},
+ dictWord{13, 0, 30},
+ dictWord{13, 0, 49},
+ dictWord{15, 0, 150},
+ dictWord{16, 0, 76},
+ dictWord{20, 0, 52},
+ dictWord{
+ 7,
+ 10,
+ 1316,
+ },
+ dictWord{7, 10, 1412},
+ dictWord{7, 10, 1839},
+ dictWord{9, 10, 589},
+ dictWord{11, 10, 241},
+ dictWord{11, 10, 676},
+ dictWord{11, 10, 811},
+ dictWord{11, 10, 891},
+ dictWord{12, 10, 140},
+ dictWord{12, 10, 346},
+ dictWord{12, 10, 479},
+ dictWord{13, 10, 381},
+ dictWord{14, 10, 188},
+ dictWord{
+ 146,
+ 10,
+ 30,
+ },
+ dictWord{149, 0, 15},
+ dictWord{6, 0, 1882},
+ dictWord{6, 0, 1883},
+ dictWord{6, 0, 1897},
+ dictWord{9, 0, 945},
+ dictWord{9, 0, 1014},
+ dictWord{9, 0, 1020},
+ dictWord{12, 0, 823},
+ dictWord{12, 0, 842},
+ dictWord{12, 0, 866},
+ dictWord{12, 0, 934},
+ dictWord{15, 0, 242},
+ dictWord{146, 0, 208},
+ dictWord{6, 0, 965},
+ dictWord{134, 0, 1499},
+ dictWord{7, 0, 33},
+ dictWord{7, 0, 120},
+ dictWord{8, 0, 489},
+ dictWord{9, 0, 319},
+ dictWord{10, 0, 820},
+ dictWord{11, 0, 1004},
+ dictWord{
+ 12,
+ 0,
+ 379,
+ },
+ dictWord{12, 0, 679},
+ dictWord{13, 0, 117},
+ dictWord{13, 0, 412},
+ dictWord{14, 0, 25},
+ dictWord{15, 0, 52},
+ dictWord{15, 0, 161},
+ dictWord{16, 0, 47},
+ dictWord{149, 0, 2},
+ dictWord{6, 11, 558},
+ dictWord{7, 11, 651},
+ dictWord{8, 11, 421},
+ dictWord{9, 11, 0},
+ dictWord{138, 11, 34},
+ dictWord{4, 0, 937},
+ dictWord{
+ 5,
+ 0,
+ 801,
+ },
+ dictWord{7, 0, 473},
+ dictWord{5, 10, 358},
+ dictWord{7, 10, 1184},
+ dictWord{10, 10, 662},
+ dictWord{13, 10, 212},
+ dictWord{13, 10, 304},
+ dictWord{
+ 13,
+ 10,
+ 333,
+ },
+ dictWord{145, 10, 98},
+ dictWord{132, 0, 877},
+ dictWord{6, 0, 693},
+ dictWord{134, 0, 824},
+ dictWord{132, 0, 365},
+ dictWord{7, 11, 1832},
+ dictWord{
+ 138,
+ 11,
+ 374,
+ },
+ dictWord{5, 0, 7},
+ dictWord{139, 0, 774},
+ dictWord{4, 0, 734},
+ dictWord{5, 0, 662},
+ dictWord{134, 0, 430},
+ dictWord{4, 0, 746},
+ dictWord{
+ 135,
+ 0,
+ 1090,
+ },
+ dictWord{5, 0, 360},
+ dictWord{8, 0, 237},
+ dictWord{10, 0, 231},
+ dictWord{147, 0, 124},
+ dictWord{138, 11, 348},
+ dictWord{6, 11, 6},
+ dictWord{7, 11, 81},
+ dictWord{7, 11, 771},
+ dictWord{7, 11, 1731},
+ dictWord{9, 11, 405},
+ dictWord{138, 11, 421},
+ dictWord{6, 0, 740},
+ dictWord{137, 0, 822},
+ dictWord{
+ 133,
+ 10,
+ 946,
+ },
+ dictWord{7, 0, 1485},
+ dictWord{136, 0, 929},
+ dictWord{7, 10, 411},
+ dictWord{8, 10, 631},
+ dictWord{9, 10, 323},
+ dictWord{10, 10, 355},
+ dictWord{
+ 11,
+ 10,
+ 491,
+ },
+ dictWord{12, 10, 143},
+ dictWord{12, 10, 402},
+ dictWord{13, 10, 73},
+ dictWord{14, 10, 408},
+ dictWord{15, 10, 107},
+ dictWord{146, 10, 71},
+ dictWord{
+ 135,
+ 10,
+ 590,
+ },
+ dictWord{5, 11, 881},
+ dictWord{133, 11, 885},
+ dictWord{150, 11, 25},
+ dictWord{4, 0, 852},
+ dictWord{5, 11, 142},
+ dictWord{134, 11, 546},
+ dictWord{7, 10, 1467},
+ dictWord{8, 10, 328},
+ dictWord{10, 10, 544},
+ dictWord{11, 10, 955},
+ dictWord{13, 10, 320},
+ dictWord{145, 10, 83},
+ dictWord{9, 0, 17},
+ dictWord{10, 0, 291},
+ dictWord{11, 10, 511},
+ dictWord{13, 10, 394},
+ dictWord{14, 10, 298},
+ dictWord{14, 10, 318},
+ dictWord{146, 10, 103},
+ dictWord{5, 11, 466},
+ dictWord{11, 11, 571},
+ dictWord{12, 11, 198},
+ dictWord{13, 11, 283},
+ dictWord{14, 11, 186},
+ dictWord{15, 11, 21},
+ dictWord{143, 11, 103},
+ dictWord{
+ 134,
+ 0,
+ 1001,
+ },
+ dictWord{4, 11, 185},
+ dictWord{5, 11, 257},
+ dictWord{5, 11, 839},
+ dictWord{5, 11, 936},
+ dictWord{7, 11, 171},
+ dictWord{9, 11, 399},
+ dictWord{
+ 10,
+ 11,
+ 258,
+ },
+ dictWord{10, 11, 395},
+ dictWord{10, 11, 734},
+ dictWord{11, 11, 1014},
+ dictWord{12, 11, 23},
+ dictWord{13, 11, 350},
+ dictWord{14, 11, 150},
+ dictWord{147, 11, 6},
+ dictWord{143, 0, 35},
+ dictWord{132, 0, 831},
+ dictWord{5, 10, 835},
+ dictWord{134, 10, 483},
+ dictWord{4, 0, 277},
+ dictWord{5, 0, 608},
+ dictWord{
+ 6,
+ 0,
+ 493,
+ },
+ dictWord{7, 0, 457},
+ dictWord{12, 0, 384},
+ dictWord{7, 11, 404},
+ dictWord{7, 11, 1377},
+ dictWord{7, 11, 1430},
+ dictWord{7, 11, 2017},
+ dictWord{
+ 8,
+ 11,
+ 149,
+ },
+ dictWord{8, 11, 239},
+ dictWord{8, 11, 512},
+ dictWord{8, 11, 793},
+ dictWord{8, 11, 818},
+ dictWord{9, 11, 474},
+ dictWord{9, 11, 595},
+ dictWord{
+ 10,
+ 11,
+ 122,
+ },
+ dictWord{10, 11, 565},
+ dictWord{10, 11, 649},
+ dictWord{10, 11, 783},
+ dictWord{11, 11, 239},
+ dictWord{11, 11, 295},
+ dictWord{11, 11, 447},
+ dictWord{
+ 11,
+ 11,
+ 528,
+ },
+ dictWord{11, 11, 639},
+ dictWord{11, 11, 800},
+ dictWord{11, 11, 936},
+ dictWord{12, 11, 25},
+ dictWord{12, 11, 73},
+ dictWord{12, 11, 77},
+ dictWord{12, 11, 157},
+ dictWord{12, 11, 316},
+ dictWord{12, 11, 390},
+ dictWord{12, 11, 391},
+ dictWord{12, 11, 394},
+ dictWord{12, 11, 395},
+ dictWord{
+ 12,
+ 11,
+ 478,
+ },
+ dictWord{12, 11, 503},
+ dictWord{12, 11, 592},
+ dictWord{12, 11, 680},
+ dictWord{13, 11, 50},
+ dictWord{13, 11, 53},
+ dictWord{13, 11, 132},
+ dictWord{
+ 13,
+ 11,
+ 198,
+ },
+ dictWord{13, 11, 275},
+ dictWord{13, 11, 322},
+ dictWord{13, 11, 415},
+ dictWord{14, 11, 71},
+ dictWord{14, 11, 257},
+ dictWord{14, 11, 395},
+ dictWord{15, 11, 71},
+ dictWord{15, 11, 136},
+ dictWord{17, 11, 123},
+ dictWord{18, 11, 93},
+ dictWord{147, 11, 58},
+ dictWord{134, 0, 1351},
+ dictWord{7, 0, 27},
+ dictWord{135, 0, 316},
+ dictWord{136, 11, 712},
+ dictWord{136, 0, 984},
+ dictWord{133, 0, 552},
+ dictWord{137, 0, 264},
+ dictWord{132, 0, 401},
+ dictWord{6, 0, 710},
+ dictWord{6, 0, 1111},
+ dictWord{134, 0, 1343},
+ dictWord{134, 0, 1211},
+ dictWord{9, 0, 543},
+ dictWord{10, 0, 524},
+ dictWord{11, 0, 108},
+ dictWord{11, 0, 653},
+ dictWord{12, 0, 524},
+ dictWord{13, 0, 123},
+ dictWord{14, 0, 252},
+ dictWord{16, 0, 18},
+ dictWord{19, 0, 38},
+ dictWord{20, 0, 26},
+ dictWord{20, 0, 65},
+ dictWord{
+ 21,
+ 0,
+ 3,
+ },
+ dictWord{151, 0, 11},
+ dictWord{4, 0, 205},
+ dictWord{5, 0, 623},
+ dictWord{7, 0, 104},
+ dictWord{8, 0, 519},
+ dictWord{137, 0, 716},
+ dictWord{132, 10, 677},
+ dictWord{4, 11, 377},
+ dictWord{152, 11, 13},
+ dictWord{135, 11, 1673},
+ dictWord{7, 0, 579},
+ dictWord{9, 0, 41},
+ dictWord{9, 0, 244},
+ dictWord{9, 0, 669},
+ dictWord{
+ 10,
+ 0,
+ 5,
+ },
+ dictWord{11, 0, 861},
+ dictWord{11, 0, 951},
+ dictWord{139, 0, 980},
+ dictWord{132, 0, 717},
+ dictWord{136, 0, 1011},
+ dictWord{132, 0, 805},
+ dictWord{
+ 4,
+ 11,
+ 180,
+ },
+ dictWord{135, 11, 1906},
+ dictWord{132, 10, 777},
+ dictWord{132, 10, 331},
+ dictWord{132, 0, 489},
+ dictWord{6, 0, 1024},
+ dictWord{4, 11, 491},
+ dictWord{133, 10, 747},
+ dictWord{135, 11, 1182},
+ dictWord{4, 11, 171},
+ dictWord{138, 11, 234},
+ dictWord{4, 11, 586},
+ dictWord{7, 11, 1186},
+ dictWord{
+ 138,
+ 11,
+ 631,
+ },
+ dictWord{135, 0, 892},
+ dictWord{135, 11, 336},
+ dictWord{9, 11, 931},
+ dictWord{10, 11, 334},
+ dictWord{148, 11, 71},
+ dictWord{137, 0, 473},
+ dictWord{6, 0, 864},
+ dictWord{12, 0, 659},
+ dictWord{139, 11, 926},
+ dictWord{7, 0, 819},
+ dictWord{9, 0, 26},
+ dictWord{9, 0, 392},
+ dictWord{10, 0, 152},
+ dictWord{
+ 10,
+ 0,
+ 226,
+ },
+ dictWord{11, 0, 19},
+ dictWord{12, 0, 276},
+ dictWord{12, 0, 426},
+ dictWord{12, 0, 589},
+ dictWord{13, 0, 460},
+ dictWord{15, 0, 97},
+ dictWord{19, 0, 48},
+ dictWord{148, 0, 104},
+ dictWord{135, 0, 51},
+ dictWord{133, 10, 326},
+ dictWord{4, 10, 691},
+ dictWord{146, 10, 16},
+ dictWord{9, 0, 130},
+ dictWord{11, 0, 765},
+ dictWord{10, 10, 680},
+ dictWord{10, 10, 793},
+ dictWord{141, 10, 357},
+ dictWord{133, 11, 765},
+ dictWord{8, 0, 229},
+ dictWord{6, 10, 32},
+ dictWord{7, 10, 385},
+ dictWord{7, 10, 757},
+ dictWord{7, 10, 1916},
+ dictWord{8, 10, 94},
+ dictWord{8, 10, 711},
+ dictWord{9, 10, 541},
+ dictWord{10, 10, 162},
+ dictWord{10, 10, 795},
+ dictWord{11, 10, 989},
+ dictWord{11, 10, 1010},
+ dictWord{12, 10, 14},
+ dictWord{142, 10, 308},
+ dictWord{7, 11, 474},
+ dictWord{137, 11, 578},
+ dictWord{
+ 132,
+ 0,
+ 674,
+ },
+ dictWord{132, 0, 770},
+ dictWord{5, 0, 79},
+ dictWord{7, 0, 1027},
+ dictWord{7, 0, 1477},
+ dictWord{139, 0, 52},
+ dictWord{133, 11, 424},
+ dictWord{
+ 134,
+ 0,
+ 1666,
+ },
+ dictWord{6, 0, 409},
+ dictWord{6, 10, 349},
+ dictWord{6, 10, 1682},
+ dictWord{7, 10, 1252},
+ dictWord{8, 10, 112},
+ dictWord{8, 11, 714},
+ dictWord{
+ 9,
+ 10,
+ 435,
+ },
+ dictWord{9, 10, 668},
+ dictWord{10, 10, 290},
+ dictWord{10, 10, 319},
+ dictWord{10, 10, 815},
+ dictWord{11, 10, 180},
+ dictWord{11, 10, 837},
+ dictWord{
+ 12,
+ 10,
+ 240,
+ },
+ dictWord{13, 10, 152},
+ dictWord{13, 10, 219},
+ dictWord{142, 10, 158},
+ dictWord{5, 0, 789},
+ dictWord{134, 0, 195},
+ dictWord{4, 0, 251},
+ dictWord{
+ 4,
+ 0,
+ 688,
+ },
+ dictWord{7, 0, 513},
+ dictWord{135, 0, 1284},
+ dictWord{132, 10, 581},
+ dictWord{9, 11, 420},
+ dictWord{10, 11, 269},
+ dictWord{10, 11, 285},
+ dictWord{10, 11, 576},
+ dictWord{11, 11, 397},
+ dictWord{13, 11, 175},
+ dictWord{145, 11, 90},
+ dictWord{6, 10, 126},
+ dictWord{7, 10, 573},
+ dictWord{8, 10, 397},
+ dictWord{142, 10, 44},
+ dictWord{132, 11, 429},
+ dictWord{133, 0, 889},
+ dictWord{4, 0, 160},
+ dictWord{5, 0, 330},
+ dictWord{7, 0, 1434},
+ dictWord{136, 0, 174},
+ dictWord{7, 11, 18},
+ dictWord{7, 11, 699},
+ dictWord{7, 11, 1966},
+ dictWord{8, 11, 752},
+ dictWord{9, 11, 273},
+ dictWord{9, 11, 412},
+ dictWord{9, 11, 703},
+ dictWord{
+ 10,
+ 11,
+ 71,
+ },
+ dictWord{10, 11, 427},
+ dictWord{10, 11, 508},
+ dictWord{146, 11, 97},
+ dictWord{6, 0, 872},
+ dictWord{134, 0, 899},
+ dictWord{133, 10, 926},
+ dictWord{134, 0, 1126},
+ dictWord{134, 0, 918},
+ dictWord{4, 11, 53},
+ dictWord{5, 11, 186},
+ dictWord{135, 11, 752},
+ dictWord{7, 0, 268},
+ dictWord{136, 0, 569},
+ dictWord{134, 0, 1224},
+ dictWord{6, 0, 1361},
+ dictWord{7, 10, 1232},
+ dictWord{137, 10, 531},
+ dictWord{8, 11, 575},
+ dictWord{10, 11, 289},
+ dictWord{
+ 139,
+ 11,
+ 319,
+ },
+ dictWord{133, 10, 670},
+ dictWord{132, 11, 675},
+ dictWord{133, 0, 374},
+ dictWord{135, 10, 1957},
+ dictWord{133, 0, 731},
+ dictWord{11, 0, 190},
+ dictWord{15, 0, 49},
+ dictWord{11, 11, 190},
+ dictWord{143, 11, 49},
+ dictWord{4, 0, 626},
+ dictWord{5, 0, 506},
+ dictWord{5, 0, 642},
+ dictWord{6, 0, 425},
+ dictWord{
+ 10,
+ 0,
+ 202,
+ },
+ dictWord{139, 0, 141},
+ dictWord{137, 0, 444},
+ dictWord{7, 10, 242},
+ dictWord{135, 10, 1942},
+ dictWord{6, 11, 209},
+ dictWord{8, 11, 468},
+ dictWord{
+ 9,
+ 11,
+ 210,
+ },
+ dictWord{11, 11, 36},
+ dictWord{12, 11, 28},
+ dictWord{12, 11, 630},
+ dictWord{13, 11, 21},
+ dictWord{13, 11, 349},
+ dictWord{14, 11, 7},
+ dictWord{
+ 145,
+ 11,
+ 13,
+ },
+ dictWord{4, 11, 342},
+ dictWord{135, 11, 1179},
+ dictWord{5, 10, 834},
+ dictWord{7, 10, 1202},
+ dictWord{8, 10, 14},
+ dictWord{9, 10, 481},
+ dictWord{
+ 137,
+ 10,
+ 880,
+ },
+ dictWord{4, 11, 928},
+ dictWord{133, 11, 910},
+ dictWord{4, 11, 318},
+ dictWord{4, 11, 496},
+ dictWord{7, 11, 856},
+ dictWord{139, 11, 654},
+ dictWord{136, 0, 835},
+ dictWord{7, 0, 1526},
+ dictWord{138, 10, 465},
+ dictWord{151, 0, 17},
+ dictWord{135, 0, 477},
+ dictWord{4, 10, 357},
+ dictWord{6, 10, 172},
+ dictWord{7, 10, 143},
+ dictWord{137, 10, 413},
+ dictWord{6, 0, 1374},
+ dictWord{138, 0, 994},
+ dictWord{18, 0, 76},
+ dictWord{132, 10, 590},
+ dictWord{7, 0, 287},
+ dictWord{8, 0, 355},
+ dictWord{9, 0, 293},
+ dictWord{137, 0, 743},
+ dictWord{134, 0, 1389},
+ dictWord{7, 11, 915},
+ dictWord{8, 11, 247},
+ dictWord{147, 11, 0},
+ dictWord{
+ 4,
+ 11,
+ 202,
+ },
+ dictWord{5, 11, 382},
+ dictWord{6, 11, 454},
+ dictWord{7, 11, 936},
+ dictWord{7, 11, 1803},
+ dictWord{8, 11, 758},
+ dictWord{9, 11, 375},
+ dictWord{
+ 9,
+ 11,
+ 895,
+ },
+ dictWord{10, 11, 743},
+ dictWord{10, 11, 792},
+ dictWord{11, 11, 978},
+ dictWord{11, 11, 1012},
+ dictWord{142, 11, 109},
+ dictWord{5, 0, 384},
+ dictWord{8, 0, 455},
+ dictWord{140, 0, 48},
+ dictWord{132, 11, 390},
+ dictWord{5, 10, 169},
+ dictWord{7, 10, 333},
+ dictWord{136, 10, 45},
+ dictWord{5, 0, 264},
+ dictWord{134, 0, 184},
+ dictWord{138, 11, 791},
+ dictWord{133, 11, 717},
+ dictWord{132, 10, 198},
+ dictWord{6, 11, 445},
+ dictWord{7, 11, 332},
+ dictWord{
+ 137,
+ 11,
+ 909,
+ },
+ dictWord{136, 0, 1001},
+ dictWord{4, 10, 24},
+ dictWord{5, 10, 140},
+ dictWord{5, 10, 185},
+ dictWord{7, 10, 1500},
+ dictWord{11, 10, 565},
+ dictWord{
+ 139,
+ 10,
+ 838,
+ },
+ dictWord{134, 11, 578},
+ dictWord{5, 0, 633},
+ dictWord{6, 0, 28},
+ dictWord{135, 0, 1323},
+ dictWord{132, 0, 851},
+ dictWord{136, 11, 267},
+ dictWord{
+ 7,
+ 0,
+ 359,
+ },
+ dictWord{8, 0, 243},
+ dictWord{140, 0, 175},
+ dictWord{4, 10, 334},
+ dictWord{133, 10, 593},
+ dictWord{141, 11, 87},
+ dictWord{136, 11, 766},
+ dictWord{10, 0, 287},
+ dictWord{12, 0, 138},
+ dictWord{10, 11, 287},
+ dictWord{140, 11, 138},
+ dictWord{4, 0, 105},
+ dictWord{132, 0, 740},
+ dictWord{140, 10, 116},
+ dictWord{134, 0, 857},
+ dictWord{135, 11, 1841},
+ dictWord{6, 0, 1402},
+ dictWord{137, 0, 819},
+ dictWord{132, 11, 584},
+ dictWord{132, 10, 709},
+ dictWord{
+ 133,
+ 10,
+ 897,
+ },
+ dictWord{5, 0, 224},
+ dictWord{13, 0, 174},
+ dictWord{146, 0, 52},
+ dictWord{135, 10, 1840},
+ dictWord{4, 10, 608},
+ dictWord{133, 10, 497},
+ dictWord{139, 11, 60},
+ dictWord{4, 0, 758},
+ dictWord{135, 0, 1649},
+ dictWord{4, 11, 226},
+ dictWord{4, 11, 326},
+ dictWord{135, 11, 1770},
+ dictWord{5, 11, 426},
+ dictWord{8, 11, 30},
+ dictWord{9, 11, 2},
+ dictWord{11, 11, 549},
+ dictWord{147, 11, 122},
+ dictWord{135, 10, 2039},
+ dictWord{6, 10, 540},
+ dictWord{
+ 136,
+ 10,
+ 136,
+ },
+ dictWord{4, 0, 573},
+ dictWord{8, 0, 655},
+ dictWord{4, 10, 897},
+ dictWord{133, 10, 786},
+ dictWord{7, 0, 351},
+ dictWord{139, 0, 128},
+ dictWord{
+ 133,
+ 10,
+ 999,
+ },
+ dictWord{4, 10, 299},
+ dictWord{135, 10, 1004},
+ dictWord{133, 0, 918},
+ dictWord{132, 11, 345},
+ dictWord{4, 11, 385},
+ dictWord{7, 11, 265},
+ dictWord{135, 11, 587},
+ dictWord{133, 10, 456},
+ dictWord{136, 10, 180},
+ dictWord{6, 0, 687},
+ dictWord{134, 0, 1537},
+ dictWord{4, 11, 347},
+ dictWord{
+ 5,
+ 11,
+ 423,
+ },
+ dictWord{5, 11, 996},
+ dictWord{135, 11, 1329},
+ dictWord{132, 10, 755},
+ dictWord{7, 11, 1259},
+ dictWord{9, 11, 125},
+ dictWord{11, 11, 65},
+ dictWord{140, 11, 285},
+ dictWord{5, 11, 136},
+ dictWord{6, 11, 136},
+ dictWord{136, 11, 644},
+ dictWord{134, 0, 1525},
+ dictWord{4, 0, 1009},
+ dictWord{
+ 135,
+ 0,
+ 1139,
+ },
+ dictWord{139, 10, 338},
+ dictWord{132, 0, 340},
+ dictWord{135, 10, 1464},
+ dictWord{8, 0, 847},
+ dictWord{10, 0, 861},
+ dictWord{10, 0, 876},
+ dictWord{
+ 10,
+ 0,
+ 889,
+ },
+ dictWord{10, 0, 922},
+ dictWord{10, 0, 929},
+ dictWord{10, 0, 933},
+ dictWord{12, 0, 784},
+ dictWord{140, 0, 791},
+ dictWord{139, 0, 176},
+ dictWord{
+ 9,
+ 11,
+ 134,
+ },
+ dictWord{10, 11, 2},
+ dictWord{10, 11, 27},
+ dictWord{10, 11, 333},
+ dictWord{11, 11, 722},
+ dictWord{143, 11, 1},
+ dictWord{4, 11, 433},
+ dictWord{
+ 133,
+ 11,
+ 719,
+ },
+ dictWord{5, 0, 985},
+ dictWord{7, 0, 509},
+ dictWord{7, 0, 529},
+ dictWord{145, 0, 96},
+ dictWord{132, 0, 615},
+ dictWord{4, 10, 890},
+ dictWord{
+ 5,
+ 10,
+ 805,
+ },
+ dictWord{5, 10, 819},
+ dictWord{5, 10, 961},
+ dictWord{6, 10, 396},
+ dictWord{6, 10, 1631},
+ dictWord{6, 10, 1678},
+ dictWord{7, 10, 1967},
+ dictWord{
+ 7,
+ 10,
+ 2041,
+ },
+ dictWord{9, 10, 630},
+ dictWord{11, 10, 8},
+ dictWord{11, 10, 1019},
+ dictWord{12, 10, 176},
+ dictWord{13, 10, 225},
+ dictWord{14, 10, 292},
+ dictWord{
+ 149,
+ 10,
+ 24,
+ },
+ dictWord{135, 0, 1919},
+ dictWord{134, 0, 1131},
+ dictWord{144, 11, 21},
+ dictWord{144, 11, 51},
+ dictWord{135, 10, 1815},
+ dictWord{4, 0, 247},
+ dictWord{7, 10, 1505},
+ dictWord{10, 10, 190},
+ dictWord{10, 10, 634},
+ dictWord{11, 10, 792},
+ dictWord{12, 10, 358},
+ dictWord{140, 10, 447},
+ dictWord{
+ 5,
+ 10,
+ 0,
+ },
+ dictWord{6, 10, 536},
+ dictWord{7, 10, 604},
+ dictWord{13, 10, 445},
+ dictWord{145, 10, 126},
+ dictWord{4, 0, 184},
+ dictWord{5, 0, 390},
+ dictWord{6, 0, 337},
+ dictWord{7, 0, 23},
+ dictWord{7, 0, 494},
+ dictWord{7, 0, 618},
+ dictWord{7, 0, 1456},
+ dictWord{8, 0, 27},
+ dictWord{8, 0, 599},
+ dictWord{10, 0, 153},
+ dictWord{
+ 139,
+ 0,
+ 710,
+ },
+ dictWord{6, 10, 232},
+ dictWord{6, 10, 412},
+ dictWord{7, 10, 1074},
+ dictWord{8, 10, 9},
+ dictWord{8, 10, 157},
+ dictWord{8, 10, 786},
+ dictWord{9, 10, 196},
+ dictWord{9, 10, 352},
+ dictWord{9, 10, 457},
+ dictWord{10, 10, 337},
+ dictWord{11, 10, 232},
+ dictWord{11, 10, 877},
+ dictWord{12, 10, 480},
+ dictWord{
+ 140,
+ 10,
+ 546,
+ },
+ dictWord{13, 0, 38},
+ dictWord{135, 10, 958},
+ dictWord{4, 10, 382},
+ dictWord{136, 10, 579},
+ dictWord{4, 10, 212},
+ dictWord{135, 10, 1206},
+ dictWord{
+ 4,
+ 11,
+ 555,
+ },
+ dictWord{8, 11, 536},
+ dictWord{138, 11, 288},
+ dictWord{11, 11, 139},
+ dictWord{139, 11, 171},
+ dictWord{9, 11, 370},
+ dictWord{138, 11, 90},
+ dictWord{132, 0, 1015},
+ dictWord{134, 0, 1088},
+ dictWord{5, 10, 655},
+ dictWord{135, 11, 977},
+ dictWord{134, 0, 1585},
+ dictWord{17, 10, 67},
+ dictWord{
+ 147,
+ 10,
+ 74,
+ },
+ dictWord{10, 0, 227},
+ dictWord{11, 0, 497},
+ dictWord{11, 0, 709},
+ dictWord{140, 0, 415},
+ dictWord{6, 0, 360},
+ dictWord{7, 0, 1664},
+ dictWord{
+ 136,
+ 0,
+ 478,
+ },
+ dictWord{7, 0, 95},
+ dictWord{6, 10, 231},
+ dictWord{136, 10, 423},
+ dictWord{140, 11, 65},
+ dictWord{4, 11, 257},
+ dictWord{135, 11, 2031},
+ dictWord{
+ 135,
+ 11,
+ 1768,
+ },
+ dictWord{133, 10, 300},
+ dictWord{139, 11, 211},
+ dictWord{136, 0, 699},
+ dictWord{6, 10, 237},
+ dictWord{7, 10, 611},
+ dictWord{8, 10, 100},
+ dictWord{9, 10, 416},
+ dictWord{11, 10, 335},
+ dictWord{12, 10, 173},
+ dictWord{146, 10, 101},
+ dictWord{14, 0, 26},
+ dictWord{146, 0, 150},
+ dictWord{6, 0, 581},
+ dictWord{135, 0, 1119},
+ dictWord{135, 10, 1208},
+ dictWord{132, 0, 739},
+ dictWord{6, 11, 83},
+ dictWord{6, 11, 1733},
+ dictWord{135, 11, 1389},
+ dictWord{
+ 137,
+ 0,
+ 869,
+ },
+ dictWord{4, 0, 67},
+ dictWord{5, 0, 422},
+ dictWord{7, 0, 1037},
+ dictWord{7, 0, 1289},
+ dictWord{7, 0, 1555},
+ dictWord{9, 0, 741},
+ dictWord{145, 0, 108},
+ dictWord{133, 10, 199},
+ dictWord{12, 10, 427},
+ dictWord{146, 10, 38},
+ dictWord{136, 0, 464},
+ dictWord{142, 0, 42},
+ dictWord{10, 0, 96},
+ dictWord{8, 11, 501},
+ dictWord{137, 11, 696},
+ dictWord{134, 11, 592},
+ dictWord{4, 0, 512},
+ dictWord{4, 0, 966},
+ dictWord{5, 0, 342},
+ dictWord{6, 0, 1855},
+ dictWord{8, 0, 869},
+ dictWord{8, 0, 875},
+ dictWord{8, 0, 901},
+ dictWord{144, 0, 26},
+ dictWord{8, 0, 203},
+ dictWord{11, 0, 823},
+ dictWord{11, 0, 846},
+ dictWord{12, 0, 482},
+ dictWord{
+ 13,
+ 0,
+ 277,
+ },
+ dictWord{13, 0, 302},
+ dictWord{13, 0, 464},
+ dictWord{14, 0, 205},
+ dictWord{142, 0, 221},
+ dictWord{4, 0, 449},
+ dictWord{133, 0, 718},
+ dictWord{
+ 7,
+ 11,
+ 1718,
+ },
+ dictWord{9, 11, 95},
+ dictWord{9, 11, 274},
+ dictWord{10, 11, 279},
+ dictWord{10, 11, 317},
+ dictWord{10, 11, 420},
+ dictWord{11, 11, 303},
+ dictWord{
+ 11,
+ 11,
+ 808,
+ },
+ dictWord{12, 11, 134},
+ dictWord{12, 11, 367},
+ dictWord{13, 11, 149},
+ dictWord{13, 11, 347},
+ dictWord{14, 11, 349},
+ dictWord{14, 11, 406},
+ dictWord{18, 11, 22},
+ dictWord{18, 11, 89},
+ dictWord{18, 11, 122},
+ dictWord{147, 11, 47},
+ dictWord{133, 11, 26},
+ dictWord{4, 0, 355},
+ dictWord{6, 0, 311},
+ dictWord{
+ 9,
+ 0,
+ 256,
+ },
+ dictWord{138, 0, 404},
+ dictWord{132, 11, 550},
+ dictWord{10, 0, 758},
+ dictWord{6, 10, 312},
+ dictWord{6, 10, 1715},
+ dictWord{10, 10, 584},
+ dictWord{11, 10, 546},
+ dictWord{11, 10, 692},
+ dictWord{12, 10, 259},
+ dictWord{12, 10, 295},
+ dictWord{13, 10, 46},
+ dictWord{141, 10, 154},
+ dictWord{
+ 136,
+ 11,
+ 822,
+ },
+ dictWord{5, 0, 827},
+ dictWord{4, 11, 902},
+ dictWord{5, 11, 809},
+ dictWord{6, 11, 122},
+ dictWord{135, 11, 896},
+ dictWord{5, 0, 64},
+ dictWord{140, 0, 581},
+ dictWord{4, 0, 442},
+ dictWord{6, 0, 739},
+ dictWord{7, 0, 1047},
+ dictWord{7, 0, 1352},
+ dictWord{7, 0, 1643},
+ dictWord{7, 11, 1911},
+ dictWord{9, 11, 449},
+ dictWord{10, 11, 192},
+ dictWord{138, 11, 740},
+ dictWord{135, 11, 262},
+ dictWord{132, 10, 588},
+ dictWord{133, 11, 620},
+ dictWord{5, 0, 977},
+ dictWord{
+ 6,
+ 0,
+ 288,
+ },
+ dictWord{7, 0, 528},
+ dictWord{4, 11, 34},
+ dictWord{5, 11, 574},
+ dictWord{7, 11, 279},
+ dictWord{7, 11, 1624},
+ dictWord{136, 11, 601},
+ dictWord{
+ 6,
+ 0,
+ 1375,
+ },
+ dictWord{4, 10, 231},
+ dictWord{5, 10, 61},
+ dictWord{6, 10, 104},
+ dictWord{7, 10, 729},
+ dictWord{7, 10, 964},
+ dictWord{7, 10, 1658},
+ dictWord{
+ 140,
+ 10,
+ 414,
+ },
+ dictWord{6, 10, 263},
+ dictWord{138, 10, 757},
+ dictWord{132, 10, 320},
+ dictWord{4, 0, 254},
+ dictWord{7, 0, 1309},
+ dictWord{5, 11, 332},
+ dictWord{
+ 135,
+ 11,
+ 1309,
+ },
+ dictWord{6, 11, 261},
+ dictWord{8, 11, 182},
+ dictWord{139, 11, 943},
+ dictWord{132, 10, 225},
+ dictWord{6, 0, 12},
+ dictWord{135, 0, 1219},
+ dictWord{4, 0, 275},
+ dictWord{12, 0, 376},
+ dictWord{6, 11, 1721},
+ dictWord{141, 11, 490},
+ dictWord{4, 11, 933},
+ dictWord{133, 11, 880},
+ dictWord{6, 0, 951},
+ dictWord{6, 0, 1109},
+ dictWord{6, 0, 1181},
+ dictWord{7, 0, 154},
+ dictWord{4, 10, 405},
+ dictWord{7, 10, 817},
+ dictWord{14, 10, 58},
+ dictWord{17, 10, 37},
+ dictWord{
+ 146,
+ 10,
+ 124,
+ },
+ dictWord{6, 0, 1520},
+ dictWord{133, 10, 974},
+ dictWord{134, 0, 1753},
+ dictWord{6, 0, 369},
+ dictWord{6, 0, 502},
+ dictWord{7, 0, 1036},
+ dictWord{
+ 8,
+ 0,
+ 348,
+ },
+ dictWord{9, 0, 452},
+ dictWord{10, 0, 26},
+ dictWord{11, 0, 224},
+ dictWord{11, 0, 387},
+ dictWord{11, 0, 772},
+ dictWord{12, 0, 95},
+ dictWord{12, 0, 629},
+ dictWord{13, 0, 195},
+ dictWord{13, 0, 207},
+ dictWord{13, 0, 241},
+ dictWord{14, 0, 260},
+ dictWord{14, 0, 270},
+ dictWord{143, 0, 140},
+ dictWord{132, 0, 269},
+ dictWord{5, 0, 480},
+ dictWord{7, 0, 532},
+ dictWord{7, 0, 1197},
+ dictWord{7, 0, 1358},
+ dictWord{8, 0, 291},
+ dictWord{11, 0, 349},
+ dictWord{142, 0, 396},
+ dictWord{
+ 5,
+ 10,
+ 235,
+ },
+ dictWord{7, 10, 1239},
+ dictWord{11, 10, 131},
+ dictWord{140, 10, 370},
+ dictWord{7, 10, 956},
+ dictWord{7, 10, 1157},
+ dictWord{7, 10, 1506},
+ dictWord{
+ 7,
+ 10,
+ 1606,
+ },
+ dictWord{7, 10, 1615},
+ dictWord{7, 10, 1619},
+ dictWord{7, 10, 1736},
+ dictWord{7, 10, 1775},
+ dictWord{8, 10, 590},
+ dictWord{9, 10, 324},
+ dictWord{9, 10, 736},
+ dictWord{9, 10, 774},
+ dictWord{9, 10, 776},
+ dictWord{9, 10, 784},
+ dictWord{10, 10, 567},
+ dictWord{10, 10, 708},
+ dictWord{11, 10, 518},
+ dictWord{11, 10, 613},
+ dictWord{11, 10, 695},
+ dictWord{11, 10, 716},
+ dictWord{11, 10, 739},
+ dictWord{11, 10, 770},
+ dictWord{11, 10, 771},
+ dictWord{
+ 11,
+ 10,
+ 848,
+ },
+ dictWord{11, 10, 857},
+ dictWord{11, 10, 931},
+ dictWord{11, 10, 947},
+ dictWord{12, 10, 326},
+ dictWord{12, 10, 387},
+ dictWord{12, 10, 484},
+ dictWord{
+ 12,
+ 10,
+ 528,
+ },
+ dictWord{12, 10, 552},
+ dictWord{12, 10, 613},
+ dictWord{13, 10, 189},
+ dictWord{13, 10, 256},
+ dictWord{13, 10, 340},
+ dictWord{13, 10, 432},
+ dictWord{13, 10, 436},
+ dictWord{13, 10, 440},
+ dictWord{13, 10, 454},
+ dictWord{14, 10, 174},
+ dictWord{14, 10, 220},
+ dictWord{14, 10, 284},
+ dictWord{
+ 14,
+ 10,
+ 390,
+ },
+ dictWord{145, 10, 121},
+ dictWord{8, 11, 598},
+ dictWord{9, 11, 664},
+ dictWord{138, 11, 441},
+ dictWord{9, 10, 137},
+ dictWord{138, 10, 221},
+ dictWord{133, 11, 812},
+ dictWord{148, 0, 15},
+ dictWord{134, 0, 1341},
+ dictWord{6, 0, 1017},
+ dictWord{4, 11, 137},
+ dictWord{7, 11, 1178},
+ dictWord{
+ 135,
+ 11,
+ 1520,
+ },
+ dictWord{7, 10, 390},
+ dictWord{138, 10, 140},
+ dictWord{7, 11, 1260},
+ dictWord{135, 11, 1790},
+ dictWord{137, 11, 191},
+ dictWord{
+ 135,
+ 10,
+ 1144,
+ },
+ dictWord{6, 0, 1810},
+ dictWord{7, 0, 657},
+ dictWord{8, 0, 886},
+ dictWord{10, 0, 857},
+ dictWord{14, 0, 440},
+ dictWord{144, 0, 96},
+ dictWord{8, 0, 533},
+ dictWord{6, 11, 1661},
+ dictWord{7, 11, 1975},
+ dictWord{7, 11, 2009},
+ dictWord{135, 11, 2011},
+ dictWord{6, 0, 1453},
+ dictWord{134, 10, 464},
+ dictWord{
+ 132,
+ 11,
+ 715,
+ },
+ dictWord{5, 10, 407},
+ dictWord{11, 10, 204},
+ dictWord{11, 10, 243},
+ dictWord{11, 10, 489},
+ dictWord{12, 10, 293},
+ dictWord{19, 10, 37},
+ dictWord{20, 10, 73},
+ dictWord{150, 10, 38},
+ dictWord{133, 11, 703},
+ dictWord{4, 0, 211},
+ dictWord{7, 0, 1483},
+ dictWord{5, 10, 325},
+ dictWord{8, 10, 5},
+ dictWord{
+ 8,
+ 10,
+ 227,
+ },
+ dictWord{9, 10, 105},
+ dictWord{10, 10, 585},
+ dictWord{140, 10, 614},
+ dictWord{4, 0, 332},
+ dictWord{5, 0, 335},
+ dictWord{6, 0, 238},
+ dictWord{
+ 7,
+ 0,
+ 269,
+ },
+ dictWord{7, 0, 811},
+ dictWord{7, 0, 1797},
+ dictWord{8, 0, 836},
+ dictWord{9, 0, 507},
+ dictWord{141, 0, 242},
+ dictWord{5, 11, 89},
+ dictWord{7, 11, 1915},
+ dictWord{9, 11, 185},
+ dictWord{9, 11, 235},
+ dictWord{9, 11, 496},
+ dictWord{10, 11, 64},
+ dictWord{10, 11, 270},
+ dictWord{10, 11, 403},
+ dictWord{10, 11, 469},
+ dictWord{10, 11, 529},
+ dictWord{10, 11, 590},
+ dictWord{11, 11, 140},
+ dictWord{11, 11, 860},
+ dictWord{13, 11, 1},
+ dictWord{13, 11, 422},
+ dictWord{14, 11, 341},
+ dictWord{14, 11, 364},
+ dictWord{17, 11, 93},
+ dictWord{18, 11, 113},
+ dictWord{19, 11, 97},
+ dictWord{147, 11, 113},
+ dictWord{133, 11, 695},
+ dictWord{
+ 16,
+ 0,
+ 19,
+ },
+ dictWord{5, 11, 6},
+ dictWord{6, 11, 183},
+ dictWord{6, 10, 621},
+ dictWord{7, 11, 680},
+ dictWord{7, 11, 978},
+ dictWord{7, 11, 1013},
+ dictWord{7, 11, 1055},
+ dictWord{12, 11, 230},
+ dictWord{13, 11, 172},
+ dictWord{13, 10, 504},
+ dictWord{146, 11, 29},
+ dictWord{136, 0, 156},
+ dictWord{133, 0, 1009},
+ dictWord{
+ 6,
+ 11,
+ 29,
+ },
+ dictWord{139, 11, 63},
+ dictWord{134, 0, 820},
+ dictWord{134, 10, 218},
+ dictWord{7, 10, 454},
+ dictWord{7, 10, 782},
+ dictWord{8, 10, 768},
+ dictWord{
+ 140,
+ 10,
+ 686,
+ },
+ dictWord{5, 0, 228},
+ dictWord{6, 0, 203},
+ dictWord{7, 0, 156},
+ dictWord{8, 0, 347},
+ dictWord{9, 0, 265},
+ dictWord{18, 0, 39},
+ dictWord{20, 0, 54},
+ dictWord{21, 0, 31},
+ dictWord{22, 0, 3},
+ dictWord{23, 0, 0},
+ dictWord{15, 11, 8},
+ dictWord{18, 11, 39},
+ dictWord{20, 11, 54},
+ dictWord{21, 11, 31},
+ dictWord{22, 11, 3},
+ dictWord{151, 11, 0},
+ dictWord{7, 0, 1131},
+ dictWord{135, 0, 1468},
+ dictWord{144, 10, 0},
+ dictWord{134, 0, 1276},
+ dictWord{10, 10, 676},
+ dictWord{
+ 140,
+ 10,
+ 462,
+ },
+ dictWord{132, 11, 311},
+ dictWord{134, 11, 1740},
+ dictWord{7, 11, 170},
+ dictWord{8, 11, 90},
+ dictWord{8, 11, 177},
+ dictWord{8, 11, 415},
+ dictWord{
+ 11,
+ 11,
+ 714,
+ },
+ dictWord{142, 11, 281},
+ dictWord{134, 10, 164},
+ dictWord{6, 0, 1792},
+ dictWord{138, 0, 849},
+ dictWord{150, 10, 50},
+ dictWord{5, 0, 291},
+ dictWord{5, 0, 318},
+ dictWord{7, 0, 765},
+ dictWord{9, 0, 389},
+ dictWord{12, 0, 548},
+ dictWord{8, 11, 522},
+ dictWord{142, 11, 328},
+ dictWord{11, 11, 91},
+ dictWord{
+ 13,
+ 11,
+ 129,
+ },
+ dictWord{15, 11, 101},
+ dictWord{145, 11, 125},
+ dictWord{4, 11, 494},
+ dictWord{6, 11, 74},
+ dictWord{7, 11, 44},
+ dictWord{7, 11, 407},
+ dictWord{
+ 8,
+ 11,
+ 551,
+ },
+ dictWord{12, 11, 17},
+ dictWord{15, 11, 5},
+ dictWord{148, 11, 11},
+ dictWord{4, 11, 276},
+ dictWord{133, 11, 296},
+ dictWord{6, 10, 343},
+ dictWord{
+ 7,
+ 10,
+ 195,
+ },
+ dictWord{7, 11, 1777},
+ dictWord{9, 10, 226},
+ dictWord{10, 10, 197},
+ dictWord{10, 10, 575},
+ dictWord{11, 10, 502},
+ dictWord{139, 10, 899},
+ dictWord{
+ 10,
+ 0,
+ 525,
+ },
+ dictWord{139, 0, 82},
+ dictWord{14, 0, 453},
+ dictWord{4, 11, 7},
+ dictWord{5, 11, 90},
+ dictWord{5, 11, 158},
+ dictWord{6, 11, 542},
+ dictWord{7, 11, 221},
+ dictWord{7, 11, 1574},
+ dictWord{9, 11, 490},
+ dictWord{10, 11, 540},
+ dictWord{11, 11, 443},
+ dictWord{139, 11, 757},
+ dictWord{135, 0, 666},
+ dictWord{
+ 22,
+ 10,
+ 29,
+ },
+ dictWord{150, 11, 29},
+ dictWord{4, 0, 422},
+ dictWord{147, 10, 8},
+ dictWord{5, 0, 355},
+ dictWord{145, 0, 0},
+ dictWord{6, 0, 1873},
+ dictWord{9, 0, 918},
+ dictWord{7, 11, 588},
+ dictWord{9, 11, 175},
+ dictWord{138, 11, 530},
+ dictWord{143, 11, 31},
+ dictWord{11, 0, 165},
+ dictWord{7, 10, 1125},
+ dictWord{9, 10, 143},
+ dictWord{14, 10, 405},
+ dictWord{150, 10, 21},
+ dictWord{9, 0, 260},
+ dictWord{137, 0, 905},
+ dictWord{5, 11, 872},
+ dictWord{6, 11, 57},
+ dictWord{6, 11, 479},
+ dictWord{
+ 6,
+ 11,
+ 562,
+ },
+ dictWord{7, 11, 471},
+ dictWord{7, 11, 1060},
+ dictWord{9, 11, 447},
+ dictWord{9, 11, 454},
+ dictWord{141, 11, 6},
+ dictWord{138, 11, 704},
+ dictWord{133, 0, 865},
+ dictWord{5, 0, 914},
+ dictWord{134, 0, 1625},
+ dictWord{133, 0, 234},
+ dictWord{7, 0, 1383},
+ dictWord{5, 11, 31},
+ dictWord{6, 11, 614},
+ dictWord{145, 11, 61},
+ dictWord{7, 11, 1200},
+ dictWord{138, 11, 460},
+ dictWord{6, 11, 424},
+ dictWord{135, 11, 1866},
+ dictWord{136, 0, 306},
+ dictWord{
+ 5,
+ 10,
+ 959,
+ },
+ dictWord{12, 11, 30},
+ dictWord{13, 11, 148},
+ dictWord{14, 11, 87},
+ dictWord{14, 11, 182},
+ dictWord{16, 11, 42},
+ dictWord{18, 11, 92},
+ dictWord{
+ 148,
+ 11,
+ 70,
+ },
+ dictWord{6, 0, 1919},
+ dictWord{6, 0, 1921},
+ dictWord{9, 0, 923},
+ dictWord{9, 0, 930},
+ dictWord{9, 0, 941},
+ dictWord{9, 0, 949},
+ dictWord{9, 0, 987},
+ dictWord{
+ 9,
+ 0,
+ 988,
+ },
+ dictWord{9, 0, 992},
+ dictWord{12, 0, 802},
+ dictWord{12, 0, 815},
+ dictWord{12, 0, 856},
+ dictWord{12, 0, 885},
+ dictWord{12, 0, 893},
+ dictWord{
+ 12,
+ 0,
+ 898,
+ },
+ dictWord{12, 0, 919},
+ dictWord{12, 0, 920},
+ dictWord{12, 0, 941},
+ dictWord{12, 0, 947},
+ dictWord{15, 0, 183},
+ dictWord{15, 0, 185},
+ dictWord{15, 0, 189},
+ dictWord{15, 0, 197},
+ dictWord{15, 0, 202},
+ dictWord{15, 0, 233},
+ dictWord{18, 0, 218},
+ dictWord{18, 0, 219},
+ dictWord{18, 0, 233},
+ dictWord{143, 11, 156},
+ dictWord{135, 10, 1759},
+ dictWord{136, 10, 173},
+ dictWord{13, 0, 163},
+ dictWord{13, 0, 180},
+ dictWord{18, 0, 78},
+ dictWord{20, 0, 35},
+ dictWord{5, 11, 13},
+ dictWord{134, 11, 142},
+ dictWord{134, 10, 266},
+ dictWord{6, 11, 97},
+ dictWord{7, 11, 116},
+ dictWord{8, 11, 322},
+ dictWord{8, 11, 755},
+ dictWord{9, 11, 548},
+ dictWord{10, 11, 714},
+ dictWord{11, 11, 884},
+ dictWord{141, 11, 324},
+ dictWord{135, 0, 1312},
+ dictWord{9, 0, 814},
+ dictWord{137, 11, 676},
+ dictWord{
+ 133,
+ 0,
+ 707,
+ },
+ dictWord{135, 0, 1493},
+ dictWord{6, 0, 421},
+ dictWord{7, 0, 61},
+ dictWord{7, 0, 1540},
+ dictWord{10, 0, 11},
+ dictWord{138, 0, 501},
+ dictWord{12, 0, 733},
+ dictWord{12, 0, 766},
+ dictWord{7, 11, 866},
+ dictWord{135, 11, 1163},
+ dictWord{137, 0, 341},
+ dictWord{142, 0, 98},
+ dictWord{145, 11, 115},
+ dictWord{
+ 135,
+ 11,
+ 1111,
+ },
+ dictWord{136, 10, 300},
+ dictWord{136, 0, 1014},
+ dictWord{8, 11, 1},
+ dictWord{9, 11, 112},
+ dictWord{138, 11, 326},
+ dictWord{132, 11, 730},
+ dictWord{5, 11, 488},
+ dictWord{6, 11, 527},
+ dictWord{7, 11, 489},
+ dictWord{7, 11, 1636},
+ dictWord{8, 11, 121},
+ dictWord{8, 11, 144},
+ dictWord{8, 11, 359},
+ dictWord{
+ 9,
+ 11,
+ 193,
+ },
+ dictWord{9, 11, 241},
+ dictWord{9, 11, 336},
+ dictWord{9, 11, 882},
+ dictWord{11, 11, 266},
+ dictWord{11, 11, 372},
+ dictWord{11, 11, 944},
+ dictWord{
+ 12,
+ 11,
+ 401,
+ },
+ dictWord{140, 11, 641},
+ dictWord{6, 0, 971},
+ dictWord{134, 0, 1121},
+ dictWord{6, 0, 102},
+ dictWord{7, 0, 72},
+ dictWord{15, 0, 142},
+ dictWord{
+ 147,
+ 0,
+ 67,
+ },
+ dictWord{151, 0, 30},
+ dictWord{135, 0, 823},
+ dictWord{134, 0, 1045},
+ dictWord{5, 10, 427},
+ dictWord{5, 10, 734},
+ dictWord{7, 10, 478},
+ dictWord{
+ 136,
+ 10,
+ 52,
+ },
+ dictWord{7, 0, 1930},
+ dictWord{11, 10, 217},
+ dictWord{142, 10, 165},
+ dictWord{6, 0, 1512},
+ dictWord{135, 0, 1870},
+ dictWord{9, 11, 31},
+ dictWord{
+ 10,
+ 11,
+ 244,
+ },
+ dictWord{10, 11, 699},
+ dictWord{12, 11, 149},
+ dictWord{141, 11, 497},
+ dictWord{133, 11, 377},
+ dictWord{145, 11, 101},
+ dictWord{
+ 10,
+ 11,
+ 158,
+ },
+ dictWord{13, 11, 13},
+ dictWord{13, 11, 137},
+ dictWord{13, 11, 258},
+ dictWord{14, 11, 111},
+ dictWord{14, 11, 225},
+ dictWord{14, 11, 253},
+ dictWord{
+ 14,
+ 11,
+ 304,
+ },
+ dictWord{14, 11, 339},
+ dictWord{14, 11, 417},
+ dictWord{146, 11, 33},
+ dictWord{6, 0, 87},
+ dictWord{6, 10, 1734},
+ dictWord{7, 10, 20},
+ dictWord{
+ 7,
+ 10,
+ 1056,
+ },
+ dictWord{8, 10, 732},
+ dictWord{9, 10, 406},
+ dictWord{9, 10, 911},
+ dictWord{138, 10, 694},
+ dictWord{134, 0, 1243},
+ dictWord{137, 0, 245},
+ dictWord{
+ 7,
+ 0,
+ 68,
+ },
+ dictWord{8, 0, 48},
+ dictWord{8, 0, 88},
+ dictWord{8, 0, 582},
+ dictWord{8, 0, 681},
+ dictWord{9, 0, 373},
+ dictWord{9, 0, 864},
+ dictWord{11, 0, 157},
+ dictWord{
+ 11,
+ 0,
+ 336,
+ },
+ dictWord{11, 0, 843},
+ dictWord{148, 0, 27},
+ dictWord{8, 11, 663},
+ dictWord{144, 11, 8},
+ dictWord{133, 10, 613},
+ dictWord{4, 0, 88},
+ dictWord{
+ 5,
+ 0,
+ 137,
+ },
+ dictWord{5, 0, 174},
+ dictWord{5, 0, 777},
+ dictWord{6, 0, 1664},
+ dictWord{6, 0, 1725},
+ dictWord{7, 0, 77},
+ dictWord{7, 0, 426},
+ dictWord{7, 0, 1317},
+ dictWord{
+ 7,
+ 0,
+ 1355,
+ },
+ dictWord{8, 0, 126},
+ dictWord{8, 0, 563},
+ dictWord{9, 0, 523},
+ dictWord{9, 0, 750},
+ dictWord{10, 0, 310},
+ dictWord{10, 0, 836},
+ dictWord{11, 0, 42},
+ dictWord{11, 0, 318},
+ dictWord{11, 0, 731},
+ dictWord{12, 0, 68},
+ dictWord{12, 0, 92},
+ dictWord{12, 0, 507},
+ dictWord{12, 0, 692},
+ dictWord{13, 0, 81},
+ dictWord{
+ 13,
+ 0,
+ 238,
+ },
+ dictWord{13, 0, 374},
+ dictWord{14, 0, 436},
+ dictWord{18, 0, 138},
+ dictWord{19, 0, 78},
+ dictWord{19, 0, 111},
+ dictWord{20, 0, 55},
+ dictWord{20, 0, 77},
+ dictWord{148, 0, 92},
+ dictWord{141, 0, 418},
+ dictWord{4, 0, 938},
+ dictWord{137, 0, 625},
+ dictWord{138, 0, 351},
+ dictWord{5, 11, 843},
+ dictWord{7, 10, 32},
+ dictWord{
+ 7,
+ 10,
+ 984,
+ },
+ dictWord{8, 10, 85},
+ dictWord{8, 10, 709},
+ dictWord{9, 10, 579},
+ dictWord{9, 10, 847},
+ dictWord{9, 10, 856},
+ dictWord{10, 10, 799},
+ dictWord{
+ 11,
+ 10,
+ 258,
+ },
+ dictWord{11, 10, 1007},
+ dictWord{12, 10, 331},
+ dictWord{12, 10, 615},
+ dictWord{13, 10, 188},
+ dictWord{13, 10, 435},
+ dictWord{14, 10, 8},
+ dictWord{
+ 15,
+ 10,
+ 165,
+ },
+ dictWord{16, 10, 27},
+ dictWord{148, 10, 40},
+ dictWord{6, 0, 1668},
+ dictWord{7, 0, 1499},
+ dictWord{8, 0, 117},
+ dictWord{9, 0, 314},
+ dictWord{
+ 138,
+ 0,
+ 174,
+ },
+ dictWord{135, 0, 707},
+ dictWord{132, 11, 554},
+ dictWord{133, 11, 536},
+ dictWord{5, 0, 403},
+ dictWord{5, 11, 207},
+ dictWord{9, 11, 79},
+ dictWord{
+ 11,
+ 11,
+ 625,
+ },
+ dictWord{145, 11, 7},
+ dictWord{132, 11, 424},
+ dictWord{136, 11, 785},
+ dictWord{4, 10, 167},
+ dictWord{135, 10, 82},
+ dictWord{9, 0, 7},
+ dictWord{
+ 23,
+ 0,
+ 6,
+ },
+ dictWord{9, 11, 7},
+ dictWord{151, 11, 6},
+ dictWord{6, 0, 282},
+ dictWord{5, 10, 62},
+ dictWord{6, 10, 534},
+ dictWord{7, 10, 74},
+ dictWord{7, 10, 678},
+ dictWord{
+ 7,
+ 10,
+ 684,
+ },
+ dictWord{7, 10, 1043},
+ dictWord{7, 10, 1072},
+ dictWord{8, 10, 280},
+ dictWord{8, 10, 541},
+ dictWord{8, 10, 686},
+ dictWord{9, 10, 258},
+ dictWord{
+ 10,
+ 10,
+ 519,
+ },
+ dictWord{11, 10, 252},
+ dictWord{140, 10, 282},
+ dictWord{138, 10, 33},
+ dictWord{132, 10, 359},
+ dictWord{4, 0, 44},
+ dictWord{5, 0, 311},
+ dictWord{
+ 6,
+ 0,
+ 156,
+ },
+ dictWord{7, 0, 639},
+ dictWord{7, 0, 762},
+ dictWord{7, 0, 1827},
+ dictWord{9, 0, 8},
+ dictWord{9, 0, 462},
+ dictWord{148, 0, 83},
+ dictWord{7, 11, 769},
+ dictWord{
+ 9,
+ 11,
+ 18,
+ },
+ dictWord{138, 11, 358},
+ dictWord{4, 0, 346},
+ dictWord{7, 0, 115},
+ dictWord{9, 0, 180},
+ dictWord{9, 0, 456},
+ dictWord{10, 0, 363},
+ dictWord{
+ 4,
+ 11,
+ 896,
+ },
+ dictWord{134, 11, 1777},
+ dictWord{133, 10, 211},
+ dictWord{7, 0, 761},
+ dictWord{7, 0, 1051},
+ dictWord{137, 0, 545},
+ dictWord{6, 10, 145},
+ dictWord{
+ 141,
+ 10,
+ 336,
+ },
+ dictWord{7, 11, 750},
+ dictWord{9, 11, 223},
+ dictWord{11, 11, 27},
+ dictWord{11, 11, 466},
+ dictWord{12, 11, 624},
+ dictWord{14, 11, 265},
+ dictWord{146, 11, 61},
+ dictWord{6, 0, 752},
+ dictWord{6, 0, 768},
+ dictWord{6, 0, 1195},
+ dictWord{6, 0, 1254},
+ dictWord{6, 0, 1619},
+ dictWord{137, 0, 835},
+ dictWord{
+ 6,
+ 0,
+ 1936,
+ },
+ dictWord{8, 0, 930},
+ dictWord{136, 0, 960},
+ dictWord{132, 10, 263},
+ dictWord{132, 11, 249},
+ dictWord{12, 0, 653},
+ dictWord{132, 10, 916},
+ dictWord{4, 11, 603},
+ dictWord{133, 11, 661},
+ dictWord{8, 0, 344},
+ dictWord{4, 11, 11},
+ dictWord{6, 11, 128},
+ dictWord{7, 11, 231},
+ dictWord{7, 11, 1533},
+ dictWord{138, 11, 725},
+ dictWord{134, 0, 1483},
+ dictWord{134, 0, 875},
+ dictWord{6, 0, 185},
+ dictWord{7, 0, 1899},
+ dictWord{9, 0, 875},
+ dictWord{139, 0, 673},
+ dictWord{15, 10, 155},
+ dictWord{144, 10, 79},
+ dictWord{7, 0, 93},
+ dictWord{7, 0, 210},
+ dictWord{7, 0, 1223},
+ dictWord{8, 0, 451},
+ dictWord{8, 0, 460},
+ dictWord{
+ 11,
+ 0,
+ 353,
+ },
+ dictWord{11, 0, 475},
+ dictWord{4, 10, 599},
+ dictWord{6, 10, 1634},
+ dictWord{7, 10, 67},
+ dictWord{7, 10, 691},
+ dictWord{7, 10, 979},
+ dictWord{
+ 7,
+ 10,
+ 1697,
+ },
+ dictWord{8, 10, 207},
+ dictWord{8, 10, 214},
+ dictWord{8, 10, 231},
+ dictWord{8, 10, 294},
+ dictWord{8, 10, 336},
+ dictWord{8, 10, 428},
+ dictWord{
+ 8,
+ 10,
+ 471,
+ },
+ dictWord{8, 10, 622},
+ dictWord{8, 10, 626},
+ dictWord{8, 10, 679},
+ dictWord{8, 10, 759},
+ dictWord{8, 10, 829},
+ dictWord{9, 10, 11},
+ dictWord{9, 10, 246},
+ dictWord{9, 10, 484},
+ dictWord{9, 10, 573},
+ dictWord{9, 10, 706},
+ dictWord{9, 10, 762},
+ dictWord{9, 10, 798},
+ dictWord{9, 10, 855},
+ dictWord{9, 10, 870},
+ dictWord{
+ 9,
+ 10,
+ 912,
+ },
+ dictWord{10, 10, 303},
+ dictWord{10, 10, 335},
+ dictWord{10, 10, 424},
+ dictWord{10, 10, 461},
+ dictWord{10, 10, 543},
+ dictWord{10, 10, 759},
+ dictWord{10, 10, 814},
+ dictWord{11, 10, 59},
+ dictWord{11, 10, 235},
+ dictWord{11, 10, 590},
+ dictWord{11, 10, 929},
+ dictWord{11, 10, 963},
+ dictWord{
+ 11,
+ 10,
+ 987,
+ },
+ dictWord{12, 10, 114},
+ dictWord{12, 10, 182},
+ dictWord{12, 10, 226},
+ dictWord{12, 10, 332},
+ dictWord{12, 10, 439},
+ dictWord{12, 10, 575},
+ dictWord{
+ 12,
+ 10,
+ 598,
+ },
+ dictWord{12, 10, 675},
+ dictWord{13, 10, 8},
+ dictWord{13, 10, 125},
+ dictWord{13, 10, 194},
+ dictWord{13, 10, 287},
+ dictWord{14, 10, 197},
+ dictWord{14, 10, 383},
+ dictWord{15, 10, 53},
+ dictWord{17, 10, 63},
+ dictWord{19, 10, 46},
+ dictWord{19, 10, 98},
+ dictWord{19, 10, 106},
+ dictWord{148, 10, 85},
+ dictWord{132, 11, 476},
+ dictWord{4, 0, 327},
+ dictWord{5, 0, 478},
+ dictWord{7, 0, 1332},
+ dictWord{136, 0, 753},
+ dictWord{5, 0, 1020},
+ dictWord{133, 0, 1022},
+ dictWord{135, 11, 1807},
+ dictWord{4, 0, 103},
+ dictWord{133, 0, 401},
+ dictWord{4, 0, 499},
+ dictWord{135, 0, 1421},
+ dictWord{10, 0, 207},
+ dictWord{13, 0, 164},
+ dictWord{147, 10, 126},
+ dictWord{9, 11, 20},
+ dictWord{10, 11, 324},
+ dictWord{139, 11, 488},
+ dictWord{132, 0, 96},
+ dictWord{9, 11, 280},
+ dictWord{
+ 138,
+ 11,
+ 134,
+ },
+ dictWord{135, 0, 968},
+ dictWord{133, 10, 187},
+ dictWord{135, 10, 1286},
+ dictWord{5, 11, 112},
+ dictWord{6, 11, 103},
+ dictWord{134, 11, 150},
+ dictWord{8, 0, 914},
+ dictWord{10, 0, 3},
+ dictWord{4, 10, 215},
+ dictWord{9, 10, 38},
+ dictWord{11, 10, 23},
+ dictWord{11, 10, 127},
+ dictWord{139, 10, 796},
+ dictWord{
+ 135,
+ 0,
+ 399,
+ },
+ dictWord{6, 0, 563},
+ dictWord{137, 0, 224},
+ dictWord{6, 0, 704},
+ dictWord{134, 0, 1214},
+ dictWord{4, 11, 708},
+ dictWord{8, 11, 15},
+ dictWord{
+ 9,
+ 11,
+ 50,
+ },
+ dictWord{9, 11, 386},
+ dictWord{11, 11, 18},
+ dictWord{11, 11, 529},
+ dictWord{140, 11, 228},
+ dictWord{4, 11, 563},
+ dictWord{7, 11, 109},
+ dictWord{
+ 7,
+ 11,
+ 592,
+ },
+ dictWord{7, 11, 637},
+ dictWord{7, 11, 770},
+ dictWord{7, 11, 1701},
+ dictWord{8, 11, 436},
+ dictWord{8, 11, 463},
+ dictWord{9, 11, 60},
+ dictWord{9, 11, 335},
+ dictWord{9, 11, 904},
+ dictWord{10, 11, 73},
+ dictWord{11, 11, 434},
+ dictWord{12, 11, 585},
+ dictWord{13, 11, 331},
+ dictWord{18, 11, 110},
+ dictWord{
+ 148,
+ 11,
+ 60,
+ },
+ dictWord{134, 0, 1559},
+ dictWord{132, 11, 502},
+ dictWord{6, 11, 347},
+ dictWord{138, 11, 161},
+ dictWord{4, 11, 33},
+ dictWord{5, 11, 102},
+ dictWord{
+ 5,
+ 11,
+ 500,
+ },
+ dictWord{6, 11, 284},
+ dictWord{7, 11, 1079},
+ dictWord{7, 11, 1423},
+ dictWord{7, 11, 1702},
+ dictWord{8, 11, 470},
+ dictWord{9, 11, 554},
+ dictWord{
+ 9,
+ 11,
+ 723,
+ },
+ dictWord{139, 11, 333},
+ dictWord{7, 11, 246},
+ dictWord{135, 11, 840},
+ dictWord{6, 11, 10},
+ dictWord{8, 11, 571},
+ dictWord{9, 11, 739},
+ dictWord{
+ 143,
+ 11,
+ 91,
+ },
+ dictWord{8, 0, 861},
+ dictWord{10, 0, 905},
+ dictWord{12, 0, 730},
+ dictWord{12, 0, 789},
+ dictWord{133, 11, 626},
+ dictWord{134, 0, 946},
+ dictWord{
+ 5,
+ 0,
+ 746,
+ },
+ dictWord{12, 0, 333},
+ dictWord{14, 0, 332},
+ dictWord{12, 11, 333},
+ dictWord{142, 11, 332},
+ dictWord{5, 11, 18},
+ dictWord{6, 11, 526},
+ dictWord{
+ 13,
+ 11,
+ 24,
+ },
+ dictWord{13, 11, 110},
+ dictWord{19, 11, 5},
+ dictWord{147, 11, 44},
+ dictWord{4, 0, 910},
+ dictWord{5, 0, 832},
+ dictWord{135, 10, 2002},
+ dictWord{
+ 10,
+ 11,
+ 768,
+ },
+ dictWord{139, 11, 787},
+ dictWord{4, 11, 309},
+ dictWord{5, 11, 462},
+ dictWord{7, 11, 970},
+ dictWord{135, 11, 1097},
+ dictWord{4, 10, 28},
+ dictWord{
+ 5,
+ 10,
+ 440,
+ },
+ dictWord{7, 10, 248},
+ dictWord{11, 10, 833},
+ dictWord{140, 10, 344},
+ dictWord{134, 10, 1654},
+ dictWord{6, 0, 632},
+ dictWord{6, 0, 652},
+ dictWord{
+ 6,
+ 0,
+ 1272,
+ },
+ dictWord{6, 0, 1384},
+ dictWord{134, 0, 1560},
+ dictWord{134, 11, 1704},
+ dictWord{6, 0, 1393},
+ dictWord{133, 10, 853},
+ dictWord{6, 10, 249},
+ dictWord{7, 10, 1234},
+ dictWord{139, 10, 573},
+ dictWord{5, 11, 86},
+ dictWord{7, 11, 743},
+ dictWord{9, 11, 85},
+ dictWord{10, 11, 281},
+ dictWord{10, 11, 432},
+ dictWord{11, 11, 490},
+ dictWord{12, 11, 251},
+ dictWord{13, 11, 118},
+ dictWord{14, 11, 378},
+ dictWord{146, 11, 143},
+ dictWord{5, 11, 524},
+ dictWord{
+ 133,
+ 11,
+ 744,
+ },
+ dictWord{134, 0, 1514},
+ dictWord{10, 0, 201},
+ dictWord{142, 0, 319},
+ dictWord{7, 0, 717},
+ dictWord{10, 0, 510},
+ dictWord{7, 10, 392},
+ dictWord{
+ 8,
+ 10,
+ 20,
+ },
+ dictWord{8, 10, 172},
+ dictWord{8, 10, 690},
+ dictWord{9, 10, 383},
+ dictWord{9, 10, 845},
+ dictWord{11, 10, 293},
+ dictWord{11, 10, 832},
+ dictWord{
+ 11,
+ 10,
+ 920,
+ },
+ dictWord{11, 10, 984},
+ dictWord{141, 10, 221},
+ dictWord{134, 0, 1381},
+ dictWord{5, 10, 858},
+ dictWord{133, 10, 992},
+ dictWord{8, 0, 528},
+ dictWord{137, 0, 348},
+ dictWord{10, 11, 107},
+ dictWord{140, 11, 436},
+ dictWord{4, 0, 20},
+ dictWord{133, 0, 616},
+ dictWord{134, 0, 1251},
+ dictWord{
+ 132,
+ 11,
+ 927,
+ },
+ dictWord{10, 11, 123},
+ dictWord{12, 11, 670},
+ dictWord{13, 11, 371},
+ dictWord{14, 11, 142},
+ dictWord{146, 11, 94},
+ dictWord{134, 0, 1163},
+ dictWord{
+ 7,
+ 11,
+ 1149,
+ },
+ dictWord{137, 11, 156},
+ dictWord{134, 0, 307},
+ dictWord{133, 11, 778},
+ dictWord{7, 0, 1091},
+ dictWord{135, 0, 1765},
+ dictWord{
+ 5,
+ 11,
+ 502,
+ },
+ dictWord{6, 10, 268},
+ dictWord{137, 10, 62},
+ dictWord{8, 11, 196},
+ dictWord{10, 11, 283},
+ dictWord{139, 11, 406},
+ dictWord{4, 0, 26},
+ dictWord{
+ 5,
+ 0,
+ 429,
+ },
+ dictWord{6, 0, 245},
+ dictWord{7, 0, 704},
+ dictWord{7, 0, 1379},
+ dictWord{135, 0, 1474},
+ dictWord{133, 11, 855},
+ dictWord{132, 0, 881},
+ dictWord{
+ 4,
+ 0,
+ 621,
+ },
+ dictWord{135, 11, 1596},
+ dictWord{7, 11, 1400},
+ dictWord{9, 11, 446},
+ dictWord{138, 11, 45},
+ dictWord{6, 0, 736},
+ dictWord{138, 10, 106},
+ dictWord{133, 0, 542},
+ dictWord{134, 0, 348},
+ dictWord{133, 0, 868},
+ dictWord{136, 0, 433},
+ dictWord{135, 0, 1495},
+ dictWord{138, 0, 771},
+ dictWord{
+ 6,
+ 10,
+ 613,
+ },
+ dictWord{136, 10, 223},
+ dictWord{138, 0, 215},
+ dictWord{141, 0, 124},
+ dictWord{136, 11, 391},
+ dictWord{135, 11, 172},
+ dictWord{132, 10, 670},
+ dictWord{140, 0, 55},
+ dictWord{9, 10, 40},
+ dictWord{139, 10, 136},
+ dictWord{7, 0, 62},
+ dictWord{147, 0, 112},
+ dictWord{132, 0, 856},
+ dictWord{132, 11, 568},
+ dictWord{12, 0, 270},
+ dictWord{139, 10, 259},
+ dictWord{8, 0, 572},
+ dictWord{137, 0, 698},
+ dictWord{4, 11, 732},
+ dictWord{9, 10, 310},
+ dictWord{137, 10, 682},
+ dictWord{142, 10, 296},
+ dictWord{134, 0, 939},
+ dictWord{136, 11, 733},
+ dictWord{135, 11, 1435},
+ dictWord{7, 10, 1401},
+ dictWord{135, 10, 1476},
+ dictWord{6, 0, 352},
+ dictWord{4, 10, 296},
+ dictWord{7, 10, 401},
+ dictWord{7, 10, 1410},
+ dictWord{7, 10, 1594},
+ dictWord{7, 10, 1674},
+ dictWord{8, 10, 63},
+ dictWord{
+ 8,
+ 10,
+ 660,
+ },
+ dictWord{137, 10, 74},
+ dictWord{4, 11, 428},
+ dictWord{133, 11, 668},
+ dictWord{4, 10, 139},
+ dictWord{4, 10, 388},
+ dictWord{140, 10, 188},
+ dictWord{7, 11, 2015},
+ dictWord{140, 11, 665},
+ dictWord{132, 0, 647},
+ dictWord{146, 0, 10},
+ dictWord{138, 0, 220},
+ dictWord{142, 0, 464},
+ dictWord{
+ 132,
+ 0,
+ 109,
+ },
+ dictWord{134, 0, 1746},
+ dictWord{6, 0, 515},
+ dictWord{4, 10, 747},
+ dictWord{6, 11, 1623},
+ dictWord{6, 11, 1681},
+ dictWord{7, 10, 649},
+ dictWord{
+ 7,
+ 10,
+ 1479,
+ },
+ dictWord{135, 10, 1583},
+ dictWord{133, 10, 232},
+ dictWord{135, 0, 566},
+ dictWord{137, 10, 887},
+ dictWord{4, 0, 40},
+ dictWord{10, 0, 67},
+ dictWord{
+ 11,
+ 0,
+ 117,
+ },
+ dictWord{11, 0, 768},
+ dictWord{139, 0, 935},
+ dictWord{132, 0, 801},
+ dictWord{7, 0, 992},
+ dictWord{8, 0, 301},
+ dictWord{9, 0, 722},
+ dictWord{
+ 12,
+ 0,
+ 63,
+ },
+ dictWord{13, 0, 29},
+ dictWord{14, 0, 161},
+ dictWord{143, 0, 18},
+ dictWord{139, 0, 923},
+ dictWord{6, 11, 1748},
+ dictWord{8, 11, 715},
+ dictWord{9, 11, 802},
+ dictWord{10, 11, 46},
+ dictWord{10, 11, 819},
+ dictWord{13, 11, 308},
+ dictWord{14, 11, 351},
+ dictWord{14, 11, 363},
+ dictWord{146, 11, 67},
+ dictWord{
+ 137,
+ 11,
+ 745,
+ },
+ dictWord{7, 0, 1145},
+ dictWord{4, 10, 14},
+ dictWord{7, 10, 1801},
+ dictWord{10, 10, 748},
+ dictWord{141, 10, 458},
+ dictWord{4, 11, 63},
+ dictWord{
+ 5,
+ 11,
+ 347,
+ },
+ dictWord{134, 11, 474},
+ dictWord{135, 0, 568},
+ dictWord{4, 10, 425},
+ dictWord{7, 11, 577},
+ dictWord{7, 11, 1432},
+ dictWord{9, 11, 475},
+ dictWord{
+ 9,
+ 11,
+ 505,
+ },
+ dictWord{9, 11, 526},
+ dictWord{9, 11, 609},
+ dictWord{9, 11, 689},
+ dictWord{9, 11, 726},
+ dictWord{9, 11, 735},
+ dictWord{9, 11, 738},
+ dictWord{
+ 10,
+ 11,
+ 556,
+ },
+ dictWord{10, 11, 674},
+ dictWord{10, 11, 684},
+ dictWord{11, 11, 89},
+ dictWord{11, 11, 202},
+ dictWord{11, 11, 272},
+ dictWord{11, 11, 380},
+ dictWord{
+ 11,
+ 11,
+ 415,
+ },
+ dictWord{11, 11, 505},
+ dictWord{11, 11, 537},
+ dictWord{11, 11, 550},
+ dictWord{11, 11, 562},
+ dictWord{11, 11, 640},
+ dictWord{11, 11, 667},
+ dictWord{11, 11, 688},
+ dictWord{11, 11, 847},
+ dictWord{11, 11, 927},
+ dictWord{11, 11, 930},
+ dictWord{11, 11, 940},
+ dictWord{12, 11, 144},
+ dictWord{
+ 12,
+ 11,
+ 325,
+ },
+ dictWord{12, 11, 329},
+ dictWord{12, 11, 389},
+ dictWord{12, 11, 403},
+ dictWord{12, 11, 451},
+ dictWord{12, 11, 515},
+ dictWord{12, 11, 604},
+ dictWord{
+ 12,
+ 11,
+ 616,
+ },
+ dictWord{12, 11, 626},
+ dictWord{13, 11, 66},
+ dictWord{13, 11, 131},
+ dictWord{13, 11, 167},
+ dictWord{13, 11, 236},
+ dictWord{13, 11, 368},
+ dictWord{13, 11, 411},
+ dictWord{13, 11, 434},
+ dictWord{13, 11, 453},
+ dictWord{13, 11, 461},
+ dictWord{13, 11, 474},
+ dictWord{14, 11, 59},
+ dictWord{14, 11, 60},
+ dictWord{14, 11, 139},
+ dictWord{14, 11, 152},
+ dictWord{14, 11, 276},
+ dictWord{14, 11, 353},
+ dictWord{14, 11, 402},
+ dictWord{15, 11, 28},
+ dictWord{
+ 15,
+ 11,
+ 81,
+ },
+ dictWord{15, 11, 123},
+ dictWord{15, 11, 152},
+ dictWord{18, 11, 136},
+ dictWord{148, 11, 88},
+ dictWord{137, 0, 247},
+ dictWord{135, 11, 1622},
+ dictWord{
+ 9,
+ 11,
+ 544,
+ },
+ dictWord{11, 11, 413},
+ dictWord{144, 11, 25},
+ dictWord{4, 0, 645},
+ dictWord{7, 0, 825},
+ dictWord{6, 10, 1768},
+ dictWord{135, 11, 89},
+ dictWord{140, 0, 328},
+ dictWord{5, 10, 943},
+ dictWord{134, 10, 1779},
+ dictWord{134, 0, 1363},
+ dictWord{5, 10, 245},
+ dictWord{6, 10, 576},
+ dictWord{7, 10, 582},
+ dictWord{136, 10, 225},
+ dictWord{134, 0, 1280},
+ dictWord{5, 11, 824},
+ dictWord{133, 11, 941},
+ dictWord{7, 11, 440},
+ dictWord{8, 11, 230},
+ dictWord{
+ 139,
+ 11,
+ 106,
+ },
+ dictWord{5, 0, 28},
+ dictWord{6, 0, 204},
+ dictWord{10, 0, 320},
+ dictWord{10, 0, 583},
+ dictWord{13, 0, 502},
+ dictWord{14, 0, 72},
+ dictWord{14, 0, 274},
+ dictWord{14, 0, 312},
+ dictWord{14, 0, 344},
+ dictWord{15, 0, 159},
+ dictWord{16, 0, 62},
+ dictWord{16, 0, 69},
+ dictWord{17, 0, 30},
+ dictWord{18, 0, 42},
+ dictWord{
+ 18,
+ 0,
+ 53,
+ },
+ dictWord{18, 0, 84},
+ dictWord{18, 0, 140},
+ dictWord{19, 0, 68},
+ dictWord{19, 0, 85},
+ dictWord{20, 0, 5},
+ dictWord{20, 0, 45},
+ dictWord{20, 0, 101},
+ dictWord{
+ 22,
+ 0,
+ 7,
+ },
+ dictWord{150, 0, 20},
+ dictWord{4, 0, 558},
+ dictWord{6, 0, 390},
+ dictWord{7, 0, 162},
+ dictWord{7, 0, 689},
+ dictWord{9, 0, 360},
+ dictWord{138, 0, 653},
+ dictWord{134, 0, 764},
+ dictWord{6, 0, 862},
+ dictWord{137, 0, 833},
+ dictWord{5, 0, 856},
+ dictWord{6, 0, 1672},
+ dictWord{6, 0, 1757},
+ dictWord{134, 0, 1781},
+ dictWord{
+ 5,
+ 0,
+ 92,
+ },
+ dictWord{10, 0, 736},
+ dictWord{140, 0, 102},
+ dictWord{6, 0, 1927},
+ dictWord{6, 0, 1944},
+ dictWord{8, 0, 924},
+ dictWord{8, 0, 948},
+ dictWord{
+ 10,
+ 0,
+ 967,
+ },
+ dictWord{138, 0, 978},
+ dictWord{134, 0, 1479},
+ dictWord{5, 0, 590},
+ dictWord{8, 0, 360},
+ dictWord{9, 0, 213},
+ dictWord{138, 0, 63},
+ dictWord{
+ 134,
+ 0,
+ 1521,
+ },
+ dictWord{6, 0, 709},
+ dictWord{134, 0, 891},
+ dictWord{132, 10, 443},
+ dictWord{13, 0, 477},
+ dictWord{14, 0, 120},
+ dictWord{148, 0, 61},
+ dictWord{
+ 4,
+ 11,
+ 914,
+ },
+ dictWord{5, 11, 800},
+ dictWord{133, 11, 852},
+ dictWord{10, 11, 54},
+ dictWord{141, 11, 115},
+ dictWord{4, 11, 918},
+ dictWord{133, 11, 876},
+ dictWord{139, 11, 152},
+ dictWord{4, 11, 92},
+ dictWord{133, 11, 274},
+ dictWord{135, 11, 1901},
+ dictWord{9, 11, 800},
+ dictWord{10, 11, 693},
+ dictWord{
+ 11,
+ 11,
+ 482,
+ },
+ dictWord{11, 11, 734},
+ dictWord{139, 11, 789},
+ dictWord{9, 0, 483},
+ dictWord{132, 10, 298},
+ dictWord{6, 0, 1213},
+ dictWord{141, 11, 498},
+ dictWord{135, 11, 1451},
+ dictWord{133, 11, 743},
+ dictWord{4, 0, 1022},
+ dictWord{10, 0, 1000},
+ dictWord{12, 0, 957},
+ dictWord{12, 0, 980},
+ dictWord{
+ 12,
+ 0,
+ 1013,
+ },
+ dictWord{14, 0, 481},
+ dictWord{144, 0, 116},
+ dictWord{8, 0, 503},
+ dictWord{17, 0, 29},
+ dictWord{4, 11, 49},
+ dictWord{7, 11, 280},
+ dictWord{
+ 135,
+ 11,
+ 1633,
+ },
+ dictWord{135, 0, 1712},
+ dictWord{134, 0, 466},
+ dictWord{136, 11, 47},
+ dictWord{5, 10, 164},
+ dictWord{7, 10, 121},
+ dictWord{142, 10, 189},
+ dictWord{
+ 7,
+ 10,
+ 812,
+ },
+ dictWord{7, 10, 1261},
+ dictWord{7, 10, 1360},
+ dictWord{9, 10, 632},
+ dictWord{140, 10, 352},
+ dictWord{139, 10, 556},
+ dictWord{132, 0, 731},
+ dictWord{5, 11, 272},
+ dictWord{5, 11, 908},
+ dictWord{5, 11, 942},
+ dictWord{7, 11, 1008},
+ dictWord{7, 11, 1560},
+ dictWord{8, 11, 197},
+ dictWord{9, 11, 47},
+ dictWord{11, 11, 538},
+ dictWord{139, 11, 742},
+ dictWord{4, 10, 172},
+ dictWord{9, 10, 611},
+ dictWord{10, 10, 436},
+ dictWord{12, 10, 673},
+ dictWord{
+ 141,
+ 10,
+ 255,
+ },
+ dictWord{133, 10, 844},
+ dictWord{10, 0, 484},
+ dictWord{11, 0, 754},
+ dictWord{12, 0, 457},
+ dictWord{14, 0, 171},
+ dictWord{14, 0, 389},
+ dictWord{
+ 146,
+ 0,
+ 153,
+ },
+ dictWord{9, 10, 263},
+ dictWord{10, 10, 147},
+ dictWord{138, 10, 492},
+ dictWord{137, 11, 891},
+ dictWord{138, 0, 241},
+ dictWord{133, 10, 537},
+ dictWord{6, 0, 2005},
+ dictWord{136, 0, 964},
+ dictWord{137, 10, 842},
+ dictWord{151, 11, 8},
+ dictWord{4, 11, 407},
+ dictWord{132, 11, 560},
+ dictWord{
+ 135,
+ 11,
+ 1884,
+ },
+ dictWord{6, 0, 1100},
+ dictWord{134, 0, 1242},
+ dictWord{135, 0, 954},
+ dictWord{5, 10, 230},
+ dictWord{5, 10, 392},
+ dictWord{6, 10, 420},
+ dictWord{
+ 9,
+ 10,
+ 568,
+ },
+ dictWord{140, 10, 612},
+ dictWord{4, 11, 475},
+ dictWord{11, 11, 35},
+ dictWord{11, 11, 90},
+ dictWord{13, 11, 7},
+ dictWord{13, 11, 71},
+ dictWord{
+ 13,
+ 11,
+ 177,
+ },
+ dictWord{142, 11, 422},
+ dictWord{136, 11, 332},
+ dictWord{135, 0, 1958},
+ dictWord{6, 0, 549},
+ dictWord{8, 0, 34},
+ dictWord{8, 0, 283},
+ dictWord{
+ 9,
+ 0,
+ 165,
+ },
+ dictWord{138, 0, 475},
+ dictWord{10, 0, 952},
+ dictWord{12, 0, 966},
+ dictWord{140, 0, 994},
+ dictWord{5, 0, 652},
+ dictWord{5, 0, 701},
+ dictWord{
+ 135,
+ 0,
+ 449,
+ },
+ dictWord{4, 0, 655},
+ dictWord{7, 0, 850},
+ dictWord{17, 0, 75},
+ dictWord{146, 0, 137},
+ dictWord{4, 0, 146},
+ dictWord{7, 0, 1618},
+ dictWord{8, 0, 670},
+ dictWord{
+ 5,
+ 10,
+ 41,
+ },
+ dictWord{7, 10, 1459},
+ dictWord{7, 10, 1469},
+ dictWord{7, 10, 1859},
+ dictWord{9, 10, 549},
+ dictWord{139, 10, 905},
+ dictWord{133, 10, 696},
+ dictWord{6, 0, 159},
+ dictWord{6, 0, 364},
+ dictWord{7, 0, 516},
+ dictWord{137, 0, 518},
+ dictWord{135, 0, 1439},
+ dictWord{6, 11, 222},
+ dictWord{7, 11, 636},
+ dictWord{
+ 7,
+ 11,
+ 1620,
+ },
+ dictWord{8, 11, 409},
+ dictWord{9, 11, 693},
+ dictWord{139, 11, 77},
+ dictWord{13, 0, 151},
+ dictWord{141, 11, 45},
+ dictWord{6, 0, 1027},
+ dictWord{
+ 4,
+ 11,
+ 336,
+ },
+ dictWord{132, 10, 771},
+ dictWord{139, 11, 392},
+ dictWord{10, 11, 121},
+ dictWord{11, 11, 175},
+ dictWord{149, 11, 16},
+ dictWord{8, 0, 950},
+ dictWord{138, 0, 983},
+ dictWord{133, 10, 921},
+ dictWord{135, 0, 993},
+ dictWord{6, 10, 180},
+ dictWord{7, 10, 1137},
+ dictWord{8, 10, 751},
+ dictWord{
+ 139,
+ 10,
+ 805,
+ },
+ dictWord{7, 0, 501},
+ dictWord{9, 0, 111},
+ dictWord{10, 0, 141},
+ dictWord{11, 0, 332},
+ dictWord{13, 0, 43},
+ dictWord{13, 0, 429},
+ dictWord{14, 0, 130},
+ dictWord{14, 0, 415},
+ dictWord{145, 0, 102},
+ dictWord{4, 10, 183},
+ dictWord{5, 11, 882},
+ dictWord{7, 10, 271},
+ dictWord{11, 10, 824},
+ dictWord{11, 10, 952},
+ dictWord{13, 10, 278},
+ dictWord{13, 10, 339},
+ dictWord{13, 10, 482},
+ dictWord{14, 10, 424},
+ dictWord{148, 10, 99},
+ dictWord{4, 10, 19},
+ dictWord{5, 10, 477},
+ dictWord{5, 10, 596},
+ dictWord{6, 10, 505},
+ dictWord{7, 10, 1221},
+ dictWord{11, 10, 907},
+ dictWord{12, 10, 209},
+ dictWord{141, 10, 214},
+ dictWord{
+ 135,
+ 10,
+ 1215,
+ },
+ dictWord{133, 0, 452},
+ dictWord{132, 11, 426},
+ dictWord{5, 0, 149},
+ dictWord{136, 0, 233},
+ dictWord{133, 0, 935},
+ dictWord{6, 11, 58},
+ dictWord{
+ 7,
+ 11,
+ 654,
+ },
+ dictWord{7, 11, 745},
+ dictWord{7, 11, 1969},
+ dictWord{8, 11, 240},
+ dictWord{8, 11, 675},
+ dictWord{9, 11, 479},
+ dictWord{9, 11, 731},
+ dictWord{
+ 10,
+ 11,
+ 330,
+ },
+ dictWord{10, 11, 593},
+ dictWord{10, 11, 817},
+ dictWord{11, 11, 32},
+ dictWord{11, 11, 133},
+ dictWord{11, 11, 221},
+ dictWord{145, 11, 68},
+ dictWord{
+ 12,
+ 0,
+ 582,
+ },
+ dictWord{18, 0, 131},
+ dictWord{7, 11, 102},
+ dictWord{137, 11, 538},
+ dictWord{136, 0, 801},
+ dictWord{134, 10, 1645},
+ dictWord{132, 0, 70},
+ dictWord{6, 10, 92},
+ dictWord{6, 10, 188},
+ dictWord{7, 10, 1269},
+ dictWord{7, 10, 1524},
+ dictWord{7, 10, 1876},
+ dictWord{10, 10, 228},
+ dictWord{139, 10, 1020},
+ dictWord{4, 10, 459},
+ dictWord{133, 10, 966},
+ dictWord{138, 0, 369},
+ dictWord{16, 0, 36},
+ dictWord{140, 10, 330},
+ dictWord{141, 11, 366},
+ dictWord{
+ 7,
+ 0,
+ 721,
+ },
+ dictWord{10, 0, 236},
+ dictWord{12, 0, 204},
+ dictWord{6, 10, 18},
+ dictWord{7, 10, 932},
+ dictWord{8, 10, 757},
+ dictWord{9, 10, 54},
+ dictWord{9, 10, 65},
+ dictWord{9, 10, 844},
+ dictWord{10, 10, 113},
+ dictWord{10, 10, 315},
+ dictWord{10, 10, 798},
+ dictWord{11, 10, 153},
+ dictWord{12, 10, 151},
+ dictWord{12, 10, 392},
+ dictWord{12, 10, 666},
+ dictWord{142, 10, 248},
+ dictWord{7, 0, 241},
+ dictWord{10, 0, 430},
+ dictWord{8, 10, 548},
+ dictWord{9, 10, 532},
+ dictWord{10, 10, 117},
+ dictWord{11, 10, 351},
+ dictWord{11, 10, 375},
+ dictWord{143, 10, 23},
+ dictWord{134, 10, 1742},
+ dictWord{133, 10, 965},
+ dictWord{133, 11, 566},
+ dictWord{
+ 6,
+ 11,
+ 48,
+ },
+ dictWord{135, 11, 63},
+ dictWord{134, 10, 182},
+ dictWord{10, 10, 65},
+ dictWord{10, 10, 488},
+ dictWord{138, 10, 497},
+ dictWord{6, 11, 114},
+ dictWord{7, 11, 1224},
+ dictWord{7, 11, 1556},
+ dictWord{136, 11, 3},
+ dictWord{134, 0, 1817},
+ dictWord{8, 11, 576},
+ dictWord{137, 11, 267},
+ dictWord{
+ 6,
+ 0,
+ 1078,
+ },
+ dictWord{144, 0, 16},
+ dictWord{9, 10, 588},
+ dictWord{138, 10, 260},
+ dictWord{138, 0, 1021},
+ dictWord{5, 0, 406},
+ dictWord{134, 0, 2022},
+ dictWord{133, 11, 933},
+ dictWord{6, 0, 69},
+ dictWord{135, 0, 117},
+ dictWord{7, 0, 1830},
+ dictWord{136, 11, 427},
+ dictWord{4, 0, 432},
+ dictWord{135, 0, 824},
+ dictWord{134, 10, 1786},
+ dictWord{133, 0, 826},
+ dictWord{139, 11, 67},
+ dictWord{133, 11, 759},
+ dictWord{135, 10, 308},
+ dictWord{137, 0, 816},
+ dictWord{
+ 133,
+ 0,
+ 1000,
+ },
+ dictWord{4, 0, 297},
+ dictWord{6, 0, 529},
+ dictWord{7, 0, 152},
+ dictWord{7, 0, 713},
+ dictWord{7, 0, 1845},
+ dictWord{8, 0, 710},
+ dictWord{8, 0, 717},
+ dictWord{12, 0, 639},
+ dictWord{140, 0, 685},
+ dictWord{7, 0, 423},
+ dictWord{136, 10, 588},
+ dictWord{136, 10, 287},
+ dictWord{136, 0, 510},
+ dictWord{
+ 134,
+ 0,
+ 1048,
+ },
+ dictWord{6, 0, 618},
+ dictWord{7, 11, 56},
+ dictWord{7, 11, 1989},
+ dictWord{8, 11, 337},
+ dictWord{8, 11, 738},
+ dictWord{9, 11, 600},
+ dictWord{
+ 10,
+ 11,
+ 483,
+ },
+ dictWord{12, 11, 37},
+ dictWord{13, 11, 447},
+ dictWord{142, 11, 92},
+ dictWord{4, 0, 520},
+ dictWord{135, 0, 575},
+ dictWord{8, 0, 990},
+ dictWord{
+ 138,
+ 0,
+ 977,
+ },
+ dictWord{135, 11, 774},
+ dictWord{9, 11, 347},
+ dictWord{11, 11, 24},
+ dictWord{140, 11, 170},
+ dictWord{136, 11, 379},
+ dictWord{140, 10, 290},
+ dictWord{132, 11, 328},
+ dictWord{4, 0, 321},
+ dictWord{134, 0, 569},
+ dictWord{4, 11, 101},
+ dictWord{135, 11, 1171},
+ dictWord{7, 0, 723},
+ dictWord{7, 0, 1135},
+ dictWord{5, 11, 833},
+ dictWord{136, 11, 744},
+ dictWord{7, 10, 719},
+ dictWord{8, 10, 809},
+ dictWord{136, 10, 834},
+ dictWord{8, 0, 921},
+ dictWord{136, 10, 796},
+ dictWord{5, 10, 210},
+ dictWord{6, 10, 213},
+ dictWord{7, 10, 60},
+ dictWord{10, 10, 364},
+ dictWord{139, 10, 135},
+ dictWord{5, 0, 397},
+ dictWord{6, 0, 154},
+ dictWord{7, 0, 676},
+ dictWord{8, 0, 443},
+ dictWord{8, 0, 609},
+ dictWord{9, 0, 24},
+ dictWord{9, 0, 325},
+ dictWord{10, 0, 35},
+ dictWord{11, 0, 535},
+ dictWord{11, 0, 672},
+ dictWord{11, 0, 1018},
+ dictWord{12, 0, 637},
+ dictWord{16, 0, 30},
+ dictWord{5, 10, 607},
+ dictWord{8, 10, 326},
+ dictWord{136, 10, 490},
+ dictWord{4, 10, 701},
+ dictWord{5, 10, 472},
+ dictWord{6, 11, 9},
+ dictWord{6, 11, 397},
+ dictWord{7, 11, 53},
+ dictWord{7, 11, 1742},
+ dictWord{9, 10, 758},
+ dictWord{10, 11, 632},
+ dictWord{
+ 11,
+ 11,
+ 828,
+ },
+ dictWord{140, 11, 146},
+ dictWord{135, 10, 380},
+ dictWord{135, 10, 1947},
+ dictWord{148, 11, 109},
+ dictWord{10, 10, 278},
+ dictWord{
+ 138,
+ 11,
+ 278,
+ },
+ dictWord{134, 0, 856},
+ dictWord{7, 0, 139},
+ dictWord{4, 10, 386},
+ dictWord{8, 10, 405},
+ dictWord{8, 10, 728},
+ dictWord{9, 10, 497},
+ dictWord{
+ 11,
+ 10,
+ 110,
+ },
+ dictWord{11, 10, 360},
+ dictWord{15, 10, 37},
+ dictWord{144, 10, 84},
+ dictWord{141, 0, 282},
+ dictWord{133, 0, 981},
+ dictWord{5, 0, 288},
+ dictWord{
+ 7,
+ 10,
+ 1452,
+ },
+ dictWord{7, 10, 1480},
+ dictWord{8, 10, 634},
+ dictWord{140, 10, 472},
+ dictWord{7, 0, 1890},
+ dictWord{8, 11, 367},
+ dictWord{10, 11, 760},
+ dictWord{
+ 14,
+ 11,
+ 79,
+ },
+ dictWord{20, 11, 17},
+ dictWord{152, 11, 0},
+ dictWord{4, 10, 524},
+ dictWord{136, 10, 810},
+ dictWord{4, 0, 56},
+ dictWord{7, 0, 1791},
+ dictWord{
+ 8,
+ 0,
+ 607,
+ },
+ dictWord{8, 0, 651},
+ dictWord{11, 0, 465},
+ dictWord{11, 0, 835},
+ dictWord{12, 0, 337},
+ dictWord{141, 0, 480},
+ dictWord{10, 10, 238},
+ dictWord{
+ 141,
+ 10,
+ 33,
+ },
+ dictWord{11, 11, 417},
+ dictWord{12, 11, 223},
+ dictWord{140, 11, 265},
+ dictWord{9, 0, 158},
+ dictWord{10, 0, 411},
+ dictWord{140, 0, 261},
+ dictWord{
+ 133,
+ 10,
+ 532,
+ },
+ dictWord{133, 10, 997},
+ dictWord{12, 11, 186},
+ dictWord{12, 11, 292},
+ dictWord{14, 11, 100},
+ dictWord{146, 11, 70},
+ dictWord{6, 0, 1403},
+ dictWord{136, 0, 617},
+ dictWord{134, 0, 1205},
+ dictWord{139, 0, 563},
+ dictWord{4, 0, 242},
+ dictWord{134, 0, 333},
+ dictWord{4, 11, 186},
+ dictWord{5, 11, 157},
+ dictWord{8, 11, 168},
+ dictWord{138, 11, 6},
+ dictWord{132, 0, 369},
+ dictWord{133, 11, 875},
+ dictWord{5, 10, 782},
+ dictWord{5, 10, 829},
+ dictWord{
+ 134,
+ 10,
+ 1738,
+ },
+ dictWord{134, 0, 622},
+ dictWord{135, 11, 1272},
+ dictWord{6, 0, 1407},
+ dictWord{7, 11, 111},
+ dictWord{136, 11, 581},
+ dictWord{7, 10, 1823},
+ dictWord{139, 10, 693},
+ dictWord{7, 0, 160},
+ dictWord{10, 0, 624},
+ dictWord{142, 0, 279},
+ dictWord{132, 0, 363},
+ dictWord{10, 11, 589},
+ dictWord{12, 11, 111},
+ dictWord{13, 11, 260},
+ dictWord{14, 11, 82},
+ dictWord{18, 11, 63},
+ dictWord{147, 11, 45},
+ dictWord{7, 11, 1364},
+ dictWord{7, 11, 1907},
+ dictWord{
+ 141,
+ 11,
+ 158,
+ },
+ dictWord{4, 11, 404},
+ dictWord{4, 11, 659},
+ dictWord{135, 11, 675},
+ dictWord{13, 11, 211},
+ dictWord{14, 11, 133},
+ dictWord{14, 11, 204},
+ dictWord{
+ 15,
+ 11,
+ 64,
+ },
+ dictWord{15, 11, 69},
+ dictWord{15, 11, 114},
+ dictWord{16, 11, 10},
+ dictWord{19, 11, 23},
+ dictWord{19, 11, 35},
+ dictWord{19, 11, 39},
+ dictWord{
+ 19,
+ 11,
+ 51,
+ },
+ dictWord{19, 11, 71},
+ dictWord{19, 11, 75},
+ dictWord{152, 11, 15},
+ dictWord{4, 10, 78},
+ dictWord{5, 10, 96},
+ dictWord{5, 10, 182},
+ dictWord{7, 10, 1724},
+ dictWord{7, 10, 1825},
+ dictWord{10, 10, 394},
+ dictWord{10, 10, 471},
+ dictWord{11, 10, 532},
+ dictWord{14, 10, 340},
+ dictWord{145, 10, 88},
+ dictWord{
+ 135,
+ 10,
+ 1964,
+ },
+ dictWord{133, 11, 391},
+ dictWord{11, 11, 887},
+ dictWord{14, 11, 365},
+ dictWord{142, 11, 375},
+ dictWord{5, 11, 540},
+ dictWord{6, 11, 1697},
+ dictWord{7, 11, 222},
+ dictWord{136, 11, 341},
+ dictWord{134, 11, 78},
+ dictWord{9, 0, 601},
+ dictWord{9, 0, 619},
+ dictWord{10, 0, 505},
+ dictWord{10, 0, 732},
+ dictWord{11, 0, 355},
+ dictWord{140, 0, 139},
+ dictWord{134, 0, 292},
+ dictWord{139, 0, 174},
+ dictWord{5, 0, 177},
+ dictWord{6, 0, 616},
+ dictWord{7, 0, 827},
+ dictWord{
+ 9,
+ 0,
+ 525,
+ },
+ dictWord{138, 0, 656},
+ dictWord{10, 0, 31},
+ dictWord{6, 10, 215},
+ dictWord{7, 10, 1028},
+ dictWord{7, 10, 1473},
+ dictWord{7, 10, 1721},
+ dictWord{
+ 9,
+ 10,
+ 424,
+ },
+ dictWord{138, 10, 779},
+ dictWord{135, 10, 584},
+ dictWord{136, 11, 293},
+ dictWord{134, 0, 685},
+ dictWord{135, 11, 1868},
+ dictWord{
+ 133,
+ 11,
+ 460,
+ },
+ dictWord{7, 0, 647},
+ dictWord{6, 10, 67},
+ dictWord{7, 10, 1630},
+ dictWord{9, 10, 354},
+ dictWord{9, 10, 675},
+ dictWord{10, 10, 830},
+ dictWord{
+ 14,
+ 10,
+ 80,
+ },
+ dictWord{145, 10, 80},
+ dictWord{4, 0, 161},
+ dictWord{133, 0, 631},
+ dictWord{6, 10, 141},
+ dictWord{7, 10, 225},
+ dictWord{9, 10, 59},
+ dictWord{9, 10, 607},
+ dictWord{10, 10, 312},
+ dictWord{11, 10, 687},
+ dictWord{12, 10, 555},
+ dictWord{13, 10, 373},
+ dictWord{13, 10, 494},
+ dictWord{148, 10, 58},
+ dictWord{
+ 7,
+ 11,
+ 965,
+ },
+ dictWord{7, 11, 1460},
+ dictWord{135, 11, 1604},
+ dictWord{136, 10, 783},
+ dictWord{134, 11, 388},
+ dictWord{6, 0, 722},
+ dictWord{6, 0, 1267},
+ dictWord{
+ 4,
+ 11,
+ 511,
+ },
+ dictWord{9, 11, 333},
+ dictWord{9, 11, 379},
+ dictWord{10, 11, 602},
+ dictWord{11, 11, 441},
+ dictWord{11, 11, 723},
+ dictWord{11, 11, 976},
+ dictWord{140, 11, 357},
+ dictWord{134, 0, 1797},
+ dictWord{135, 0, 1684},
+ dictWord{9, 0, 469},
+ dictWord{9, 0, 709},
+ dictWord{12, 0, 512},
+ dictWord{14, 0, 65},
+ dictWord{17, 0, 12},
+ dictWord{5, 11, 938},
+ dictWord{136, 11, 707},
+ dictWord{7, 0, 1230},
+ dictWord{136, 0, 531},
+ dictWord{10, 0, 229},
+ dictWord{11, 0, 73},
+ dictWord{
+ 11,
+ 0,
+ 376,
+ },
+ dictWord{139, 0, 433},
+ dictWord{12, 0, 268},
+ dictWord{12, 0, 640},
+ dictWord{142, 0, 119},
+ dictWord{7, 10, 430},
+ dictWord{139, 10, 46},
+ dictWord{
+ 6,
+ 0,
+ 558,
+ },
+ dictWord{7, 0, 651},
+ dictWord{8, 0, 421},
+ dictWord{9, 0, 0},
+ dictWord{10, 0, 34},
+ dictWord{139, 0, 1008},
+ dictWord{6, 0, 106},
+ dictWord{7, 0, 1786},
+ dictWord{7, 0, 1821},
+ dictWord{9, 0, 102},
+ dictWord{9, 0, 763},
+ dictWord{5, 10, 602},
+ dictWord{7, 10, 2018},
+ dictWord{137, 10, 418},
+ dictWord{5, 0, 65},
+ dictWord{
+ 6,
+ 0,
+ 416,
+ },
+ dictWord{7, 0, 1720},
+ dictWord{7, 0, 1924},
+ dictWord{10, 0, 109},
+ dictWord{11, 0, 14},
+ dictWord{11, 0, 70},
+ dictWord{11, 0, 569},
+ dictWord{11, 0, 735},
+ dictWord{15, 0, 153},
+ dictWord{20, 0, 80},
+ dictWord{136, 10, 677},
+ dictWord{135, 11, 1625},
+ dictWord{137, 11, 772},
+ dictWord{136, 0, 595},
+ dictWord{
+ 6,
+ 11,
+ 469,
+ },
+ dictWord{7, 11, 1709},
+ dictWord{138, 11, 515},
+ dictWord{7, 0, 1832},
+ dictWord{138, 0, 374},
+ dictWord{9, 0, 106},
+ dictWord{9, 0, 163},
+ dictWord{
+ 9,
+ 0,
+ 296,
+ },
+ dictWord{10, 0, 167},
+ dictWord{10, 0, 172},
+ dictWord{10, 0, 777},
+ dictWord{139, 0, 16},
+ dictWord{6, 0, 6},
+ dictWord{7, 0, 81},
+ dictWord{7, 0, 771},
+ dictWord{
+ 7,
+ 0,
+ 1731,
+ },
+ dictWord{9, 0, 405},
+ dictWord{138, 0, 421},
+ dictWord{4, 11, 500},
+ dictWord{135, 11, 938},
+ dictWord{5, 11, 68},
+ dictWord{134, 11, 383},
+ dictWord{
+ 5,
+ 0,
+ 881,
+ },
+ dictWord{133, 0, 885},
+ dictWord{6, 0, 854},
+ dictWord{6, 0, 1132},
+ dictWord{6, 0, 1495},
+ dictWord{6, 0, 1526},
+ dictWord{6, 0, 1533},
+ dictWord{
+ 134,
+ 0,
+ 1577,
+ },
+ dictWord{4, 11, 337},
+ dictWord{6, 11, 353},
+ dictWord{7, 11, 1934},
+ dictWord{8, 11, 488},
+ dictWord{137, 11, 429},
+ dictWord{7, 11, 236},
+ dictWord{
+ 7,
+ 11,
+ 1795,
+ },
+ dictWord{8, 11, 259},
+ dictWord{9, 11, 135},
+ dictWord{9, 11, 177},
+ dictWord{10, 11, 825},
+ dictWord{11, 11, 115},
+ dictWord{11, 11, 370},
+ dictWord{
+ 11,
+ 11,
+ 405,
+ },
+ dictWord{11, 11, 604},
+ dictWord{12, 11, 10},
+ dictWord{12, 11, 667},
+ dictWord{12, 11, 669},
+ dictWord{13, 11, 76},
+ dictWord{14, 11, 310},
+ dictWord{15, 11, 76},
+ dictWord{15, 11, 147},
+ dictWord{148, 11, 23},
+ dictWord{5, 0, 142},
+ dictWord{134, 0, 546},
+ dictWord{4, 11, 15},
+ dictWord{5, 11, 22},
+ dictWord{
+ 6,
+ 11,
+ 244,
+ },
+ dictWord{7, 11, 40},
+ dictWord{7, 11, 200},
+ dictWord{7, 11, 906},
+ dictWord{7, 11, 1199},
+ dictWord{9, 11, 616},
+ dictWord{10, 11, 716},
+ dictWord{
+ 11,
+ 11,
+ 635,
+ },
+ dictWord{11, 11, 801},
+ dictWord{140, 11, 458},
+ dictWord{5, 0, 466},
+ dictWord{11, 0, 571},
+ dictWord{12, 0, 198},
+ dictWord{13, 0, 283},
+ dictWord{
+ 14,
+ 0,
+ 186,
+ },
+ dictWord{15, 0, 21},
+ dictWord{15, 0, 103},
+ dictWord{135, 10, 329},
+ dictWord{4, 0, 185},
+ dictWord{5, 0, 257},
+ dictWord{5, 0, 839},
+ dictWord{5, 0, 936},
+ dictWord{9, 0, 399},
+ dictWord{10, 0, 258},
+ dictWord{10, 0, 395},
+ dictWord{10, 0, 734},
+ dictWord{11, 0, 1014},
+ dictWord{12, 0, 23},
+ dictWord{13, 0, 350},
+ dictWord{
+ 14,
+ 0,
+ 150,
+ },
+ dictWord{19, 0, 6},
+ dictWord{135, 11, 1735},
+ dictWord{12, 11, 36},
+ dictWord{141, 11, 337},
+ dictWord{5, 11, 598},
+ dictWord{7, 11, 791},
+ dictWord{
+ 8,
+ 11,
+ 108,
+ },
+ dictWord{137, 11, 123},
+ dictWord{132, 10, 469},
+ dictWord{7, 0, 404},
+ dictWord{7, 0, 1377},
+ dictWord{7, 0, 1430},
+ dictWord{7, 0, 2017},
+ dictWord{
+ 8,
+ 0,
+ 149,
+ },
+ dictWord{8, 0, 239},
+ dictWord{8, 0, 512},
+ dictWord{8, 0, 793},
+ dictWord{8, 0, 818},
+ dictWord{9, 0, 474},
+ dictWord{9, 0, 595},
+ dictWord{10, 0, 122},
+ dictWord{10, 0, 565},
+ dictWord{10, 0, 649},
+ dictWord{10, 0, 783},
+ dictWord{11, 0, 239},
+ dictWord{11, 0, 295},
+ dictWord{11, 0, 447},
+ dictWord{11, 0, 528},
+ dictWord{
+ 11,
+ 0,
+ 639,
+ },
+ dictWord{11, 0, 800},
+ dictWord{12, 0, 25},
+ dictWord{12, 0, 77},
+ dictWord{12, 0, 157},
+ dictWord{12, 0, 256},
+ dictWord{12, 0, 316},
+ dictWord{12, 0, 390},
+ dictWord{12, 0, 391},
+ dictWord{12, 0, 395},
+ dictWord{12, 0, 478},
+ dictWord{12, 0, 503},
+ dictWord{12, 0, 592},
+ dictWord{12, 0, 680},
+ dictWord{13, 0, 50},
+ dictWord{13, 0, 53},
+ dictWord{13, 0, 132},
+ dictWord{13, 0, 198},
+ dictWord{13, 0, 322},
+ dictWord{13, 0, 415},
+ dictWord{13, 0, 511},
+ dictWord{14, 0, 71},
+ dictWord{
+ 14,
+ 0,
+ 395,
+ },
+ dictWord{15, 0, 71},
+ dictWord{15, 0, 136},
+ dictWord{17, 0, 123},
+ dictWord{18, 0, 93},
+ dictWord{147, 0, 58},
+ dictWord{136, 0, 712},
+ dictWord{
+ 134,
+ 10,
+ 1743,
+ },
+ dictWord{5, 10, 929},
+ dictWord{6, 10, 340},
+ dictWord{8, 10, 376},
+ dictWord{136, 10, 807},
+ dictWord{6, 0, 1848},
+ dictWord{8, 0, 860},
+ dictWord{
+ 10,
+ 0,
+ 856,
+ },
+ dictWord{10, 0, 859},
+ dictWord{10, 0, 925},
+ dictWord{10, 0, 941},
+ dictWord{140, 0, 762},
+ dictWord{6, 0, 629},
+ dictWord{6, 0, 906},
+ dictWord{9, 0, 810},
+ dictWord{140, 0, 652},
+ dictWord{5, 10, 218},
+ dictWord{7, 10, 1610},
+ dictWord{138, 10, 83},
+ dictWord{7, 10, 1512},
+ dictWord{135, 10, 1794},
+ dictWord{
+ 4,
+ 0,
+ 377,
+ },
+ dictWord{24, 0, 13},
+ dictWord{4, 11, 155},
+ dictWord{7, 11, 1689},
+ dictWord{11, 10, 0},
+ dictWord{144, 10, 78},
+ dictWord{4, 11, 164},
+ dictWord{5, 11, 151},
+ dictWord{5, 11, 730},
+ dictWord{5, 11, 741},
+ dictWord{7, 11, 498},
+ dictWord{7, 11, 870},
+ dictWord{7, 11, 1542},
+ dictWord{12, 11, 213},
+ dictWord{14, 11, 36},
+ dictWord{14, 11, 391},
+ dictWord{17, 11, 111},
+ dictWord{18, 11, 6},
+ dictWord{18, 11, 46},
+ dictWord{18, 11, 151},
+ dictWord{19, 11, 36},
+ dictWord{20, 11, 32},
+ dictWord{20, 11, 56},
+ dictWord{20, 11, 69},
+ dictWord{20, 11, 102},
+ dictWord{21, 11, 4},
+ dictWord{22, 11, 8},
+ dictWord{22, 11, 10},
+ dictWord{22, 11, 14},
+ dictWord{
+ 150,
+ 11,
+ 31,
+ },
+ dictWord{7, 0, 1842},
+ dictWord{133, 10, 571},
+ dictWord{4, 10, 455},
+ dictWord{4, 11, 624},
+ dictWord{135, 11, 1752},
+ dictWord{134, 0, 1501},
+ dictWord{4, 11, 492},
+ dictWord{5, 11, 451},
+ dictWord{6, 10, 161},
+ dictWord{7, 10, 372},
+ dictWord{137, 10, 597},
+ dictWord{132, 10, 349},
+ dictWord{4, 0, 180},
+ dictWord{135, 0, 1906},
+ dictWord{135, 11, 835},
+ dictWord{141, 11, 70},
+ dictWord{132, 0, 491},
+ dictWord{137, 10, 751},
+ dictWord{6, 10, 432},
+ dictWord{
+ 139,
+ 10,
+ 322,
+ },
+ dictWord{4, 0, 171},
+ dictWord{138, 0, 234},
+ dictWord{6, 11, 113},
+ dictWord{135, 11, 436},
+ dictWord{4, 0, 586},
+ dictWord{7, 0, 1186},
+ dictWord{
+ 138,
+ 0,
+ 631,
+ },
+ dictWord{5, 10, 468},
+ dictWord{10, 10, 325},
+ dictWord{11, 10, 856},
+ dictWord{12, 10, 345},
+ dictWord{143, 10, 104},
+ dictWord{5, 10, 223},
+ dictWord{10, 11, 592},
+ dictWord{10, 11, 753},
+ dictWord{12, 11, 317},
+ dictWord{12, 11, 355},
+ dictWord{12, 11, 465},
+ dictWord{12, 11, 469},
+ dictWord{
+ 12,
+ 11,
+ 560,
+ },
+ dictWord{12, 11, 578},
+ dictWord{141, 11, 243},
+ dictWord{132, 10, 566},
+ dictWord{135, 11, 520},
+ dictWord{4, 10, 59},
+ dictWord{135, 10, 1394},
+ dictWord{6, 10, 436},
+ dictWord{139, 10, 481},
+ dictWord{9, 0, 931},
+ dictWord{10, 0, 334},
+ dictWord{20, 0, 71},
+ dictWord{4, 10, 48},
+ dictWord{5, 10, 271},
+ dictWord{
+ 7,
+ 10,
+ 953,
+ },
+ dictWord{135, 11, 1878},
+ dictWord{11, 0, 170},
+ dictWord{5, 10, 610},
+ dictWord{136, 10, 457},
+ dictWord{133, 10, 755},
+ dictWord{6, 0, 1587},
+ dictWord{135, 10, 1217},
+ dictWord{4, 10, 197},
+ dictWord{149, 11, 26},
+ dictWord{133, 11, 585},
+ dictWord{137, 11, 521},
+ dictWord{133, 0, 765},
+ dictWord{
+ 133,
+ 10,
+ 217,
+ },
+ dictWord{139, 11, 586},
+ dictWord{133, 0, 424},
+ dictWord{9, 11, 752},
+ dictWord{12, 11, 610},
+ dictWord{13, 11, 431},
+ dictWord{16, 11, 59},
+ dictWord{146, 11, 109},
+ dictWord{136, 0, 714},
+ dictWord{7, 0, 685},
+ dictWord{132, 11, 307},
+ dictWord{9, 0, 420},
+ dictWord{10, 0, 269},
+ dictWord{10, 0, 285},
+ dictWord{10, 0, 576},
+ dictWord{11, 0, 397},
+ dictWord{13, 0, 175},
+ dictWord{145, 0, 90},
+ dictWord{132, 0, 429},
+ dictWord{133, 11, 964},
+ dictWord{9, 11, 463},
+ dictWord{138, 11, 595},
+ dictWord{7, 0, 18},
+ dictWord{7, 0, 699},
+ dictWord{7, 0, 1966},
+ dictWord{8, 0, 752},
+ dictWord{9, 0, 273},
+ dictWord{9, 0, 412},
+ dictWord{
+ 9,
+ 0,
+ 703,
+ },
+ dictWord{10, 0, 71},
+ dictWord{10, 0, 427},
+ dictWord{138, 0, 508},
+ dictWord{4, 10, 165},
+ dictWord{7, 10, 1398},
+ dictWord{135, 10, 1829},
+ dictWord{
+ 4,
+ 0,
+ 53,
+ },
+ dictWord{5, 0, 186},
+ dictWord{7, 0, 752},
+ dictWord{7, 0, 828},
+ dictWord{142, 0, 116},
+ dictWord{8, 0, 575},
+ dictWord{10, 0, 289},
+ dictWord{139, 0, 319},
+ dictWord{132, 0, 675},
+ dictWord{134, 0, 1424},
+ dictWord{4, 11, 75},
+ dictWord{5, 11, 180},
+ dictWord{6, 11, 500},
+ dictWord{7, 11, 58},
+ dictWord{7, 11, 710},
+ dictWord{138, 11, 645},
+ dictWord{133, 11, 649},
+ dictWord{6, 11, 276},
+ dictWord{7, 11, 282},
+ dictWord{7, 11, 879},
+ dictWord{7, 11, 924},
+ dictWord{8, 11, 459},
+ dictWord{9, 11, 599},
+ dictWord{9, 11, 754},
+ dictWord{11, 11, 574},
+ dictWord{12, 11, 128},
+ dictWord{12, 11, 494},
+ dictWord{13, 11, 52},
+ dictWord{13, 11, 301},
+ dictWord{15, 11, 30},
+ dictWord{143, 11, 132},
+ dictWord{6, 0, 647},
+ dictWord{134, 0, 1095},
+ dictWord{5, 10, 9},
+ dictWord{7, 10, 297},
+ dictWord{7, 10, 966},
+ dictWord{140, 10, 306},
+ dictWord{132, 11, 200},
+ dictWord{134, 0, 1334},
+ dictWord{5, 10, 146},
+ dictWord{6, 10, 411},
+ dictWord{138, 10, 721},
+ dictWord{
+ 6,
+ 0,
+ 209,
+ },
+ dictWord{6, 0, 1141},
+ dictWord{6, 0, 1288},
+ dictWord{8, 0, 468},
+ dictWord{9, 0, 210},
+ dictWord{11, 0, 36},
+ dictWord{12, 0, 28},
+ dictWord{12, 0, 630},
+ dictWord{13, 0, 21},
+ dictWord{13, 0, 349},
+ dictWord{14, 0, 7},
+ dictWord{145, 0, 13},
+ dictWord{6, 10, 177},
+ dictWord{135, 10, 467},
+ dictWord{4, 0, 342},
+ dictWord{
+ 135,
+ 0,
+ 1179,
+ },
+ dictWord{10, 11, 454},
+ dictWord{140, 11, 324},
+ dictWord{4, 0, 928},
+ dictWord{133, 0, 910},
+ dictWord{7, 0, 1838},
+ dictWord{6, 11, 225},
+ dictWord{
+ 137,
+ 11,
+ 211,
+ },
+ dictWord{16, 0, 101},
+ dictWord{20, 0, 115},
+ dictWord{20, 0, 118},
+ dictWord{148, 0, 122},
+ dictWord{4, 0, 496},
+ dictWord{135, 0, 856},
+ dictWord{
+ 4,
+ 0,
+ 318,
+ },
+ dictWord{11, 0, 654},
+ dictWord{7, 11, 718},
+ dictWord{139, 11, 102},
+ dictWord{8, 11, 58},
+ dictWord{9, 11, 724},
+ dictWord{11, 11, 809},
+ dictWord{
+ 13,
+ 11,
+ 113,
+ },
+ dictWord{145, 11, 72},
+ dictWord{5, 10, 200},
+ dictWord{6, 11, 345},
+ dictWord{135, 11, 1247},
+ dictWord{8, 11, 767},
+ dictWord{8, 11, 803},
+ dictWord{
+ 9,
+ 11,
+ 301,
+ },
+ dictWord{137, 11, 903},
+ dictWord{7, 0, 915},
+ dictWord{8, 0, 247},
+ dictWord{19, 0, 0},
+ dictWord{7, 11, 1949},
+ dictWord{136, 11, 674},
+ dictWord{
+ 4,
+ 0,
+ 202,
+ },
+ dictWord{5, 0, 382},
+ dictWord{6, 0, 454},
+ dictWord{7, 0, 936},
+ dictWord{7, 0, 1803},
+ dictWord{8, 0, 758},
+ dictWord{9, 0, 375},
+ dictWord{9, 0, 895},
+ dictWord{
+ 10,
+ 0,
+ 743,
+ },
+ dictWord{10, 0, 792},
+ dictWord{11, 0, 978},
+ dictWord{11, 0, 1012},
+ dictWord{142, 0, 109},
+ dictWord{7, 0, 1150},
+ dictWord{7, 0, 1425},
+ dictWord{
+ 7,
+ 0,
+ 1453,
+ },
+ dictWord{140, 0, 513},
+ dictWord{134, 11, 259},
+ dictWord{138, 0, 791},
+ dictWord{11, 0, 821},
+ dictWord{12, 0, 110},
+ dictWord{12, 0, 153},
+ dictWord{
+ 18,
+ 0,
+ 41,
+ },
+ dictWord{150, 0, 19},
+ dictWord{134, 10, 481},
+ dictWord{132, 0, 796},
+ dictWord{6, 0, 445},
+ dictWord{9, 0, 909},
+ dictWord{136, 11, 254},
+ dictWord{
+ 10,
+ 0,
+ 776,
+ },
+ dictWord{13, 0, 345},
+ dictWord{142, 0, 425},
+ dictWord{4, 10, 84},
+ dictWord{7, 10, 1482},
+ dictWord{10, 10, 76},
+ dictWord{138, 10, 142},
+ dictWord{
+ 135,
+ 11,
+ 742,
+ },
+ dictWord{6, 0, 578},
+ dictWord{133, 10, 1015},
+ dictWord{6, 0, 1387},
+ dictWord{4, 10, 315},
+ dictWord{5, 10, 507},
+ dictWord{135, 10, 1370},
+ dictWord{4, 0, 438},
+ dictWord{133, 0, 555},
+ dictWord{136, 0, 766},
+ dictWord{133, 11, 248},
+ dictWord{134, 10, 1722},
+ dictWord{4, 11, 116},
+ dictWord{5, 11, 95},
+ dictWord{5, 11, 445},
+ dictWord{7, 11, 1688},
+ dictWord{8, 11, 29},
+ dictWord{9, 11, 272},
+ dictWord{11, 11, 509},
+ dictWord{139, 11, 915},
+ dictWord{135, 0, 541},
+ dictWord{133, 11, 543},
+ dictWord{8, 10, 222},
+ dictWord{8, 10, 476},
+ dictWord{9, 10, 238},
+ dictWord{11, 10, 516},
+ dictWord{11, 10, 575},
+ dictWord{
+ 15,
+ 10,
+ 109,
+ },
+ dictWord{146, 10, 100},
+ dictWord{6, 0, 880},
+ dictWord{134, 0, 1191},
+ dictWord{5, 11, 181},
+ dictWord{136, 11, 41},
+ dictWord{134, 0, 1506},
+ dictWord{132, 11, 681},
+ dictWord{7, 11, 25},
+ dictWord{8, 11, 202},
+ dictWord{138, 11, 536},
+ dictWord{139, 0, 983},
+ dictWord{137, 0, 768},
+ dictWord{132, 0, 584},
+ dictWord{9, 11, 423},
+ dictWord{140, 11, 89},
+ dictWord{8, 11, 113},
+ dictWord{9, 11, 877},
+ dictWord{10, 11, 554},
+ dictWord{11, 11, 83},
+ dictWord{12, 11, 136},
+ dictWord{147, 11, 109},
+ dictWord{7, 10, 706},
+ dictWord{7, 10, 1058},
+ dictWord{138, 10, 538},
+ dictWord{133, 11, 976},
+ dictWord{4, 11, 206},
+ dictWord{
+ 135,
+ 11,
+ 746,
+ },
+ dictWord{136, 11, 526},
+ dictWord{140, 0, 737},
+ dictWord{11, 10, 92},
+ dictWord{11, 10, 196},
+ dictWord{11, 10, 409},
+ dictWord{11, 10, 450},
+ dictWord{11, 10, 666},
+ dictWord{11, 10, 777},
+ dictWord{12, 10, 262},
+ dictWord{13, 10, 385},
+ dictWord{13, 10, 393},
+ dictWord{15, 10, 115},
+ dictWord{
+ 16,
+ 10,
+ 45,
+ },
+ dictWord{145, 10, 82},
+ dictWord{4, 0, 226},
+ dictWord{4, 0, 326},
+ dictWord{7, 0, 1770},
+ dictWord{4, 11, 319},
+ dictWord{5, 11, 699},
+ dictWord{138, 11, 673},
+ dictWord{6, 10, 40},
+ dictWord{135, 10, 1781},
+ dictWord{5, 0, 426},
+ dictWord{8, 0, 30},
+ dictWord{9, 0, 2},
+ dictWord{11, 0, 549},
+ dictWord{147, 0, 122},
+ dictWord{
+ 6,
+ 0,
+ 1161,
+ },
+ dictWord{134, 0, 1329},
+ dictWord{138, 10, 97},
+ dictWord{6, 10, 423},
+ dictWord{7, 10, 665},
+ dictWord{135, 10, 1210},
+ dictWord{7, 11, 13},
+ dictWord{
+ 8,
+ 11,
+ 226,
+ },
+ dictWord{10, 11, 537},
+ dictWord{11, 11, 570},
+ dictWord{11, 11, 605},
+ dictWord{11, 11, 799},
+ dictWord{11, 11, 804},
+ dictWord{12, 11, 85},
+ dictWord{12, 11, 516},
+ dictWord{12, 11, 623},
+ dictWord{13, 11, 112},
+ dictWord{13, 11, 361},
+ dictWord{14, 11, 77},
+ dictWord{14, 11, 78},
+ dictWord{17, 11, 28},
+ dictWord{147, 11, 110},
+ dictWord{132, 11, 769},
+ dictWord{132, 11, 551},
+ dictWord{132, 11, 728},
+ dictWord{147, 0, 117},
+ dictWord{9, 11, 57},
+ dictWord{
+ 9,
+ 11,
+ 459,
+ },
+ dictWord{10, 11, 425},
+ dictWord{11, 11, 119},
+ dictWord{12, 11, 184},
+ dictWord{12, 11, 371},
+ dictWord{13, 11, 358},
+ dictWord{145, 11, 51},
+ dictWord{
+ 5,
+ 11,
+ 188,
+ },
+ dictWord{5, 11, 814},
+ dictWord{8, 11, 10},
+ dictWord{9, 11, 421},
+ dictWord{9, 11, 729},
+ dictWord{10, 11, 609},
+ dictWord{139, 11, 689},
+ dictWord{134, 11, 624},
+ dictWord{135, 11, 298},
+ dictWord{135, 0, 462},
+ dictWord{4, 0, 345},
+ dictWord{139, 10, 624},
+ dictWord{136, 10, 574},
+ dictWord{
+ 4,
+ 0,
+ 385,
+ },
+ dictWord{7, 0, 265},
+ dictWord{135, 0, 587},
+ dictWord{6, 0, 808},
+ dictWord{132, 11, 528},
+ dictWord{133, 0, 398},
+ dictWord{132, 10, 354},
+ dictWord{
+ 4,
+ 0,
+ 347,
+ },
+ dictWord{5, 0, 423},
+ dictWord{5, 0, 996},
+ dictWord{135, 0, 1329},
+ dictWord{135, 10, 1558},
+ dictWord{7, 0, 1259},
+ dictWord{9, 0, 125},
+ dictWord{
+ 139,
+ 0,
+ 65,
+ },
+ dictWord{5, 0, 136},
+ dictWord{6, 0, 136},
+ dictWord{136, 0, 644},
+ dictWord{5, 11, 104},
+ dictWord{6, 11, 173},
+ dictWord{135, 11, 1631},
+ dictWord{
+ 135,
+ 0,
+ 469,
+ },
+ dictWord{133, 10, 830},
+ dictWord{4, 0, 278},
+ dictWord{5, 0, 465},
+ dictWord{135, 0, 1367},
+ dictWord{7, 11, 810},
+ dictWord{8, 11, 138},
+ dictWord{
+ 8,
+ 11,
+ 342,
+ },
+ dictWord{9, 11, 84},
+ dictWord{10, 11, 193},
+ dictWord{11, 11, 883},
+ dictWord{140, 11, 359},
+ dictWord{5, 10, 496},
+ dictWord{135, 10, 203},
+ dictWord{
+ 4,
+ 0,
+ 433,
+ },
+ dictWord{133, 0, 719},
+ dictWord{6, 11, 95},
+ dictWord{134, 10, 547},
+ dictWord{5, 10, 88},
+ dictWord{137, 10, 239},
+ dictWord{6, 11, 406},
+ dictWord{
+ 10,
+ 11,
+ 409,
+ },
+ dictWord{10, 11, 447},
+ dictWord{11, 11, 44},
+ dictWord{140, 11, 100},
+ dictWord{134, 0, 1423},
+ dictWord{7, 10, 650},
+ dictWord{135, 10, 1310},
+ dictWord{134, 0, 749},
+ dictWord{135, 11, 1243},
+ dictWord{135, 0, 1363},
+ dictWord{6, 0, 381},
+ dictWord{7, 0, 645},
+ dictWord{7, 0, 694},
+ dictWord{8, 0, 546},
+ dictWord{7, 10, 1076},
+ dictWord{9, 10, 80},
+ dictWord{11, 10, 78},
+ dictWord{11, 10, 421},
+ dictWord{11, 10, 534},
+ dictWord{140, 10, 545},
+ dictWord{
+ 134,
+ 11,
+ 1636,
+ },
+ dictWord{135, 11, 1344},
+ dictWord{12, 0, 277},
+ dictWord{7, 10, 274},
+ dictWord{11, 10, 479},
+ dictWord{139, 10, 507},
+ dictWord{6, 0, 705},
+ dictWord{
+ 6,
+ 0,
+ 783,
+ },
+ dictWord{6, 0, 1275},
+ dictWord{6, 0, 1481},
+ dictWord{4, 11, 282},
+ dictWord{7, 11, 1034},
+ dictWord{11, 11, 398},
+ dictWord{11, 11, 634},
+ dictWord{
+ 12,
+ 11,
+ 1,
+ },
+ dictWord{12, 11, 79},
+ dictWord{12, 11, 544},
+ dictWord{14, 11, 237},
+ dictWord{17, 11, 10},
+ dictWord{146, 11, 20},
+ dictWord{134, 0, 453},
+ dictWord{
+ 4,
+ 0,
+ 555,
+ },
+ dictWord{8, 0, 536},
+ dictWord{10, 0, 288},
+ dictWord{11, 0, 1005},
+ dictWord{4, 10, 497},
+ dictWord{135, 10, 1584},
+ dictWord{5, 11, 118},
+ dictWord{
+ 5,
+ 11,
+ 499,
+ },
+ dictWord{6, 11, 476},
+ dictWord{7, 11, 600},
+ dictWord{7, 11, 888},
+ dictWord{135, 11, 1096},
+ dictWord{138, 0, 987},
+ dictWord{7, 0, 1107},
+ dictWord{
+ 7,
+ 10,
+ 261,
+ },
+ dictWord{7, 10, 1115},
+ dictWord{7, 10, 1354},
+ dictWord{7, 10, 1588},
+ dictWord{7, 10, 1705},
+ dictWord{7, 10, 1902},
+ dictWord{9, 10, 465},
+ dictWord{10, 10, 248},
+ dictWord{10, 10, 349},
+ dictWord{10, 10, 647},
+ dictWord{11, 10, 527},
+ dictWord{11, 10, 660},
+ dictWord{11, 10, 669},
+ dictWord{
+ 12,
+ 10,
+ 529,
+ },
+ dictWord{141, 10, 305},
+ dictWord{7, 11, 296},
+ dictWord{7, 11, 596},
+ dictWord{8, 11, 560},
+ dictWord{8, 11, 586},
+ dictWord{9, 11, 612},
+ dictWord{
+ 11,
+ 11,
+ 100,
+ },
+ dictWord{11, 11, 304},
+ dictWord{12, 11, 46},
+ dictWord{13, 11, 89},
+ dictWord{14, 11, 112},
+ dictWord{145, 11, 122},
+ dictWord{9, 0, 370},
+ dictWord{
+ 138,
+ 0,
+ 90,
+ },
+ dictWord{136, 10, 13},
+ dictWord{132, 0, 860},
+ dictWord{7, 10, 642},
+ dictWord{8, 10, 250},
+ dictWord{11, 10, 123},
+ dictWord{11, 10, 137},
+ dictWord{
+ 13,
+ 10,
+ 48,
+ },
+ dictWord{142, 10, 95},
+ dictWord{135, 10, 1429},
+ dictWord{137, 11, 321},
+ dictWord{132, 0, 257},
+ dictWord{135, 0, 2031},
+ dictWord{7, 0, 1768},
+ dictWord{7, 11, 1599},
+ dictWord{7, 11, 1723},
+ dictWord{8, 11, 79},
+ dictWord{8, 11, 106},
+ dictWord{8, 11, 190},
+ dictWord{8, 11, 302},
+ dictWord{8, 11, 383},
+ dictWord{9, 11, 119},
+ dictWord{9, 11, 233},
+ dictWord{9, 11, 298},
+ dictWord{9, 11, 419},
+ dictWord{9, 11, 471},
+ dictWord{10, 11, 181},
+ dictWord{10, 11, 406},
+ dictWord{11, 11, 57},
+ dictWord{11, 11, 85},
+ dictWord{11, 11, 120},
+ dictWord{11, 11, 177},
+ dictWord{11, 11, 296},
+ dictWord{11, 11, 382},
+ dictWord{11, 11, 454},
+ dictWord{11, 11, 758},
+ dictWord{11, 11, 999},
+ dictWord{12, 11, 27},
+ dictWord{12, 11, 98},
+ dictWord{12, 11, 131},
+ dictWord{12, 11, 245},
+ dictWord{
+ 12,
+ 11,
+ 312,
+ },
+ dictWord{12, 11, 446},
+ dictWord{12, 11, 454},
+ dictWord{13, 11, 25},
+ dictWord{13, 11, 98},
+ dictWord{13, 11, 426},
+ dictWord{13, 11, 508},
+ dictWord{
+ 14,
+ 11,
+ 6,
+ },
+ dictWord{14, 11, 163},
+ dictWord{14, 11, 272},
+ dictWord{14, 11, 277},
+ dictWord{14, 11, 370},
+ dictWord{15, 11, 95},
+ dictWord{15, 11, 138},
+ dictWord{
+ 15,
+ 11,
+ 167,
+ },
+ dictWord{17, 11, 18},
+ dictWord{17, 11, 38},
+ dictWord{20, 11, 96},
+ dictWord{149, 11, 32},
+ dictWord{5, 11, 722},
+ dictWord{134, 11, 1759},
+ dictWord{145, 11, 16},
+ dictWord{6, 0, 1071},
+ dictWord{134, 0, 1561},
+ dictWord{10, 10, 545},
+ dictWord{140, 10, 301},
+ dictWord{6, 0, 83},
+ dictWord{6, 0, 1733},
+ dictWord{135, 0, 1389},
+ dictWord{4, 0, 835},
+ dictWord{135, 0, 1818},
+ dictWord{133, 11, 258},
+ dictWord{4, 10, 904},
+ dictWord{133, 10, 794},
+ dictWord{
+ 134,
+ 0,
+ 2006,
+ },
+ dictWord{5, 11, 30},
+ dictWord{7, 11, 495},
+ dictWord{8, 11, 134},
+ dictWord{9, 11, 788},
+ dictWord{140, 11, 438},
+ dictWord{135, 11, 2004},
+ dictWord{
+ 137,
+ 0,
+ 696,
+ },
+ dictWord{5, 11, 50},
+ dictWord{6, 11, 439},
+ dictWord{7, 11, 780},
+ dictWord{135, 11, 1040},
+ dictWord{7, 11, 772},
+ dictWord{7, 11, 1104},
+ dictWord{
+ 7,
+ 11,
+ 1647,
+ },
+ dictWord{11, 11, 269},
+ dictWord{11, 11, 539},
+ dictWord{11, 11, 607},
+ dictWord{11, 11, 627},
+ dictWord{11, 11, 706},
+ dictWord{11, 11, 975},
+ dictWord{12, 11, 248},
+ dictWord{12, 11, 311},
+ dictWord{12, 11, 434},
+ dictWord{12, 11, 600},
+ dictWord{12, 11, 622},
+ dictWord{13, 11, 297},
+ dictWord{
+ 13,
+ 11,
+ 367,
+ },
+ dictWord{13, 11, 485},
+ dictWord{14, 11, 69},
+ dictWord{14, 11, 409},
+ dictWord{143, 11, 108},
+ dictWord{5, 11, 1},
+ dictWord{6, 11, 81},
+ dictWord{
+ 138,
+ 11,
+ 520,
+ },
+ dictWord{7, 0, 1718},
+ dictWord{9, 0, 95},
+ dictWord{9, 0, 274},
+ dictWord{10, 0, 279},
+ dictWord{10, 0, 317},
+ dictWord{10, 0, 420},
+ dictWord{11, 0, 303},
+ dictWord{11, 0, 808},
+ dictWord{12, 0, 134},
+ dictWord{12, 0, 367},
+ dictWord{13, 0, 149},
+ dictWord{13, 0, 347},
+ dictWord{14, 0, 349},
+ dictWord{14, 0, 406},
+ dictWord{
+ 18,
+ 0,
+ 22,
+ },
+ dictWord{18, 0, 89},
+ dictWord{18, 0, 122},
+ dictWord{147, 0, 47},
+ dictWord{5, 11, 482},
+ dictWord{8, 11, 98},
+ dictWord{9, 11, 172},
+ dictWord{10, 11, 222},
+ dictWord{10, 11, 700},
+ dictWord{10, 11, 822},
+ dictWord{11, 11, 302},
+ dictWord{11, 11, 778},
+ dictWord{12, 11, 50},
+ dictWord{12, 11, 127},
+ dictWord{
+ 12,
+ 11,
+ 396,
+ },
+ dictWord{13, 11, 62},
+ dictWord{13, 11, 328},
+ dictWord{14, 11, 122},
+ dictWord{147, 11, 72},
+ dictWord{7, 10, 386},
+ dictWord{138, 10, 713},
+ dictWord{
+ 6,
+ 10,
+ 7,
+ },
+ dictWord{6, 10, 35},
+ dictWord{7, 10, 147},
+ dictWord{7, 10, 1069},
+ dictWord{7, 10, 1568},
+ dictWord{7, 10, 1575},
+ dictWord{7, 10, 1917},
+ dictWord{
+ 8,
+ 10,
+ 43,
+ },
+ dictWord{8, 10, 208},
+ dictWord{9, 10, 128},
+ dictWord{9, 10, 866},
+ dictWord{10, 10, 20},
+ dictWord{11, 10, 981},
+ dictWord{147, 10, 33},
+ dictWord{
+ 133,
+ 0,
+ 26,
+ },
+ dictWord{132, 0, 550},
+ dictWord{5, 11, 2},
+ dictWord{7, 11, 1494},
+ dictWord{136, 11, 589},
+ dictWord{6, 11, 512},
+ dictWord{7, 11, 797},
+ dictWord{
+ 8,
+ 11,
+ 253,
+ },
+ dictWord{9, 11, 77},
+ dictWord{10, 11, 1},
+ dictWord{10, 11, 129},
+ dictWord{10, 11, 225},
+ dictWord{11, 11, 118},
+ dictWord{11, 11, 226},
+ dictWord{
+ 11,
+ 11,
+ 251,
+ },
+ dictWord{11, 11, 430},
+ dictWord{11, 11, 701},
+ dictWord{11, 11, 974},
+ dictWord{11, 11, 982},
+ dictWord{12, 11, 64},
+ dictWord{12, 11, 260},
+ dictWord{
+ 12,
+ 11,
+ 488,
+ },
+ dictWord{140, 11, 690},
+ dictWord{7, 10, 893},
+ dictWord{141, 10, 424},
+ dictWord{134, 0, 901},
+ dictWord{136, 0, 822},
+ dictWord{4, 0, 902},
+ dictWord{5, 0, 809},
+ dictWord{134, 0, 122},
+ dictWord{6, 0, 807},
+ dictWord{134, 0, 1366},
+ dictWord{7, 0, 262},
+ dictWord{5, 11, 748},
+ dictWord{134, 11, 553},
+ dictWord{133, 0, 620},
+ dictWord{4, 0, 34},
+ dictWord{5, 0, 574},
+ dictWord{7, 0, 279},
+ dictWord{7, 0, 1624},
+ dictWord{136, 0, 601},
+ dictWord{9, 0, 170},
+ dictWord{
+ 6,
+ 10,
+ 322,
+ },
+ dictWord{9, 10, 552},
+ dictWord{11, 10, 274},
+ dictWord{13, 10, 209},
+ dictWord{13, 10, 499},
+ dictWord{14, 10, 85},
+ dictWord{15, 10, 126},
+ dictWord{
+ 145,
+ 10,
+ 70,
+ },
+ dictWord{132, 0, 537},
+ dictWord{4, 11, 12},
+ dictWord{7, 11, 420},
+ dictWord{7, 11, 522},
+ dictWord{7, 11, 809},
+ dictWord{8, 11, 797},
+ dictWord{
+ 141,
+ 11,
+ 88,
+ },
+ dictWord{133, 0, 332},
+ dictWord{8, 10, 83},
+ dictWord{8, 10, 742},
+ dictWord{8, 10, 817},
+ dictWord{9, 10, 28},
+ dictWord{9, 10, 29},
+ dictWord{9, 10, 885},
+ dictWord{10, 10, 387},
+ dictWord{11, 10, 633},
+ dictWord{11, 10, 740},
+ dictWord{13, 10, 235},
+ dictWord{13, 10, 254},
+ dictWord{15, 10, 143},
+ dictWord{
+ 143,
+ 10,
+ 146,
+ },
+ dictWord{6, 0, 1909},
+ dictWord{9, 0, 964},
+ dictWord{12, 0, 822},
+ dictWord{12, 0, 854},
+ dictWord{12, 0, 865},
+ dictWord{12, 0, 910},
+ dictWord{12, 0, 938},
+ dictWord{15, 0, 169},
+ dictWord{15, 0, 208},
+ dictWord{15, 0, 211},
+ dictWord{18, 0, 205},
+ dictWord{18, 0, 206},
+ dictWord{18, 0, 220},
+ dictWord{18, 0, 223},
+ dictWord{152, 0, 24},
+ dictWord{140, 10, 49},
+ dictWord{5, 11, 528},
+ dictWord{135, 11, 1580},
+ dictWord{6, 0, 261},
+ dictWord{8, 0, 182},
+ dictWord{139, 0, 943},
+ dictWord{134, 0, 1721},
+ dictWord{4, 0, 933},
+ dictWord{133, 0, 880},
+ dictWord{136, 11, 321},
+ dictWord{5, 11, 266},
+ dictWord{9, 11, 290},
+ dictWord{9, 11, 364},
+ dictWord{10, 11, 293},
+ dictWord{11, 11, 606},
+ dictWord{142, 11, 45},
+ dictWord{6, 0, 1609},
+ dictWord{4, 11, 50},
+ dictWord{6, 11, 510},
+ dictWord{6, 11, 594},
+ dictWord{9, 11, 121},
+ dictWord{10, 11, 49},
+ dictWord{10, 11, 412},
+ dictWord{139, 11, 834},
+ dictWord{7, 0, 895},
+ dictWord{136, 11, 748},
+ dictWord{132, 11, 466},
+ dictWord{4, 10, 110},
+ dictWord{10, 10, 415},
+ dictWord{10, 10, 597},
+ dictWord{142, 10, 206},
+ dictWord{133, 0, 812},
+ dictWord{135, 11, 281},
+ dictWord{
+ 6,
+ 0,
+ 1890,
+ },
+ dictWord{6, 0, 1902},
+ dictWord{6, 0, 1916},
+ dictWord{9, 0, 929},
+ dictWord{9, 0, 942},
+ dictWord{9, 0, 975},
+ dictWord{9, 0, 984},
+ dictWord{9, 0, 986},
+ dictWord{
+ 9,
+ 0,
+ 1011,
+ },
+ dictWord{9, 0, 1019},
+ dictWord{12, 0, 804},
+ dictWord{12, 0, 851},
+ dictWord{12, 0, 867},
+ dictWord{12, 0, 916},
+ dictWord{12, 0, 923},
+ dictWord{
+ 15,
+ 0,
+ 194,
+ },
+ dictWord{15, 0, 204},
+ dictWord{15, 0, 210},
+ dictWord{15, 0, 222},
+ dictWord{15, 0, 223},
+ dictWord{15, 0, 229},
+ dictWord{15, 0, 250},
+ dictWord{
+ 18,
+ 0,
+ 179,
+ },
+ dictWord{18, 0, 186},
+ dictWord{18, 0, 192},
+ dictWord{7, 10, 205},
+ dictWord{135, 10, 2000},
+ dictWord{132, 11, 667},
+ dictWord{135, 0, 778},
+ dictWord{
+ 4,
+ 0,
+ 137,
+ },
+ dictWord{7, 0, 1178},
+ dictWord{135, 0, 1520},
+ dictWord{134, 0, 1314},
+ dictWord{4, 11, 242},
+ dictWord{134, 11, 333},
+ dictWord{6, 0, 1661},
+ dictWord{7, 0, 1975},
+ dictWord{7, 0, 2009},
+ dictWord{135, 0, 2011},
+ dictWord{134, 0, 1591},
+ dictWord{4, 10, 283},
+ dictWord{135, 10, 1194},
+ dictWord{
+ 11,
+ 0,
+ 820,
+ },
+ dictWord{150, 0, 51},
+ dictWord{4, 11, 39},
+ dictWord{5, 11, 36},
+ dictWord{7, 11, 1843},
+ dictWord{8, 11, 407},
+ dictWord{11, 11, 144},
+ dictWord{
+ 140,
+ 11,
+ 523,
+ },
+ dictWord{134, 10, 1720},
+ dictWord{4, 11, 510},
+ dictWord{7, 11, 29},
+ dictWord{7, 11, 66},
+ dictWord{7, 11, 1980},
+ dictWord{10, 11, 487},
+ dictWord{
+ 10,
+ 11,
+ 809,
+ },
+ dictWord{146, 11, 9},
+ dictWord{5, 0, 89},
+ dictWord{7, 0, 1915},
+ dictWord{9, 0, 185},
+ dictWord{9, 0, 235},
+ dictWord{10, 0, 64},
+ dictWord{10, 0, 270},
+ dictWord{10, 0, 403},
+ dictWord{10, 0, 469},
+ dictWord{10, 0, 529},
+ dictWord{10, 0, 590},
+ dictWord{11, 0, 140},
+ dictWord{11, 0, 860},
+ dictWord{13, 0, 1},
+ dictWord{
+ 13,
+ 0,
+ 422,
+ },
+ dictWord{14, 0, 341},
+ dictWord{14, 0, 364},
+ dictWord{17, 0, 93},
+ dictWord{18, 0, 113},
+ dictWord{19, 0, 97},
+ dictWord{147, 0, 113},
+ dictWord{133, 0, 695},
+ dictWord{6, 0, 987},
+ dictWord{134, 0, 1160},
+ dictWord{5, 0, 6},
+ dictWord{6, 0, 183},
+ dictWord{7, 0, 680},
+ dictWord{7, 0, 978},
+ dictWord{7, 0, 1013},
+ dictWord{
+ 7,
+ 0,
+ 1055,
+ },
+ dictWord{12, 0, 230},
+ dictWord{13, 0, 172},
+ dictWord{146, 0, 29},
+ dictWord{134, 11, 570},
+ dictWord{132, 11, 787},
+ dictWord{134, 11, 518},
+ dictWord{
+ 6,
+ 0,
+ 29,
+ },
+ dictWord{139, 0, 63},
+ dictWord{132, 11, 516},
+ dictWord{136, 11, 821},
+ dictWord{132, 0, 311},
+ dictWord{134, 0, 1740},
+ dictWord{7, 0, 170},
+ dictWord{8, 0, 90},
+ dictWord{8, 0, 177},
+ dictWord{8, 0, 415},
+ dictWord{11, 0, 714},
+ dictWord{14, 0, 281},
+ dictWord{136, 10, 735},
+ dictWord{134, 0, 1961},
+ dictWord{
+ 135,
+ 11,
+ 1405,
+ },
+ dictWord{4, 11, 10},
+ dictWord{7, 11, 917},
+ dictWord{139, 11, 786},
+ dictWord{5, 10, 132},
+ dictWord{9, 10, 486},
+ dictWord{9, 10, 715},
+ dictWord{
+ 10,
+ 10,
+ 458,
+ },
+ dictWord{11, 10, 373},
+ dictWord{11, 10, 668},
+ dictWord{11, 10, 795},
+ dictWord{11, 10, 897},
+ dictWord{12, 10, 272},
+ dictWord{12, 10, 424},
+ dictWord{12, 10, 539},
+ dictWord{12, 10, 558},
+ dictWord{14, 10, 245},
+ dictWord{14, 10, 263},
+ dictWord{14, 10, 264},
+ dictWord{14, 10, 393},
+ dictWord{
+ 142,
+ 10,
+ 403,
+ },
+ dictWord{11, 0, 91},
+ dictWord{13, 0, 129},
+ dictWord{15, 0, 101},
+ dictWord{145, 0, 125},
+ dictWord{135, 0, 1132},
+ dictWord{4, 0, 494},
+ dictWord{6, 0, 74},
+ dictWord{7, 0, 44},
+ dictWord{7, 0, 407},
+ dictWord{12, 0, 17},
+ dictWord{15, 0, 5},
+ dictWord{148, 0, 11},
+ dictWord{133, 10, 379},
+ dictWord{5, 0, 270},
+ dictWord{
+ 5,
+ 11,
+ 684,
+ },
+ dictWord{6, 10, 89},
+ dictWord{6, 10, 400},
+ dictWord{7, 10, 1569},
+ dictWord{7, 10, 1623},
+ dictWord{7, 10, 1850},
+ dictWord{8, 10, 218},
+ dictWord{
+ 8,
+ 10,
+ 422,
+ },
+ dictWord{9, 10, 570},
+ dictWord{138, 10, 626},
+ dictWord{4, 0, 276},
+ dictWord{133, 0, 296},
+ dictWord{6, 0, 1523},
+ dictWord{134, 11, 27},
+ dictWord{
+ 6,
+ 10,
+ 387,
+ },
+ dictWord{7, 10, 882},
+ dictWord{141, 10, 111},
+ dictWord{6, 10, 224},
+ dictWord{7, 10, 877},
+ dictWord{137, 10, 647},
+ dictWord{135, 10, 790},
+ dictWord{
+ 4,
+ 0,
+ 7,
+ },
+ dictWord{5, 0, 90},
+ dictWord{5, 0, 158},
+ dictWord{6, 0, 542},
+ dictWord{7, 0, 221},
+ dictWord{7, 0, 1574},
+ dictWord{9, 0, 490},
+ dictWord{10, 0, 540},
+ dictWord{
+ 11,
+ 0,
+ 443,
+ },
+ dictWord{139, 0, 757},
+ dictWord{7, 0, 588},
+ dictWord{9, 0, 175},
+ dictWord{138, 0, 530},
+ dictWord{135, 10, 394},
+ dictWord{142, 11, 23},
+ dictWord{
+ 134,
+ 0,
+ 786,
+ },
+ dictWord{135, 0, 580},
+ dictWord{7, 0, 88},
+ dictWord{136, 0, 627},
+ dictWord{5, 0, 872},
+ dictWord{6, 0, 57},
+ dictWord{7, 0, 471},
+ dictWord{9, 0, 447},
+ dictWord{137, 0, 454},
+ dictWord{6, 11, 342},
+ dictWord{6, 11, 496},
+ dictWord{8, 11, 275},
+ dictWord{137, 11, 206},
+ dictWord{4, 11, 909},
+ dictWord{133, 11, 940},
+ dictWord{6, 0, 735},
+ dictWord{132, 11, 891},
+ dictWord{8, 0, 845},
+ dictWord{8, 0, 916},
+ dictWord{135, 10, 1409},
+ dictWord{5, 0, 31},
+ dictWord{134, 0, 614},
+ dictWord{11, 0, 458},
+ dictWord{12, 0, 15},
+ dictWord{140, 0, 432},
+ dictWord{8, 0, 330},
+ dictWord{140, 0, 477},
+ dictWord{4, 0, 530},
+ dictWord{5, 0, 521},
+ dictWord{
+ 7,
+ 0,
+ 1200,
+ },
+ dictWord{10, 0, 460},
+ dictWord{132, 11, 687},
+ dictWord{6, 0, 424},
+ dictWord{135, 0, 1866},
+ dictWord{9, 0, 569},
+ dictWord{12, 0, 12},
+ dictWord{
+ 12,
+ 0,
+ 81,
+ },
+ dictWord{12, 0, 319},
+ dictWord{13, 0, 69},
+ dictWord{14, 0, 259},
+ dictWord{16, 0, 87},
+ dictWord{17, 0, 1},
+ dictWord{17, 0, 21},
+ dictWord{17, 0, 24},
+ dictWord{
+ 18,
+ 0,
+ 15,
+ },
+ dictWord{18, 0, 56},
+ dictWord{18, 0, 59},
+ dictWord{18, 0, 127},
+ dictWord{18, 0, 154},
+ dictWord{19, 0, 19},
+ dictWord{148, 0, 31},
+ dictWord{7, 0, 1302},
+ dictWord{136, 10, 38},
+ dictWord{134, 11, 253},
+ dictWord{5, 10, 261},
+ dictWord{7, 10, 78},
+ dictWord{7, 10, 199},
+ dictWord{8, 10, 815},
+ dictWord{9, 10, 126},
+ dictWord{138, 10, 342},
+ dictWord{5, 0, 595},
+ dictWord{135, 0, 1863},
+ dictWord{6, 11, 41},
+ dictWord{141, 11, 160},
+ dictWord{5, 0, 13},
+ dictWord{134, 0, 142},
+ dictWord{6, 0, 97},
+ dictWord{7, 0, 116},
+ dictWord{8, 0, 322},
+ dictWord{8, 0, 755},
+ dictWord{9, 0, 548},
+ dictWord{10, 0, 714},
+ dictWord{11, 0, 884},
+ dictWord{13, 0, 324},
+ dictWord{7, 11, 1304},
+ dictWord{138, 11, 477},
+ dictWord{132, 10, 628},
+ dictWord{134, 11, 1718},
+ dictWord{7, 10, 266},
+ dictWord{136, 10, 804},
+ dictWord{135, 10, 208},
+ dictWord{7, 0, 1021},
+ dictWord{6, 10, 79},
+ dictWord{135, 10, 1519},
+ dictWord{7, 0, 1472},
+ dictWord{135, 0, 1554},
+ dictWord{6, 11, 362},
+ dictWord{146, 11, 51},
+ dictWord{7, 0, 1071},
+ dictWord{7, 0, 1541},
+ dictWord{7, 0, 1767},
+ dictWord{7, 0, 1806},
+ dictWord{11, 0, 162},
+ dictWord{11, 0, 242},
+ dictWord{11, 0, 452},
+ dictWord{12, 0, 605},
+ dictWord{15, 0, 26},
+ dictWord{144, 0, 44},
+ dictWord{136, 10, 741},
+ dictWord{133, 11, 115},
+ dictWord{145, 0, 115},
+ dictWord{134, 10, 376},
+ dictWord{6, 0, 1406},
+ dictWord{134, 0, 1543},
+ dictWord{5, 11, 193},
+ dictWord{12, 11, 178},
+ dictWord{13, 11, 130},
+ dictWord{
+ 145,
+ 11,
+ 84,
+ },
+ dictWord{135, 0, 1111},
+ dictWord{8, 0, 1},
+ dictWord{9, 0, 650},
+ dictWord{10, 0, 326},
+ dictWord{5, 11, 705},
+ dictWord{137, 11, 606},
+ dictWord{5, 0, 488},
+ dictWord{6, 0, 527},
+ dictWord{7, 0, 489},
+ dictWord{7, 0, 1636},
+ dictWord{8, 0, 121},
+ dictWord{8, 0, 144},
+ dictWord{8, 0, 359},
+ dictWord{9, 0, 193},
+ dictWord{9, 0, 241},
+ dictWord{9, 0, 336},
+ dictWord{9, 0, 882},
+ dictWord{11, 0, 266},
+ dictWord{11, 0, 372},
+ dictWord{11, 0, 944},
+ dictWord{12, 0, 401},
+ dictWord{140, 0, 641},
+ dictWord{135, 11, 174},
+ dictWord{6, 0, 267},
+ dictWord{7, 10, 244},
+ dictWord{7, 10, 632},
+ dictWord{7, 10, 1609},
+ dictWord{8, 10, 178},
+ dictWord{8, 10, 638},
+ dictWord{141, 10, 58},
+ dictWord{134, 0, 1983},
+ dictWord{134, 0, 1155},
+ dictWord{134, 0, 1575},
+ dictWord{134, 0, 1438},
+ dictWord{9, 0, 31},
+ dictWord{
+ 10,
+ 0,
+ 244,
+ },
+ dictWord{10, 0, 699},
+ dictWord{12, 0, 149},
+ dictWord{141, 0, 497},
+ dictWord{133, 0, 377},
+ dictWord{4, 11, 122},
+ dictWord{5, 11, 796},
+ dictWord{
+ 5,
+ 11,
+ 952,
+ },
+ dictWord{6, 11, 1660},
+ dictWord{6, 11, 1671},
+ dictWord{8, 11, 567},
+ dictWord{9, 11, 687},
+ dictWord{9, 11, 742},
+ dictWord{10, 11, 686},
+ dictWord{
+ 11,
+ 11,
+ 356,
+ },
+ dictWord{11, 11, 682},
+ dictWord{140, 11, 281},
+ dictWord{145, 0, 101},
+ dictWord{11, 11, 0},
+ dictWord{144, 11, 78},
+ dictWord{5, 11, 179},
+ dictWord{
+ 5,
+ 10,
+ 791,
+ },
+ dictWord{7, 11, 1095},
+ dictWord{135, 11, 1213},
+ dictWord{8, 11, 372},
+ dictWord{9, 11, 122},
+ dictWord{138, 11, 175},
+ dictWord{7, 10, 686},
+ dictWord{8, 10, 33},
+ dictWord{8, 10, 238},
+ dictWord{10, 10, 616},
+ dictWord{11, 10, 467},
+ dictWord{11, 10, 881},
+ dictWord{13, 10, 217},
+ dictWord{13, 10, 253},
+ dictWord{142, 10, 268},
+ dictWord{9, 0, 476},
+ dictWord{4, 11, 66},
+ dictWord{7, 11, 722},
+ dictWord{135, 11, 904},
+ dictWord{7, 11, 352},
+ dictWord{137, 11, 684},
+ dictWord{135, 0, 2023},
+ dictWord{135, 0, 1836},
+ dictWord{132, 10, 447},
+ dictWord{5, 0, 843},
+ dictWord{144, 0, 35},
+ dictWord{137, 11, 779},
+ dictWord{
+ 141,
+ 11,
+ 35,
+ },
+ dictWord{4, 10, 128},
+ dictWord{5, 10, 415},
+ dictWord{6, 10, 462},
+ dictWord{7, 10, 294},
+ dictWord{7, 10, 578},
+ dictWord{10, 10, 710},
+ dictWord{
+ 139,
+ 10,
+ 86,
+ },
+ dictWord{132, 0, 554},
+ dictWord{133, 0, 536},
+ dictWord{136, 10, 587},
+ dictWord{5, 0, 207},
+ dictWord{9, 0, 79},
+ dictWord{11, 0, 625},
+ dictWord{
+ 145,
+ 0,
+ 7,
+ },
+ dictWord{7, 0, 1371},
+ dictWord{6, 10, 427},
+ dictWord{138, 10, 692},
+ dictWord{4, 0, 424},
+ dictWord{4, 10, 195},
+ dictWord{135, 10, 802},
+ dictWord{
+ 8,
+ 0,
+ 785,
+ },
+ dictWord{133, 11, 564},
+ dictWord{135, 0, 336},
+ dictWord{4, 0, 896},
+ dictWord{6, 0, 1777},
+ dictWord{134, 11, 556},
+ dictWord{137, 11, 103},
+ dictWord{134, 10, 1683},
+ dictWord{7, 11, 544},
+ dictWord{8, 11, 719},
+ dictWord{138, 11, 61},
+ dictWord{138, 10, 472},
+ dictWord{4, 11, 5},
+ dictWord{5, 11, 498},
+ dictWord{136, 11, 637},
+ dictWord{7, 0, 750},
+ dictWord{9, 0, 223},
+ dictWord{11, 0, 27},
+ dictWord{11, 0, 466},
+ dictWord{12, 0, 624},
+ dictWord{14, 0, 265},
+ dictWord{
+ 146,
+ 0,
+ 61,
+ },
+ dictWord{12, 0, 238},
+ dictWord{18, 0, 155},
+ dictWord{12, 11, 238},
+ dictWord{146, 11, 155},
+ dictWord{151, 10, 28},
+ dictWord{133, 11, 927},
+ dictWord{12, 0, 383},
+ dictWord{5, 10, 3},
+ dictWord{8, 10, 578},
+ dictWord{9, 10, 118},
+ dictWord{10, 10, 705},
+ dictWord{141, 10, 279},
+ dictWord{4, 11, 893},
+ dictWord{
+ 5,
+ 11,
+ 780,
+ },
+ dictWord{133, 11, 893},
+ dictWord{4, 0, 603},
+ dictWord{133, 0, 661},
+ dictWord{4, 0, 11},
+ dictWord{6, 0, 128},
+ dictWord{7, 0, 231},
+ dictWord{
+ 7,
+ 0,
+ 1533,
+ },
+ dictWord{10, 0, 725},
+ dictWord{5, 10, 229},
+ dictWord{5, 11, 238},
+ dictWord{135, 11, 1350},
+ dictWord{8, 10, 102},
+ dictWord{10, 10, 578},
+ dictWord{
+ 10,
+ 10,
+ 672,
+ },
+ dictWord{12, 10, 496},
+ dictWord{13, 10, 408},
+ dictWord{14, 10, 121},
+ dictWord{145, 10, 106},
+ dictWord{132, 0, 476},
+ dictWord{134, 0, 1552},
+ dictWord{134, 11, 1729},
+ dictWord{8, 10, 115},
+ dictWord{8, 10, 350},
+ dictWord{9, 10, 489},
+ dictWord{10, 10, 128},
+ dictWord{11, 10, 306},
+ dictWord{
+ 12,
+ 10,
+ 373,
+ },
+ dictWord{14, 10, 30},
+ dictWord{17, 10, 79},
+ dictWord{19, 10, 80},
+ dictWord{150, 10, 55},
+ dictWord{135, 0, 1807},
+ dictWord{4, 0, 680},
+ dictWord{
+ 4,
+ 11,
+ 60,
+ },
+ dictWord{7, 11, 760},
+ dictWord{7, 11, 1800},
+ dictWord{8, 11, 314},
+ dictWord{9, 11, 700},
+ dictWord{139, 11, 487},
+ dictWord{4, 10, 230},
+ dictWord{
+ 5,
+ 10,
+ 702,
+ },
+ dictWord{148, 11, 94},
+ dictWord{132, 11, 228},
+ dictWord{139, 0, 435},
+ dictWord{9, 0, 20},
+ dictWord{10, 0, 324},
+ dictWord{10, 0, 807},
+ dictWord{
+ 139,
+ 0,
+ 488,
+ },
+ dictWord{6, 10, 1728},
+ dictWord{136, 11, 419},
+ dictWord{4, 10, 484},
+ dictWord{18, 10, 26},
+ dictWord{19, 10, 42},
+ dictWord{20, 10, 43},
+ dictWord{
+ 21,
+ 10,
+ 0,
+ },
+ dictWord{23, 10, 27},
+ dictWord{152, 10, 14},
+ dictWord{135, 0, 1431},
+ dictWord{133, 11, 828},
+ dictWord{5, 0, 112},
+ dictWord{6, 0, 103},
+ dictWord{
+ 6,
+ 0,
+ 150,
+ },
+ dictWord{7, 0, 1303},
+ dictWord{9, 0, 292},
+ dictWord{10, 0, 481},
+ dictWord{20, 0, 13},
+ dictWord{7, 11, 176},
+ dictWord{7, 11, 178},
+ dictWord{7, 11, 1110},
+ dictWord{10, 11, 481},
+ dictWord{148, 11, 13},
+ dictWord{138, 0, 356},
+ dictWord{4, 11, 51},
+ dictWord{5, 11, 39},
+ dictWord{6, 11, 4},
+ dictWord{7, 11, 591},
+ dictWord{
+ 7,
+ 11,
+ 849,
+ },
+ dictWord{7, 11, 951},
+ dictWord{7, 11, 1129},
+ dictWord{7, 11, 1613},
+ dictWord{7, 11, 1760},
+ dictWord{7, 11, 1988},
+ dictWord{9, 11, 434},
+ dictWord{10, 11, 754},
+ dictWord{11, 11, 25},
+ dictWord{11, 11, 37},
+ dictWord{139, 11, 414},
+ dictWord{6, 0, 1963},
+ dictWord{134, 0, 2000},
+ dictWord{
+ 132,
+ 10,
+ 633,
+ },
+ dictWord{6, 0, 1244},
+ dictWord{133, 11, 902},
+ dictWord{135, 11, 928},
+ dictWord{140, 0, 18},
+ dictWord{138, 0, 204},
+ dictWord{135, 11, 1173},
+ dictWord{134, 0, 867},
+ dictWord{4, 0, 708},
+ dictWord{8, 0, 15},
+ dictWord{9, 0, 50},
+ dictWord{9, 0, 386},
+ dictWord{11, 0, 18},
+ dictWord{11, 0, 529},
+ dictWord{140, 0, 228},
+ dictWord{134, 11, 270},
+ dictWord{4, 0, 563},
+ dictWord{7, 0, 109},
+ dictWord{7, 0, 592},
+ dictWord{7, 0, 637},
+ dictWord{7, 0, 770},
+ dictWord{8, 0, 463},
+ dictWord{
+ 9,
+ 0,
+ 60,
+ },
+ dictWord{9, 0, 335},
+ dictWord{9, 0, 904},
+ dictWord{10, 0, 73},
+ dictWord{11, 0, 434},
+ dictWord{12, 0, 585},
+ dictWord{13, 0, 331},
+ dictWord{18, 0, 110},
+ dictWord{148, 0, 60},
+ dictWord{132, 0, 502},
+ dictWord{14, 11, 359},
+ dictWord{19, 11, 52},
+ dictWord{148, 11, 47},
+ dictWord{6, 11, 377},
+ dictWord{7, 11, 1025},
+ dictWord{9, 11, 613},
+ dictWord{145, 11, 104},
+ dictWord{6, 0, 347},
+ dictWord{10, 0, 161},
+ dictWord{5, 10, 70},
+ dictWord{5, 10, 622},
+ dictWord{6, 10, 334},
+ dictWord{
+ 7,
+ 10,
+ 1032,
+ },
+ dictWord{9, 10, 171},
+ dictWord{11, 10, 26},
+ dictWord{11, 10, 213},
+ dictWord{11, 10, 637},
+ dictWord{11, 10, 707},
+ dictWord{12, 10, 202},
+ dictWord{12, 10, 380},
+ dictWord{13, 10, 226},
+ dictWord{13, 10, 355},
+ dictWord{14, 10, 222},
+ dictWord{145, 10, 42},
+ dictWord{132, 11, 416},
+ dictWord{4, 0, 33},
+ dictWord{5, 0, 102},
+ dictWord{6, 0, 284},
+ dictWord{7, 0, 1079},
+ dictWord{7, 0, 1423},
+ dictWord{7, 0, 1702},
+ dictWord{8, 0, 470},
+ dictWord{9, 0, 554},
+ dictWord{
+ 9,
+ 0,
+ 723,
+ },
+ dictWord{11, 0, 333},
+ dictWord{142, 11, 372},
+ dictWord{5, 11, 152},
+ dictWord{5, 11, 197},
+ dictWord{7, 11, 340},
+ dictWord{7, 11, 867},
+ dictWord{
+ 10,
+ 11,
+ 548,
+ },
+ dictWord{10, 11, 581},
+ dictWord{11, 11, 6},
+ dictWord{12, 11, 3},
+ dictWord{12, 11, 19},
+ dictWord{14, 11, 110},
+ dictWord{142, 11, 289},
+ dictWord{
+ 7,
+ 0,
+ 246,
+ },
+ dictWord{135, 0, 840},
+ dictWord{6, 0, 10},
+ dictWord{8, 0, 571},
+ dictWord{9, 0, 739},
+ dictWord{143, 0, 91},
+ dictWord{6, 0, 465},
+ dictWord{7, 0, 1465},
+ dictWord{
+ 4,
+ 10,
+ 23,
+ },
+ dictWord{4, 10, 141},
+ dictWord{5, 10, 313},
+ dictWord{5, 10, 1014},
+ dictWord{6, 10, 50},
+ dictWord{7, 10, 142},
+ dictWord{7, 10, 559},
+ dictWord{
+ 8,
+ 10,
+ 640,
+ },
+ dictWord{9, 10, 460},
+ dictWord{9, 10, 783},
+ dictWord{11, 10, 741},
+ dictWord{12, 10, 183},
+ dictWord{141, 10, 488},
+ dictWord{133, 0, 626},
+ dictWord{
+ 136,
+ 0,
+ 614,
+ },
+ dictWord{138, 0, 237},
+ dictWord{7, 11, 34},
+ dictWord{7, 11, 190},
+ dictWord{8, 11, 28},
+ dictWord{8, 11, 141},
+ dictWord{8, 11, 444},
+ dictWord{
+ 8,
+ 11,
+ 811,
+ },
+ dictWord{9, 11, 468},
+ dictWord{11, 11, 334},
+ dictWord{12, 11, 24},
+ dictWord{12, 11, 386},
+ dictWord{140, 11, 576},
+ dictWord{133, 11, 757},
+ dictWord{
+ 5,
+ 0,
+ 18,
+ },
+ dictWord{6, 0, 526},
+ dictWord{13, 0, 24},
+ dictWord{13, 0, 110},
+ dictWord{19, 0, 5},
+ dictWord{147, 0, 44},
+ dictWord{6, 0, 506},
+ dictWord{134, 11, 506},
+ dictWord{135, 11, 1553},
+ dictWord{4, 0, 309},
+ dictWord{5, 0, 462},
+ dictWord{7, 0, 970},
+ dictWord{7, 0, 1097},
+ dictWord{22, 0, 30},
+ dictWord{22, 0, 33},
+ dictWord{
+ 7,
+ 11,
+ 1385,
+ },
+ dictWord{11, 11, 582},
+ dictWord{11, 11, 650},
+ dictWord{11, 11, 901},
+ dictWord{11, 11, 949},
+ dictWord{12, 11, 232},
+ dictWord{12, 11, 236},
+ dictWord{13, 11, 413},
+ dictWord{13, 11, 501},
+ dictWord{146, 11, 116},
+ dictWord{9, 0, 140},
+ dictWord{5, 10, 222},
+ dictWord{138, 10, 534},
+ dictWord{6, 0, 1056},
+ dictWord{137, 10, 906},
+ dictWord{134, 0, 1704},
+ dictWord{138, 10, 503},
+ dictWord{134, 0, 1036},
+ dictWord{5, 10, 154},
+ dictWord{7, 10, 1491},
+ dictWord{
+ 10,
+ 10,
+ 379,
+ },
+ dictWord{138, 10, 485},
+ dictWord{4, 11, 383},
+ dictWord{133, 10, 716},
+ dictWord{134, 0, 1315},
+ dictWord{5, 0, 86},
+ dictWord{7, 0, 743},
+ dictWord{
+ 9,
+ 0,
+ 85,
+ },
+ dictWord{10, 0, 281},
+ dictWord{10, 0, 432},
+ dictWord{11, 0, 825},
+ dictWord{12, 0, 251},
+ dictWord{13, 0, 118},
+ dictWord{142, 0, 378},
+ dictWord{
+ 8,
+ 0,
+ 264,
+ },
+ dictWord{4, 10, 91},
+ dictWord{5, 10, 388},
+ dictWord{5, 10, 845},
+ dictWord{6, 10, 206},
+ dictWord{6, 10, 252},
+ dictWord{6, 10, 365},
+ dictWord{7, 10, 136},
+ dictWord{7, 10, 531},
+ dictWord{136, 10, 621},
+ dictWord{5, 0, 524},
+ dictWord{133, 0, 744},
+ dictWord{5, 11, 277},
+ dictWord{141, 11, 247},
+ dictWord{
+ 132,
+ 11,
+ 435,
+ },
+ dictWord{10, 0, 107},
+ dictWord{140, 0, 436},
+ dictWord{132, 0, 927},
+ dictWord{10, 0, 123},
+ dictWord{12, 0, 670},
+ dictWord{146, 0, 94},
+ dictWord{
+ 7,
+ 0,
+ 1149,
+ },
+ dictWord{9, 0, 156},
+ dictWord{138, 0, 957},
+ dictWord{5, 11, 265},
+ dictWord{6, 11, 212},
+ dictWord{135, 11, 28},
+ dictWord{133, 0, 778},
+ dictWord{
+ 133,
+ 0,
+ 502,
+ },
+ dictWord{8, 0, 196},
+ dictWord{10, 0, 283},
+ dictWord{139, 0, 406},
+ dictWord{135, 10, 576},
+ dictWord{136, 11, 535},
+ dictWord{134, 0, 1312},
+ dictWord{
+ 5,
+ 10,
+ 771,
+ },
+ dictWord{5, 10, 863},
+ dictWord{5, 10, 898},
+ dictWord{6, 10, 1632},
+ dictWord{6, 10, 1644},
+ dictWord{134, 10, 1780},
+ dictWord{5, 0, 855},
+ dictWord{5, 10, 331},
+ dictWord{135, 11, 1487},
+ dictWord{132, 11, 702},
+ dictWord{5, 11, 808},
+ dictWord{135, 11, 2045},
+ dictWord{7, 0, 1400},
+ dictWord{
+ 9,
+ 0,
+ 446,
+ },
+ dictWord{138, 0, 45},
+ dictWord{140, 10, 632},
+ dictWord{132, 0, 1003},
+ dictWord{5, 11, 166},
+ dictWord{8, 11, 739},
+ dictWord{140, 11, 511},
+ dictWord{
+ 5,
+ 10,
+ 107,
+ },
+ dictWord{7, 10, 201},
+ dictWord{136, 10, 518},
+ dictWord{6, 10, 446},
+ dictWord{135, 10, 1817},
+ dictWord{134, 0, 1532},
+ dictWord{
+ 134,
+ 0,
+ 1097,
+ },
+ dictWord{4, 11, 119},
+ dictWord{5, 11, 170},
+ dictWord{5, 11, 447},
+ dictWord{7, 11, 1708},
+ dictWord{7, 11, 1889},
+ dictWord{9, 11, 357},
+ dictWord{
+ 9,
+ 11,
+ 719,
+ },
+ dictWord{12, 11, 486},
+ dictWord{140, 11, 596},
+ dictWord{9, 10, 851},
+ dictWord{141, 10, 510},
+ dictWord{7, 0, 612},
+ dictWord{8, 0, 545},
+ dictWord{
+ 8,
+ 0,
+ 568,
+ },
+ dictWord{8, 0, 642},
+ dictWord{9, 0, 717},
+ dictWord{10, 0, 541},
+ dictWord{10, 0, 763},
+ dictWord{11, 0, 449},
+ dictWord{12, 0, 489},
+ dictWord{13, 0, 153},
+ dictWord{13, 0, 296},
+ dictWord{14, 0, 138},
+ dictWord{14, 0, 392},
+ dictWord{15, 0, 50},
+ dictWord{16, 0, 6},
+ dictWord{16, 0, 12},
+ dictWord{20, 0, 9},
+ dictWord{
+ 132,
+ 10,
+ 504,
+ },
+ dictWord{4, 11, 450},
+ dictWord{135, 11, 1158},
+ dictWord{11, 0, 54},
+ dictWord{13, 0, 173},
+ dictWord{13, 0, 294},
+ dictWord{5, 10, 883},
+ dictWord{
+ 5,
+ 10,
+ 975,
+ },
+ dictWord{8, 10, 392},
+ dictWord{148, 10, 7},
+ dictWord{13, 0, 455},
+ dictWord{15, 0, 99},
+ dictWord{15, 0, 129},
+ dictWord{144, 0, 68},
+ dictWord{135, 0, 172},
+ dictWord{132, 11, 754},
+ dictWord{5, 10, 922},
+ dictWord{134, 10, 1707},
+ dictWord{134, 0, 1029},
+ dictWord{17, 11, 39},
+ dictWord{148, 11, 36},
+ dictWord{
+ 4,
+ 0,
+ 568,
+ },
+ dictWord{5, 10, 993},
+ dictWord{7, 10, 515},
+ dictWord{137, 10, 91},
+ dictWord{132, 0, 732},
+ dictWord{10, 0, 617},
+ dictWord{138, 11, 617},
+ dictWord{
+ 134,
+ 0,
+ 974,
+ },
+ dictWord{7, 0, 989},
+ dictWord{10, 0, 377},
+ dictWord{12, 0, 363},
+ dictWord{13, 0, 68},
+ dictWord{13, 0, 94},
+ dictWord{14, 0, 108},
+ dictWord{
+ 142,
+ 0,
+ 306,
+ },
+ dictWord{136, 0, 733},
+ dictWord{132, 0, 428},
+ dictWord{7, 0, 1789},
+ dictWord{135, 11, 1062},
+ dictWord{7, 0, 2015},
+ dictWord{140, 0, 665},
+ dictWord{135, 10, 1433},
+ dictWord{5, 0, 287},
+ dictWord{7, 10, 921},
+ dictWord{8, 10, 580},
+ dictWord{8, 10, 593},
+ dictWord{8, 10, 630},
+ dictWord{138, 10, 28},
+ dictWord{138, 0, 806},
+ dictWord{4, 10, 911},
+ dictWord{5, 10, 867},
+ dictWord{5, 10, 1013},
+ dictWord{7, 10, 2034},
+ dictWord{8, 10, 798},
+ dictWord{136, 10, 813},
+ dictWord{134, 0, 1539},
+ dictWord{8, 11, 523},
+ dictWord{150, 11, 34},
+ dictWord{135, 11, 740},
+ dictWord{7, 11, 238},
+ dictWord{7, 11, 2033},
+ dictWord{
+ 8,
+ 11,
+ 120,
+ },
+ dictWord{8, 11, 188},
+ dictWord{8, 11, 659},
+ dictWord{9, 11, 598},
+ dictWord{10, 11, 466},
+ dictWord{12, 11, 342},
+ dictWord{12, 11, 588},
+ dictWord{
+ 13,
+ 11,
+ 503,
+ },
+ dictWord{14, 11, 246},
+ dictWord{143, 11, 92},
+ dictWord{7, 0, 1563},
+ dictWord{141, 0, 182},
+ dictWord{5, 10, 135},
+ dictWord{6, 10, 519},
+ dictWord{
+ 7,
+ 10,
+ 1722,
+ },
+ dictWord{10, 10, 271},
+ dictWord{11, 10, 261},
+ dictWord{145, 10, 54},
+ dictWord{14, 10, 338},
+ dictWord{148, 10, 81},
+ dictWord{7, 0, 484},
+ dictWord{
+ 4,
+ 10,
+ 300,
+ },
+ dictWord{133, 10, 436},
+ dictWord{145, 11, 114},
+ dictWord{6, 0, 1623},
+ dictWord{134, 0, 1681},
+ dictWord{133, 11, 640},
+ dictWord{4, 11, 201},
+ dictWord{7, 11, 1744},
+ dictWord{8, 11, 602},
+ dictWord{11, 11, 247},
+ dictWord{11, 11, 826},
+ dictWord{145, 11, 65},
+ dictWord{8, 11, 164},
+ dictWord{
+ 146,
+ 11,
+ 62,
+ },
+ dictWord{6, 0, 1833},
+ dictWord{6, 0, 1861},
+ dictWord{136, 0, 878},
+ dictWord{134, 0, 1569},
+ dictWord{8, 10, 357},
+ dictWord{10, 10, 745},
+ dictWord{
+ 14,
+ 10,
+ 426,
+ },
+ dictWord{17, 10, 94},
+ dictWord{147, 10, 57},
+ dictWord{12, 0, 93},
+ dictWord{12, 0, 501},
+ dictWord{13, 0, 362},
+ dictWord{14, 0, 151},
+ dictWord{15, 0, 40},
+ dictWord{15, 0, 59},
+ dictWord{16, 0, 46},
+ dictWord{17, 0, 25},
+ dictWord{18, 0, 14},
+ dictWord{18, 0, 134},
+ dictWord{19, 0, 25},
+ dictWord{19, 0, 69},
+ dictWord{
+ 20,
+ 0,
+ 16,
+ },
+ dictWord{20, 0, 19},
+ dictWord{20, 0, 66},
+ dictWord{21, 0, 23},
+ dictWord{21, 0, 25},
+ dictWord{150, 0, 42},
+ dictWord{6, 0, 1748},
+ dictWord{8, 0, 715},
+ dictWord{
+ 9,
+ 0,
+ 802,
+ },
+ dictWord{10, 0, 46},
+ dictWord{10, 0, 819},
+ dictWord{13, 0, 308},
+ dictWord{14, 0, 351},
+ dictWord{14, 0, 363},
+ dictWord{146, 0, 67},
+ dictWord{
+ 132,
+ 0,
+ 994,
+ },
+ dictWord{4, 0, 63},
+ dictWord{133, 0, 347},
+ dictWord{132, 0, 591},
+ dictWord{133, 0, 749},
+ dictWord{7, 11, 1577},
+ dictWord{10, 11, 304},
+ dictWord{
+ 10,
+ 11,
+ 549,
+ },
+ dictWord{11, 11, 424},
+ dictWord{12, 11, 365},
+ dictWord{13, 11, 220},
+ dictWord{13, 11, 240},
+ dictWord{142, 11, 33},
+ dictWord{133, 0, 366},
+ dictWord{
+ 7,
+ 0,
+ 557,
+ },
+ dictWord{12, 0, 547},
+ dictWord{14, 0, 86},
+ dictWord{133, 10, 387},
+ dictWord{135, 0, 1747},
+ dictWord{132, 11, 907},
+ dictWord{5, 11, 100},
+ dictWord{10, 11, 329},
+ dictWord{12, 11, 416},
+ dictWord{149, 11, 29},
+ dictWord{4, 10, 6},
+ dictWord{5, 10, 708},
+ dictWord{136, 10, 75},
+ dictWord{7, 10, 1351},
+ dictWord{9, 10, 581},
+ dictWord{10, 10, 639},
+ dictWord{11, 10, 453},
+ dictWord{140, 10, 584},
+ dictWord{7, 0, 89},
+ dictWord{132, 10, 303},
+ dictWord{138, 10, 772},
+ dictWord{132, 11, 176},
+ dictWord{5, 11, 636},
+ dictWord{5, 11, 998},
+ dictWord{8, 11, 26},
+ dictWord{137, 11, 358},
+ dictWord{7, 11, 9},
+ dictWord{7, 11, 1508},
+ dictWord{9, 11, 317},
+ dictWord{10, 11, 210},
+ dictWord{10, 11, 292},
+ dictWord{10, 11, 533},
+ dictWord{11, 11, 555},
+ dictWord{12, 11, 526},
+ dictWord{
+ 12,
+ 11,
+ 607,
+ },
+ dictWord{13, 11, 263},
+ dictWord{13, 11, 459},
+ dictWord{142, 11, 271},
+ dictWord{134, 0, 1463},
+ dictWord{6, 0, 772},
+ dictWord{6, 0, 1137},
+ dictWord{
+ 139,
+ 11,
+ 595,
+ },
+ dictWord{7, 0, 977},
+ dictWord{139, 11, 66},
+ dictWord{138, 0, 893},
+ dictWord{20, 0, 48},
+ dictWord{148, 11, 48},
+ dictWord{5, 0, 824},
+ dictWord{
+ 133,
+ 0,
+ 941,
+ },
+ dictWord{134, 11, 295},
+ dictWord{7, 0, 1543},
+ dictWord{7, 0, 1785},
+ dictWord{10, 0, 690},
+ dictWord{4, 10, 106},
+ dictWord{139, 10, 717},
+ dictWord{
+ 7,
+ 0,
+ 440,
+ },
+ dictWord{8, 0, 230},
+ dictWord{139, 0, 106},
+ dictWord{5, 10, 890},
+ dictWord{133, 10, 988},
+ dictWord{6, 10, 626},
+ dictWord{142, 10, 431},
+ dictWord{
+ 10,
+ 11,
+ 127,
+ },
+ dictWord{141, 11, 27},
+ dictWord{17, 0, 32},
+ dictWord{10, 10, 706},
+ dictWord{150, 10, 44},
+ dictWord{132, 0, 216},
+ dictWord{137, 0, 332},
+ dictWord{4, 10, 698},
+ dictWord{136, 11, 119},
+ dictWord{139, 11, 267},
+ dictWord{138, 10, 17},
+ dictWord{11, 11, 526},
+ dictWord{11, 11, 939},
+ dictWord{
+ 141,
+ 11,
+ 290,
+ },
+ dictWord{7, 11, 1167},
+ dictWord{11, 11, 934},
+ dictWord{13, 11, 391},
+ dictWord{145, 11, 76},
+ dictWord{139, 11, 39},
+ dictWord{134, 10, 84},
+ dictWord{
+ 4,
+ 0,
+ 914,
+ },
+ dictWord{5, 0, 800},
+ dictWord{133, 0, 852},
+ dictWord{10, 0, 416},
+ dictWord{141, 0, 115},
+ dictWord{7, 0, 564},
+ dictWord{142, 0, 168},
+ dictWord{
+ 4,
+ 0,
+ 918,
+ },
+ dictWord{133, 0, 876},
+ dictWord{134, 0, 1764},
+ dictWord{152, 0, 3},
+ dictWord{4, 0, 92},
+ dictWord{5, 0, 274},
+ dictWord{7, 11, 126},
+ dictWord{136, 11, 84},
+ dictWord{140, 10, 498},
+ dictWord{136, 11, 790},
+ dictWord{8, 0, 501},
+ dictWord{5, 10, 986},
+ dictWord{6, 10, 130},
+ dictWord{7, 10, 1582},
+ dictWord{
+ 8,
+ 10,
+ 458,
+ },
+ dictWord{10, 10, 101},
+ dictWord{10, 10, 318},
+ dictWord{138, 10, 823},
+ dictWord{6, 11, 64},
+ dictWord{12, 11, 377},
+ dictWord{141, 11, 309},
+ dictWord{
+ 5,
+ 0,
+ 743,
+ },
+ dictWord{138, 0, 851},
+ dictWord{4, 0, 49},
+ dictWord{7, 0, 280},
+ dictWord{135, 0, 1633},
+ dictWord{134, 0, 879},
+ dictWord{136, 0, 47},
+ dictWord{
+ 7,
+ 10,
+ 1644,
+ },
+ dictWord{137, 10, 129},
+ dictWord{132, 0, 865},
+ dictWord{134, 0, 1202},
+ dictWord{9, 11, 34},
+ dictWord{139, 11, 484},
+ dictWord{135, 10, 997},
+ dictWord{5, 0, 272},
+ dictWord{5, 0, 908},
+ dictWord{5, 0, 942},
+ dictWord{8, 0, 197},
+ dictWord{9, 0, 47},
+ dictWord{11, 0, 538},
+ dictWord{139, 0, 742},
+ dictWord{
+ 6,
+ 11,
+ 1700,
+ },
+ dictWord{7, 11, 26},
+ dictWord{7, 11, 293},
+ dictWord{7, 11, 382},
+ dictWord{7, 11, 1026},
+ dictWord{7, 11, 1087},
+ dictWord{7, 11, 2027},
+ dictWord{
+ 8,
+ 11,
+ 24,
+ },
+ dictWord{8, 11, 114},
+ dictWord{8, 11, 252},
+ dictWord{8, 11, 727},
+ dictWord{8, 11, 729},
+ dictWord{9, 11, 30},
+ dictWord{9, 11, 199},
+ dictWord{9, 11, 231},
+ dictWord{9, 11, 251},
+ dictWord{9, 11, 334},
+ dictWord{9, 11, 361},
+ dictWord{9, 11, 488},
+ dictWord{9, 11, 712},
+ dictWord{10, 11, 55},
+ dictWord{10, 11, 60},
+ dictWord{
+ 10,
+ 11,
+ 232,
+ },
+ dictWord{10, 11, 332},
+ dictWord{10, 11, 384},
+ dictWord{10, 11, 396},
+ dictWord{10, 11, 504},
+ dictWord{10, 11, 542},
+ dictWord{10, 11, 652},
+ dictWord{11, 11, 20},
+ dictWord{11, 11, 48},
+ dictWord{11, 11, 207},
+ dictWord{11, 11, 291},
+ dictWord{11, 11, 298},
+ dictWord{11, 11, 342},
+ dictWord{
+ 11,
+ 11,
+ 365,
+ },
+ dictWord{11, 11, 394},
+ dictWord{11, 11, 620},
+ dictWord{11, 11, 705},
+ dictWord{11, 11, 1017},
+ dictWord{12, 11, 123},
+ dictWord{12, 11, 340},
+ dictWord{12, 11, 406},
+ dictWord{12, 11, 643},
+ dictWord{13, 11, 61},
+ dictWord{13, 11, 269},
+ dictWord{13, 11, 311},
+ dictWord{13, 11, 319},
+ dictWord{13, 11, 486},
+ dictWord{14, 11, 234},
+ dictWord{15, 11, 62},
+ dictWord{15, 11, 85},
+ dictWord{16, 11, 71},
+ dictWord{18, 11, 119},
+ dictWord{148, 11, 105},
+ dictWord{
+ 6,
+ 0,
+ 1455,
+ },
+ dictWord{150, 11, 37},
+ dictWord{135, 10, 1927},
+ dictWord{135, 0, 1911},
+ dictWord{137, 0, 891},
+ dictWord{7, 10, 1756},
+ dictWord{137, 10, 98},
+ dictWord{7, 10, 1046},
+ dictWord{139, 10, 160},
+ dictWord{132, 0, 761},
+ dictWord{6, 11, 379},
+ dictWord{7, 11, 270},
+ dictWord{7, 11, 1116},
+ dictWord{
+ 8,
+ 11,
+ 176,
+ },
+ dictWord{8, 11, 183},
+ dictWord{9, 11, 432},
+ dictWord{9, 11, 661},
+ dictWord{12, 11, 247},
+ dictWord{12, 11, 617},
+ dictWord{146, 11, 125},
+ dictWord{
+ 6,
+ 10,
+ 45,
+ },
+ dictWord{7, 10, 433},
+ dictWord{8, 10, 129},
+ dictWord{9, 10, 21},
+ dictWord{10, 10, 392},
+ dictWord{11, 10, 79},
+ dictWord{12, 10, 499},
+ dictWord{
+ 13,
+ 10,
+ 199,
+ },
+ dictWord{141, 10, 451},
+ dictWord{4, 0, 407},
+ dictWord{5, 11, 792},
+ dictWord{133, 11, 900},
+ dictWord{132, 0, 560},
+ dictWord{135, 0, 183},
+ dictWord{
+ 13,
+ 0,
+ 490,
+ },
+ dictWord{7, 10, 558},
+ dictWord{136, 10, 353},
+ dictWord{4, 0, 475},
+ dictWord{6, 0, 731},
+ dictWord{11, 0, 35},
+ dictWord{13, 0, 71},
+ dictWord{13, 0, 177},
+ dictWord{14, 0, 422},
+ dictWord{133, 10, 785},
+ dictWord{8, 10, 81},
+ dictWord{9, 10, 189},
+ dictWord{9, 10, 201},
+ dictWord{11, 10, 478},
+ dictWord{11, 10, 712},
+ dictWord{141, 10, 338},
+ dictWord{4, 0, 418},
+ dictWord{4, 0, 819},
+ dictWord{133, 10, 353},
+ dictWord{151, 10, 26},
+ dictWord{4, 11, 901},
+ dictWord{
+ 133,
+ 11,
+ 776,
+ },
+ dictWord{132, 0, 575},
+ dictWord{7, 0, 818},
+ dictWord{16, 0, 92},
+ dictWord{17, 0, 14},
+ dictWord{17, 0, 45},
+ dictWord{18, 0, 75},
+ dictWord{148, 0, 18},
+ dictWord{
+ 6,
+ 0,
+ 222,
+ },
+ dictWord{7, 0, 636},
+ dictWord{7, 0, 1620},
+ dictWord{8, 0, 409},
+ dictWord{9, 0, 693},
+ dictWord{139, 0, 77},
+ dictWord{6, 10, 25},
+ dictWord{7, 10, 855},
+ dictWord{7, 10, 1258},
+ dictWord{144, 10, 32},
+ dictWord{6, 0, 1880},
+ dictWord{6, 0, 1887},
+ dictWord{6, 0, 1918},
+ dictWord{6, 0, 1924},
+ dictWord{9, 0, 967},
+ dictWord{9, 0, 995},
+ dictWord{9, 0, 1015},
+ dictWord{12, 0, 826},
+ dictWord{12, 0, 849},
+ dictWord{12, 0, 857},
+ dictWord{12, 0, 860},
+ dictWord{12, 0, 886},
+ dictWord{
+ 12,
+ 0,
+ 932,
+ },
+ dictWord{18, 0, 228},
+ dictWord{18, 0, 231},
+ dictWord{146, 0, 240},
+ dictWord{134, 0, 633},
+ dictWord{134, 0, 1308},
+ dictWord{4, 11, 37},
+ dictWord{
+ 5,
+ 11,
+ 334,
+ },
+ dictWord{135, 11, 1253},
+ dictWord{10, 0, 86},
+ dictWord{4, 10, 4},
+ dictWord{7, 10, 1118},
+ dictWord{7, 10, 1320},
+ dictWord{7, 10, 1706},
+ dictWord{
+ 8,
+ 10,
+ 277,
+ },
+ dictWord{9, 10, 622},
+ dictWord{11, 10, 724},
+ dictWord{12, 10, 350},
+ dictWord{12, 10, 397},
+ dictWord{13, 10, 28},
+ dictWord{13, 10, 159},
+ dictWord{
+ 15,
+ 10,
+ 89,
+ },
+ dictWord{18, 10, 5},
+ dictWord{19, 10, 9},
+ dictWord{20, 10, 34},
+ dictWord{150, 10, 47},
+ dictWord{132, 11, 508},
+ dictWord{137, 11, 448},
+ dictWord{
+ 12,
+ 11,
+ 107,
+ },
+ dictWord{146, 11, 31},
+ dictWord{132, 0, 817},
+ dictWord{134, 0, 663},
+ dictWord{133, 0, 882},
+ dictWord{134, 0, 914},
+ dictWord{132, 11, 540},
+ dictWord{132, 11, 533},
+ dictWord{136, 11, 608},
+ dictWord{8, 0, 885},
+ dictWord{138, 0, 865},
+ dictWord{132, 0, 426},
+ dictWord{6, 0, 58},
+ dictWord{7, 0, 745},
+ dictWord{7, 0, 1969},
+ dictWord{8, 0, 399},
+ dictWord{8, 0, 675},
+ dictWord{9, 0, 479},
+ dictWord{9, 0, 731},
+ dictWord{10, 0, 330},
+ dictWord{10, 0, 593},
+ dictWord{
+ 10,
+ 0,
+ 817,
+ },
+ dictWord{11, 0, 32},
+ dictWord{11, 0, 133},
+ dictWord{11, 0, 221},
+ dictWord{145, 0, 68},
+ dictWord{134, 10, 255},
+ dictWord{7, 0, 102},
+ dictWord{
+ 137,
+ 0,
+ 538,
+ },
+ dictWord{137, 10, 216},
+ dictWord{7, 11, 253},
+ dictWord{136, 11, 549},
+ dictWord{135, 11, 912},
+ dictWord{9, 10, 183},
+ dictWord{139, 10, 286},
+ dictWord{11, 10, 956},
+ dictWord{151, 10, 3},
+ dictWord{8, 11, 527},
+ dictWord{18, 11, 60},
+ dictWord{147, 11, 24},
+ dictWord{4, 10, 536},
+ dictWord{7, 10, 1141},
+ dictWord{10, 10, 723},
+ dictWord{139, 10, 371},
+ dictWord{133, 11, 920},
+ dictWord{7, 0, 876},
+ dictWord{135, 10, 285},
+ dictWord{135, 10, 560},
+ dictWord{
+ 132,
+ 10,
+ 690,
+ },
+ dictWord{142, 11, 126},
+ dictWord{11, 10, 33},
+ dictWord{12, 10, 571},
+ dictWord{149, 10, 1},
+ dictWord{133, 0, 566},
+ dictWord{9, 0, 139},
+ dictWord{
+ 10,
+ 0,
+ 399,
+ },
+ dictWord{11, 0, 469},
+ dictWord{12, 0, 634},
+ dictWord{13, 0, 223},
+ dictWord{132, 11, 483},
+ dictWord{6, 0, 48},
+ dictWord{135, 0, 63},
+ dictWord{18, 0, 12},
+ dictWord{7, 10, 1862},
+ dictWord{12, 10, 491},
+ dictWord{12, 10, 520},
+ dictWord{13, 10, 383},
+ dictWord{142, 10, 244},
+ dictWord{135, 11, 1665},
+ dictWord{132, 11, 448},
+ dictWord{9, 11, 495},
+ dictWord{146, 11, 104},
+ dictWord{6, 0, 114},
+ dictWord{7, 0, 1224},
+ dictWord{7, 0, 1556},
+ dictWord{136, 0, 3},
+ dictWord{
+ 4,
+ 10,
+ 190,
+ },
+ dictWord{133, 10, 554},
+ dictWord{8, 0, 576},
+ dictWord{9, 0, 267},
+ dictWord{133, 10, 1001},
+ dictWord{133, 10, 446},
+ dictWord{133, 0, 933},
+ dictWord{139, 11, 1009},
+ dictWord{8, 11, 653},
+ dictWord{13, 11, 93},
+ dictWord{147, 11, 14},
+ dictWord{6, 0, 692},
+ dictWord{6, 0, 821},
+ dictWord{134, 0, 1077},
+ dictWord{5, 11, 172},
+ dictWord{135, 11, 801},
+ dictWord{138, 0, 752},
+ dictWord{4, 0, 375},
+ dictWord{134, 0, 638},
+ dictWord{134, 0, 1011},
+ dictWord{
+ 140,
+ 11,
+ 540,
+ },
+ dictWord{9, 0, 96},
+ dictWord{133, 11, 260},
+ dictWord{139, 11, 587},
+ dictWord{135, 10, 1231},
+ dictWord{12, 0, 30},
+ dictWord{13, 0, 148},
+ dictWord{
+ 14,
+ 0,
+ 87,
+ },
+ dictWord{14, 0, 182},
+ dictWord{16, 0, 42},
+ dictWord{20, 0, 70},
+ dictWord{132, 10, 304},
+ dictWord{6, 0, 1398},
+ dictWord{7, 0, 56},
+ dictWord{7, 0, 1989},
+ dictWord{8, 0, 337},
+ dictWord{8, 0, 738},
+ dictWord{9, 0, 600},
+ dictWord{12, 0, 37},
+ dictWord{13, 0, 447},
+ dictWord{142, 0, 92},
+ dictWord{138, 0, 666},
+ dictWord{
+ 5,
+ 0,
+ 394,
+ },
+ dictWord{7, 0, 487},
+ dictWord{136, 0, 246},
+ dictWord{9, 0, 437},
+ dictWord{6, 10, 53},
+ dictWord{6, 10, 199},
+ dictWord{7, 10, 1408},
+ dictWord{8, 10, 32},
+ dictWord{8, 10, 93},
+ dictWord{10, 10, 397},
+ dictWord{10, 10, 629},
+ dictWord{11, 10, 593},
+ dictWord{11, 10, 763},
+ dictWord{13, 10, 326},
+ dictWord{145, 10, 35},
+ dictWord{134, 10, 105},
+ dictWord{9, 0, 320},
+ dictWord{10, 0, 506},
+ dictWord{138, 10, 794},
+ dictWord{7, 11, 57},
+ dictWord{8, 11, 167},
+ dictWord{8, 11, 375},
+ dictWord{9, 11, 82},
+ dictWord{9, 11, 561},
+ dictWord{10, 11, 620},
+ dictWord{10, 11, 770},
+ dictWord{11, 10, 704},
+ dictWord{141, 10, 396},
+ dictWord{6, 0, 1003},
+ dictWord{5, 10, 114},
+ dictWord{5, 10, 255},
+ dictWord{141, 10, 285},
+ dictWord{7, 0, 866},
+ dictWord{135, 0, 1163},
+ dictWord{133, 11, 531},
+ dictWord{
+ 132,
+ 0,
+ 328,
+ },
+ dictWord{7, 10, 2035},
+ dictWord{8, 10, 19},
+ dictWord{9, 10, 89},
+ dictWord{138, 10, 831},
+ dictWord{8, 11, 194},
+ dictWord{136, 11, 756},
+ dictWord{
+ 136,
+ 0,
+ 1000,
+ },
+ dictWord{5, 11, 453},
+ dictWord{134, 11, 441},
+ dictWord{4, 0, 101},
+ dictWord{5, 0, 833},
+ dictWord{7, 0, 1171},
+ dictWord{136, 0, 744},
+ dictWord{
+ 133,
+ 0,
+ 726,
+ },
+ dictWord{136, 10, 746},
+ dictWord{138, 0, 176},
+ dictWord{6, 0, 9},
+ dictWord{6, 0, 397},
+ dictWord{7, 0, 53},
+ dictWord{7, 0, 1742},
+ dictWord{10, 0, 632},
+ dictWord{11, 0, 828},
+ dictWord{140, 0, 146},
+ dictWord{135, 11, 22},
+ dictWord{145, 11, 64},
+ dictWord{132, 0, 839},
+ dictWord{11, 0, 417},
+ dictWord{12, 0, 223},
+ dictWord{140, 0, 265},
+ dictWord{4, 11, 102},
+ dictWord{7, 11, 815},
+ dictWord{7, 11, 1699},
+ dictWord{139, 11, 964},
+ dictWord{5, 10, 955},
+ dictWord{
+ 136,
+ 10,
+ 814,
+ },
+ dictWord{6, 0, 1931},
+ dictWord{6, 0, 2007},
+ dictWord{18, 0, 246},
+ dictWord{146, 0, 247},
+ dictWord{8, 0, 198},
+ dictWord{11, 0, 29},
+ dictWord{140, 0, 534},
+ dictWord{135, 0, 1771},
+ dictWord{6, 0, 846},
+ dictWord{7, 11, 1010},
+ dictWord{11, 11, 733},
+ dictWord{11, 11, 759},
+ dictWord{12, 11, 563},
+ dictWord{
+ 13,
+ 11,
+ 34,
+ },
+ dictWord{14, 11, 101},
+ dictWord{18, 11, 45},
+ dictWord{146, 11, 129},
+ dictWord{4, 0, 186},
+ dictWord{5, 0, 157},
+ dictWord{8, 0, 168},
+ dictWord{138, 0, 6},
+ dictWord{132, 11, 899},
+ dictWord{133, 10, 56},
+ dictWord{148, 10, 100},
+ dictWord{133, 0, 875},
+ dictWord{5, 0, 773},
+ dictWord{5, 0, 991},
+ dictWord{6, 0, 1635},
+ dictWord{134, 0, 1788},
+ dictWord{6, 0, 1274},
+ dictWord{9, 0, 477},
+ dictWord{141, 0, 78},
+ dictWord{4, 0, 639},
+ dictWord{7, 0, 111},
+ dictWord{8, 0, 581},
+ dictWord{
+ 12,
+ 0,
+ 177,
+ },
+ dictWord{6, 11, 52},
+ dictWord{9, 11, 104},
+ dictWord{9, 11, 559},
+ dictWord{10, 10, 4},
+ dictWord{10, 10, 13},
+ dictWord{11, 10, 638},
+ dictWord{
+ 12,
+ 11,
+ 308,
+ },
+ dictWord{19, 11, 87},
+ dictWord{148, 10, 57},
+ dictWord{132, 11, 604},
+ dictWord{4, 11, 301},
+ dictWord{133, 10, 738},
+ dictWord{133, 10, 758},
+ dictWord{134, 0, 1747},
+ dictWord{7, 11, 1440},
+ dictWord{11, 11, 854},
+ dictWord{11, 11, 872},
+ dictWord{11, 11, 921},
+ dictWord{12, 11, 551},
+ dictWord{
+ 13,
+ 11,
+ 472,
+ },
+ dictWord{142, 11, 367},
+ dictWord{7, 0, 1364},
+ dictWord{7, 0, 1907},
+ dictWord{141, 0, 158},
+ dictWord{134, 0, 873},
+ dictWord{4, 0, 404},
+ dictWord{
+ 4,
+ 0,
+ 659,
+ },
+ dictWord{7, 0, 552},
+ dictWord{135, 0, 675},
+ dictWord{135, 10, 1112},
+ dictWord{139, 10, 328},
+ dictWord{7, 11, 508},
+ dictWord{137, 10, 133},
+ dictWord{133, 0, 391},
+ dictWord{5, 10, 110},
+ dictWord{6, 10, 169},
+ dictWord{6, 10, 1702},
+ dictWord{7, 10, 400},
+ dictWord{8, 10, 538},
+ dictWord{9, 10, 184},
+ dictWord{
+ 9,
+ 10,
+ 524,
+ },
+ dictWord{140, 10, 218},
+ dictWord{6, 11, 310},
+ dictWord{7, 11, 1849},
+ dictWord{8, 11, 72},
+ dictWord{8, 11, 272},
+ dictWord{8, 11, 431},
+ dictWord{
+ 9,
+ 11,
+ 12,
+ },
+ dictWord{9, 11, 351},
+ dictWord{10, 11, 563},
+ dictWord{10, 11, 630},
+ dictWord{10, 11, 810},
+ dictWord{11, 11, 367},
+ dictWord{11, 11, 599},
+ dictWord{11, 11, 686},
+ dictWord{140, 11, 672},
+ dictWord{5, 0, 540},
+ dictWord{6, 0, 1697},
+ dictWord{136, 0, 668},
+ dictWord{132, 0, 883},
+ dictWord{134, 0, 78},
+ dictWord{12, 0, 628},
+ dictWord{18, 0, 79},
+ dictWord{6, 10, 133},
+ dictWord{9, 10, 353},
+ dictWord{139, 10, 993},
+ dictWord{6, 11, 181},
+ dictWord{7, 11, 537},
+ dictWord{
+ 8,
+ 11,
+ 64,
+ },
+ dictWord{9, 11, 127},
+ dictWord{10, 11, 496},
+ dictWord{12, 11, 510},
+ dictWord{141, 11, 384},
+ dictWord{6, 10, 93},
+ dictWord{7, 10, 1422},
+ dictWord{
+ 7,
+ 10,
+ 1851,
+ },
+ dictWord{8, 10, 673},
+ dictWord{9, 10, 529},
+ dictWord{140, 10, 43},
+ dictWord{137, 10, 371},
+ dictWord{134, 0, 1460},
+ dictWord{134, 0, 962},
+ dictWord{4, 11, 244},
+ dictWord{135, 11, 233},
+ dictWord{9, 10, 25},
+ dictWord{10, 10, 467},
+ dictWord{138, 10, 559},
+ dictWord{4, 10, 335},
+ dictWord{
+ 135,
+ 10,
+ 942,
+ },
+ dictWord{133, 0, 460},
+ dictWord{135, 11, 334},
+ dictWord{134, 11, 1650},
+ dictWord{4, 0, 199},
+ dictWord{139, 0, 34},
+ dictWord{5, 10, 601},
+ dictWord{
+ 8,
+ 10,
+ 39,
+ },
+ dictWord{10, 10, 773},
+ dictWord{11, 10, 84},
+ dictWord{12, 10, 205},
+ dictWord{142, 10, 1},
+ dictWord{133, 10, 870},
+ dictWord{134, 0, 388},
+ dictWord{14, 0, 474},
+ dictWord{148, 0, 120},
+ dictWord{133, 11, 369},
+ dictWord{139, 0, 271},
+ dictWord{4, 0, 511},
+ dictWord{9, 0, 333},
+ dictWord{9, 0, 379},
+ dictWord{
+ 10,
+ 0,
+ 602,
+ },
+ dictWord{11, 0, 441},
+ dictWord{11, 0, 723},
+ dictWord{11, 0, 976},
+ dictWord{12, 0, 357},
+ dictWord{132, 10, 181},
+ dictWord{134, 0, 608},
+ dictWord{134, 10, 1652},
+ dictWord{22, 0, 49},
+ dictWord{137, 11, 338},
+ dictWord{140, 0, 988},
+ dictWord{134, 0, 617},
+ dictWord{5, 0, 938},
+ dictWord{136, 0, 707},
+ dictWord{132, 10, 97},
+ dictWord{5, 10, 147},
+ dictWord{6, 10, 286},
+ dictWord{7, 10, 1362},
+ dictWord{141, 10, 176},
+ dictWord{6, 0, 756},
+ dictWord{
+ 134,
+ 0,
+ 1149,
+ },
+ dictWord{133, 11, 896},
+ dictWord{6, 10, 375},
+ dictWord{7, 10, 169},
+ dictWord{7, 10, 254},
+ dictWord{136, 10, 780},
+ dictWord{134, 0, 1583},
+ dictWord{135, 10, 1447},
+ dictWord{139, 0, 285},
+ dictWord{7, 11, 1117},
+ dictWord{8, 11, 393},
+ dictWord{136, 11, 539},
+ dictWord{135, 0, 344},
+ dictWord{
+ 6,
+ 0,
+ 469,
+ },
+ dictWord{7, 0, 1709},
+ dictWord{138, 0, 515},
+ dictWord{5, 10, 629},
+ dictWord{135, 10, 1549},
+ dictWord{5, 11, 4},
+ dictWord{5, 11, 810},
+ dictWord{
+ 6,
+ 11,
+ 13,
+ },
+ dictWord{6, 11, 538},
+ dictWord{6, 11, 1690},
+ dictWord{6, 11, 1726},
+ dictWord{7, 11, 499},
+ dictWord{7, 11, 1819},
+ dictWord{8, 11, 148},
+ dictWord{
+ 8,
+ 11,
+ 696,
+ },
+ dictWord{8, 11, 791},
+ dictWord{12, 11, 125},
+ dictWord{13, 11, 54},
+ dictWord{143, 11, 9},
+ dictWord{135, 11, 1268},
+ dictWord{137, 0, 404},
+ dictWord{
+ 132,
+ 0,
+ 500,
+ },
+ dictWord{5, 0, 68},
+ dictWord{134, 0, 383},
+ dictWord{11, 0, 216},
+ dictWord{139, 0, 340},
+ dictWord{4, 11, 925},
+ dictWord{5, 11, 803},
+ dictWord{
+ 8,
+ 11,
+ 698,
+ },
+ dictWord{138, 11, 828},
+ dictWord{4, 0, 337},
+ dictWord{6, 0, 353},
+ dictWord{7, 0, 1934},
+ dictWord{8, 0, 488},
+ dictWord{137, 0, 429},
+ dictWord{7, 0, 236},
+ dictWord{7, 0, 1795},
+ dictWord{8, 0, 259},
+ dictWord{9, 0, 135},
+ dictWord{9, 0, 177},
+ dictWord{9, 0, 860},
+ dictWord{10, 0, 825},
+ dictWord{11, 0, 115},
+ dictWord{
+ 11,
+ 0,
+ 370,
+ },
+ dictWord{11, 0, 405},
+ dictWord{11, 0, 604},
+ dictWord{12, 0, 10},
+ dictWord{12, 0, 667},
+ dictWord{12, 0, 669},
+ dictWord{13, 0, 76},
+ dictWord{14, 0, 310},
+ dictWord{15, 0, 76},
+ dictWord{15, 0, 147},
+ dictWord{148, 0, 23},
+ dictWord{4, 0, 15},
+ dictWord{4, 0, 490},
+ dictWord{5, 0, 22},
+ dictWord{6, 0, 244},
+ dictWord{7, 0, 40},
+ dictWord{7, 0, 200},
+ dictWord{7, 0, 906},
+ dictWord{7, 0, 1199},
+ dictWord{9, 0, 616},
+ dictWord{10, 0, 716},
+ dictWord{11, 0, 635},
+ dictWord{11, 0, 801},
+ dictWord{
+ 140,
+ 0,
+ 458,
+ },
+ dictWord{12, 0, 756},
+ dictWord{132, 10, 420},
+ dictWord{134, 0, 1504},
+ dictWord{6, 0, 757},
+ dictWord{133, 11, 383},
+ dictWord{6, 0, 1266},
+ dictWord{
+ 135,
+ 0,
+ 1735,
+ },
+ dictWord{5, 0, 598},
+ dictWord{7, 0, 791},
+ dictWord{8, 0, 108},
+ dictWord{9, 0, 123},
+ dictWord{7, 10, 1570},
+ dictWord{140, 10, 542},
+ dictWord{
+ 142,
+ 11,
+ 410,
+ },
+ dictWord{9, 11, 660},
+ dictWord{138, 11, 347},
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/symbol_list.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/symbol_list.go
new file mode 100644
index 000000000000..c5cb49e5a9dd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/symbol_list.go
@@ -0,0 +1,22 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Utilities for building Huffman decoding tables. */
+
+type symbolList struct {
+ storage []uint16
+ offset int
+}
+
+func symbolListGet(sl symbolList, i int) uint16 {
+ return sl.storage[i+sl.offset]
+}
+
+func symbolListPut(sl symbolList, i int, val uint16) {
+ sl.storage[i+sl.offset] = val
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/transform.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/transform.go
new file mode 100644
index 000000000000..d2c043a6227b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/transform.go
@@ -0,0 +1,641 @@
+package brotli
+
+const (
+ transformIdentity = 0
+ transformOmitLast1 = 1
+ transformOmitLast2 = 2
+ transformOmitLast3 = 3
+ transformOmitLast4 = 4
+ transformOmitLast5 = 5
+ transformOmitLast6 = 6
+ transformOmitLast7 = 7
+ transformOmitLast8 = 8
+ transformOmitLast9 = 9
+ transformUppercaseFirst = 10
+ transformUppercaseAll = 11
+ transformOmitFirst1 = 12
+ transformOmitFirst2 = 13
+ transformOmitFirst3 = 14
+ transformOmitFirst4 = 15
+ transformOmitFirst5 = 16
+ transformOmitFirst6 = 17
+ transformOmitFirst7 = 18
+ transformOmitFirst8 = 19
+ transformOmitFirst9 = 20
+ transformShiftFirst = 21
+ transformShiftAll = 22 + iota - 22
+ numTransformTypes
+)
+
+const transformsMaxCutOff = transformOmitLast9
+
+type transforms struct {
+ prefix_suffix_size uint16
+ prefix_suffix []byte
+ prefix_suffix_map []uint16
+ num_transforms uint32
+ transforms []byte
+ params []byte
+ cutOffTransforms [transformsMaxCutOff + 1]int16
+}
+
+func transformPrefixId(t *transforms, I int) byte {
+ return t.transforms[(I*3)+0]
+}
+
+func transformType(t *transforms, I int) byte {
+ return t.transforms[(I*3)+1]
+}
+
+func transformSuffixId(t *transforms, I int) byte {
+ return t.transforms[(I*3)+2]
+}
+
+func transformPrefix(t *transforms, I int) []byte {
+ return t.prefix_suffix[t.prefix_suffix_map[transformPrefixId(t, I)]:]
+}
+
+func transformSuffix(t *transforms, I int) []byte {
+ return t.prefix_suffix[t.prefix_suffix_map[transformSuffixId(t, I)]:]
+}
+
+/* RFC 7932 transforms string data */
+const kPrefixSuffix string = "\001 \002, \010 of the \004 of \002s \001.\005 and \004 " + "in \001\"\004 to \002\">\001\n\002. \001]\005 for \003 a \006 " + "that \001'\006 with \006 from \004 by \001(\006. T" + "he \004 on \004 as \004 is \004ing \002\n\t\001:\003ed " + "\002=\"\004 at \003ly \001,\002='\005.com/\007. This \005" + " not \003er \003al \004ful \004ive \005less \004es" + "t \004ize \002\xc2\xa0\004ous \005 the \002e \000"
+
+var kPrefixSuffixMap = [50]uint16{
+ 0x00,
+ 0x02,
+ 0x05,
+ 0x0E,
+ 0x13,
+ 0x16,
+ 0x18,
+ 0x1E,
+ 0x23,
+ 0x25,
+ 0x2A,
+ 0x2D,
+ 0x2F,
+ 0x32,
+ 0x34,
+ 0x3A,
+ 0x3E,
+ 0x45,
+ 0x47,
+ 0x4E,
+ 0x55,
+ 0x5A,
+ 0x5C,
+ 0x63,
+ 0x68,
+ 0x6D,
+ 0x72,
+ 0x77,
+ 0x7A,
+ 0x7C,
+ 0x80,
+ 0x83,
+ 0x88,
+ 0x8C,
+ 0x8E,
+ 0x91,
+ 0x97,
+ 0x9F,
+ 0xA5,
+ 0xA9,
+ 0xAD,
+ 0xB2,
+ 0xB7,
+ 0xBD,
+ 0xC2,
+ 0xC7,
+ 0xCA,
+ 0xCF,
+ 0xD5,
+ 0xD8,
+}
+
+/* RFC 7932 transforms */
+var kTransformsData = []byte{
+ 49,
+ transformIdentity,
+ 49,
+ 49,
+ transformIdentity,
+ 0,
+ 0,
+ transformIdentity,
+ 0,
+ 49,
+ transformOmitFirst1,
+ 49,
+ 49,
+ transformUppercaseFirst,
+ 0,
+ 49,
+ transformIdentity,
+ 47,
+ 0,
+ transformIdentity,
+ 49,
+ 4,
+ transformIdentity,
+ 0,
+ 49,
+ transformIdentity,
+ 3,
+ 49,
+ transformUppercaseFirst,
+ 49,
+ 49,
+ transformIdentity,
+ 6,
+ 49,
+ transformOmitFirst2,
+ 49,
+ 49,
+ transformOmitLast1,
+ 49,
+ 1,
+ transformIdentity,
+ 0,
+ 49,
+ transformIdentity,
+ 1,
+ 0,
+ transformUppercaseFirst,
+ 0,
+ 49,
+ transformIdentity,
+ 7,
+ 49,
+ transformIdentity,
+ 9,
+ 48,
+ transformIdentity,
+ 0,
+ 49,
+ transformIdentity,
+ 8,
+ 49,
+ transformIdentity,
+ 5,
+ 49,
+ transformIdentity,
+ 10,
+ 49,
+ transformIdentity,
+ 11,
+ 49,
+ transformOmitLast3,
+ 49,
+ 49,
+ transformIdentity,
+ 13,
+ 49,
+ transformIdentity,
+ 14,
+ 49,
+ transformOmitFirst3,
+ 49,
+ 49,
+ transformOmitLast2,
+ 49,
+ 49,
+ transformIdentity,
+ 15,
+ 49,
+ transformIdentity,
+ 16,
+ 0,
+ transformUppercaseFirst,
+ 49,
+ 49,
+ transformIdentity,
+ 12,
+ 5,
+ transformIdentity,
+ 49,
+ 0,
+ transformIdentity,
+ 1,
+ 49,
+ transformOmitFirst4,
+ 49,
+ 49,
+ transformIdentity,
+ 18,
+ 49,
+ transformIdentity,
+ 17,
+ 49,
+ transformIdentity,
+ 19,
+ 49,
+ transformIdentity,
+ 20,
+ 49,
+ transformOmitFirst5,
+ 49,
+ 49,
+ transformOmitFirst6,
+ 49,
+ 47,
+ transformIdentity,
+ 49,
+ 49,
+ transformOmitLast4,
+ 49,
+ 49,
+ transformIdentity,
+ 22,
+ 49,
+ transformUppercaseAll,
+ 49,
+ 49,
+ transformIdentity,
+ 23,
+ 49,
+ transformIdentity,
+ 24,
+ 49,
+ transformIdentity,
+ 25,
+ 49,
+ transformOmitLast7,
+ 49,
+ 49,
+ transformOmitLast1,
+ 26,
+ 49,
+ transformIdentity,
+ 27,
+ 49,
+ transformIdentity,
+ 28,
+ 0,
+ transformIdentity,
+ 12,
+ 49,
+ transformIdentity,
+ 29,
+ 49,
+ transformOmitFirst9,
+ 49,
+ 49,
+ transformOmitFirst7,
+ 49,
+ 49,
+ transformOmitLast6,
+ 49,
+ 49,
+ transformIdentity,
+ 21,
+ 49,
+ transformUppercaseFirst,
+ 1,
+ 49,
+ transformOmitLast8,
+ 49,
+ 49,
+ transformIdentity,
+ 31,
+ 49,
+ transformIdentity,
+ 32,
+ 47,
+ transformIdentity,
+ 3,
+ 49,
+ transformOmitLast5,
+ 49,
+ 49,
+ transformOmitLast9,
+ 49,
+ 0,
+ transformUppercaseFirst,
+ 1,
+ 49,
+ transformUppercaseFirst,
+ 8,
+ 5,
+ transformIdentity,
+ 21,
+ 49,
+ transformUppercaseAll,
+ 0,
+ 49,
+ transformUppercaseFirst,
+ 10,
+ 49,
+ transformIdentity,
+ 30,
+ 0,
+ transformIdentity,
+ 5,
+ 35,
+ transformIdentity,
+ 49,
+ 47,
+ transformIdentity,
+ 2,
+ 49,
+ transformUppercaseFirst,
+ 17,
+ 49,
+ transformIdentity,
+ 36,
+ 49,
+ transformIdentity,
+ 33,
+ 5,
+ transformIdentity,
+ 0,
+ 49,
+ transformUppercaseFirst,
+ 21,
+ 49,
+ transformUppercaseFirst,
+ 5,
+ 49,
+ transformIdentity,
+ 37,
+ 0,
+ transformIdentity,
+ 30,
+ 49,
+ transformIdentity,
+ 38,
+ 0,
+ transformUppercaseAll,
+ 0,
+ 49,
+ transformIdentity,
+ 39,
+ 0,
+ transformUppercaseAll,
+ 49,
+ 49,
+ transformIdentity,
+ 34,
+ 49,
+ transformUppercaseAll,
+ 8,
+ 49,
+ transformUppercaseFirst,
+ 12,
+ 0,
+ transformIdentity,
+ 21,
+ 49,
+ transformIdentity,
+ 40,
+ 0,
+ transformUppercaseFirst,
+ 12,
+ 49,
+ transformIdentity,
+ 41,
+ 49,
+ transformIdentity,
+ 42,
+ 49,
+ transformUppercaseAll,
+ 17,
+ 49,
+ transformIdentity,
+ 43,
+ 0,
+ transformUppercaseFirst,
+ 5,
+ 49,
+ transformUppercaseAll,
+ 10,
+ 0,
+ transformIdentity,
+ 34,
+ 49,
+ transformUppercaseFirst,
+ 33,
+ 49,
+ transformIdentity,
+ 44,
+ 49,
+ transformUppercaseAll,
+ 5,
+ 45,
+ transformIdentity,
+ 49,
+ 0,
+ transformIdentity,
+ 33,
+ 49,
+ transformUppercaseFirst,
+ 30,
+ 49,
+ transformUppercaseAll,
+ 30,
+ 49,
+ transformIdentity,
+ 46,
+ 49,
+ transformUppercaseAll,
+ 1,
+ 49,
+ transformUppercaseFirst,
+ 34,
+ 0,
+ transformUppercaseFirst,
+ 33,
+ 0,
+ transformUppercaseAll,
+ 30,
+ 0,
+ transformUppercaseAll,
+ 1,
+ 49,
+ transformUppercaseAll,
+ 33,
+ 49,
+ transformUppercaseAll,
+ 21,
+ 49,
+ transformUppercaseAll,
+ 12,
+ 0,
+ transformUppercaseAll,
+ 5,
+ 49,
+ transformUppercaseAll,
+ 34,
+ 0,
+ transformUppercaseAll,
+ 12,
+ 0,
+ transformUppercaseFirst,
+ 30,
+ 0,
+ transformUppercaseAll,
+ 34,
+ 0,
+ transformUppercaseFirst,
+ 34,
+}
+
+var kBrotliTransforms = transforms{
+ 217,
+ []byte(kPrefixSuffix),
+ kPrefixSuffixMap[:],
+ 121,
+ kTransformsData,
+ nil, /* no extra parameters */
+ [transformsMaxCutOff + 1]int16{0, 12, 27, 23, 42, 63, 56, 48, 59, 64},
+}
+
+func getTransforms() *transforms {
+ return &kBrotliTransforms
+}
+
+func toUpperCase(p []byte) int {
+ if p[0] < 0xC0 {
+ if p[0] >= 'a' && p[0] <= 'z' {
+ p[0] ^= 32
+ }
+
+ return 1
+ }
+
+ /* An overly simplified uppercasing model for UTF-8. */
+ if p[0] < 0xE0 {
+ p[1] ^= 32
+ return 2
+ }
+
+ /* An arbitrary transform for three byte characters. */
+ p[2] ^= 5
+
+ return 3
+}
+
+func shiftTransform(word []byte, word_len int, parameter uint16) int {
+ /* Limited sign extension: scalar < (1 << 24). */
+ var scalar uint32 = (uint32(parameter) & 0x7FFF) + (0x1000000 - (uint32(parameter) & 0x8000))
+ if word[0] < 0x80 {
+ /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
+ scalar += uint32(word[0])
+
+ word[0] = byte(scalar & 0x7F)
+ return 1
+ } else if word[0] < 0xC0 {
+ /* Continuation / 10AAAAAA. */
+ return 1
+ } else if word[0] < 0xE0 {
+ /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
+ if word_len < 2 {
+ return 1
+ }
+ scalar += uint32(word[1]&0x3F | (word[0]&0x1F)<<6)
+ word[0] = byte(0xC0 | (scalar>>6)&0x1F)
+ word[1] = byte(uint32(word[1]&0xC0) | scalar&0x3F)
+ return 2
+ } else if word[0] < 0xF0 {
+ /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
+ if word_len < 3 {
+ return word_len
+ }
+ scalar += uint32(word[2])&0x3F | uint32(word[1]&0x3F)<<6 | uint32(word[0]&0x0F)<<12
+ word[0] = byte(0xE0 | (scalar>>12)&0x0F)
+ word[1] = byte(uint32(word[1]&0xC0) | (scalar>>6)&0x3F)
+ word[2] = byte(uint32(word[2]&0xC0) | scalar&0x3F)
+ return 3
+ } else if word[0] < 0xF8 {
+ /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
+ if word_len < 4 {
+ return word_len
+ }
+ scalar += uint32(word[3])&0x3F | uint32(word[2]&0x3F)<<6 | uint32(word[1]&0x3F)<<12 | uint32(word[0]&0x07)<<18
+ word[0] = byte(0xF0 | (scalar>>18)&0x07)
+ word[1] = byte(uint32(word[1]&0xC0) | (scalar>>12)&0x3F)
+ word[2] = byte(uint32(word[2]&0xC0) | (scalar>>6)&0x3F)
+ word[3] = byte(uint32(word[3]&0xC0) | scalar&0x3F)
+ return 4
+ }
+
+ return 1
+}
+
+func transformDictionaryWord(dst []byte, word []byte, len int, trans *transforms, transform_idx int) int {
+ var idx int = 0
+ var prefix []byte = transformPrefix(trans, transform_idx)
+ var type_ byte = transformType(trans, transform_idx)
+ var suffix []byte = transformSuffix(trans, transform_idx)
+ {
+ var prefix_len int = int(prefix[0])
+ prefix = prefix[1:]
+ for {
+ tmp1 := prefix_len
+ prefix_len--
+ if tmp1 == 0 {
+ break
+ }
+ dst[idx] = prefix[0]
+ idx++
+ prefix = prefix[1:]
+ }
+ }
+ {
+ var t int = int(type_)
+ var i int = 0
+ if t <= transformOmitLast9 {
+ len -= t
+ } else if t >= transformOmitFirst1 && t <= transformOmitFirst9 {
+ var skip int = t - (transformOmitFirst1 - 1)
+ word = word[skip:]
+ len -= skip
+ }
+
+ for i < len {
+ dst[idx] = word[i]
+ idx++
+ i++
+ }
+ if t == transformUppercaseFirst {
+ toUpperCase(dst[idx-len:])
+ } else if t == transformUppercaseAll {
+ var uppercase []byte = dst
+ uppercase = uppercase[idx-len:]
+ for len > 0 {
+ var step int = toUpperCase(uppercase)
+ uppercase = uppercase[step:]
+ len -= step
+ }
+ } else if t == transformShiftFirst {
+ var param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8
+ shiftTransform(dst[idx-len:], int(len), param)
+ } else if t == transformShiftAll {
+ var param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8
+ var shift []byte = dst
+ shift = shift[idx-len:]
+ for len > 0 {
+ var step int = shiftTransform(shift, int(len), param)
+ shift = shift[step:]
+ len -= step
+ }
+ }
+ }
+ {
+ var suffix_len int = int(suffix[0])
+ suffix = suffix[1:]
+ for {
+ tmp2 := suffix_len
+ suffix_len--
+ if tmp2 == 0 {
+ break
+ }
+ dst[idx] = suffix[0]
+ idx++
+ suffix = suffix[1:]
+ }
+ return idx
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/utf8_util.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/utf8_util.go
new file mode 100644
index 000000000000..3244247eecc1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/utf8_util.go
@@ -0,0 +1,70 @@
+package brotli
+
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Heuristics for deciding about the UTF8-ness of strings. */
+
+const kMinUTF8Ratio float64 = 0.75
+
+/* Returns 1 if at least min_fraction of the bytes between pos and
+ pos + length in the (data, mask) ring-buffer is UTF8-encoded, otherwise
+ returns 0. */
+func parseAsUTF8(symbol *int, input []byte, size uint) uint {
+ /* ASCII */
+ if input[0]&0x80 == 0 {
+ *symbol = int(input[0])
+ if *symbol > 0 {
+ return 1
+ }
+ }
+
+ /* 2-byte UTF8 */
+ if size > 1 && input[0]&0xE0 == 0xC0 && input[1]&0xC0 == 0x80 {
+ *symbol = (int(input[0])&0x1F)<<6 | int(input[1])&0x3F
+ if *symbol > 0x7F {
+ return 2
+ }
+ }
+
+ /* 3-byte UFT8 */
+ if size > 2 && input[0]&0xF0 == 0xE0 && input[1]&0xC0 == 0x80 && input[2]&0xC0 == 0x80 {
+ *symbol = (int(input[0])&0x0F)<<12 | (int(input[1])&0x3F)<<6 | int(input[2])&0x3F
+ if *symbol > 0x7FF {
+ return 3
+ }
+ }
+
+ /* 4-byte UFT8 */
+ if size > 3 && input[0]&0xF8 == 0xF0 && input[1]&0xC0 == 0x80 && input[2]&0xC0 == 0x80 && input[3]&0xC0 == 0x80 {
+ *symbol = (int(input[0])&0x07)<<18 | (int(input[1])&0x3F)<<12 | (int(input[2])&0x3F)<<6 | int(input[3])&0x3F
+ if *symbol > 0xFFFF && *symbol <= 0x10FFFF {
+ return 4
+ }
+ }
+
+ /* Not UTF8, emit a special symbol above the UTF8-code space */
+ *symbol = 0x110000 | int(input[0])
+
+ return 1
+}
+
+/* Returns 1 if at least min_fraction of the data is UTF8-encoded.*/
+func isMostlyUTF8(data []byte, pos uint, mask uint, length uint, min_fraction float64) bool {
+ var size_utf8 uint = 0
+ var i uint = 0
+ for i < length {
+ var symbol int
+ current_data := data[(pos+i)&mask:]
+ var bytes_read uint = parseAsUTF8(&symbol, current_data, length-i)
+ i += bytes_read
+ if symbol < 0x110000 {
+ size_utf8 += bytes_read
+ }
+ }
+
+ return float64(size_utf8) > min_fraction*float64(length)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/util.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/util.go
new file mode 100644
index 000000000000..a84553a63967
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/util.go
@@ -0,0 +1,7 @@
+package brotli
+
+func assert(cond bool) {
+ if !cond {
+ panic("assertion failure")
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/write_bits.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/write_bits.go
new file mode 100644
index 000000000000..87299011985a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/write_bits.go
@@ -0,0 +1,52 @@
+package brotli
+
+import "encoding/binary"
+
+/* Copyright 2010 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Write bits into a byte array. */
+
+/* This function writes bits into bytes in increasing addresses, and within
+ a byte least-significant-bit first.
+
+ The function can write up to 56 bits in one go with WriteBits
+ Example: let's assume that 3 bits (Rs below) have been written already:
+
+ BYTE-0 BYTE+1 BYTE+2
+
+ 0000 0RRR 0000 0000 0000 0000
+
+ Now, we could write 5 or less bits in MSB by just sifting by 3
+ and OR'ing to BYTE-0.
+
+ For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
+ and locate the rest in BYTE+1, BYTE+2, etc. */
+func writeBits(n_bits uint, bits uint64, pos *uint, array []byte) {
+ /* This branch of the code can write up to 56 bits at a time,
+ 7 bits are lost by being perhaps already in *p and at least
+ 1 bit is needed to initialize the bit-stream ahead (i.e. if 7
+ bits are in *p and we write 57 bits, then the next write will
+ access a byte that was never initialized). */
+ p := array[*pos>>3:]
+ v := uint64(p[0])
+ v |= bits << (*pos & 7)
+ binary.LittleEndian.PutUint64(p, v)
+ *pos += n_bits
+}
+
+func writeSingleBit(bit bool, pos *uint, array []byte) {
+ if bit {
+ writeBits(1, 1, pos, array)
+ } else {
+ writeBits(1, 0, pos, array)
+ }
+}
+
+func writeBitsPrepareStorage(pos uint, array []byte) {
+ assert(pos&7 == 0)
+ array[pos>>3] = 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/writer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/writer.go
new file mode 100644
index 000000000000..39feaef52173
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/andybalholm/brotli/writer.go
@@ -0,0 +1,119 @@
+package brotli
+
+import (
+ "errors"
+ "io"
+)
+
+const (
+ BestSpeed = 0
+ BestCompression = 11
+ DefaultCompression = 6
+)
+
+// WriterOptions configures Writer.
+type WriterOptions struct {
+ // Quality controls the compression-speed vs compression-density trade-offs.
+ // The higher the quality, the slower the compression. Range is 0 to 11.
+ Quality int
+ // LGWin is the base 2 logarithm of the sliding window size.
+ // Range is 10 to 24. 0 indicates automatic configuration based on Quality.
+ LGWin int
+}
+
+var (
+ errEncode = errors.New("brotli: encode error")
+ errWriterClosed = errors.New("brotli: Writer is closed")
+)
+
+// Writes to the returned writer are compressed and written to dst.
+// It is the caller's responsibility to call Close on the Writer when done.
+// Writes may be buffered and not flushed until Close.
+func NewWriter(dst io.Writer) *Writer {
+ return NewWriterLevel(dst, DefaultCompression)
+}
+
+// NewWriterLevel is like NewWriter but specifies the compression level instead
+// of assuming DefaultCompression.
+// The compression level can be DefaultCompression or any integer value between
+// BestSpeed and BestCompression inclusive.
+func NewWriterLevel(dst io.Writer, level int) *Writer {
+ return NewWriterOptions(dst, WriterOptions{
+ Quality: level,
+ })
+}
+
+// NewWriterOptions is like NewWriter but specifies WriterOptions
+func NewWriterOptions(dst io.Writer, options WriterOptions) *Writer {
+ w := new(Writer)
+ w.options = options
+ w.Reset(dst)
+ return w
+}
+
+// Reset discards the Writer's state and makes it equivalent to the result of
+// its original state from NewWriter or NewWriterLevel, but writing to dst
+// instead. This permits reusing a Writer rather than allocating a new one.
+func (w *Writer) Reset(dst io.Writer) {
+ encoderInitState(w)
+ w.params.quality = w.options.Quality
+ if w.options.LGWin > 0 {
+ w.params.lgwin = uint(w.options.LGWin)
+ }
+ w.dst = dst
+ w.err = nil
+}
+
+func (w *Writer) writeChunk(p []byte, op int) (n int, err error) {
+ if w.dst == nil {
+ return 0, errWriterClosed
+ }
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ for {
+ availableIn := uint(len(p))
+ nextIn := p
+ success := encoderCompressStream(w, op, &availableIn, &nextIn)
+ bytesConsumed := len(p) - int(availableIn)
+ p = p[bytesConsumed:]
+ n += bytesConsumed
+ if !success {
+ return n, errEncode
+ }
+
+ if len(p) == 0 || w.err != nil {
+ return n, w.err
+ }
+ }
+}
+
+// Flush outputs encoded data for all input provided to Write. The resulting
+// output can be decoded to match all input before Flush, but the stream is
+// not yet complete until after Close.
+// Flush has a negative impact on compression.
+func (w *Writer) Flush() error {
+ _, err := w.writeChunk(nil, operationFlush)
+ return err
+}
+
+// Close flushes remaining data to the decorated writer.
+func (w *Writer) Close() error {
+ // If stream is already closed, it is reported by `writeChunk`.
+ _, err := w.writeChunk(nil, operationFinish)
+ w.dst = nil
+ return err
+}
+
+// Write implements io.Writer. Flush or Close must be called to ensure that the
+// encoded bytes are actually flushed to the underlying Writer.
+func (w *Writer) Write(p []byte) (n int, err error) {
+ return w.writeChunk(p, operationProcess)
+}
+
+type nopCloser struct {
+ io.Writer
+}
+
+func (nopCloser) Close() error { return nil }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/.editorconfig b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/.editorconfig
new file mode 100644
index 000000000000..e4f9beca31a7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/.editorconfig
@@ -0,0 +1,42 @@
+# unifying the coding style for different editors and IDEs => editorconfig.org
+
+; indicate this is the root of the project
+root = true
+
+###########################################################
+; common
+###########################################################
+
+[*]
+charset = utf-8
+
+end_of_line = LF
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+indent_style = space
+indent_size = 2
+
+###########################################################
+; make
+###########################################################
+
+[Makefile]
+indent_style = tab
+
+[makefile]
+indent_style = tab
+
+###########################################################
+; markdown
+###########################################################
+
+[*.md]
+trim_trailing_whitespace = false
+
+###########################################################
+; golang
+###########################################################
+
+[*.go]
+indent_style = tab
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/.gitignore
new file mode 100644
index 000000000000..d93b5c92d867
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/.gitignore
@@ -0,0 +1,27 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+.DS_Store
+.vscode
+coverage.out
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/LICENSE
new file mode 100644
index 000000000000..446bb8b425a9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Bo-Yi Wu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/README.md
new file mode 100644
index 000000000000..330ba0e15157
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/README.md
@@ -0,0 +1,347 @@
+# JWT Middleware for Gin Framework
+
+[![Run Tests](https://github.com/appleboy/gin-jwt/actions/workflows/go.yml/badge.svg)](https://github.com/appleboy/gin-jwt/actions/workflows/go.yml)
+[![GitHub tag](https://img.shields.io/github/tag/appleboy/gin-jwt.svg)](https://github.com/appleboy/gin-jwt/releases)
+[![GoDoc](https://godoc.org/github.com/appleboy/gin-jwt?status.svg)](https://godoc.org/github.com/appleboy/gin-jwt)
+[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/gin-jwt)](https://goreportcard.com/report/github.com/appleboy/gin-jwt)
+[![codecov](https://codecov.io/gh/appleboy/gin-jwt/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/gin-jwt)
+[![codebeat badge](https://codebeat.co/badges/c4015f07-df23-4c7c-95ba-9193a12e14b1)](https://codebeat.co/projects/github-com-appleboy-gin-jwt)
+[![Sourcegraph](https://sourcegraph.com/github.com/appleboy/gin-jwt/-/badge.svg)](https://sourcegraph.com/github.com/appleboy/gin-jwt?badge)
+
+This is a middleware for [Gin](https://github.com/gin-gonic/gin) framework.
+
+It uses [jwt-go](https://github.com/golang-jwt/jwt) to provide a jwt authentication middleware. It provides additional handler functions to provide the `login` api that will generate the token and an additional `refresh` handler that can be used to refresh tokens.
+
+## Security Issue
+
+Simple HS256 JWT token brute force cracker. Effective only to crack JWT tokens with weak secrets. **Recommendation**: Use strong long secrets or `RS256` tokens. See the [jwt-cracker repository](https://github.com/lmammino/jwt-cracker).
+
+## Usage
+
+Download and install using [go module](https://blog.golang.org/using-go-modules):
+
+```sh
+export GO111MODULE=on
+go get github.com/appleboy/gin-jwt/v2
+```
+
+Import it in your code:
+
+```go
+import "github.com/appleboy/gin-jwt/v2"
+```
+
+Download and install without using [go module](https://blog.golang.org/using-go-modules):
+
+```sh
+go get github.com/appleboy/gin-jwt
+```
+
+Import it in your code:
+
+```go
+import "github.com/appleboy/gin-jwt"
+```
+
+## Example
+
+Please see [the example file](_example/basic/server.go) and you can use `ExtractClaims` to fetch user data.
+
+
+```go
+package main
+
+import (
+ "log"
+ "net/http"
+ "os"
+ "time"
+
+ jwt "github.com/appleboy/gin-jwt/v2"
+ "github.com/gin-gonic/gin"
+)
+
+type login struct {
+ Username string `form:"username" json:"username" binding:"required"`
+ Password string `form:"password" json:"password" binding:"required"`
+}
+
+var identityKey = "id"
+
+func helloHandler(c *gin.Context) {
+ claims := jwt.ExtractClaims(c)
+ user, _ := c.Get(identityKey)
+ c.JSON(200, gin.H{
+ "userID": claims[identityKey],
+ "userName": user.(*User).UserName,
+ "text": "Hello World.",
+ })
+}
+
+// User demo
+type User struct {
+ UserName string
+ FirstName string
+ LastName string
+}
+
+func main() {
+ port := os.Getenv("PORT")
+ r := gin.New()
+ r.Use(gin.Logger())
+ r.Use(gin.Recovery())
+
+ if port == "" {
+ port = "8000"
+ }
+
+ // the jwt middleware
+ authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
+ Realm: "test zone",
+ Key: []byte("secret key"),
+ Timeout: time.Hour,
+ MaxRefresh: time.Hour,
+ IdentityKey: identityKey,
+ PayloadFunc: func(data interface{}) jwt.MapClaims {
+ if v, ok := data.(*User); ok {
+ return jwt.MapClaims{
+ identityKey: v.UserName,
+ }
+ }
+ return jwt.MapClaims{}
+ },
+ IdentityHandler: func(c *gin.Context) interface{} {
+ claims := jwt.ExtractClaims(c)
+ return &User{
+ UserName: claims[identityKey].(string),
+ }
+ },
+ Authenticator: func(c *gin.Context) (interface{}, error) {
+ var loginVals login
+ if err := c.ShouldBind(&loginVals); err != nil {
+ return "", jwt.ErrMissingLoginValues
+ }
+ userID := loginVals.Username
+ password := loginVals.Password
+
+ if (userID == "admin" && password == "admin") || (userID == "test" && password == "test") {
+ return &User{
+ UserName: userID,
+ LastName: "Bo-Yi",
+ FirstName: "Wu",
+ }, nil
+ }
+
+ return nil, jwt.ErrFailedAuthentication
+ },
+ Authorizator: func(data interface{}, c *gin.Context) bool {
+ if v, ok := data.(*User); ok && v.UserName == "admin" {
+ return true
+ }
+
+ return false
+ },
+ Unauthorized: func(c *gin.Context, code int, message string) {
+ c.JSON(code, gin.H{
+ "code": code,
+ "message": message,
+ })
+ },
+ // TokenLookup is a string in the form of ":" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:"
+ // - "query:"
+ // - "cookie:"
+ // - "param:"
+ TokenLookup: "header: Authorization, query: token, cookie: jwt",
+ // TokenLookup: "query:token",
+ // TokenLookup: "cookie:token",
+
+ // TokenHeadName is a string in the header. Default value is "Bearer"
+ TokenHeadName: "Bearer",
+
+ // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
+ TimeFunc: time.Now,
+ })
+
+ if err != nil {
+ log.Fatal("JWT Error:" + err.Error())
+ }
+
+ // When you use jwt.New(), the function is already automatically called for checking,
+ // which means you don't need to call it again.
+ errInit := authMiddleware.MiddlewareInit()
+
+ if errInit != nil {
+ log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
+ }
+
+ r.POST("/login", authMiddleware.LoginHandler)
+
+ r.NoRoute(authMiddleware.MiddlewareFunc(), func(c *gin.Context) {
+ claims := jwt.ExtractClaims(c)
+ log.Printf("NoRoute claims: %#v\n", claims)
+ c.JSON(404, gin.H{"code": "PAGE_NOT_FOUND", "message": "Page not found"})
+ })
+
+ auth := r.Group("/auth")
+ // Refresh time can be longer than token timeout
+ auth.GET("/refresh_token", authMiddleware.RefreshHandler)
+ auth.Use(authMiddleware.MiddlewareFunc())
+ {
+ auth.GET("/hello", helloHandler)
+ }
+
+ if err := http.ListenAndServe(":"+port, r); err != nil {
+ log.Fatal(err)
+ }
+}
+```
+
+## Demo
+
+Please run _example/server.go file and listen `8000` port.
+
+```sh
+go run _example/server.go
+```
+
+Download and install [httpie](https://github.com/jkbrzt/httpie) CLI HTTP client.
+
+### Login API
+
+```sh
+http -v --json POST localhost:8000/login username=admin password=admin
+```
+
+Output screenshot
+
+![api screenshot](screenshot/login.png)
+
+### Refresh token API
+
+```bash
+http -v -f GET localhost:8000/auth/refresh_token "Authorization:Bearer xxxxxxxxx" "Content-Type: application/json"
+```
+
+Output screenshot
+
+![api screenshot](screenshot/refresh_token.png)
+
+### Hello world
+
+Please login as `admin` and password as `admin`
+
+```bash
+http -f GET localhost:8000/auth/hello "Authorization:Bearer xxxxxxxxx" "Content-Type: application/json"
+```
+
+Response message `200 OK`:
+
+```sh
+HTTP/1.1 200 OK
+Content-Length: 24
+Content-Type: application/json; charset=utf-8
+Date: Sat, 19 Mar 2016 03:02:57 GMT
+
+{
+ "text": "Hello World.",
+ "userID": "admin"
+}
+```
+
+### Authorization
+
+Please login as `test` and password as `test`
+
+```bash
+http -f GET localhost:8000/auth/hello "Authorization:Bearer xxxxxxxxx" "Content-Type: application/json"
+```
+
+Response message `403 Forbidden`:
+
+```sh
+HTTP/1.1 403 Forbidden
+Content-Length: 62
+Content-Type: application/json; charset=utf-8
+Date: Sat, 19 Mar 2016 03:05:40 GMT
+Www-Authenticate: JWT realm=test zone
+
+{
+ "code": 403,
+ "message": "You don't have permission to access."
+}
+```
+
+### Cookie Token
+
+Use these options for setting the JWT in a cookie. See the Mozilla [documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies) for more information on these options.
+
+```go
+ SendCookie: true,
+ SecureCookie: false, //non HTTPS dev environments
+ CookieHTTPOnly: true, // JS can't modify
+ CookieDomain: "localhost:8080",
+ CookieName: "token", // default jwt
+ TokenLookup: "cookie:token",
+ CookieSameSite: http.SameSiteDefaultMode, //SameSiteDefaultMode, SameSiteLaxMode, SameSiteStrictMode, SameSiteNoneMode
+```
+
+### Login request flow (using the LoginHandler)
+
+1. PROVIDED: `LoginHandler`
+
+ This is a provided function to be called on any login endpoint, which will trigger the flow described below.
+
+2. REQUIRED: `Authenticator`
+ This function should verify the user credentials given the gin context (i.e. password matches hashed password for a given user email, and any other authentication logic). Then the authenticator should return a struct or map that contains the user data that will be embedded in the jwt token. This might be something like an account id, role, is_verified, etc. After having successfully authenticated, the data returned from the authenticator is passed in as a parameter into the `PayloadFunc`, which is used to embed the user identifiers mentioned above into the jwt token. If an error is returned, the `Unauthorized` function is used (explained below).
+
+3. OPTIONAL: `PayloadFunc`
+
+ This function is called after having successfully authenticated (logged in). It should take whatever was returned from `Authenticator` and convert it into `MapClaims` (i.e. map[string]interface{}). A typical use case of this function is for when `Authenticator` returns a struct which holds the user identifiers, and that struct needs to be converted into a map. `MapClaims` should include one element that is [`IdentityKey` (default is "identity"): some_user_identity]. The elements of `MapClaims` returned in `PayloadFunc` will be embedded within the jwt token (as token claims). When users pass in their token on subsequent requests, you can get these claims back by using `ExtractClaims`.
+
+4. OPTIONAL: `LoginResponse`
+
+ After having successfully authenticated with `Authenticator`, created the jwt token using the identifiers from map returned from `PayloadFunc`, and set it as a cookie if `SendCookie` is enabled, this function is called. It is used to handle any post-login logic. This might look something like using the gin context to return a JSON of the token back to the user.
+
+### Subsequent requests on endpoints requiring jwt token (using MiddlewareFunc).
+
+1. PROVIDED: `MiddlewareFunc`
+
+ This is gin middleware that should be used within any endpoints that require the jwt token to be present. This middleware will parse the request headers for the token if it exists, and check that the jwt token is valid (not expired, correct signature). Then it will call `IdentityHandler` followed by `Authorizator`. If `Authorizator` passes and all of the previous token validity checks passed, the middleware will continue the request. If any of these checks fail, the `Unauthorized` function is used (explained below).
+
+2. OPTIONAL: `IdentityHandler`
+
+ The default of this function is likely sufficient for your needs. The purpose of this function is to fetch the user identity from claims embedded within the jwt token, and pass this identity value to `Authorizator`. This function assummes [`IdentityKey`: some_user_identity] is one of the attributes embedded within the claims of the jwt token (determined by `PayloadFunc`).
+
+3. OPTIONAL: `Authorizator`
+
+ Given the user identity value (`data` parameter) and the gin context, this function should check if the user is authorized to be reaching this endpoint (on the endpoints where the `MiddlewareFunc` applies). This function should likely use `ExtractClaims` to check if the user has the sufficient permissions to reach this endpoint, as opposed to hitting the database on every request. This function should return true if the user is authorized to continue through with the request, or false if they are not authorized (where `Unauthorized` will be called).
+
+### Logout Request flow (using LogoutHandler)
+
+1. PROVIDED: `LogoutHandler`
+
+ This is a provided function to be called on any logout endpoint, which will clear any cookies if `SendCookie` is set, and then call `LogoutResponse`.
+
+2. OPTIONAL: `LogoutResponse`
+
+ This should likely just return back to the user the http status code, if logout was successful or not.
+
+### Refresh Request flow (using RefreshHandler)
+
+1. PROVIDED: `RefreshHandler`:
+
+ This is a provided function to be called on any refresh token endpoint. If the token passed in is was issued within the `MaxRefreshTime` time frame, then this handler will create/set a new token similar to the `LoginHandler`, and pass this token into `RefreshResponse`
+
+2. OPTIONAL: `RefreshResponse`:
+
+ This should likely return a JSON of the token back to the user, similar to `LoginResponse`
+
+### Failures with logging in, bad tokens, or lacking privileges
+
+1. OPTIONAL `Unauthorized`:
+
+ On any error logging in, authorizing the user, or when there was no token or a invalid token passed in with the request, the following will happen. The gin context will be aborted depending on `DisabledAbort`, then `HTTPStatusMessageFunc` is called which by default converts the error into a string. Finally the `Unauthorized` function will be called. This function should likely return a JSON containing the http error code and error message to the user.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/auth_jwt.go b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/auth_jwt.go
new file mode 100644
index 000000000000..89ec00d862e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/auth_jwt.go
@@ -0,0 +1,821 @@
+package jwt
+
+import (
+ "crypto/rsa"
+ "errors"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "github.com/golang-jwt/jwt/v4"
+)
+
+// MapClaims type that uses the map[string]interface{} for JSON decoding
+// This is the default claims type if you don't supply one
+type MapClaims map[string]interface{}
+
+// GinJWTMiddleware provides a Json-Web-Token authentication implementation. On failure, a 401 HTTP response
+// is returned. On success, the wrapped middleware is called, and the userID is made available as
+// c.Get("userID").(string).
+// Users can get a token by posting a json request to LoginHandler. The token then needs to be passed in
+// the Authentication header. Example: Authorization:Bearer XXX_TOKEN_XXX
+type GinJWTMiddleware struct {
+ // Realm name to display to the user. Required.
+ Realm string
+
+ // signing algorithm - possible values are HS256, HS384, HS512, RS256, RS384 or RS512
+ // Optional, default is HS256.
+ SigningAlgorithm string
+
+ // Secret key used for signing. Required.
+ Key []byte
+
+ // Callback to retrieve key used for signing. Setting KeyFunc will bypass
+ // all other key settings
+ KeyFunc func(token *jwt.Token) (interface{}, error)
+
+ // Duration that a jwt token is valid. Optional, defaults to one hour.
+ Timeout time.Duration
+
+ // This field allows clients to refresh their token until MaxRefresh has passed.
+ // Note that clients can refresh their token in the last moment of MaxRefresh.
+ // This means that the maximum validity timespan for a token is TokenTime + MaxRefresh.
+ // Optional, defaults to 0 meaning not refreshable.
+ MaxRefresh time.Duration
+
+ // Callback function that should perform the authentication of the user based on login info.
+ // Must return user data as user identifier, it will be stored in Claim Array. Required.
+ // Check error (e) to determine the appropriate error message.
+ Authenticator func(c *gin.Context) (interface{}, error)
+
+ // Callback function that should perform the authorization of the authenticated user. Called
+ // only after an authentication success. Must return true on success, false on failure.
+ // Optional, default to success.
+ Authorizator func(data interface{}, c *gin.Context) bool
+
+ // Callback function that will be called during login.
+ // Using this function it is possible to add additional payload data to the webtoken.
+ // The data is then made available during requests via c.Get("JWT_PAYLOAD").
+ // Note that the payload is not encrypted.
+ // The attributes mentioned on jwt.io can't be used as keys for the map.
+ // Optional, by default no additional data will be set.
+ PayloadFunc func(data interface{}) MapClaims
+
+ // User can define own Unauthorized func.
+ Unauthorized func(c *gin.Context, code int, message string)
+
+ // User can define own LoginResponse func.
+ LoginResponse func(c *gin.Context, code int, message string, time time.Time)
+
+ // User can define own LogoutResponse func.
+ LogoutResponse func(c *gin.Context, code int)
+
+ // User can define own RefreshResponse func.
+ RefreshResponse func(c *gin.Context, code int, message string, time time.Time)
+
+ // Set the identity handler function
+ IdentityHandler func(*gin.Context) interface{}
+
+ // Set the identity key
+ IdentityKey string
+
+ // TokenLookup is a string in the form of ":" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:"
+ // - "query:"
+ // - "cookie:"
+ TokenLookup string
+
+ // TokenHeadName is a string in the header. Default value is "Bearer"
+ TokenHeadName string
+
+ // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
+ TimeFunc func() time.Time
+
+ // HTTP Status messages for when something in the JWT middleware fails.
+ // Check error (e) to determine the appropriate error message.
+ HTTPStatusMessageFunc func(e error, c *gin.Context) string
+
+ // Private key file for asymmetric algorithms
+ PrivKeyFile string
+
+ // Private Key bytes for asymmetric algorithms
+ //
+ // Note: PrivKeyFile takes precedence over PrivKeyBytes if both are set
+ PrivKeyBytes []byte
+
+ // Public key file for asymmetric algorithms
+ PubKeyFile string
+
+ // Private key passphrase
+ PrivateKeyPassphrase string
+
+ // Public key bytes for asymmetric algorithms.
+ //
+ // Note: PubKeyFile takes precedence over PubKeyBytes if both are set
+ PubKeyBytes []byte
+
+ // Private key
+ privKey *rsa.PrivateKey
+
+ // Public key
+ pubKey *rsa.PublicKey
+
+ // Optionally return the token as a cookie
+ SendCookie bool
+
+ // Duration that a cookie is valid. Optional, by default equals to Timeout value.
+ CookieMaxAge time.Duration
+
+ // Allow insecure cookies for development over http
+ SecureCookie bool
+
+ // Allow cookies to be accessed client side for development
+ CookieHTTPOnly bool
+
+ // Allow cookie domain change for development
+ CookieDomain string
+
+ // SendAuthorization allow return authorization header for every request
+ SendAuthorization bool
+
+ // Disable abort() of context.
+ DisabledAbort bool
+
+ // CookieName allow cookie name change for development
+ CookieName string
+
+ // CookieSameSite allow use http.SameSite cookie param
+ CookieSameSite http.SameSite
+}
+
+var (
+ // ErrMissingSecretKey indicates Secret key is required
+ ErrMissingSecretKey = errors.New("secret key is required")
+
+ // ErrForbidden when HTTP status 403 is given
+ ErrForbidden = errors.New("you don't have permission to access this resource")
+
+ // ErrMissingAuthenticatorFunc indicates Authenticator is required
+ ErrMissingAuthenticatorFunc = errors.New("ginJWTMiddleware.Authenticator func is undefined")
+
+ // ErrMissingLoginValues indicates a user tried to authenticate without username or password
+ ErrMissingLoginValues = errors.New("missing Username or Password")
+
+ // ErrFailedAuthentication indicates authentication failed, could be faulty username or password
+ ErrFailedAuthentication = errors.New("incorrect Username or Password")
+
+ // ErrFailedTokenCreation indicates JWT Token failed to create, reason unknown
+ ErrFailedTokenCreation = errors.New("failed to create JWT Token")
+
+ // ErrExpiredToken indicates JWT token has expired. Can't refresh.
+ ErrExpiredToken = errors.New("token is expired") // in practice, this is generated from the jwt library not by us
+
+ // ErrEmptyAuthHeader can be thrown if authing with a HTTP header, the Auth header needs to be set
+ ErrEmptyAuthHeader = errors.New("auth header is empty")
+
+ // ErrMissingExpField missing exp field in token
+ ErrMissingExpField = errors.New("missing exp field")
+
+ // ErrWrongFormatOfExp field must be float64 format
+ ErrWrongFormatOfExp = errors.New("exp must be float64 format")
+
+ // ErrInvalidAuthHeader indicates auth header is invalid, could for example have the wrong Realm name
+ ErrInvalidAuthHeader = errors.New("auth header is invalid")
+
+ // ErrEmptyQueryToken can be thrown if authing with URL Query, the query token variable is empty
+ ErrEmptyQueryToken = errors.New("query token is empty")
+
+ // ErrEmptyCookieToken can be thrown if authing with a cookie, the token cookie is empty
+ ErrEmptyCookieToken = errors.New("cookie token is empty")
+
+ // ErrEmptyParamToken can be thrown if authing with parameter in path, the parameter in path is empty
+ ErrEmptyParamToken = errors.New("parameter token is empty")
+
+ // ErrInvalidSigningAlgorithm indicates signing algorithm is invalid, needs to be HS256, HS384, HS512, RS256, RS384 or RS512
+ ErrInvalidSigningAlgorithm = errors.New("invalid signing algorithm")
+
+ // ErrNoPrivKeyFile indicates that the given private key is unreadable
+ ErrNoPrivKeyFile = errors.New("private key file unreadable")
+
+ // ErrNoPubKeyFile indicates that the given public key is unreadable
+ ErrNoPubKeyFile = errors.New("public key file unreadable")
+
+ // ErrInvalidPrivKey indicates that the given private key is invalid
+ ErrInvalidPrivKey = errors.New("private key invalid")
+
+ // ErrInvalidPubKey indicates the the given public key is invalid
+ ErrInvalidPubKey = errors.New("public key invalid")
+
+ // IdentityKey default identity key
+ IdentityKey = "identity"
+)
+
+// New for check error with GinJWTMiddleware
+func New(m *GinJWTMiddleware) (*GinJWTMiddleware, error) {
+ if err := m.MiddlewareInit(); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+func (mw *GinJWTMiddleware) readKeys() error {
+ err := mw.privateKey()
+ if err != nil {
+ return err
+ }
+ err = mw.publicKey()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (mw *GinJWTMiddleware) privateKey() error {
+ var keyData []byte
+ if mw.PrivKeyFile == "" {
+ keyData = mw.PrivKeyBytes
+ } else {
+ filecontent, err := ioutil.ReadFile(mw.PrivKeyFile)
+ if err != nil {
+ return ErrNoPrivKeyFile
+ }
+ keyData = filecontent
+ }
+
+ if mw.PrivateKeyPassphrase != "" {
+ //nolint:staticcheck
+ key, err := jwt.ParseRSAPrivateKeyFromPEMWithPassword(keyData, mw.PrivateKeyPassphrase)
+ if err != nil {
+ return ErrInvalidPrivKey
+ }
+ mw.privKey = key
+ return nil
+ }
+
+ key, err := jwt.ParseRSAPrivateKeyFromPEM(keyData)
+ if err != nil {
+ return ErrInvalidPrivKey
+ }
+ mw.privKey = key
+ return nil
+}
+
+func (mw *GinJWTMiddleware) publicKey() error {
+ var keyData []byte
+ if mw.PubKeyFile == "" {
+ keyData = mw.PubKeyBytes
+ } else {
+ filecontent, err := ioutil.ReadFile(mw.PubKeyFile)
+ if err != nil {
+ return ErrNoPubKeyFile
+ }
+ keyData = filecontent
+ }
+
+ key, err := jwt.ParseRSAPublicKeyFromPEM(keyData)
+ if err != nil {
+ return ErrInvalidPubKey
+ }
+ mw.pubKey = key
+ return nil
+}
+
+func (mw *GinJWTMiddleware) usingPublicKeyAlgo() bool {
+ switch mw.SigningAlgorithm {
+ case "RS256", "RS512", "RS384":
+ return true
+ }
+ return false
+}
+
+// MiddlewareInit initialize jwt configs.
+func (mw *GinJWTMiddleware) MiddlewareInit() error {
+ if mw.TokenLookup == "" {
+ mw.TokenLookup = "header:Authorization"
+ }
+
+ if mw.SigningAlgorithm == "" {
+ mw.SigningAlgorithm = "HS256"
+ }
+
+ if mw.Timeout == 0 {
+ mw.Timeout = time.Hour
+ }
+
+ if mw.TimeFunc == nil {
+ mw.TimeFunc = time.Now
+ }
+
+ mw.TokenHeadName = strings.TrimSpace(mw.TokenHeadName)
+ if len(mw.TokenHeadName) == 0 {
+ mw.TokenHeadName = "Bearer"
+ }
+
+ if mw.Authorizator == nil {
+ mw.Authorizator = func(data interface{}, c *gin.Context) bool {
+ return true
+ }
+ }
+
+ if mw.Unauthorized == nil {
+ mw.Unauthorized = func(c *gin.Context, code int, message string) {
+ c.JSON(code, gin.H{
+ "code": code,
+ "message": message,
+ })
+ }
+ }
+
+ if mw.LoginResponse == nil {
+ mw.LoginResponse = func(c *gin.Context, code int, token string, expire time.Time) {
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusOK,
+ "token": token,
+ "expire": expire.Format(time.RFC3339),
+ })
+ }
+ }
+
+ if mw.LogoutResponse == nil {
+ mw.LogoutResponse = func(c *gin.Context, code int) {
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusOK,
+ })
+ }
+ }
+
+ if mw.RefreshResponse == nil {
+ mw.RefreshResponse = func(c *gin.Context, code int, token string, expire time.Time) {
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusOK,
+ "token": token,
+ "expire": expire.Format(time.RFC3339),
+ })
+ }
+ }
+
+ if mw.IdentityKey == "" {
+ mw.IdentityKey = IdentityKey
+ }
+
+ if mw.IdentityHandler == nil {
+ mw.IdentityHandler = func(c *gin.Context) interface{} {
+ claims := ExtractClaims(c)
+ return claims[mw.IdentityKey]
+ }
+ }
+
+ if mw.HTTPStatusMessageFunc == nil {
+ mw.HTTPStatusMessageFunc = func(e error, c *gin.Context) string {
+ return e.Error()
+ }
+ }
+
+ if mw.Realm == "" {
+ mw.Realm = "gin jwt"
+ }
+
+ if mw.CookieMaxAge == 0 {
+ mw.CookieMaxAge = mw.Timeout
+ }
+
+ if mw.CookieName == "" {
+ mw.CookieName = "jwt"
+ }
+
+ // bypass other key settings if KeyFunc is set
+ if mw.KeyFunc != nil {
+ return nil
+ }
+
+ if mw.usingPublicKeyAlgo() {
+ return mw.readKeys()
+ }
+
+ if mw.Key == nil {
+ return ErrMissingSecretKey
+ }
+ return nil
+}
+
+// MiddlewareFunc makes GinJWTMiddleware implement the Middleware interface.
+func (mw *GinJWTMiddleware) MiddlewareFunc() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ mw.middlewareImpl(c)
+ }
+}
+
+func (mw *GinJWTMiddleware) middlewareImpl(c *gin.Context) {
+ claims, err := mw.GetClaimsFromJWT(c)
+ if err != nil {
+ mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
+ return
+ }
+
+ if claims["exp"] == nil {
+ mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrMissingExpField, c))
+ return
+ }
+
+ if _, ok := claims["exp"].(float64); !ok {
+ mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrWrongFormatOfExp, c))
+ return
+ }
+
+ if int64(claims["exp"].(float64)) < mw.TimeFunc().Unix() {
+ mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrExpiredToken, c))
+ return
+ }
+
+ c.Set("JWT_PAYLOAD", claims)
+ identity := mw.IdentityHandler(c)
+
+ if identity != nil {
+ c.Set(mw.IdentityKey, identity)
+ }
+
+ if !mw.Authorizator(identity, c) {
+ mw.unauthorized(c, http.StatusForbidden, mw.HTTPStatusMessageFunc(ErrForbidden, c))
+ return
+ }
+
+ c.Next()
+}
+
+// GetClaimsFromJWT get claims from JWT token
+func (mw *GinJWTMiddleware) GetClaimsFromJWT(c *gin.Context) (MapClaims, error) {
+ token, err := mw.ParseToken(c)
+ if err != nil {
+ return nil, err
+ }
+
+ if mw.SendAuthorization {
+ if v, ok := c.Get("JWT_TOKEN"); ok {
+ c.Header("Authorization", mw.TokenHeadName+" "+v.(string))
+ }
+ }
+
+ claims := MapClaims{}
+ for key, value := range token.Claims.(jwt.MapClaims) {
+ claims[key] = value
+ }
+
+ return claims, nil
+}
+
+// LoginHandler can be used by clients to get a jwt token.
+// Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
+// Reply will be of the form {"token": "TOKEN"}.
+func (mw *GinJWTMiddleware) LoginHandler(c *gin.Context) {
+ if mw.Authenticator == nil {
+ mw.unauthorized(c, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrMissingAuthenticatorFunc, c))
+ return
+ }
+
+ data, err := mw.Authenticator(c)
+ if err != nil {
+ mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
+ return
+ }
+
+ // Create the token
+ token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
+ claims := token.Claims.(jwt.MapClaims)
+
+ if mw.PayloadFunc != nil {
+ for key, value := range mw.PayloadFunc(data) {
+ claims[key] = value
+ }
+ }
+
+ expire := mw.TimeFunc().Add(mw.Timeout)
+ claims["exp"] = expire.Unix()
+ claims["orig_iat"] = mw.TimeFunc().Unix()
+ tokenString, err := mw.signedString(token)
+ if err != nil {
+ mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrFailedTokenCreation, c))
+ return
+ }
+
+ // set cookie
+ if mw.SendCookie {
+ expireCookie := mw.TimeFunc().Add(mw.CookieMaxAge)
+ maxage := int(expireCookie.Unix() - mw.TimeFunc().Unix())
+
+ if mw.CookieSameSite != 0 {
+ c.SetSameSite(mw.CookieSameSite)
+ }
+
+ c.SetCookie(
+ mw.CookieName,
+ tokenString,
+ maxage,
+ "/",
+ mw.CookieDomain,
+ mw.SecureCookie,
+ mw.CookieHTTPOnly,
+ )
+ }
+
+ mw.LoginResponse(c, http.StatusOK, tokenString, expire)
+}
+
+// LogoutHandler can be used by clients to remove the jwt cookie (if set)
+func (mw *GinJWTMiddleware) LogoutHandler(c *gin.Context) {
+ // delete auth cookie
+ if mw.SendCookie {
+ if mw.CookieSameSite != 0 {
+ c.SetSameSite(mw.CookieSameSite)
+ }
+
+ c.SetCookie(
+ mw.CookieName,
+ "",
+ -1,
+ "/",
+ mw.CookieDomain,
+ mw.SecureCookie,
+ mw.CookieHTTPOnly,
+ )
+ }
+
+ mw.LogoutResponse(c, http.StatusOK)
+}
+
+func (mw *GinJWTMiddleware) signedString(token *jwt.Token) (string, error) {
+ var tokenString string
+ var err error
+ if mw.usingPublicKeyAlgo() {
+ tokenString, err = token.SignedString(mw.privKey)
+ } else {
+ tokenString, err = token.SignedString(mw.Key)
+ }
+ return tokenString, err
+}
+
+// RefreshHandler can be used to refresh a token. The token still needs to be valid on refresh.
+// Shall be put under an endpoint that is using the GinJWTMiddleware.
+// Reply will be of the form {"token": "TOKEN"}.
+func (mw *GinJWTMiddleware) RefreshHandler(c *gin.Context) {
+ tokenString, expire, err := mw.RefreshToken(c)
+ if err != nil {
+ mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
+ return
+ }
+
+ mw.RefreshResponse(c, http.StatusOK, tokenString, expire)
+}
+
+// RefreshToken refresh token and check if token is expired
+func (mw *GinJWTMiddleware) RefreshToken(c *gin.Context) (string, time.Time, error) {
+ claims, err := mw.CheckIfTokenExpire(c)
+ if err != nil {
+ return "", time.Now(), err
+ }
+
+ // Create the token
+ newToken := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
+ newClaims := newToken.Claims.(jwt.MapClaims)
+
+ for key := range claims {
+ newClaims[key] = claims[key]
+ }
+
+ expire := mw.TimeFunc().Add(mw.Timeout)
+ newClaims["exp"] = expire.Unix()
+ newClaims["orig_iat"] = mw.TimeFunc().Unix()
+ tokenString, err := mw.signedString(newToken)
+ if err != nil {
+ return "", time.Now(), err
+ }
+
+ // set cookie
+ if mw.SendCookie {
+ expireCookie := mw.TimeFunc().Add(mw.CookieMaxAge)
+ maxage := int(expireCookie.Unix() - time.Now().Unix())
+
+ if mw.CookieSameSite != 0 {
+ c.SetSameSite(mw.CookieSameSite)
+ }
+
+ c.SetCookie(
+ mw.CookieName,
+ tokenString,
+ maxage,
+ "/",
+ mw.CookieDomain,
+ mw.SecureCookie,
+ mw.CookieHTTPOnly,
+ )
+ }
+
+ return tokenString, expire, nil
+}
+
+// CheckIfTokenExpire check if token expire
+func (mw *GinJWTMiddleware) CheckIfTokenExpire(c *gin.Context) (jwt.MapClaims, error) {
+ token, err := mw.ParseToken(c)
+ if err != nil {
+ // If we receive an error, and the error is anything other than a single
+ // ValidationErrorExpired, we want to return the error.
+ // If the error is just ValidationErrorExpired, we want to continue, as we can still
+ // refresh the token if it's within the MaxRefresh time.
+ // (see https://github.com/appleboy/gin-jwt/issues/176)
+ validationErr, ok := err.(*jwt.ValidationError)
+ if !ok || validationErr.Errors != jwt.ValidationErrorExpired {
+ return nil, err
+ }
+ }
+
+ claims := token.Claims.(jwt.MapClaims)
+
+ origIat := int64(claims["orig_iat"].(float64))
+
+ if origIat < mw.TimeFunc().Add(-mw.MaxRefresh).Unix() {
+ return nil, ErrExpiredToken
+ }
+
+ return claims, nil
+}
+
+// TokenGenerator method that clients can use to get a jwt token.
+func (mw *GinJWTMiddleware) TokenGenerator(data interface{}) (string, time.Time, error) {
+ token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
+ claims := token.Claims.(jwt.MapClaims)
+
+ if mw.PayloadFunc != nil {
+ for key, value := range mw.PayloadFunc(data) {
+ claims[key] = value
+ }
+ }
+
+ expire := mw.TimeFunc().UTC().Add(mw.Timeout)
+ claims["exp"] = expire.Unix()
+ claims["orig_iat"] = mw.TimeFunc().Unix()
+ tokenString, err := mw.signedString(token)
+ if err != nil {
+ return "", time.Time{}, err
+ }
+
+ return tokenString, expire, nil
+}
+
+func (mw *GinJWTMiddleware) jwtFromHeader(c *gin.Context, key string) (string, error) {
+ authHeader := c.Request.Header.Get(key)
+
+ if authHeader == "" {
+ return "", ErrEmptyAuthHeader
+ }
+
+ parts := strings.SplitN(authHeader, " ", 2)
+ if !(len(parts) == 2 && parts[0] == mw.TokenHeadName) {
+ return "", ErrInvalidAuthHeader
+ }
+
+ return parts[1], nil
+}
+
+func (mw *GinJWTMiddleware) jwtFromQuery(c *gin.Context, key string) (string, error) {
+ token := c.Query(key)
+
+ if token == "" {
+ return "", ErrEmptyQueryToken
+ }
+
+ return token, nil
+}
+
+func (mw *GinJWTMiddleware) jwtFromCookie(c *gin.Context, key string) (string, error) {
+ cookie, _ := c.Cookie(key)
+
+ if cookie == "" {
+ return "", ErrEmptyCookieToken
+ }
+
+ return cookie, nil
+}
+
+func (mw *GinJWTMiddleware) jwtFromParam(c *gin.Context, key string) (string, error) {
+ token := c.Param(key)
+
+ if token == "" {
+ return "", ErrEmptyParamToken
+ }
+
+ return token, nil
+}
+
+// ParseToken parse jwt token from gin context
+func (mw *GinJWTMiddleware) ParseToken(c *gin.Context) (*jwt.Token, error) {
+ var token string
+ var err error
+
+ methods := strings.Split(mw.TokenLookup, ",")
+ for _, method := range methods {
+ if len(token) > 0 {
+ break
+ }
+ parts := strings.Split(strings.TrimSpace(method), ":")
+ k := strings.TrimSpace(parts[0])
+ v := strings.TrimSpace(parts[1])
+ switch k {
+ case "header":
+ token, err = mw.jwtFromHeader(c, v)
+ case "query":
+ token, err = mw.jwtFromQuery(c, v)
+ case "cookie":
+ token, err = mw.jwtFromCookie(c, v)
+ case "param":
+ token, err = mw.jwtFromParam(c, v)
+ }
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ if mw.KeyFunc != nil {
+ return jwt.Parse(token, mw.KeyFunc)
+ }
+
+ return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
+ if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
+ return nil, ErrInvalidSigningAlgorithm
+ }
+ if mw.usingPublicKeyAlgo() {
+ return mw.pubKey, nil
+ }
+
+ // save token string if vaild
+ c.Set("JWT_TOKEN", token)
+
+ return mw.Key, nil
+ })
+}
+
+// ParseTokenString parse jwt token string
+func (mw *GinJWTMiddleware) ParseTokenString(token string) (*jwt.Token, error) {
+ if mw.KeyFunc != nil {
+ return jwt.Parse(token, mw.KeyFunc)
+ }
+
+ return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
+ if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
+ return nil, ErrInvalidSigningAlgorithm
+ }
+ if mw.usingPublicKeyAlgo() {
+ return mw.pubKey, nil
+ }
+
+ return mw.Key, nil
+ })
+}
+
+func (mw *GinJWTMiddleware) unauthorized(c *gin.Context, code int, message string) {
+ c.Header("WWW-Authenticate", "JWT realm="+mw.Realm)
+ if !mw.DisabledAbort {
+ c.Abort()
+ }
+
+ mw.Unauthorized(c, code, message)
+}
+
+// ExtractClaims help to extract the JWT claims
+func ExtractClaims(c *gin.Context) MapClaims {
+ claims, exists := c.Get("JWT_PAYLOAD")
+ if !exists {
+ return make(MapClaims)
+ }
+
+ return claims.(MapClaims)
+}
+
+// ExtractClaimsFromToken help to extract the JWT claims from token
+func ExtractClaimsFromToken(token *jwt.Token) MapClaims {
+ if token == nil {
+ return make(MapClaims)
+ }
+
+ claims := MapClaims{}
+ for key, value := range token.Claims.(jwt.MapClaims) {
+ claims[key] = value
+ }
+
+ return claims
+}
+
+// GetToken help to get the JWT token string
+func GetToken(c *gin.Context) string {
+ token, exists := c.Get("JWT_TOKEN")
+ if !exists {
+ return ""
+ }
+
+ return token.(string)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go
deleted file mode 100644
index 87a117f1f921..000000000000
--- a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/appleboy/gin-jwt/v2, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/appleboy/gin-jwt/v2 (exports: GinJWTMiddleware; functions: New)
-
-// Package gin is a stub of github.com/appleboy/gin-jwt/v2, generated by depstubber.
-package gin
-
-import (
- http "net/http"
- time "time"
-)
-
-type GinJWTMiddleware struct {
- Realm string
- SigningAlgorithm string
- Key []byte
- KeyFunc func(interface{}) (interface{}, error)
- Timeout time.Duration
- MaxRefresh time.Duration
- Authenticator func(interface{}) (interface{}, error)
- Authorizator func(interface{}, interface{}) bool
- PayloadFunc func(interface{}) MapClaims
- Unauthorized func(interface{}, int, string)
- LoginResponse func(interface{}, int, string, time.Time)
- LogoutResponse func(interface{}, int)
- RefreshResponse func(interface{}, int, string, time.Time)
- IdentityHandler func(interface{}) interface{}
- IdentityKey string
- TokenLookup string
- TokenHeadName string
- TimeFunc func() time.Time
- HTTPStatusMessageFunc func(error, interface{}) string
- PrivKeyFile string
- PrivKeyBytes []byte
- PubKeyFile string
- PrivateKeyPassphrase string
- PubKeyBytes []byte
- SendCookie bool
- CookieMaxAge time.Duration
- SecureCookie bool
- CookieHTTPOnly bool
- CookieDomain string
- SendAuthorization bool
- DisabledAbort bool
- CookieName string
- CookieSameSite http.SameSite
-}
-
-func (_ *GinJWTMiddleware) CheckIfTokenExpire(_ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ *GinJWTMiddleware) GetClaimsFromJWT(_ interface{}) (MapClaims, error) {
- return nil, nil
-}
-
-func (_ *GinJWTMiddleware) LoginHandler(_ interface{}) {}
-
-func (_ *GinJWTMiddleware) LogoutHandler(_ interface{}) {}
-
-func (_ *GinJWTMiddleware) MiddlewareFunc() interface{} {
- return nil
-}
-
-func (_ *GinJWTMiddleware) MiddlewareInit() error {
- return nil
-}
-
-func (_ *GinJWTMiddleware) ParseToken(_ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ *GinJWTMiddleware) ParseTokenString(_ string) (interface{}, error) {
- return nil, nil
-}
-
-func (_ *GinJWTMiddleware) RefreshHandler(_ interface{}) {}
-
-func (_ *GinJWTMiddleware) RefreshToken(_ interface{}) (string, time.Time, error) {
- return "", time.Time{}, nil
-}
-
-func (_ *GinJWTMiddleware) TokenGenerator(_ interface{}) (string, time.Time, error) {
- return "", time.Time{}, nil
-}
-
-type MapClaims map[string]interface{}
-
-func New(_ *GinJWTMiddleware) (*GinJWTMiddleware, error) {
- return nil, nil
-}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/LICENSE
new file mode 100644
index 000000000000..6ce87cd37454
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Aymerick JEHANNE
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/declaration.go b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/declaration.go
new file mode 100644
index 000000000000..61d29d335901
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/declaration.go
@@ -0,0 +1,60 @@
+package css
+
+import "fmt"
+
+// Declaration represents a parsed style property
+type Declaration struct {
+ Property string
+ Value string
+ Important bool
+}
+
+// NewDeclaration instanciates a new Declaration
+func NewDeclaration() *Declaration {
+ return &Declaration{}
+}
+
+// Returns string representation of the Declaration
+func (decl *Declaration) String() string {
+ return decl.StringWithImportant(true)
+}
+
+// StringWithImportant returns string representation with optional !important part
+func (decl *Declaration) StringWithImportant(option bool) string {
+ result := fmt.Sprintf("%s: %s", decl.Property, decl.Value)
+
+ if option && decl.Important {
+ result += " !important"
+ }
+
+ result += ";"
+
+ return result
+}
+
+// Equal returns true if both Declarations are equals
+func (decl *Declaration) Equal(other *Declaration) bool {
+ return (decl.Property == other.Property) && (decl.Value == other.Value) && (decl.Important == other.Important)
+}
+
+//
+// DeclarationsByProperty
+//
+
+// DeclarationsByProperty represents sortable style declarations
+type DeclarationsByProperty []*Declaration
+
+// Implements sort.Interface
+func (declarations DeclarationsByProperty) Len() int {
+ return len(declarations)
+}
+
+// Implements sort.Interface
+func (declarations DeclarationsByProperty) Swap(i, j int) {
+ declarations[i], declarations[j] = declarations[j], declarations[i]
+}
+
+// Implements sort.Interface
+func (declarations DeclarationsByProperty) Less(i, j int) bool {
+ return declarations[i].Property < declarations[j].Property
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/rule.go b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/rule.go
new file mode 100644
index 000000000000..b5a44b542929
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/rule.go
@@ -0,0 +1,230 @@
+package css
+
+import (
+ "fmt"
+ "strings"
+)
+
+const (
+ indentSpace = 2
+)
+
+// RuleKind represents a Rule kind
+type RuleKind int
+
+// Rule kinds
+const (
+ QualifiedRule RuleKind = iota
+ AtRule
+)
+
+// At Rules than have Rules inside their block instead of Declarations
+var atRulesWithRulesBlock = []string{
+ "@document", "@font-feature-values", "@keyframes", "@media", "@supports",
+}
+
+// Rule represents a parsed CSS rule
+type Rule struct {
+ Kind RuleKind
+
+ // At Rule name (eg: "@media")
+ Name string
+
+ // Raw prelude
+ Prelude string
+
+ // Qualified Rule selectors parsed from prelude
+ Selectors []string
+
+ // Style properties
+ Declarations []*Declaration
+
+ // At Rule embedded rules
+ Rules []*Rule
+
+ // Current rule embedding level
+ EmbedLevel int
+}
+
+// NewRule instanciates a new Rule
+func NewRule(kind RuleKind) *Rule {
+ return &Rule{
+ Kind: kind,
+ }
+}
+
+// Returns string representation of rule kind
+func (kind RuleKind) String() string {
+ switch kind {
+ case QualifiedRule:
+ return "Qualified Rule"
+ case AtRule:
+ return "At Rule"
+ default:
+ return "WAT"
+ }
+}
+
+// EmbedsRules returns true if this rule embeds another rules
+func (rule *Rule) EmbedsRules() bool {
+ if rule.Kind == AtRule {
+ for _, atRuleName := range atRulesWithRulesBlock {
+ if rule.Name == atRuleName {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+// Equal returns true if both rules are equals
+func (rule *Rule) Equal(other *Rule) bool {
+ if (rule.Kind != other.Kind) ||
+ (rule.Prelude != other.Prelude) ||
+ (rule.Name != other.Name) {
+ return false
+ }
+
+ if (len(rule.Selectors) != len(other.Selectors)) ||
+ (len(rule.Declarations) != len(other.Declarations)) ||
+ (len(rule.Rules) != len(other.Rules)) {
+ return false
+ }
+
+ for i, sel := range rule.Selectors {
+ if sel != other.Selectors[i] {
+ return false
+ }
+ }
+
+ for i, decl := range rule.Declarations {
+ if !decl.Equal(other.Declarations[i]) {
+ return false
+ }
+ }
+
+ for i, rule := range rule.Rules {
+ if !rule.Equal(other.Rules[i]) {
+ return false
+ }
+ }
+
+ return true
+}
+
+// Diff returns a string representation of rules differences
+func (rule *Rule) Diff(other *Rule) []string {
+ result := []string{}
+
+ if rule.Kind != other.Kind {
+ result = append(result, fmt.Sprintf("Kind: %s | %s", rule.Kind.String(), other.Kind.String()))
+ }
+
+ if rule.Prelude != other.Prelude {
+ result = append(result, fmt.Sprintf("Prelude: \"%s\" | \"%s\"", rule.Prelude, other.Prelude))
+ }
+
+ if rule.Name != other.Name {
+ result = append(result, fmt.Sprintf("Name: \"%s\" | \"%s\"", rule.Name, other.Name))
+ }
+
+ if len(rule.Selectors) != len(other.Selectors) {
+ result = append(result, fmt.Sprintf("Selectors: %v | %v", strings.Join(rule.Selectors, ", "), strings.Join(other.Selectors, ", ")))
+ } else {
+ for i, sel := range rule.Selectors {
+ if sel != other.Selectors[i] {
+ result = append(result, fmt.Sprintf("Selector: \"%s\" | \"%s\"", sel, other.Selectors[i]))
+ }
+ }
+ }
+
+ if len(rule.Declarations) != len(other.Declarations) {
+ result = append(result, fmt.Sprintf("Declarations Nb: %d | %d", len(rule.Declarations), len(other.Declarations)))
+ } else {
+ for i, decl := range rule.Declarations {
+ if !decl.Equal(other.Declarations[i]) {
+ result = append(result, fmt.Sprintf("Declaration: \"%s\" | \"%s\"", decl.String(), other.Declarations[i].String()))
+ }
+ }
+ }
+
+ if len(rule.Rules) != len(other.Rules) {
+ result = append(result, fmt.Sprintf("Rules Nb: %d | %d", len(rule.Rules), len(other.Rules)))
+ } else {
+
+ for i, rule := range rule.Rules {
+ if !rule.Equal(other.Rules[i]) {
+ result = append(result, fmt.Sprintf("Rule: \"%s\" | \"%s\"", rule.String(), other.Rules[i].String()))
+ }
+ }
+ }
+
+ return result
+}
+
+// Returns the string representation of a rule
+func (rule *Rule) String() string {
+ result := ""
+
+ if rule.Kind == QualifiedRule {
+ for i, sel := range rule.Selectors {
+ if i != 0 {
+ result += ", "
+ }
+ result += sel
+ }
+ } else {
+ // AtRule
+ result += fmt.Sprintf("%s", rule.Name)
+
+ if rule.Prelude != "" {
+ if result != "" {
+ result += " "
+ }
+ result += fmt.Sprintf("%s", rule.Prelude)
+ }
+ }
+
+ if (len(rule.Declarations) == 0) && (len(rule.Rules) == 0) {
+ result += ";"
+ } else {
+ result += " {\n"
+
+ if rule.EmbedsRules() {
+ for _, subRule := range rule.Rules {
+ result += fmt.Sprintf("%s%s\n", rule.indent(), subRule.String())
+ }
+ } else {
+ for _, decl := range rule.Declarations {
+ result += fmt.Sprintf("%s%s\n", rule.indent(), decl.String())
+ }
+ }
+
+ result += fmt.Sprintf("%s}", rule.indentEndBlock())
+ }
+
+ return result
+}
+
+// Returns identation spaces for declarations and rules
+func (rule *Rule) indent() string {
+ result := ""
+
+ for i := 0; i < ((rule.EmbedLevel + 1) * indentSpace); i++ {
+ result += " "
+ }
+
+ return result
+}
+
+// Returns identation spaces for end of block character
+func (rule *Rule) indentEndBlock() string {
+ result := ""
+
+ for i := 0; i < (rule.EmbedLevel * indentSpace); i++ {
+ result += " "
+ }
+
+ return result
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/stylesheet.go b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/stylesheet.go
new file mode 100644
index 000000000000..6b32c2ec90f4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/css/stylesheet.go
@@ -0,0 +1,25 @@
+package css
+
+// Stylesheet represents a parsed stylesheet
+type Stylesheet struct {
+ Rules []*Rule
+}
+
+// NewStylesheet instanciate a new Stylesheet
+func NewStylesheet() *Stylesheet {
+ return &Stylesheet{}
+}
+
+// Returns string representation of the Stylesheet
+func (sheet *Stylesheet) String() string {
+ result := ""
+
+ for _, rule := range sheet.Rules {
+ if result != "" {
+ result += "\n"
+ }
+ result += rule.String()
+ }
+
+ return result
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/parser/parser.go b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/parser/parser.go
new file mode 100644
index 000000000000..6c4917ccf984
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/aymerick/douceur/parser/parser.go
@@ -0,0 +1,409 @@
+package parser
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/gorilla/css/scanner"
+
+ "github.com/aymerick/douceur/css"
+)
+
+const (
+ importantSuffixRegexp = `(?i)\s*!important\s*$`
+)
+
+var (
+ importantRegexp *regexp.Regexp
+)
+
+// Parser represents a CSS parser
+type Parser struct {
+ scan *scanner.Scanner // Tokenizer
+
+ // Tokens parsed but not consumed yet
+ tokens []*scanner.Token
+
+ // Rule embedding level
+ embedLevel int
+}
+
+func init() {
+ importantRegexp = regexp.MustCompile(importantSuffixRegexp)
+}
+
+// NewParser instanciates a new parser
+func NewParser(txt string) *Parser {
+ return &Parser{
+ scan: scanner.New(txt),
+ }
+}
+
+// Parse parses a whole stylesheet
+func Parse(text string) (*css.Stylesheet, error) {
+ result, err := NewParser(text).ParseStylesheet()
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
+
+// ParseDeclarations parses CSS declarations
+func ParseDeclarations(text string) ([]*css.Declaration, error) {
+ result, err := NewParser(text).ParseDeclarations()
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
+
+// ParseStylesheet parses a stylesheet
+func (parser *Parser) ParseStylesheet() (*css.Stylesheet, error) {
+ result := css.NewStylesheet()
+
+ // Parse BOM
+ if _, err := parser.parseBOM(); err != nil {
+ return result, err
+ }
+
+ // Parse list of rules
+ rules, err := parser.ParseRules()
+ if err != nil {
+ return result, err
+ }
+
+ result.Rules = rules
+
+ return result, nil
+}
+
+// ParseRules parses a list of rules
+func (parser *Parser) ParseRules() ([]*css.Rule, error) {
+ result := []*css.Rule{}
+
+ inBlock := false
+ if parser.tokenChar("{") {
+ // parsing a block of rules
+ inBlock = true
+ parser.embedLevel++
+
+ parser.shiftToken()
+ }
+
+ for parser.tokenParsable() {
+ if parser.tokenIgnorable() {
+ parser.shiftToken()
+ } else if parser.tokenChar("}") {
+ if !inBlock {
+ errMsg := fmt.Sprintf("Unexpected } character: %s", parser.nextToken().String())
+ return result, errors.New(errMsg)
+ }
+
+ parser.shiftToken()
+ parser.embedLevel--
+
+ // finished
+ break
+ } else {
+ rule, err := parser.ParseRule()
+ if err != nil {
+ return result, err
+ }
+
+ rule.EmbedLevel = parser.embedLevel
+ result = append(result, rule)
+ }
+ }
+
+ return result, parser.err()
+}
+
+// ParseRule parses a rule
+func (parser *Parser) ParseRule() (*css.Rule, error) {
+ if parser.tokenAtKeyword() {
+ return parser.parseAtRule()
+ }
+
+ return parser.parseQualifiedRule()
+}
+
+// ParseDeclarations parses a list of declarations
+func (parser *Parser) ParseDeclarations() ([]*css.Declaration, error) {
+ result := []*css.Declaration{}
+
+ if parser.tokenChar("{") {
+ parser.shiftToken()
+ }
+
+ for parser.tokenParsable() {
+ if parser.tokenIgnorable() {
+ parser.shiftToken()
+ } else if parser.tokenChar("}") {
+ // end of block
+ parser.shiftToken()
+ break
+ } else {
+ declaration, err := parser.ParseDeclaration()
+ if err != nil {
+ return result, err
+ }
+
+ result = append(result, declaration)
+ }
+ }
+
+ return result, parser.err()
+}
+
+// ParseDeclaration parses a declaration
+func (parser *Parser) ParseDeclaration() (*css.Declaration, error) {
+ result := css.NewDeclaration()
+ curValue := ""
+
+ for parser.tokenParsable() {
+ if parser.tokenChar(":") {
+ result.Property = strings.TrimSpace(curValue)
+ curValue = ""
+
+ parser.shiftToken()
+ } else if parser.tokenChar(";") || parser.tokenChar("}") {
+ if result.Property == "" {
+ errMsg := fmt.Sprintf("Unexpected ; character: %s", parser.nextToken().String())
+ return result, errors.New(errMsg)
+ }
+
+ if importantRegexp.MatchString(curValue) {
+ result.Important = true
+ curValue = importantRegexp.ReplaceAllString(curValue, "")
+ }
+
+ result.Value = strings.TrimSpace(curValue)
+
+ if parser.tokenChar(";") {
+ parser.shiftToken()
+ }
+
+ // finished
+ break
+ } else {
+ token := parser.shiftToken()
+ curValue += token.Value
+ }
+ }
+
+ // log.Printf("[parsed] Declaration: %s", result.String())
+
+ return result, parser.err()
+}
+
+// Parse an At Rule
+func (parser *Parser) parseAtRule() (*css.Rule, error) {
+ // parse rule name (eg: "@import")
+ token := parser.shiftToken()
+
+ result := css.NewRule(css.AtRule)
+ result.Name = token.Value
+
+ for parser.tokenParsable() {
+ if parser.tokenChar(";") {
+ parser.shiftToken()
+
+ // finished
+ break
+ } else if parser.tokenChar("{") {
+ if result.EmbedsRules() {
+ // parse rules block
+ rules, err := parser.ParseRules()
+ if err != nil {
+ return result, err
+ }
+
+ result.Rules = rules
+ } else {
+ // parse declarations block
+ declarations, err := parser.ParseDeclarations()
+ if err != nil {
+ return result, err
+ }
+
+ result.Declarations = declarations
+ }
+
+ // finished
+ break
+ } else {
+ // parse prelude
+ prelude, err := parser.parsePrelude()
+ if err != nil {
+ return result, err
+ }
+
+ result.Prelude = prelude
+ }
+ }
+
+ // log.Printf("[parsed] Rule: %s", result.String())
+
+ return result, parser.err()
+}
+
+// Parse a Qualified Rule
+func (parser *Parser) parseQualifiedRule() (*css.Rule, error) {
+ result := css.NewRule(css.QualifiedRule)
+
+ for parser.tokenParsable() {
+ if parser.tokenChar("{") {
+ if result.Prelude == "" {
+ errMsg := fmt.Sprintf("Unexpected { character: %s", parser.nextToken().String())
+ return result, errors.New(errMsg)
+ }
+
+ // parse declarations block
+ declarations, err := parser.ParseDeclarations()
+ if err != nil {
+ return result, err
+ }
+
+ result.Declarations = declarations
+
+ // finished
+ break
+ } else {
+ // parse prelude
+ prelude, err := parser.parsePrelude()
+ if err != nil {
+ return result, err
+ }
+
+ result.Prelude = prelude
+ }
+ }
+
+ result.Selectors = strings.Split(result.Prelude, ",")
+ for i, sel := range result.Selectors {
+ result.Selectors[i] = strings.TrimSpace(sel)
+ }
+
+ // log.Printf("[parsed] Rule: %s", result.String())
+
+ return result, parser.err()
+}
+
+// Parse Rule prelude
+func (parser *Parser) parsePrelude() (string, error) {
+ result := ""
+
+ for parser.tokenParsable() && !parser.tokenEndOfPrelude() {
+ token := parser.shiftToken()
+ result += token.Value
+ }
+
+ result = strings.TrimSpace(result)
+
+ // log.Printf("[parsed] prelude: %s", result)
+
+ return result, parser.err()
+}
+
+// Parse BOM
+func (parser *Parser) parseBOM() (bool, error) {
+ if parser.nextToken().Type == scanner.TokenBOM {
+ parser.shiftToken()
+ return true, nil
+ }
+
+ return false, parser.err()
+}
+
+// Returns next token without removing it from tokens buffer
+func (parser *Parser) nextToken() *scanner.Token {
+ if len(parser.tokens) == 0 {
+ // fetch next token
+ nextToken := parser.scan.Next()
+
+ // log.Printf("[token] %s => %v", nextToken.Type.String(), nextToken.Value)
+
+ // queue it
+ parser.tokens = append(parser.tokens, nextToken)
+ }
+
+ return parser.tokens[0]
+}
+
+// Returns next token and remove it from the tokens buffer
+func (parser *Parser) shiftToken() *scanner.Token {
+ var result *scanner.Token
+
+ result, parser.tokens = parser.tokens[0], parser.tokens[1:]
+ return result
+}
+
+// Returns tokenizer error, or nil if no error
+func (parser *Parser) err() error {
+ if parser.tokenError() {
+ token := parser.nextToken()
+ return fmt.Errorf("Tokenizer error: %s", token.String())
+ }
+
+ return nil
+}
+
+// Returns true if next token is Error
+func (parser *Parser) tokenError() bool {
+ return parser.nextToken().Type == scanner.TokenError
+}
+
+// Returns true if next token is EOF
+func (parser *Parser) tokenEOF() bool {
+ return parser.nextToken().Type == scanner.TokenEOF
+}
+
+// Returns true if next token is a whitespace
+func (parser *Parser) tokenWS() bool {
+ return parser.nextToken().Type == scanner.TokenS
+}
+
+// Returns true if next token is a comment
+func (parser *Parser) tokenComment() bool {
+ return parser.nextToken().Type == scanner.TokenComment
+}
+
+// Returns true if next token is a CDO or a CDC
+func (parser *Parser) tokenCDOorCDC() bool {
+ switch parser.nextToken().Type {
+ case scanner.TokenCDO, scanner.TokenCDC:
+ return true
+ default:
+ return false
+ }
+}
+
+// Returns true if next token is ignorable
+func (parser *Parser) tokenIgnorable() bool {
+ return parser.tokenWS() || parser.tokenComment() || parser.tokenCDOorCDC()
+}
+
+// Returns true if next token is parsable
+func (parser *Parser) tokenParsable() bool {
+ return !parser.tokenEOF() && !parser.tokenError()
+}
+
+// Returns true if next token is an At Rule keyword
+func (parser *Parser) tokenAtKeyword() bool {
+ return parser.nextToken().Type == scanner.TokenAtKeyword
+}
+
+// Returns true if next token is given character
+func (parser *Parser) tokenChar(value string) bool {
+ token := parser.nextToken()
+ return (token.Type == scanner.TokenChar) && (token.Value == value)
+}
+
+// Returns true if next token marks the end of a prelude
+func (parser *Parser) tokenEndOfPrelude() bool {
+ return parser.tokenChar(";") || parser.tokenChar("{")
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/LICENSE.txt b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/LICENSE.txt
new file mode 100644
index 000000000000..24b53065f40b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2016 Caleb Spare
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/README.md
new file mode 100644
index 000000000000..8bf0e5b78153
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/README.md
@@ -0,0 +1,72 @@
+# xxhash
+
+[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2)
+[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml)
+
+xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
+high-quality hashing algorithm that is much faster than anything in the Go
+standard library.
+
+This package provides a straightforward API:
+
+```
+func Sum64(b []byte) uint64
+func Sum64String(s string) uint64
+type Digest struct{ ... }
+ func New() *Digest
+```
+
+The `Digest` type implements hash.Hash64. Its key methods are:
+
+```
+func (*Digest) Write([]byte) (int, error)
+func (*Digest) WriteString(string) (int, error)
+func (*Digest) Sum64() uint64
+```
+
+The package is written with optimized pure Go and also contains even faster
+assembly implementations for amd64 and arm64. If desired, the `purego` build tag
+opts into using the Go code even on those architectures.
+
+[xxHash]: http://cyan4973.github.io/xxHash/
+
+## Compatibility
+
+This package is in a module and the latest code is in version 2 of the module.
+You need a version of Go with at least "minimal module compatibility" to use
+github.com/cespare/xxhash/v2:
+
+* 1.9.7+ for Go 1.9
+* 1.10.3+ for Go 1.10
+* Go 1.11 or later
+
+I recommend using the latest release of Go.
+
+## Benchmarks
+
+Here are some quick benchmarks comparing the pure-Go and assembly
+implementations of Sum64.
+
+| input size | purego | asm |
+| ---------- | --------- | --------- |
+| 4 B | 1.3 GB/s | 1.2 GB/s |
+| 16 B | 2.9 GB/s | 3.5 GB/s |
+| 100 B | 6.9 GB/s | 8.1 GB/s |
+| 4 KB | 11.7 GB/s | 16.7 GB/s |
+| 10 MB | 12.0 GB/s | 17.3 GB/s |
+
+These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
+CPU using the following commands under Go 1.19.2:
+
+```
+benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
+benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
+```
+
+## Projects using this package
+
+- [InfluxDB](https://github.com/influxdata/influxdb)
+- [Prometheus](https://github.com/prometheus/prometheus)
+- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
+- [FreeCache](https://github.com/coocood/freecache)
+- [FastCache](https://github.com/VictoriaMetrics/fastcache)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/testall.sh b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/testall.sh
new file mode 100644
index 000000000000..94b9c443987c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/testall.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -eu -o pipefail
+
+# Small convenience script for running the tests with various combinations of
+# arch/tags. This assumes we're running on amd64 and have qemu available.
+
+go test ./...
+go test -tags purego ./...
+GOARCH=arm64 go test
+GOARCH=arm64 go test -tags purego
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash.go
new file mode 100644
index 000000000000..a9e0d45c9dcc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash.go
@@ -0,0 +1,228 @@
+// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
+// at http://cyan4973.github.io/xxHash/.
+package xxhash
+
+import (
+ "encoding/binary"
+ "errors"
+ "math/bits"
+)
+
+const (
+ prime1 uint64 = 11400714785074694791
+ prime2 uint64 = 14029467366897019727
+ prime3 uint64 = 1609587929392839161
+ prime4 uint64 = 9650029242287828579
+ prime5 uint64 = 2870177450012600261
+)
+
+// Store the primes in an array as well.
+//
+// The consts are used when possible in Go code to avoid MOVs but we need a
+// contiguous array of the assembly code.
+var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
+
+// Digest implements hash.Hash64.
+type Digest struct {
+ v1 uint64
+ v2 uint64
+ v3 uint64
+ v4 uint64
+ total uint64
+ mem [32]byte
+ n int // how much of mem is used
+}
+
+// New creates a new Digest that computes the 64-bit xxHash algorithm.
+func New() *Digest {
+ var d Digest
+ d.Reset()
+ return &d
+}
+
+// Reset clears the Digest's state so that it can be reused.
+func (d *Digest) Reset() {
+ d.v1 = primes[0] + prime2
+ d.v2 = prime2
+ d.v3 = 0
+ d.v4 = -primes[0]
+ d.total = 0
+ d.n = 0
+}
+
+// Size always returns 8 bytes.
+func (d *Digest) Size() int { return 8 }
+
+// BlockSize always returns 32 bytes.
+func (d *Digest) BlockSize() int { return 32 }
+
+// Write adds more data to d. It always returns len(b), nil.
+func (d *Digest) Write(b []byte) (n int, err error) {
+ n = len(b)
+ d.total += uint64(n)
+
+ memleft := d.mem[d.n&(len(d.mem)-1):]
+
+ if d.n+n < 32 {
+ // This new data doesn't even fill the current block.
+ copy(memleft, b)
+ d.n += n
+ return
+ }
+
+ if d.n > 0 {
+ // Finish off the partial block.
+ c := copy(memleft, b)
+ d.v1 = round(d.v1, u64(d.mem[0:8]))
+ d.v2 = round(d.v2, u64(d.mem[8:16]))
+ d.v3 = round(d.v3, u64(d.mem[16:24]))
+ d.v4 = round(d.v4, u64(d.mem[24:32]))
+ b = b[c:]
+ d.n = 0
+ }
+
+ if len(b) >= 32 {
+ // One or more full blocks left.
+ nw := writeBlocks(d, b)
+ b = b[nw:]
+ }
+
+ // Store any remaining partial block.
+ copy(d.mem[:], b)
+ d.n = len(b)
+
+ return
+}
+
+// Sum appends the current hash to b and returns the resulting slice.
+func (d *Digest) Sum(b []byte) []byte {
+ s := d.Sum64()
+ return append(
+ b,
+ byte(s>>56),
+ byte(s>>48),
+ byte(s>>40),
+ byte(s>>32),
+ byte(s>>24),
+ byte(s>>16),
+ byte(s>>8),
+ byte(s),
+ )
+}
+
+// Sum64 returns the current hash.
+func (d *Digest) Sum64() uint64 {
+ var h uint64
+
+ if d.total >= 32 {
+ v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
+ h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
+ h = mergeRound(h, v1)
+ h = mergeRound(h, v2)
+ h = mergeRound(h, v3)
+ h = mergeRound(h, v4)
+ } else {
+ h = d.v3 + prime5
+ }
+
+ h += d.total
+
+ b := d.mem[:d.n&(len(d.mem)-1)]
+ for ; len(b) >= 8; b = b[8:] {
+ k1 := round(0, u64(b[:8]))
+ h ^= k1
+ h = rol27(h)*prime1 + prime4
+ }
+ if len(b) >= 4 {
+ h ^= uint64(u32(b[:4])) * prime1
+ h = rol23(h)*prime2 + prime3
+ b = b[4:]
+ }
+ for ; len(b) > 0; b = b[1:] {
+ h ^= uint64(b[0]) * prime5
+ h = rol11(h) * prime1
+ }
+
+ h ^= h >> 33
+ h *= prime2
+ h ^= h >> 29
+ h *= prime3
+ h ^= h >> 32
+
+ return h
+}
+
+const (
+ magic = "xxh\x06"
+ marshaledSize = len(magic) + 8*5 + 32
+)
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (d *Digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ b = append(b, magic...)
+ b = appendUint64(b, d.v1)
+ b = appendUint64(b, d.v2)
+ b = appendUint64(b, d.v3)
+ b = appendUint64(b, d.v4)
+ b = appendUint64(b, d.total)
+ b = append(b, d.mem[:d.n]...)
+ b = b[:len(b)+len(d.mem)-d.n]
+ return b, nil
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+func (d *Digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic) || string(b[:len(magic)]) != magic {
+ return errors.New("xxhash: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("xxhash: invalid hash state size")
+ }
+ b = b[len(magic):]
+ b, d.v1 = consumeUint64(b)
+ b, d.v2 = consumeUint64(b)
+ b, d.v3 = consumeUint64(b)
+ b, d.v4 = consumeUint64(b)
+ b, d.total = consumeUint64(b)
+ copy(d.mem[:], b)
+ d.n = int(d.total % uint64(len(d.mem)))
+ return nil
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+ var a [8]byte
+ binary.LittleEndian.PutUint64(a[:], x)
+ return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ x := u64(b)
+ return b[8:], x
+}
+
+func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
+func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
+
+func round(acc, input uint64) uint64 {
+ acc += input * prime2
+ acc = rol31(acc)
+ acc *= prime1
+ return acc
+}
+
+func mergeRound(acc, val uint64) uint64 {
+ val = round(0, val)
+ acc ^= val
+ acc = acc*prime1 + prime4
+ return acc
+}
+
+func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) }
+func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) }
+func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
+func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
+func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
+func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
+func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
+func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
new file mode 100644
index 000000000000..3e8b132579ec
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
@@ -0,0 +1,209 @@
+//go:build !appengine && gc && !purego
+// +build !appengine
+// +build gc
+// +build !purego
+
+#include "textflag.h"
+
+// Registers:
+#define h AX
+#define d AX
+#define p SI // pointer to advance through b
+#define n DX
+#define end BX // loop end
+#define v1 R8
+#define v2 R9
+#define v3 R10
+#define v4 R11
+#define x R12
+#define prime1 R13
+#define prime2 R14
+#define prime4 DI
+
+#define round(acc, x) \
+ IMULQ prime2, x \
+ ADDQ x, acc \
+ ROLQ $31, acc \
+ IMULQ prime1, acc
+
+// round0 performs the operation x = round(0, x).
+#define round0(x) \
+ IMULQ prime2, x \
+ ROLQ $31, x \
+ IMULQ prime1, x
+
+// mergeRound applies a merge round on the two registers acc and x.
+// It assumes that prime1, prime2, and prime4 have been loaded.
+#define mergeRound(acc, x) \
+ round0(x) \
+ XORQ x, acc \
+ IMULQ prime1, acc \
+ ADDQ prime4, acc
+
+// blockLoop processes as many 32-byte blocks as possible,
+// updating v1, v2, v3, and v4. It assumes that there is at least one block
+// to process.
+#define blockLoop() \
+loop: \
+ MOVQ +0(p), x \
+ round(v1, x) \
+ MOVQ +8(p), x \
+ round(v2, x) \
+ MOVQ +16(p), x \
+ round(v3, x) \
+ MOVQ +24(p), x \
+ round(v4, x) \
+ ADDQ $32, p \
+ CMPQ p, end \
+ JLE loop
+
+// func Sum64(b []byte) uint64
+TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
+ // Load fixed primes.
+ MOVQ ·primes+0(SB), prime1
+ MOVQ ·primes+8(SB), prime2
+ MOVQ ·primes+24(SB), prime4
+
+ // Load slice.
+ MOVQ b_base+0(FP), p
+ MOVQ b_len+8(FP), n
+ LEAQ (p)(n*1), end
+
+ // The first loop limit will be len(b)-32.
+ SUBQ $32, end
+
+ // Check whether we have at least one block.
+ CMPQ n, $32
+ JLT noBlocks
+
+ // Set up initial state (v1, v2, v3, v4).
+ MOVQ prime1, v1
+ ADDQ prime2, v1
+ MOVQ prime2, v2
+ XORQ v3, v3
+ XORQ v4, v4
+ SUBQ prime1, v4
+
+ blockLoop()
+
+ MOVQ v1, h
+ ROLQ $1, h
+ MOVQ v2, x
+ ROLQ $7, x
+ ADDQ x, h
+ MOVQ v3, x
+ ROLQ $12, x
+ ADDQ x, h
+ MOVQ v4, x
+ ROLQ $18, x
+ ADDQ x, h
+
+ mergeRound(h, v1)
+ mergeRound(h, v2)
+ mergeRound(h, v3)
+ mergeRound(h, v4)
+
+ JMP afterBlocks
+
+noBlocks:
+ MOVQ ·primes+32(SB), h
+
+afterBlocks:
+ ADDQ n, h
+
+ ADDQ $24, end
+ CMPQ p, end
+ JG try4
+
+loop8:
+ MOVQ (p), x
+ ADDQ $8, p
+ round0(x)
+ XORQ x, h
+ ROLQ $27, h
+ IMULQ prime1, h
+ ADDQ prime4, h
+
+ CMPQ p, end
+ JLE loop8
+
+try4:
+ ADDQ $4, end
+ CMPQ p, end
+ JG try1
+
+ MOVL (p), x
+ ADDQ $4, p
+ IMULQ prime1, x
+ XORQ x, h
+
+ ROLQ $23, h
+ IMULQ prime2, h
+ ADDQ ·primes+16(SB), h
+
+try1:
+ ADDQ $4, end
+ CMPQ p, end
+ JGE finalize
+
+loop1:
+ MOVBQZX (p), x
+ ADDQ $1, p
+ IMULQ ·primes+32(SB), x
+ XORQ x, h
+ ROLQ $11, h
+ IMULQ prime1, h
+
+ CMPQ p, end
+ JL loop1
+
+finalize:
+ MOVQ h, x
+ SHRQ $33, x
+ XORQ x, h
+ IMULQ prime2, h
+ MOVQ h, x
+ SHRQ $29, x
+ XORQ x, h
+ IMULQ ·primes+16(SB), h
+ MOVQ h, x
+ SHRQ $32, x
+ XORQ x, h
+
+ MOVQ h, ret+24(FP)
+ RET
+
+// func writeBlocks(d *Digest, b []byte) int
+TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
+ // Load fixed primes needed for round.
+ MOVQ ·primes+0(SB), prime1
+ MOVQ ·primes+8(SB), prime2
+
+ // Load slice.
+ MOVQ b_base+8(FP), p
+ MOVQ b_len+16(FP), n
+ LEAQ (p)(n*1), end
+ SUBQ $32, end
+
+ // Load vN from d.
+ MOVQ s+0(FP), d
+ MOVQ 0(d), v1
+ MOVQ 8(d), v2
+ MOVQ 16(d), v3
+ MOVQ 24(d), v4
+
+ // We don't need to check the loop condition here; this function is
+ // always called with at least one block of data to process.
+ blockLoop()
+
+ // Copy vN back to d.
+ MOVQ v1, 0(d)
+ MOVQ v2, 8(d)
+ MOVQ v3, 16(d)
+ MOVQ v4, 24(d)
+
+ // The number of bytes written is p minus the old base pointer.
+ SUBQ b_base+8(FP), p
+ MOVQ p, ret+32(FP)
+
+ RET
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s
new file mode 100644
index 000000000000..7e3145a22186
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s
@@ -0,0 +1,183 @@
+//go:build !appengine && gc && !purego
+// +build !appengine
+// +build gc
+// +build !purego
+
+#include "textflag.h"
+
+// Registers:
+#define digest R1
+#define h R2 // return value
+#define p R3 // input pointer
+#define n R4 // input length
+#define nblocks R5 // n / 32
+#define prime1 R7
+#define prime2 R8
+#define prime3 R9
+#define prime4 R10
+#define prime5 R11
+#define v1 R12
+#define v2 R13
+#define v3 R14
+#define v4 R15
+#define x1 R20
+#define x2 R21
+#define x3 R22
+#define x4 R23
+
+#define round(acc, x) \
+ MADD prime2, acc, x, acc \
+ ROR $64-31, acc \
+ MUL prime1, acc
+
+// round0 performs the operation x = round(0, x).
+#define round0(x) \
+ MUL prime2, x \
+ ROR $64-31, x \
+ MUL prime1, x
+
+#define mergeRound(acc, x) \
+ round0(x) \
+ EOR x, acc \
+ MADD acc, prime4, prime1, acc
+
+// blockLoop processes as many 32-byte blocks as possible,
+// updating v1, v2, v3, and v4. It assumes that n >= 32.
+#define blockLoop() \
+ LSR $5, n, nblocks \
+ PCALIGN $16 \
+ loop: \
+ LDP.P 16(p), (x1, x2) \
+ LDP.P 16(p), (x3, x4) \
+ round(v1, x1) \
+ round(v2, x2) \
+ round(v3, x3) \
+ round(v4, x4) \
+ SUB $1, nblocks \
+ CBNZ nblocks, loop
+
+// func Sum64(b []byte) uint64
+TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
+ LDP b_base+0(FP), (p, n)
+
+ LDP ·primes+0(SB), (prime1, prime2)
+ LDP ·primes+16(SB), (prime3, prime4)
+ MOVD ·primes+32(SB), prime5
+
+ CMP $32, n
+ CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
+ BLT afterLoop
+
+ ADD prime1, prime2, v1
+ MOVD prime2, v2
+ MOVD $0, v3
+ NEG prime1, v4
+
+ blockLoop()
+
+ ROR $64-1, v1, x1
+ ROR $64-7, v2, x2
+ ADD x1, x2
+ ROR $64-12, v3, x3
+ ROR $64-18, v4, x4
+ ADD x3, x4
+ ADD x2, x4, h
+
+ mergeRound(h, v1)
+ mergeRound(h, v2)
+ mergeRound(h, v3)
+ mergeRound(h, v4)
+
+afterLoop:
+ ADD n, h
+
+ TBZ $4, n, try8
+ LDP.P 16(p), (x1, x2)
+
+ round0(x1)
+
+ // NOTE: here and below, sequencing the EOR after the ROR (using a
+ // rotated register) is worth a small but measurable speedup for small
+ // inputs.
+ ROR $64-27, h
+ EOR x1 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+ round0(x2)
+ ROR $64-27, h
+ EOR x2 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+try8:
+ TBZ $3, n, try4
+ MOVD.P 8(p), x1
+
+ round0(x1)
+ ROR $64-27, h
+ EOR x1 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+try4:
+ TBZ $2, n, try2
+ MOVWU.P 4(p), x2
+
+ MUL prime1, x2
+ ROR $64-23, h
+ EOR x2 @> 64-23, h, h
+ MADD h, prime3, prime2, h
+
+try2:
+ TBZ $1, n, try1
+ MOVHU.P 2(p), x3
+ AND $255, x3, x1
+ LSR $8, x3, x2
+
+ MUL prime5, x1
+ ROR $64-11, h
+ EOR x1 @> 64-11, h, h
+ MUL prime1, h
+
+ MUL prime5, x2
+ ROR $64-11, h
+ EOR x2 @> 64-11, h, h
+ MUL prime1, h
+
+try1:
+ TBZ $0, n, finalize
+ MOVBU (p), x4
+
+ MUL prime5, x4
+ ROR $64-11, h
+ EOR x4 @> 64-11, h, h
+ MUL prime1, h
+
+finalize:
+ EOR h >> 33, h
+ MUL prime2, h
+ EOR h >> 29, h
+ MUL prime3, h
+ EOR h >> 32, h
+
+ MOVD h, ret+24(FP)
+ RET
+
+// func writeBlocks(d *Digest, b []byte) int
+TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
+ LDP ·primes+0(SB), (prime1, prime2)
+
+ // Load state. Assume v[1-4] are stored contiguously.
+ MOVD d+0(FP), digest
+ LDP 0(digest), (v1, v2)
+ LDP 16(digest), (v3, v4)
+
+ LDP b_base+8(FP), (p, n)
+
+ blockLoop()
+
+ // Store updated state.
+ STP (v1, v2), 0(digest)
+ STP (v3, v4), 16(digest)
+
+ BIC $31, n
+ MOVD n, ret+32(FP)
+ RET
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go
new file mode 100644
index 000000000000..9216e0a40c1a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go
@@ -0,0 +1,15 @@
+//go:build (amd64 || arm64) && !appengine && gc && !purego
+// +build amd64 arm64
+// +build !appengine
+// +build gc
+// +build !purego
+
+package xxhash
+
+// Sum64 computes the 64-bit xxHash digest of b.
+//
+//go:noescape
+func Sum64(b []byte) uint64
+
+//go:noescape
+func writeBlocks(d *Digest, b []byte) int
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_other.go
new file mode 100644
index 000000000000..26df13bba4b7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_other.go
@@ -0,0 +1,76 @@
+//go:build (!amd64 && !arm64) || appengine || !gc || purego
+// +build !amd64,!arm64 appengine !gc purego
+
+package xxhash
+
+// Sum64 computes the 64-bit xxHash digest of b.
+func Sum64(b []byte) uint64 {
+ // A simpler version would be
+ // d := New()
+ // d.Write(b)
+ // return d.Sum64()
+ // but this is faster, particularly for small inputs.
+
+ n := len(b)
+ var h uint64
+
+ if n >= 32 {
+ v1 := primes[0] + prime2
+ v2 := prime2
+ v3 := uint64(0)
+ v4 := -primes[0]
+ for len(b) >= 32 {
+ v1 = round(v1, u64(b[0:8:len(b)]))
+ v2 = round(v2, u64(b[8:16:len(b)]))
+ v3 = round(v3, u64(b[16:24:len(b)]))
+ v4 = round(v4, u64(b[24:32:len(b)]))
+ b = b[32:len(b):len(b)]
+ }
+ h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
+ h = mergeRound(h, v1)
+ h = mergeRound(h, v2)
+ h = mergeRound(h, v3)
+ h = mergeRound(h, v4)
+ } else {
+ h = prime5
+ }
+
+ h += uint64(n)
+
+ for ; len(b) >= 8; b = b[8:] {
+ k1 := round(0, u64(b[:8]))
+ h ^= k1
+ h = rol27(h)*prime1 + prime4
+ }
+ if len(b) >= 4 {
+ h ^= uint64(u32(b[:4])) * prime1
+ h = rol23(h)*prime2 + prime3
+ b = b[4:]
+ }
+ for ; len(b) > 0; b = b[1:] {
+ h ^= uint64(b[0]) * prime5
+ h = rol11(h) * prime1
+ }
+
+ h ^= h >> 33
+ h *= prime2
+ h ^= h >> 29
+ h *= prime3
+ h ^= h >> 32
+
+ return h
+}
+
+func writeBlocks(d *Digest, b []byte) int {
+ v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
+ n := len(b)
+ for len(b) >= 32 {
+ v1 = round(v1, u64(b[0:8:len(b)]))
+ v2 = round(v2, u64(b[8:16:len(b)]))
+ v3 = round(v3, u64(b[16:24:len(b)]))
+ v4 = round(v4, u64(b[24:32:len(b)]))
+ b = b[32:len(b):len(b)]
+ }
+ d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
+ return n - len(b)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
new file mode 100644
index 000000000000..e86f1b5fd8e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
@@ -0,0 +1,16 @@
+//go:build appengine
+// +build appengine
+
+// This file contains the safe implementations of otherwise unsafe-using code.
+
+package xxhash
+
+// Sum64String computes the 64-bit xxHash digest of s.
+func Sum64String(s string) uint64 {
+ return Sum64([]byte(s))
+}
+
+// WriteString adds more data to d. It always returns len(s), nil.
+func (d *Digest) WriteString(s string) (n int, err error) {
+ return d.Write([]byte(s))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
new file mode 100644
index 000000000000..1c1638fd88a1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
@@ -0,0 +1,58 @@
+//go:build !appengine
+// +build !appengine
+
+// This file encapsulates usage of unsafe.
+// xxhash_safe.go contains the safe implementations.
+
+package xxhash
+
+import (
+ "unsafe"
+)
+
+// In the future it's possible that compiler optimizations will make these
+// XxxString functions unnecessary by realizing that calls such as
+// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
+// If that happens, even if we keep these functions they can be replaced with
+// the trivial safe code.
+
+// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
+//
+// var b []byte
+// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
+// bh.Len = len(s)
+// bh.Cap = len(s)
+//
+// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
+// weight to this sequence of expressions that any function that uses it will
+// not be inlined. Instead, the functions below use a different unsafe
+// conversion designed to minimize the inliner weight and allow both to be
+// inlined. There is also a test (TestInlining) which verifies that these are
+// inlined.
+//
+// See https://github.com/golang/go/issues/42739 for discussion.
+
+// Sum64String computes the 64-bit xxHash digest of s.
+// It may be faster than Sum64([]byte(s)) by avoiding a copy.
+func Sum64String(s string) uint64 {
+ b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
+ return Sum64(b)
+}
+
+// WriteString adds more data to d. It always returns len(s), nil.
+// It may be faster than Write([]byte(s)) by avoiding a copy.
+func (d *Digest) WriteString(s string) (n int, err error) {
+ d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
+ // d.Write always returns len(s), nil.
+ // Ignoring the return output and returning these fixed values buys a
+ // savings of 6 in the inliner's cost model.
+ return len(s), nil
+}
+
+// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
+// of the first two words is the same as the layout of a string.
+type sliceHeader struct {
+ s string
+ cap int
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/.travis.yml
new file mode 100644
index 000000000000..9c8611554b35
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/.travis.yml
@@ -0,0 +1,4 @@
+language: go
+
+go:
+- 1.x
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/LICENSE
new file mode 100644
index 000000000000..1ada8807dfb1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012-2021 Charles Banning . All rights reserved.
+
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/anyxml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/anyxml.go
new file mode 100644
index 000000000000..63970ee2492a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/anyxml.go
@@ -0,0 +1,201 @@
+package mxj
+
+import (
+ "bytes"
+ "encoding/xml"
+ "reflect"
+)
+
+const (
+ DefaultElementTag = "element"
+)
+
+// Encode arbitrary value as XML.
+//
+// Note: unmarshaling the resultant
+// XML may not return the original value, since tag labels may have been injected
+// to create the XML representation of the value.
+/*
+ Encode an arbitrary JSON object.
+ package main
+
+ import (
+ "encoding/json"
+ "fmt"
+ "github.com/clbanning/mxj"
+ )
+
+ func main() {
+ jsondata := []byte(`[
+ { "somekey":"somevalue" },
+ "string",
+ 3.14159265,
+ true
+ ]`)
+ var i interface{}
+ err := json.Unmarshal(jsondata, &i)
+ if err != nil {
+ // do something
+ }
+ x, err := mxj.AnyXmlIndent(i, "", " ", "mydoc")
+ if err != nil {
+ // do something else
+ }
+ fmt.Println(string(x))
+ }
+
+ output:
+
+ somevalue
+ string
+ 3.14159265
+ true
+
+
+An extreme example is available in examples/goofy_map.go.
+*/
+// Alternative values for DefaultRootTag and DefaultElementTag can be set as:
+// AnyXml( v, myRootTag, myElementTag).
+func AnyXml(v interface{}, tags ...string) ([]byte, error) {
+ var rt, et string
+ if len(tags) == 1 || len(tags) == 2 {
+ rt = tags[0]
+ } else {
+ rt = DefaultRootTag
+ }
+ if len(tags) == 2 {
+ et = tags[1]
+ } else {
+ et = DefaultElementTag
+ }
+
+ if v == nil {
+ if useGoXmlEmptyElemSyntax {
+ return []byte("<" + rt + ">" + rt + ">"), nil
+ }
+ return []byte("<" + rt + "/>"), nil
+ }
+ if reflect.TypeOf(v).Kind() == reflect.Struct {
+ return xml.Marshal(v)
+ }
+
+ var err error
+ s := new(bytes.Buffer)
+ p := new(pretty)
+
+ var b []byte
+ switch v.(type) {
+ case []interface{}:
+ if _, err = s.WriteString("<" + rt + ">"); err != nil {
+ return nil, err
+ }
+ for _, vv := range v.([]interface{}) {
+ switch vv.(type) {
+ case map[string]interface{}:
+ m := vv.(map[string]interface{})
+ if len(m) == 1 {
+ for tag, val := range m {
+ err = marshalMapToXmlIndent(false, s, tag, val, p)
+ }
+ } else {
+ err = marshalMapToXmlIndent(false, s, et, vv, p)
+ }
+ default:
+ err = marshalMapToXmlIndent(false, s, et, vv, p)
+ }
+ if err != nil {
+ break
+ }
+ }
+ if _, err = s.WriteString("" + rt + ">"); err != nil {
+ return nil, err
+ }
+ b = s.Bytes()
+ case map[string]interface{}:
+ m := Map(v.(map[string]interface{}))
+ b, err = m.Xml(rt)
+ default:
+ err = marshalMapToXmlIndent(false, s, rt, v, p)
+ b = s.Bytes()
+ }
+
+ return b, err
+}
+
+// Encode an arbitrary value as a pretty XML string.
+// Alternative values for DefaultRootTag and DefaultElementTag can be set as:
+// AnyXmlIndent( v, "", " ", myRootTag, myElementTag).
+func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) {
+ var rt, et string
+ if len(tags) == 1 || len(tags) == 2 {
+ rt = tags[0]
+ } else {
+ rt = DefaultRootTag
+ }
+ if len(tags) == 2 {
+ et = tags[1]
+ } else {
+ et = DefaultElementTag
+ }
+
+ if v == nil {
+ if useGoXmlEmptyElemSyntax {
+ return []byte(prefix + "<" + rt + ">" + rt + ">"), nil
+ }
+ return []byte(prefix + "<" + rt + "/>"), nil
+ }
+ if reflect.TypeOf(v).Kind() == reflect.Struct {
+ return xml.MarshalIndent(v, prefix, indent)
+ }
+
+ var err error
+ s := new(bytes.Buffer)
+ p := new(pretty)
+ p.indent = indent
+ p.padding = prefix
+
+ var b []byte
+ switch v.(type) {
+ case []interface{}:
+ if _, err = s.WriteString("<" + rt + ">\n"); err != nil {
+ return nil, err
+ }
+ p.Indent()
+ for _, vv := range v.([]interface{}) {
+ switch vv.(type) {
+ case map[string]interface{}:
+ m := vv.(map[string]interface{})
+ if len(m) == 1 {
+ for tag, val := range m {
+ err = marshalMapToXmlIndent(true, s, tag, val, p)
+ }
+ } else {
+ p.start = 1 // we 1 tag in
+ err = marshalMapToXmlIndent(true, s, et, vv, p)
+ // *s += "\n"
+ if _, err = s.WriteString("\n"); err != nil {
+ return nil, err
+ }
+ }
+ default:
+ p.start = 0 // in case trailing p.start = 1
+ err = marshalMapToXmlIndent(true, s, et, vv, p)
+ }
+ if err != nil {
+ break
+ }
+ }
+ if _, err = s.WriteString(`` + rt + `>`); err != nil {
+ return nil, err
+ }
+ b = s.Bytes()
+ case map[string]interface{}:
+ m := Map(v.(map[string]interface{}))
+ b, err = m.XmlIndent(prefix, indent, rt)
+ default:
+ err = marshalMapToXmlIndent(true, s, rt, v, p)
+ b = s.Bytes()
+ }
+
+ return b, err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/atomFeedString.xml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/atomFeedString.xml
new file mode 100644
index 000000000000..474575a41ca9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/atomFeedString.xml
@@ -0,0 +1,54 @@
+
+Code Review - My issues http://codereview.appspot.com/ rietveld<> rietveld: an attempt at pubsubhubbub
+ 2009-10-04T01:35:58+00:00 email-address-removed urn:md5:134d9179c41f806be79b3a5f7877d19a
+ An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+ 1. add a <link rel="hub" href="hub-server"> tag to all
+ feeds that will be pubsubhubbubbed.
+ 2. every time one of those feeds changes, tell the hub
+ with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can't quite get the server to work, but I think the bug
+is not in my code. I think that the server expects to be
+able to grab the feed and see the feed's actual URL in
+the link rel="self", but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+ rietveld: correct tab handling
+ 2009-10-03T23:02:17+00:00 email-address-removed urn:md5:0a2a4f19bb815101f0ba2904aed7c35a
+ This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn't know where to put the tab stops. Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites. I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+ `
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/doc.go
new file mode 100644
index 000000000000..bede3126510c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/doc.go
@@ -0,0 +1,138 @@
+// mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
+// Copyright 2012-2019, Charles Banning. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file
+
+/*
+Marshal/Unmarshal XML to/from map[string]interface{} values (and JSON); extract/modify values from maps by key or key-path, including wildcards.
+
+mxj supplants the legacy x2j and j2x packages. The subpackage x2j-wrapper is provided to facilitate migrating from the x2j package. The x2j and j2x subpackages provide similar functionality of the old packages but are not function-name compatible with them.
+
+Note: this library was designed for processing ad hoc anonymous messages. Bulk processing large data sets may be much more efficiently performed using the encoding/xml or encoding/json packages from Go's standard library directly.
+
+Related Packages:
+ checkxml: github.com/clbanning/checkxml provides functions for validating XML data.
+
+Notes:
+ 2020.05.01: v2.2 - optimize map to XML encoding for large XML docs.
+ 2019.07.04: v2.0 - remove unnecessary methods - mv.XmlWriterRaw, mv.XmlIndentWriterRaw - for Map and MapSeq.
+ 2019.07.04: Add MapSeq type and move associated functions and methods from Map to MapSeq.
+ 2019.01.21: DecodeSimpleValuesAsMap - decode to map[:map["#text":]] rather than map[:].
+ 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc.
+ 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps.
+ 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package.
+ 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing.
+ 2017.02.21: github.com/clbanning/checkxml provides functions for validating XML data.
+ 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods.
+ 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag().
+ 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc.
+ 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix().
+ 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable.
+ 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars().
+ 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf".
+ To cast them to float64, first set flag with CastNanInf(true).
+ 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure.
+ 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization.
+ 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM).
+ 2015-12-02: NewMapXmlSeq() with mv.XmlSeq() & co. will try to preserve structure of XML doc when re-encoding.
+ 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML.
+
+SUMMARY
+
+ type Map map[string]interface{}
+
+ Create a Map value, 'mv', from any map[string]interface{} value, 'v':
+ mv := Map(v)
+
+ Unmarshal / marshal XML as a Map value, 'mv':
+ mv, err := NewMapXml(xmlValue) // unmarshal
+ xmlValue, err := mv.Xml() // marshal
+
+ Unmarshal XML from an io.Reader as a Map value, 'mv':
+ mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream
+ mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
+
+ Marshal Map value, 'mv', to an XML Writer (io.Writer):
+ err := mv.XmlWriter(xmlWriter)
+ raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
+
+ Also, for prettified output:
+ xmlValue, err := mv.XmlIndent(prefix, indent, ...)
+ err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...)
+ raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
+
+ Bulk process XML with error handling (note: handlers must return a boolean value):
+ err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
+ err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
+
+ Converting XML to JSON: see Examples for NewMapXml and HandleXmlReader.
+
+ There are comparable functions and methods for JSON processing.
+
+ Arbitrary structure values can be decoded to / encoded from Map values:
+ mv, err := NewMapStruct(structVal)
+ err := mv.Struct(structPointer)
+
+ To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON
+ or structure to a Map value, 'mv', or cast a map[string]interface{} value to a Map value, 'mv', then:
+ paths := mv.PathsForKey(key)
+ path := mv.PathForKeyShortest(key)
+ values, err := mv.ValuesForKey(key, subkeys)
+ values, err := mv.ValuesForPath(path, subkeys) // 'path' can be dot-notation with wildcards and indexed arrays.
+ count, err := mv.UpdateValuesForPath(newVal, path, subkeys)
+
+ Get everything at once, irrespective of path depth:
+ leafnodes := mv.LeafNodes()
+ leafvalues := mv.LeafValues()
+
+ A new Map with whatever keys are desired can be created from the current Map and then encoded in XML
+ or JSON. (Note: keys can use dot-notation. 'oldKey' can also use wildcards and indexed arrays.)
+ newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
+ newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
+ newXml, err := newMap.Xml() // for example
+ newJson, err := newMap.Json() // ditto
+
+XML PARSING CONVENTIONS
+
+ Using NewMapXml()
+
+ - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`,
+ to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or
+ `SetAttrPrefix()`.)
+ - If the element is a simple element and has attributes, the element value
+ is given the key `#text` for its `map[string]interface{}` representation. (See
+ the 'atomFeedString.xml' test data, below.)
+ - XML comments, directives, and process instructions are ignored.
+ - If CoerceKeysToLower() has been called, then the resultant keys will be lower case.
+
+ Using NewMapXmlSeq()
+
+ - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values
+ where the `` value has "#text" and "#seq" keys - the "#text" key holds the
+ value for ``.
+ - All elements, except for the root, have a "#seq" key.
+ - Comments, directives, and process instructions are unmarshalled into the Map using the
+ keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more
+ specifics.)
+ - Name space syntax is preserved:
+ - something parses to map["ns:key"]interface{}{"something"}
+ - xmlns:ns="http://myns.com/ns" parses to map["xmlns:ns"]interface{}{"http://myns.com/ns"}
+
+ Both
+
+ - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them
+ to be cast, set a flag to cast them using CastNanInf(true).
+
+XML ENCODING CONVENTIONS
+
+ - 'nil' Map values, which may represent 'null' JSON values, are encoded as " ".
+ NOTE: the operation is not symmetric as " " elements are decoded as 'tag:""' Map values,
+ which, then, encode in JSON as '"tag":""' values..
+ - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go
+ randomizes the walk through map[string]interface{} values.) If you plan to re-encode the
+ Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and
+ mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when
+ working with the Map representation.
+
+*/
+package mxj
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/escapechars.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/escapechars.go
new file mode 100644
index 000000000000..eeb3d25010e5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/escapechars.go
@@ -0,0 +1,93 @@
+// Copyright 2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "bytes"
+)
+
+var xmlEscapeChars bool
+
+// XMLEscapeChars(true) forces escaping invalid characters in attribute and element values.
+// NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is
+// then '&' will be re-escaped as '&'.
+//
+/*
+ The values are:
+ " "
+ ' '
+ < <
+ > >
+ & &
+*/
+//
+// Note: if XMLEscapeCharsDecoder(true) has been called - or the default, 'false,' value
+// has been toggled to 'true' - then XMLEscapeChars(true) is ignored. If XMLEscapeChars(true)
+// has already been called before XMLEscapeCharsDecoder(true), XMLEscapeChars(false) is called
+// to turn escape encoding on mv.Xml, etc., to prevent double escaping ampersands, '&'.
+func XMLEscapeChars(b ...bool) {
+ var bb bool
+ if len(b) == 0 {
+ bb = !xmlEscapeChars
+ } else {
+ bb = b[0]
+ }
+ if bb == true && xmlEscapeCharsDecoder == false {
+ xmlEscapeChars = true
+ } else {
+ xmlEscapeChars = false
+ }
+}
+
+// Scan for '&' first, since 's' may contain "&" that is parsed to "&"
+// - or "<" that is parsed to "<".
+var escapechars = [][2][]byte{
+ {[]byte(`&`), []byte(`&`)},
+ {[]byte(`<`), []byte(`<`)},
+ {[]byte(`>`), []byte(`>`)},
+ {[]byte(`"`), []byte(`"`)},
+ {[]byte(`'`), []byte(`'`)},
+}
+
+func escapeChars(s string) string {
+ if len(s) == 0 {
+ return s
+ }
+
+ b := []byte(s)
+ for _, v := range escapechars {
+ n := bytes.Count(b, v[0])
+ if n == 0 {
+ continue
+ }
+ b = bytes.Replace(b, v[0], v[1], n)
+ }
+ return string(b)
+}
+
+// per issue #84, escape CharData values from xml.Decoder
+
+var xmlEscapeCharsDecoder bool
+
+// XMLEscapeCharsDecoder(b ...bool) escapes XML characters in xml.CharData values
+// returned by Decoder.Token. Thus, the internal Map values will contain escaped
+// values, and you do not need to set XMLEscapeChars for proper encoding.
+//
+// By default, the Map values have the non-escaped values returned by Decoder.Token.
+// XMLEscapeCharsDecoder(true) - or, XMLEscapeCharsDecoder() - will toggle escape
+// encoding 'on.'
+//
+// Note: if XMLEscapeCharDecoder(true) is call then XMLEscapeChars(false) is
+// called to prevent re-escaping the values on encoding using mv.Xml, etc.
+func XMLEscapeCharsDecoder(b ...bool) {
+ if len(b) == 0 {
+ xmlEscapeCharsDecoder = !xmlEscapeCharsDecoder
+ } else {
+ xmlEscapeCharsDecoder = b[0]
+ }
+ if xmlEscapeCharsDecoder == true && xmlEscapeChars == true {
+ xmlEscapeChars = false
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/exists.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/exists.go
new file mode 100644
index 000000000000..07aeda43f894
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/exists.go
@@ -0,0 +1,9 @@
+package mxj
+
+// Checks whether the path exists. If err != nil then 'false' is returned
+// along with the error encountered parsing either the "path" or "subkeys"
+// argument.
+func (mv Map) Exists(path string, subkeys ...string) (bool, error) {
+ v, err := mv.ValuesForPath(path, subkeys...)
+ return (err == nil && len(v) > 0), err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files.go
new file mode 100644
index 000000000000..27e06e1e8019
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files.go
@@ -0,0 +1,287 @@
+package mxj
+
+import (
+ "fmt"
+ "io"
+ "os"
+)
+
+type Maps []Map
+
+func NewMaps() Maps {
+ return make(Maps, 0)
+}
+
+type MapRaw struct {
+ M Map
+ R []byte
+}
+
+// NewMapsFromXmlFile - creates an array from a file of JSON values.
+func NewMapsFromJsonFile(name string) (Maps, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]Map, 0)
+ for {
+ m, raw, err := NewMapJsonReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw))
+ }
+ if len(m) > 0 {
+ am = append(am, m)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// ReadMapsFromJsonFileRaw - creates an array of MapRaw from a file of JSON values.
+func NewMapsFromJsonFileRaw(name string) ([]MapRaw, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]MapRaw, 0)
+ for {
+ mr := new(MapRaw)
+ mr.M, mr.R, err = NewMapJsonReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R))
+ }
+ if len(mr.M) > 0 {
+ am = append(am, *mr)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// NewMapsFromXmlFile - creates an array from a file of XML values.
+func NewMapsFromXmlFile(name string) (Maps, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]Map, 0)
+ for {
+ m, raw, err := NewMapXmlReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw))
+ }
+ if len(m) > 0 {
+ am = append(am, m)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// NewMapsFromXmlFileRaw - creates an array of MapRaw from a file of XML values.
+// NOTE: the slice with the raw XML is clean with no extra capacity - unlike NewMapXmlReaderRaw().
+// It is slow at parsing a file from disk and is intended for relatively small utility files.
+func NewMapsFromXmlFileRaw(name string) ([]MapRaw, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]MapRaw, 0)
+ for {
+ mr := new(MapRaw)
+ mr.M, mr.R, err = NewMapXmlReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R))
+ }
+ if len(mr.M) > 0 {
+ am = append(am, *mr)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// ------------------------ Maps writing -------------------------
+// These are handy-dandy methods for dumping configuration data, etc.
+
+// JsonString - analogous to mv.Json()
+func (mvs Maps) JsonString(safeEncoding ...bool) (string, error) {
+ var s string
+ for _, v := range mvs {
+ j, err := v.Json()
+ if err != nil {
+ return s, err
+ }
+ s += string(j)
+ }
+ return s, nil
+}
+
+// JsonStringIndent - analogous to mv.JsonIndent()
+func (mvs Maps) JsonStringIndent(prefix, indent string, safeEncoding ...bool) (string, error) {
+ var s string
+ var haveFirst bool
+ for _, v := range mvs {
+ j, err := v.JsonIndent(prefix, indent)
+ if err != nil {
+ return s, err
+ }
+ if haveFirst {
+ s += "\n"
+ } else {
+ haveFirst = true
+ }
+ s += string(j)
+ }
+ return s, nil
+}
+
+// XmlString - analogous to mv.Xml()
+func (mvs Maps) XmlString() (string, error) {
+ var s string
+ for _, v := range mvs {
+ x, err := v.Xml()
+ if err != nil {
+ return s, err
+ }
+ s += string(x)
+ }
+ return s, nil
+}
+
+// XmlStringIndent - analogous to mv.XmlIndent()
+func (mvs Maps) XmlStringIndent(prefix, indent string) (string, error) {
+ var s string
+ for _, v := range mvs {
+ x, err := v.XmlIndent(prefix, indent)
+ if err != nil {
+ return s, err
+ }
+ s += string(x)
+ }
+ return s, nil
+}
+
+// JsonFile - write Maps to named file as JSON
+// Note: the file will be created, if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use JsonWriter method.
+func (mvs Maps) JsonFile(file string, safeEncoding ...bool) error {
+ var encoding bool
+ if len(safeEncoding) == 1 {
+ encoding = safeEncoding[0]
+ }
+ s, err := mvs.JsonString(encoding)
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
+
+// JsonFileIndent - write Maps to named file as pretty JSON
+// Note: the file will be created, if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use JsonIndentWriter method.
+func (mvs Maps) JsonFileIndent(file, prefix, indent string, safeEncoding ...bool) error {
+ var encoding bool
+ if len(safeEncoding) == 1 {
+ encoding = safeEncoding[0]
+ }
+ s, err := mvs.JsonStringIndent(prefix, indent, encoding)
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
+
+// XmlFile - write Maps to named file as XML
+// Note: the file will be created, if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use XmlWriter method.
+func (mvs Maps) XmlFile(file string) error {
+ s, err := mvs.XmlString()
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
+
+// XmlFileIndent - write Maps to named file as pretty XML
+// Note: the file will be created,if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use XmlIndentWriter method.
+func (mvs Maps) XmlFileIndent(file, prefix, indent string) error {
+ s, err := mvs.XmlStringIndent(prefix, indent)
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.badjson b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.badjson
new file mode 100644
index 000000000000..d18720044ac0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.badjson
@@ -0,0 +1,2 @@
+{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" }
+{ "with":"some", "bad":JSON, "in":"it" }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.badxml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.badxml
new file mode 100644
index 000000000000..4736ef973dd7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.badxml
@@ -0,0 +1,9 @@
+
+ test
+ for files.go
+
+
+ some
+ doc
+ test case
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.json b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.json
new file mode 100644
index 000000000000..e9a3ddf40ec3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.json
@@ -0,0 +1,2 @@
+{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" }
+{ "with":"just", "two":2, "JSON":"values", "true":true }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.xml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.xml
new file mode 100644
index 000000000000..65cf021fb70a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test.xml
@@ -0,0 +1,9 @@
+
+ test
+ for files.go
+
+
+ some
+ doc
+ test case
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_dup.json b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_dup.json
new file mode 100644
index 000000000000..2becb6a4512b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_dup.json
@@ -0,0 +1 @@
+{"a":"test","file":"for","files_test.go":"case","this":"is"}{"JSON":"values","true":true,"two":2,"with":"just"}
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_dup.xml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_dup.xml
new file mode 100644
index 000000000000..f68d22e28eae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_dup.xml
@@ -0,0 +1 @@
+for files.go test doc test case some
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_indent.json b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_indent.json
new file mode 100644
index 000000000000..6fde15634dfd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_indent.json
@@ -0,0 +1,12 @@
+{
+ "a": "test",
+ "file": "for",
+ "files_test.go": "case",
+ "this": "is"
+}
+{
+ "JSON": "values",
+ "true": true,
+ "two": 2,
+ "with": "just"
+}
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_indent.xml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_indent.xml
new file mode 100644
index 000000000000..8c91a1dc20a7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/files_test_indent.xml
@@ -0,0 +1,8 @@
+
+ for files.go
+ test
+
+ doc
+ test case
+ some
+
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/gob.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/gob.go
new file mode 100644
index 000000000000..d56c2fd6fe8d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/gob.go
@@ -0,0 +1,35 @@
+// gob.go - Encode/Decode a Map into a gob object.
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/gob"
+)
+
+// NewMapGob returns a Map value for a gob object that has been
+// encoded from a map[string]interface{} (or compatible type) value.
+// It is intended to provide symmetric handling of Maps that have
+// been encoded using mv.Gob.
+func NewMapGob(gobj []byte) (Map, error) {
+ m := make(map[string]interface{}, 0)
+ if len(gobj) == 0 {
+ return m, nil
+ }
+ r := bytes.NewReader(gobj)
+ dec := gob.NewDecoder(r)
+ if err := dec.Decode(&m); err != nil {
+ return m, err
+ }
+ return m, nil
+}
+
+// Gob returns a gob-encoded value for the Map 'mv'.
+func (mv Map) Gob() ([]byte, error) {
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ if err := enc.Encode(map[string]interface{}(mv)); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/json.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/json.go
new file mode 100644
index 000000000000..eb2c05a18691
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/json.go
@@ -0,0 +1,323 @@
+// Copyright 2012-2014 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "time"
+)
+
+// ------------------------------ write JSON -----------------------
+
+// Just a wrapper on json.Marshal.
+// If option safeEncoding is'true' then safe encoding of '<', '>' and '&'
+// is preserved. (see encoding/json#Marshal, encoding/json#Encode)
+func (mv Map) Json(safeEncoding ...bool) ([]byte, error) {
+ var s bool
+ if len(safeEncoding) == 1 {
+ s = safeEncoding[0]
+ }
+
+ b, err := json.Marshal(mv)
+
+ if !s {
+ b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
+ b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
+ b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
+ }
+ return b, err
+}
+
+// Just a wrapper on json.MarshalIndent.
+// If option safeEncoding is'true' then safe encoding of '<' , '>' and '&'
+// is preserved. (see encoding/json#Marshal, encoding/json#Encode)
+func (mv Map) JsonIndent(prefix, indent string, safeEncoding ...bool) ([]byte, error) {
+ var s bool
+ if len(safeEncoding) == 1 {
+ s = safeEncoding[0]
+ }
+
+ b, err := json.MarshalIndent(mv, prefix, indent)
+ if !s {
+ b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
+ b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
+ b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
+ }
+ return b, err
+}
+
+// The following implementation is provided for symmetry with NewMapJsonReader[Raw]
+// The names will also provide a key for the number of return arguments.
+
+// Writes the Map as JSON on the Writer.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonWriter(jsonWriter io.Writer, safeEncoding ...bool) error {
+ b, err := mv.Json(safeEncoding...)
+ if err != nil {
+ return err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return err
+}
+
+// Writes the Map as JSON on the Writer. []byte is the raw JSON that was written.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonWriterRaw(jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) {
+ b, err := mv.Json(safeEncoding...)
+ if err != nil {
+ return b, err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return b, err
+}
+
+// Writes the Map as pretty JSON on the Writer.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonIndentWriter(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) error {
+ b, err := mv.JsonIndent(prefix, indent, safeEncoding...)
+ if err != nil {
+ return err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return err
+}
+
+// Writes the Map as pretty JSON on the Writer. []byte is the raw JSON that was written.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonIndentWriterRaw(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) ([]byte, error) {
+ b, err := mv.JsonIndent(prefix, indent, safeEncoding...)
+ if err != nil {
+ return b, err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return b, err
+}
+
+// --------------------------- read JSON -----------------------------
+
+// Decode numericvalues as json.Number type Map values - see encoding/json#Number.
+// NOTE: this is for decoding JSON into a Map with NewMapJson(), NewMapJsonReader(),
+// etc.; it does not affect NewMapXml(), etc. The XML encoders mv.Xml() and mv.XmlIndent()
+// do recognize json.Number types; a JSON object can be decoded to a Map with json.Number
+// value types and the resulting Map can be correctly encoded into a XML object.
+var JsonUseNumber bool
+
+// Just a wrapper on json.Unmarshal
+// Converting JSON to XML is a simple as:
+// ...
+// mapVal, merr := mxj.NewMapJson(jsonVal)
+// if merr != nil {
+// // handle error
+// }
+// xmlVal, xerr := mapVal.Xml()
+// if xerr != nil {
+// // handle error
+// }
+// NOTE: as a special case, passing a list, e.g., [{"some-null-value":"", "a-non-null-value":"bar"}],
+// will be interpreted as having the root key 'object' prepended - {"object":[ ... ]} - to unmarshal to a Map.
+// See mxj/j2x/j2x_test.go.
+func NewMapJson(jsonVal []byte) (Map, error) {
+ // empty or nil begets empty
+ if len(jsonVal) == 0 {
+ m := make(map[string]interface{}, 0)
+ return m, nil
+ }
+ // handle a goofy case ...
+ if jsonVal[0] == '[' {
+ jsonVal = []byte(`{"object":` + string(jsonVal) + `}`)
+ }
+ m := make(map[string]interface{})
+ // err := json.Unmarshal(jsonVal, &m)
+ buf := bytes.NewReader(jsonVal)
+ dec := json.NewDecoder(buf)
+ if JsonUseNumber {
+ dec.UseNumber()
+ }
+ err := dec.Decode(&m)
+ return m, err
+}
+
+// Retrieve a Map value from an io.Reader.
+// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an
+// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte
+// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal
+// a JSON object.
+func NewMapJsonReader(jsonReader io.Reader) (Map, error) {
+ jb, err := getJson(jsonReader)
+ if err != nil || len(*jb) == 0 {
+ return nil, err
+ }
+
+ // Unmarshal the 'presumed' JSON string
+ return NewMapJson(*jb)
+}
+
+// Retrieve a Map value and raw JSON - []byte - from an io.Reader.
+// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an
+// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte
+// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal
+// a JSON object and retrieve the raw JSON in a single call.
+func NewMapJsonReaderRaw(jsonReader io.Reader) (Map, []byte, error) {
+ jb, err := getJson(jsonReader)
+ if err != nil || len(*jb) == 0 {
+ return nil, *jb, err
+ }
+
+ // Unmarshal the 'presumed' JSON string
+ m, merr := NewMapJson(*jb)
+ return m, *jb, merr
+}
+
+// Pull the next JSON string off the stream: just read from first '{' to its closing '}'.
+// Returning a pointer to the slice saves 16 bytes - maybe unnecessary, but internal to package.
+func getJson(rdr io.Reader) (*[]byte, error) {
+ bval := make([]byte, 1)
+ jb := make([]byte, 0)
+ var inQuote, inJson bool
+ var parenCnt int
+ var previous byte
+
+ // scan the input for a matched set of {...}
+ // json.Unmarshal will handle syntax checking.
+ for {
+ _, err := rdr.Read(bval)
+ if err != nil {
+ if err == io.EOF && inJson && parenCnt > 0 {
+ return &jb, fmt.Errorf("no closing } for JSON string: %s", string(jb))
+ }
+ return &jb, err
+ }
+ switch bval[0] {
+ case '{':
+ if !inQuote {
+ parenCnt++
+ inJson = true
+ }
+ case '}':
+ if !inQuote {
+ parenCnt--
+ }
+ if parenCnt < 0 {
+ return nil, fmt.Errorf("closing } without opening {: %s", string(jb))
+ }
+ case '"':
+ if inQuote {
+ if previous == '\\' {
+ break
+ }
+ inQuote = false
+ } else {
+ inQuote = true
+ }
+ case '\n', '\r', '\t', ' ':
+ if !inQuote {
+ continue
+ }
+ }
+ if inJson {
+ jb = append(jb, bval[0])
+ if parenCnt == 0 {
+ break
+ }
+ }
+ previous = bval[0]
+ }
+
+ return &jb, nil
+}
+
+// ------------------------------- JSON Reader handler via Map values -----------------------
+
+// Default poll delay to keep Handler from spinning on an open stream
+// like sitting on os.Stdin waiting for imput.
+var jhandlerPollInterval = time.Duration(1e6)
+
+// While unnecessary, we make HandleJsonReader() have the same signature as HandleXmlReader().
+// This avoids treating one or other as a special case and discussing the underlying stdlib logic.
+
+// Bulk process JSON using handlers that process a Map value.
+// 'rdr' is an io.Reader for the JSON (stream).
+// 'mapHandler' is the Map processing handler. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'.
+func HandleJsonReader(jsonReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error {
+ var n int
+ for {
+ m, merr := NewMapJsonReader(jsonReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ <-time.After(jhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
+
+// Bulk process JSON using handlers that process a Map value and the raw JSON.
+// 'rdr' is an io.Reader for the JSON (stream).
+// 'mapHandler' is the Map and raw JSON - []byte - processor. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error and raw JSON processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'.
+func HandleJsonReaderRaw(jsonReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error {
+ var n int
+ for {
+ m, raw, merr := NewMapJsonReaderRaw(jsonReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr, raw); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m, raw); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ <-time.After(jhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/keyvalues.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/keyvalues.go
new file mode 100644
index 000000000000..55620ca22b78
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/keyvalues.go
@@ -0,0 +1,668 @@
+// Copyright 2012-2014 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// keyvalues.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters.
+
+package mxj
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// ----------------------------- get everything FOR a single key -------------------------
+
+const (
+ minArraySize = 32
+)
+
+var defaultArraySize int = minArraySize
+
+// SetArraySize adjust the buffers for expected number of values to return from ValuesForKey() and ValuesForPath().
+// This can have the effect of significantly reducing memory allocation-copy functions for large data sets.
+// Returns the initial buffer size.
+func SetArraySize(size int) int {
+ if size > minArraySize {
+ defaultArraySize = size
+ } else {
+ defaultArraySize = minArraySize
+ }
+ return defaultArraySize
+}
+
+// ValuesForKey return all values in Map, 'mv', associated with a 'key'. If len(returned_values) == 0, then no match.
+// On error, the returned slice is 'nil'. NOTE: 'key' can be wildcard, "*".
+// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list.
+// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them.
+// - For attributes prefix the label with the attribute prefix character, by default a
+// hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.)
+// - If the 'key' refers to a list, then "key:value" could select a list member of the list.
+// - The subkey can be wildcarded - "key:*" - to require that it's there with some value.
+// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an
+// exclusion critera - e.g., "!author:William T. Gaddis".
+// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|".
+func (mv Map) ValuesForKey(key string, subkeys ...string) ([]interface{}, error) {
+ m := map[string]interface{}(mv)
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ ret := make([]interface{}, 0, defaultArraySize)
+ var cnt int
+ hasKey(m, key, &ret, &cnt, subKeyMap)
+ return ret[:cnt], nil
+}
+
+var KeyNotExistError = errors.New("Key does not exist")
+
+// ValueForKey is a wrapper on ValuesForKey. It returns the first member of []interface{}, if any.
+// If there is no value, "nil, nil" is returned.
+func (mv Map) ValueForKey(key string, subkeys ...string) (interface{}, error) {
+ vals, err := mv.ValuesForKey(key, subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ if len(vals) == 0 {
+ return nil, KeyNotExistError
+ }
+ return vals[0], nil
+}
+
+// hasKey - if the map 'key' exists append it to array
+// if it doesn't do nothing except scan array and map values
+func hasKey(iv interface{}, key string, ret *[]interface{}, cnt *int, subkeys map[string]interface{}) {
+ // func hasKey(iv interface{}, key string, ret *[]interface{}, subkeys map[string]interface{}) {
+ switch iv.(type) {
+ case map[string]interface{}:
+ vv := iv.(map[string]interface{})
+ // see if the current value is of interest
+ if v, ok := vv[key]; ok {
+ switch v.(type) {
+ case map[string]interface{}:
+ if hasSubKeys(v, subkeys) {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ case []interface{}:
+ for _, av := range v.([]interface{}) {
+ if hasSubKeys(av, subkeys) {
+ *ret = append(*ret, av)
+ *cnt++
+ }
+ }
+ default:
+ if len(subkeys) == 0 {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ }
+ }
+
+ // wildcard case
+ if key == "*" {
+ for _, v := range vv {
+ switch v.(type) {
+ case map[string]interface{}:
+ if hasSubKeys(v, subkeys) {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ case []interface{}:
+ for _, av := range v.([]interface{}) {
+ if hasSubKeys(av, subkeys) {
+ *ret = append(*ret, av)
+ *cnt++
+ }
+ }
+ default:
+ if len(subkeys) == 0 {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ }
+ }
+ }
+
+ // scan the rest
+ for _, v := range vv {
+ hasKey(v, key, ret, cnt, subkeys)
+ }
+ case []interface{}:
+ for _, v := range iv.([]interface{}) {
+ hasKey(v, key, ret, cnt, subkeys)
+ }
+ }
+}
+
+// ----------------------- get everything for a node in the Map ---------------------------
+
+// Allow indexed arrays in "path" specification. (Request from Abhijit Kadam - abhijitk100@gmail.com.)
+// 2014.04.28 - implementation note.
+// Implemented as a wrapper of (old)ValuesForPath() because we need look-ahead logic to handle expansion
+// of wildcards and unindexed arrays. Embedding such logic into valuesForKeyPath() would have made the
+// code much more complicated; this wrapper is straightforward, easy to debug, and doesn't add significant overhead.
+
+// ValuesForPatb retrieves all values for a path from the Map. If len(returned_values) == 0, then no match.
+// On error, the returned array is 'nil'.
+// 'path' is a dot-separated path of key values.
+// - If a node in the path is '*', then everything beyond is walked.
+// - 'path' can contain indexed array references, such as, "*.data[1]" and "msgs[2].data[0].field" -
+// even "*[2].*[0].field".
+// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list.
+// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them.
+// - For attributes prefix the label with the attribute prefix character, by default a
+// hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.)
+// - If the 'path' refers to a list, then "tag:value" would return member of the list.
+// - The subkey can be wildcarded - "key:*" - to require that it's there with some value.
+// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an
+// exclusion critera - e.g., "!author:William T. Gaddis".
+// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|".
+func (mv Map) ValuesForPath(path string, subkeys ...string) ([]interface{}, error) {
+ // If there are no array indexes in path, use legacy ValuesForPath() logic.
+ if strings.Index(path, "[") < 0 {
+ return mv.oldValuesForPath(path, subkeys...)
+ }
+
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ keys, kerr := parsePath(path)
+ if kerr != nil {
+ return nil, kerr
+ }
+
+ vals, verr := valuesForArray(keys, mv)
+ if verr != nil {
+ return nil, verr // Vals may be nil, but return empty array.
+ }
+
+ // Need to handle subkeys ... only return members of vals that satisfy conditions.
+ retvals := make([]interface{}, 0)
+ for _, v := range vals {
+ if hasSubKeys(v, subKeyMap) {
+ retvals = append(retvals, v)
+ }
+ }
+ return retvals, nil
+}
+
+func valuesForArray(keys []*key, m Map) ([]interface{}, error) {
+ var tmppath string
+ var haveFirst bool
+ var vals []interface{}
+ var verr error
+
+ lastkey := len(keys) - 1
+ for i := 0; i <= lastkey; i++ {
+ if !haveFirst {
+ tmppath = keys[i].name
+ haveFirst = true
+ } else {
+ tmppath += "." + keys[i].name
+ }
+
+ // Look-ahead: explode wildcards and unindexed arrays.
+ // Need to handle un-indexed list recursively:
+ // e.g., path is "stuff.data[0]" rather than "stuff[0].data[0]".
+ // Need to treat it as "stuff[0].data[0]", "stuff[1].data[0]", ...
+ if !keys[i].isArray && i < lastkey && keys[i+1].isArray {
+ // Can't pass subkeys because we may not be at literal end of path.
+ vv, vverr := m.oldValuesForPath(tmppath)
+ if vverr != nil {
+ return nil, vverr
+ }
+ for _, v := range vv {
+ // See if we can walk the value.
+ am, ok := v.(map[string]interface{})
+ if !ok {
+ continue
+ }
+ // Work the backend.
+ nvals, nvalserr := valuesForArray(keys[i+1:], Map(am))
+ if nvalserr != nil {
+ return nil, nvalserr
+ }
+ vals = append(vals, nvals...)
+ }
+ break // have recursed the whole path - return
+ }
+
+ if keys[i].isArray || i == lastkey {
+ // Don't pass subkeys because may not be at literal end of path.
+ vals, verr = m.oldValuesForPath(tmppath)
+ } else {
+ continue
+ }
+ if verr != nil {
+ return nil, verr
+ }
+
+ if i == lastkey && !keys[i].isArray {
+ break
+ }
+
+ // Now we're looking at an array - supposedly.
+ // Is index in range of vals?
+ if len(vals) <= keys[i].position {
+ vals = nil
+ break
+ }
+
+ // Return the array member of interest, if at end of path.
+ if i == lastkey {
+ vals = vals[keys[i].position:(keys[i].position + 1)]
+ break
+ }
+
+ // Extract the array member of interest.
+ am := vals[keys[i].position:(keys[i].position + 1)]
+
+ // must be a map[string]interface{} value so we can keep walking the path
+ amm, ok := am[0].(map[string]interface{})
+ if !ok {
+ vals = nil
+ break
+ }
+
+ m = Map(amm)
+ haveFirst = false
+ }
+
+ return vals, nil
+}
+
+type key struct {
+ name string
+ isArray bool
+ position int
+}
+
+func parsePath(s string) ([]*key, error) {
+ keys := strings.Split(s, ".")
+
+ ret := make([]*key, 0)
+
+ for i := 0; i < len(keys); i++ {
+ if keys[i] == "" {
+ continue
+ }
+
+ newkey := new(key)
+ if strings.Index(keys[i], "[") < 0 {
+ newkey.name = keys[i]
+ ret = append(ret, newkey)
+ continue
+ }
+
+ p := strings.Split(keys[i], "[")
+ newkey.name = p[0]
+ p = strings.Split(p[1], "]")
+ if p[0] == "" { // no right bracket
+ return nil, fmt.Errorf("no right bracket on key index: %s", keys[i])
+ }
+ // convert p[0] to a int value
+ pos, nerr := strconv.ParseInt(p[0], 10, 32)
+ if nerr != nil {
+ return nil, fmt.Errorf("cannot convert index to int value: %s", p[0])
+ }
+ newkey.position = int(pos)
+ newkey.isArray = true
+ ret = append(ret, newkey)
+ }
+
+ return ret, nil
+}
+
+// legacy ValuesForPath() - now wrapped to handle special case of indexed arrays in 'path'.
+func (mv Map) oldValuesForPath(path string, subkeys ...string) ([]interface{}, error) {
+ m := map[string]interface{}(mv)
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ keys := strings.Split(path, ".")
+ if keys[len(keys)-1] == "" {
+ keys = keys[:len(keys)-1]
+ }
+ ivals := make([]interface{}, 0, defaultArraySize)
+ var cnt int
+ valuesForKeyPath(&ivals, &cnt, m, keys, subKeyMap)
+ return ivals[:cnt], nil
+}
+
+func valuesForKeyPath(ret *[]interface{}, cnt *int, m interface{}, keys []string, subkeys map[string]interface{}) {
+ lenKeys := len(keys)
+
+ // load 'm' values into 'ret'
+ // expand any lists
+ if lenKeys == 0 {
+ switch m.(type) {
+ case map[string]interface{}:
+ if subkeys != nil {
+ if ok := hasSubKeys(m, subkeys); !ok {
+ return
+ }
+ }
+ *ret = append(*ret, m)
+ *cnt++
+ case []interface{}:
+ for i, v := range m.([]interface{}) {
+ if subkeys != nil {
+ if ok := hasSubKeys(v, subkeys); !ok {
+ continue // only load list members with subkeys
+ }
+ }
+ *ret = append(*ret, (m.([]interface{}))[i])
+ *cnt++
+ }
+ default:
+ if subkeys != nil {
+ return // must be map[string]interface{} if there are subkeys
+ }
+ *ret = append(*ret, m)
+ *cnt++
+ }
+ return
+ }
+
+ // key of interest
+ key := keys[0]
+ switch key {
+ case "*": // wildcard - scan all values
+ switch m.(type) {
+ case map[string]interface{}:
+ for _, v := range m.(map[string]interface{}) {
+ // valuesForKeyPath(ret, v, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, v, keys[1:], subkeys)
+ }
+ case []interface{}:
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ // flatten out a list of maps - keys are processed
+ case map[string]interface{}:
+ for _, vv := range v.(map[string]interface{}) {
+ // valuesForKeyPath(ret, vv, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys)
+ }
+ default:
+ // valuesForKeyPath(ret, v, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, v, keys[1:], subkeys)
+ }
+ }
+ }
+ default: // key - must be map[string]interface{}
+ switch m.(type) {
+ case map[string]interface{}:
+ if v, ok := m.(map[string]interface{})[key]; ok {
+ // valuesForKeyPath(ret, v, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, v, keys[1:], subkeys)
+ }
+ case []interface{}: // may be buried in list
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}:
+ if vv, ok := v.(map[string]interface{})[key]; ok {
+ // valuesForKeyPath(ret, vv, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys)
+ }
+ }
+ }
+ }
+ }
+}
+
+// hasSubKeys() - interface{} equality works for string, float64, bool
+// 'v' must be a map[string]interface{} value to have subkeys
+// 'a' can have k:v pairs with v.(string) == "*", which is treated like a wildcard.
+func hasSubKeys(v interface{}, subkeys map[string]interface{}) bool {
+ if len(subkeys) == 0 {
+ return true
+ }
+
+ switch v.(type) {
+ case map[string]interface{}:
+ // do all subKey name:value pairs match?
+ mv := v.(map[string]interface{})
+ for skey, sval := range subkeys {
+ isNotKey := false
+ if skey[:1] == "!" { // a NOT-key
+ skey = skey[1:]
+ isNotKey = true
+ }
+ vv, ok := mv[skey]
+ if !ok { // key doesn't exist
+ if isNotKey { // key not there, but that's what we want
+ if kv, ok := sval.(string); ok && kv == "*" {
+ continue
+ }
+ }
+ return false
+ }
+ // wildcard check
+ if kv, ok := sval.(string); ok && kv == "*" {
+ if isNotKey { // key is there, and we don't want it
+ return false
+ }
+ continue
+ }
+ switch sval.(type) {
+ case string:
+ if s, ok := vv.(string); ok && s == sval.(string) {
+ if isNotKey {
+ return false
+ }
+ continue
+ }
+ case bool:
+ if b, ok := vv.(bool); ok && b == sval.(bool) {
+ if isNotKey {
+ return false
+ }
+ continue
+ }
+ case float64:
+ if f, ok := vv.(float64); ok && f == sval.(float64) {
+ if isNotKey {
+ return false
+ }
+ continue
+ }
+ }
+ // key there but didn't match subkey value
+ if isNotKey { // that's what we want
+ continue
+ }
+ return false
+ }
+ // all subkeys matched
+ return true
+ }
+
+ // not a map[string]interface{} value, can't have subkeys
+ return false
+}
+
+// Generate map of key:value entries as map[string]string.
+// 'kv' arguments are "name:value" pairs: attribute keys are designated with prepended hyphen, '-'.
+// If len(kv) == 0, the return is (nil, nil).
+func getSubKeyMap(kv ...string) (map[string]interface{}, error) {
+ if len(kv) == 0 {
+ return nil, nil
+ }
+ m := make(map[string]interface{}, 0)
+ for _, v := range kv {
+ vv := strings.Split(v, fieldSep)
+ switch len(vv) {
+ case 2:
+ m[vv[0]] = interface{}(vv[1])
+ case 3:
+ switch vv[2] {
+ case "string", "char", "text":
+ m[vv[0]] = interface{}(vv[1])
+ case "bool", "boolean":
+ // ParseBool treats "1"==true & "0"==false
+ b, err := strconv.ParseBool(vv[1])
+ if err != nil {
+ return nil, fmt.Errorf("can't convert subkey value to bool: %s", vv[1])
+ }
+ m[vv[0]] = interface{}(b)
+ case "float", "float64", "num", "number", "numeric":
+ f, err := strconv.ParseFloat(vv[1], 64)
+ if err != nil {
+ return nil, fmt.Errorf("can't convert subkey value to float: %s", vv[1])
+ }
+ m[vv[0]] = interface{}(f)
+ default:
+ return nil, fmt.Errorf("unknown subkey conversion spec: %s", v)
+ }
+ default:
+ return nil, fmt.Errorf("unknown subkey spec: %s", v)
+ }
+ }
+ return m, nil
+}
+
+// ------------------------------- END of valuesFor ... ----------------------------
+
+// ----------------------- locate where a key value is in the tree -------------------
+
+//----------------------------- find all paths to a key --------------------------------
+
+// PathsForKey returns all paths through Map, 'mv', (in dot-notation) that terminate with the specified key.
+// Results can be used with ValuesForPath.
+func (mv Map) PathsForKey(key string) []string {
+ m := map[string]interface{}(mv)
+ breadbasket := make(map[string]bool, 0)
+ breadcrumbs := ""
+
+ hasKeyPath(breadcrumbs, m, key, breadbasket)
+ if len(breadbasket) == 0 {
+ return nil
+ }
+
+ // unpack map keys to return
+ res := make([]string, len(breadbasket))
+ var i int
+ for k := range breadbasket {
+ res[i] = k
+ i++
+ }
+
+ return res
+}
+
+// PathForKeyShortest extracts the shortest path from all possible paths - from PathsForKey() - in Map, 'mv'..
+// Paths are strings using dot-notation.
+func (mv Map) PathForKeyShortest(key string) string {
+ paths := mv.PathsForKey(key)
+
+ lp := len(paths)
+ if lp == 0 {
+ return ""
+ }
+ if lp == 1 {
+ return paths[0]
+ }
+
+ shortest := paths[0]
+ shortestLen := len(strings.Split(shortest, "."))
+
+ for i := 1; i < len(paths); i++ {
+ vlen := len(strings.Split(paths[i], "."))
+ if vlen < shortestLen {
+ shortest = paths[i]
+ shortestLen = vlen
+ }
+ }
+
+ return shortest
+}
+
+// hasKeyPath - if the map 'key' exists append it to KeyPath.path and increment KeyPath.depth
+// This is really just a breadcrumber that saves all trails that hit the prescribed 'key'.
+func hasKeyPath(crumbs string, iv interface{}, key string, basket map[string]bool) {
+ switch iv.(type) {
+ case map[string]interface{}:
+ vv := iv.(map[string]interface{})
+ if _, ok := vv[key]; ok {
+ // create a new breadcrumb, intialized with the one we have
+ var nbc string
+ if crumbs == "" {
+ nbc = key
+ } else {
+ nbc = crumbs + "." + key
+ }
+ basket[nbc] = true
+ }
+ // walk on down the path, key could occur again at deeper node
+ for k, v := range vv {
+ // create a new breadcrumb, intialized with the one we have
+ var nbc string
+ if crumbs == "" {
+ nbc = k
+ } else {
+ nbc = crumbs + "." + k
+ }
+ hasKeyPath(nbc, v, key, basket)
+ }
+ case []interface{}:
+ // crumb-trail doesn't change, pass it on
+ for _, v := range iv.([]interface{}) {
+ hasKeyPath(crumbs, v, key, basket)
+ }
+ }
+}
+
+var PathNotExistError = errors.New("Path does not exist")
+
+// ValueForPath wraps ValuesFor Path and returns the first value returned.
+// If no value is found it returns 'nil' and PathNotExistError.
+func (mv Map) ValueForPath(path string) (interface{}, error) {
+ vals, err := mv.ValuesForPath(path)
+ if err != nil {
+ return nil, err
+ }
+ if len(vals) == 0 {
+ return nil, PathNotExistError
+ }
+ return vals[0], nil
+}
+
+// ValuesForPathString returns the first found value for the path as a string.
+func (mv Map) ValueForPathString(path string) (string, error) {
+ vals, err := mv.ValuesForPath(path)
+ if err != nil {
+ return "", err
+ }
+ if len(vals) == 0 {
+ return "", errors.New("ValueForPath: path not found")
+ }
+ val := vals[0]
+ return fmt.Sprintf("%v", val), nil
+}
+
+// ValueOrEmptyForPathString returns the first found value for the path as a string.
+// If the path is not found then it returns an empty string.
+func (mv Map) ValueOrEmptyForPathString(path string) string {
+ str, _ := mv.ValueForPathString(path)
+ return str
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/leafnode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/leafnode.go
new file mode 100644
index 000000000000..cf413ebdd4fe
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/leafnode.go
@@ -0,0 +1,112 @@
+package mxj
+
+// leafnode.go - return leaf nodes with paths and values for the Map
+// inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw
+
+import (
+ "strconv"
+ "strings"
+)
+
+const (
+ NoAttributes = true // suppress LeafNode values that are attributes
+)
+
+// LeafNode - a terminal path value in a Map.
+// For XML Map values it represents an attribute or simple element value - of type
+// string unless Map was created using Cast flag. For JSON Map values it represents
+// a string, numeric, boolean, or null value.
+type LeafNode struct {
+ Path string // a dot-notation representation of the path with array subscripting
+ Value interface{} // the value at the path termination
+}
+
+// LeafNodes - returns an array of all LeafNode values for the Map.
+// The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-')
+// as well as the "#text" key for the associated simple element value.
+//
+// PrependAttrWithHypen(false) will result in attributes having .attr-name as
+// terminal node in 'path' while the path for the element value, itself, will be
+// the base path w/o "#text".
+//
+// LeafUseDotNotation(true) causes list members to be identified using ".N" syntax
+// rather than "[N]" syntax.
+func (mv Map) LeafNodes(no_attr ...bool) []LeafNode {
+ var a bool
+ if len(no_attr) == 1 {
+ a = no_attr[0]
+ }
+
+ l := make([]LeafNode, 0)
+ getLeafNodes("", "", map[string]interface{}(mv), &l, a)
+ return l
+}
+
+func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) {
+ // if stripping attributes, then also strip "#text" key
+ if !noattr || node != "#text" {
+ if path != "" && node[:1] != "[" {
+ path += "."
+ }
+ path += node
+ }
+ switch mv.(type) {
+ case map[string]interface{}:
+ for k, v := range mv.(map[string]interface{}) {
+ // if noattr && k[:1] == "-" {
+ if noattr && len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 {
+ continue
+ }
+ getLeafNodes(path, k, v, l, noattr)
+ }
+ case []interface{}:
+ for i, v := range mv.([]interface{}) {
+ if useDotNotation {
+ getLeafNodes(path, strconv.Itoa(i), v, l, noattr)
+ } else {
+ getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr)
+ }
+ }
+ default:
+ // can't walk any further, so create leaf
+ n := LeafNode{path, mv}
+ *l = append(*l, n)
+ }
+}
+
+// LeafPaths - all paths that terminate in LeafNode values.
+func (mv Map) LeafPaths(no_attr ...bool) []string {
+ ln := mv.LeafNodes()
+ ss := make([]string, len(ln))
+ for i := 0; i < len(ln); i++ {
+ ss[i] = ln[i].Path
+ }
+ return ss
+}
+
+// LeafValues - all terminal values in the Map.
+func (mv Map) LeafValues(no_attr ...bool) []interface{} {
+ ln := mv.LeafNodes()
+ vv := make([]interface{}, len(ln))
+ for i := 0; i < len(ln); i++ {
+ vv[i] = ln[i].Value
+ }
+ return vv
+}
+
+// ====================== utilities ======================
+
+// https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I
+var useDotNotation bool
+
+// LeafUseDotNotation sets a flag that list members in LeafNode paths
+// should be identified using ".N" syntax rather than the default "[N]"
+// syntax. Calling LeafUseDotNotation with no arguments toggles the
+// flag on/off; otherwise, the argument sets the flag value 'true'/'false'.
+func LeafUseDotNotation(b ...bool) {
+ if len(b) == 0 {
+ useDotNotation = !useDotNotation
+ return
+ }
+ useDotNotation = b[0]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/misc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/misc.go
new file mode 100644
index 000000000000..5b4fab2165d5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/misc.go
@@ -0,0 +1,86 @@
+// Copyright 2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// misc.go - mimic functions (+others) called out in:
+// https://groups.google.com/forum/#!topic/golang-nuts/jm_aGsJNbdQ
+// Primarily these methods let you retrive XML structure information.
+
+package mxj
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// Return the root element of the Map. If there is not a single key in Map,
+// then an error is returned.
+func (mv Map) Root() (string, error) {
+ mm := map[string]interface{}(mv)
+ if len(mm) != 1 {
+ return "", fmt.Errorf("Map does not have singleton root. Len: %d.", len(mm))
+ }
+ for k, _ := range mm {
+ return k, nil
+ }
+ return "", nil
+}
+
+// If the path is an element with sub-elements, return a list of the sub-element
+// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are prefixed with
+// '-', a hyphen, are considered attributes; see m.Attributes(path).
+func (mv Map) Elements(path string) ([]string, error) {
+ e, err := mv.ValueForPath(path)
+ if err != nil {
+ return nil, err
+ }
+ switch e.(type) {
+ case map[string]interface{}:
+ ee := e.(map[string]interface{})
+ elems := make([]string, len(ee))
+ var i int
+ for k, _ := range ee {
+ if len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 {
+ continue // skip attributes
+ }
+ elems[i] = k
+ i++
+ }
+ elems = elems[:i]
+ // alphabetic sort keeps things tidy
+ sort.Strings(elems)
+ return elems, nil
+ }
+ return nil, fmt.Errorf("no elements for path: %s", path)
+}
+
+// If the path is an element with attributes, return a list of the attribute
+// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are not prefixed with
+// '-', a hyphen, are not treated as attributes; see m.Elements(path). Also, if the
+// attribute prefix is "" - SetAttrPrefix("") or PrependAttrWithHyphen(false) - then
+// there are no identifiable attributes.
+func (mv Map) Attributes(path string) ([]string, error) {
+ a, err := mv.ValueForPath(path)
+ if err != nil {
+ return nil, err
+ }
+ switch a.(type) {
+ case map[string]interface{}:
+ aa := a.(map[string]interface{})
+ attrs := make([]string, len(aa))
+ var i int
+ for k, _ := range aa {
+ if len(attrPrefix) == 0 || strings.Index(k, attrPrefix) != 0 {
+ continue // skip non-attributes
+ }
+ attrs[i] = k[len(attrPrefix):]
+ i++
+ }
+ attrs = attrs[:i]
+ // alphabetic sort keeps things tidy
+ sort.Strings(attrs)
+ return attrs, nil
+ }
+ return nil, fmt.Errorf("no attributes for path: %s", path)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/mxj.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/mxj.go
new file mode 100644
index 000000000000..f0592f06c8ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/mxj.go
@@ -0,0 +1,128 @@
+// mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
+// Copyright 2012-2014 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "fmt"
+ "sort"
+)
+
+const (
+ Cast = true // for clarity - e.g., mxj.NewMapXml(doc, mxj.Cast)
+ SafeEncoding = true // ditto - e.g., mv.Json(mxj.SafeEncoding)
+)
+
+type Map map[string]interface{}
+
+// Allocate a Map.
+func New() Map {
+ m := make(map[string]interface{}, 0)
+ return m
+}
+
+// Cast a Map to map[string]interface{}
+func (mv Map) Old() map[string]interface{} {
+ return mv
+}
+
+// Return a copy of mv as a newly allocated Map. If the Map only contains string,
+// numeric, map[string]interface{}, and []interface{} values, then it can be thought
+// of as a "deep copy." Copying a structure (or structure reference) value is subject
+// to the noted restrictions.
+// NOTE: If 'mv' includes structure values with, possibly, JSON encoding tags
+// then only public fields of the structure are in the new Map - and with
+// keys that conform to any encoding tag instructions. The structure itself will
+// be represented as a map[string]interface{} value.
+func (mv Map) Copy() (Map, error) {
+ // this is the poor-man's deep copy
+ // not efficient, but it works
+ j, jerr := mv.Json()
+ // must handle, we don't know how mv got built
+ if jerr != nil {
+ return nil, jerr
+ }
+ return NewMapJson(j)
+}
+
+// --------------- StringIndent ... from x2j.WriteMap -------------
+
+// Pretty print a Map.
+func (mv Map) StringIndent(offset ...int) string {
+ return writeMap(map[string]interface{}(mv), true, true, offset...)
+}
+
+// Pretty print a Map without the value type information - just key:value entries.
+func (mv Map) StringIndentNoTypeInfo(offset ...int) string {
+ return writeMap(map[string]interface{}(mv), false, true, offset...)
+}
+
+// writeMap - dumps the map[string]interface{} for examination.
+// 'typeInfo' causes value type to be printed.
+// 'offset' is initial indentation count; typically: Write(m).
+func writeMap(m interface{}, typeInfo, root bool, offset ...int) string {
+ var indent int
+ if len(offset) == 1 {
+ indent = offset[0]
+ }
+
+ var s string
+ switch m.(type) {
+ case []interface{}:
+ if typeInfo {
+ s += "[[]interface{}]"
+ }
+ for _, v := range m.([]interface{}) {
+ s += "\n"
+ for i := 0; i < indent; i++ {
+ s += " "
+ }
+ s += writeMap(v, typeInfo, false, indent+1)
+ }
+ case map[string]interface{}:
+ list := make([][2]string, len(m.(map[string]interface{})))
+ var n int
+ for k, v := range m.(map[string]interface{}) {
+ list[n][0] = k
+ list[n][1] = writeMap(v, typeInfo, false, indent+1)
+ n++
+ }
+ sort.Sort(mapList(list))
+ for _, v := range list {
+ if root {
+ root = false
+ } else {
+ s += "\n"
+ }
+ for i := 0; i < indent; i++ {
+ s += " "
+ }
+ s += v[0] + " : " + v[1]
+ }
+ default:
+ if typeInfo {
+ s += fmt.Sprintf("[%T] %+v", m, m)
+ } else {
+ s += fmt.Sprintf("%+v", m)
+ }
+ }
+ return s
+}
+
+// ======================== utility ===============
+
+type mapList [][2]string
+
+func (ml mapList) Len() int {
+ return len(ml)
+}
+
+func (ml mapList) Swap(i, j int) {
+ ml[i], ml[j] = ml[j], ml[i]
+}
+
+func (ml mapList) Less(i, j int) bool {
+ return ml[i][0] <= ml[j][0]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/newmap.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/newmap.go
new file mode 100644
index 000000000000..b293949056dc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/newmap.go
@@ -0,0 +1,184 @@
+// mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
+// Copyright 2012-2014, 2018 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// remap.go - build a new Map from the current Map based on keyOld:keyNew mapppings
+// keys can use dot-notation, keyOld can use wildcard, '*'
+//
+// Computational strategy -
+// Using the key path - []string - traverse a new map[string]interface{} and
+// insert the oldVal as the newVal when we arrive at the end of the path.
+// If the type at the end is nil, then that is newVal
+// If the type at the end is a singleton (string, float64, bool) an array is created.
+// If the type at the end is an array, newVal is just appended.
+// If the type at the end is a map, it is inserted if possible or the map value
+// is converted into an array if necessary.
+
+package mxj
+
+import (
+ "errors"
+ "strings"
+)
+
+// (Map)NewMap - create a new Map from data in the current Map.
+// 'keypairs' are key mappings "oldKey:newKey" and specify that the current value of 'oldKey'
+// should be the value for 'newKey' in the returned Map.
+// - 'oldKey' supports dot-notation as described for (Map)ValuesForPath()
+// - 'newKey' supports dot-notation but with no wildcards, '*', or indexed arrays
+// - "oldKey" is shorthand for the keypair value "oldKey:oldKey"
+// - "oldKey:" and ":newKey" are invalid keypair values
+// - if 'oldKey' does not exist in the current Map, it is not written to the new Map.
+// "null" is not supported unless it is the current Map.
+// - see newmap_test.go for several syntax examples
+// - mv.NewMap() == mxj.New()
+//
+// NOTE: "examples/partial.go" shows how to create arbitrary sub-docs of an XML doc.
+func (mv Map) NewMap(keypairs ...string) (Map, error) {
+ n := make(map[string]interface{}, 0)
+ if len(keypairs) == 0 {
+ return n, nil
+ }
+
+ // loop through the pairs
+ var oldKey, newKey string
+ var path []string
+ for _, v := range keypairs {
+ if len(v) == 0 {
+ continue // just skip over empty keypair arguments
+ }
+
+ // initialize oldKey, newKey and check
+ vv := strings.Split(v, ":")
+ if len(vv) > 2 {
+ return n, errors.New("oldKey:newKey keypair value not valid - " + v)
+ }
+ if len(vv) == 1 {
+ oldKey, newKey = vv[0], vv[0]
+ } else {
+ oldKey, newKey = vv[0], vv[1]
+ }
+ strings.TrimSpace(oldKey)
+ strings.TrimSpace(newKey)
+ if i := strings.Index(newKey, "*"); i > -1 {
+ return n, errors.New("newKey value cannot contain wildcard character - " + v)
+ }
+ if i := strings.Index(newKey, "["); i > -1 {
+ return n, errors.New("newKey value cannot contain indexed arrays - " + v)
+ }
+ if oldKey == "" || newKey == "" {
+ return n, errors.New("oldKey or newKey is not specified - " + v)
+ }
+
+ // get oldKey value
+ oldVal, err := mv.ValuesForPath(oldKey)
+ if err != nil {
+ return n, err
+ }
+ if len(oldVal) == 0 {
+ continue // oldKey has no value, may not exist in mv
+ }
+
+ // break down path
+ path = strings.Split(newKey, ".")
+ if path[len(path)-1] == "" { // ignore a trailing dot in newKey spec
+ path = path[:len(path)-1]
+ }
+
+ addNewVal(&n, path, oldVal)
+ }
+
+ return n, nil
+}
+
+// navigate 'n' to end of path and add val
+func addNewVal(n *map[string]interface{}, path []string, val []interface{}) {
+ // newVal - either singleton or array
+ var newVal interface{}
+ if len(val) == 1 {
+ newVal = val[0] // is type interface{}
+ } else {
+ newVal = interface{}(val)
+ }
+
+ // walk to the position of interest, create it if necessary
+ m := (*n) // initialize map walker
+ var k string // key for m
+ lp := len(path) - 1 // when to stop looking
+ for i := 0; i < len(path); i++ {
+ k = path[i]
+ if i == lp {
+ break
+ }
+ var nm map[string]interface{} // holds position of next-map
+ switch m[k].(type) {
+ case nil: // need a map for next node in path, so go there
+ nm = make(map[string]interface{}, 0)
+ m[k] = interface{}(nm)
+ m = m[k].(map[string]interface{})
+ case map[string]interface{}:
+ // OK - got somewhere to walk to, go there
+ m = m[k].(map[string]interface{})
+ case []interface{}:
+ // add a map and nm points to new map unless there's already
+ // a map in the array, then nm points there
+ // The placement of the next value in the array is dependent
+ // on the sequence of members - could land on a map or a nil
+ // value first. TODO: how to test this.
+ a := make([]interface{}, 0)
+ var foundmap bool
+ for _, vv := range m[k].([]interface{}) {
+ switch vv.(type) {
+ case nil: // doesn't appear that this occurs, need a test case
+ if foundmap { // use the first one in array
+ a = append(a, vv)
+ continue
+ }
+ nm = make(map[string]interface{}, 0)
+ a = append(a, interface{}(nm))
+ foundmap = true
+ case map[string]interface{}:
+ if foundmap { // use the first one in array
+ a = append(a, vv)
+ continue
+ }
+ nm = vv.(map[string]interface{})
+ a = append(a, vv)
+ foundmap = true
+ default:
+ a = append(a, vv)
+ }
+ }
+ // no map found in array
+ if !foundmap {
+ nm = make(map[string]interface{}, 0)
+ a = append(a, interface{}(nm))
+ }
+ m[k] = interface{}(a) // must insert in map
+ m = nm
+ default: // it's a string, float, bool, etc.
+ aa := make([]interface{}, 0)
+ nm = make(map[string]interface{}, 0)
+ aa = append(aa, m[k], nm)
+ m[k] = interface{}(aa)
+ m = nm
+ }
+ }
+
+ // value is nil, array or a singleton of some kind
+ // initially m.(type) == map[string]interface{}
+ v := m[k]
+ switch v.(type) {
+ case nil: // initialized
+ m[k] = newVal
+ case []interface{}:
+ a := m[k].([]interface{})
+ a = append(a, newVal)
+ m[k] = interface{}(a)
+ default: // v exists:string, float64, bool, map[string]interface, etc.
+ a := make([]interface{}, 0)
+ a = append(a, v, newVal)
+ m[k] = interface{}(a)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/readme.md b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/readme.md
new file mode 100644
index 000000000000..323a747d4d81
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/readme.md
@@ -0,0 +1,207 @@
+mxj - to/from maps, XML and JSON
+Decode/encode XML to/from map[string]interface{} (or JSON) values, and extract/modify values from maps by key or key-path, including wildcards.
+
+mxj supplants the legacy x2j and j2x packages. If you want the old syntax, use mxj/x2j and mxj/j2x packages.
+
+Installation
+Using go.mod:
+
+go get github.com/clbanning/mxj/v2@v2.3.2
+
+
+
+import "github.com/clbanning/mxj/v2"
+
+
+... or just vendor the package.
+
+Related Packages
+
+https://github.com/clbanning/checkxml provides functions for validating XML data.
+
+Refactor Encoder - 2020.05.01
+Issue #70 highlighted that encoding large maps does not scale well, since the original logic used string appends operations. Using bytes.Buffer results in linear scaling for very large XML docs. (Metrics based on MacBook Pro i7 w/ 16 GB.)
+
+ Nodes m.XML() time
+ 54809 12.53708ms
+ 109780 32.403183ms
+ 164678 59.826412ms
+ 482598 109.358007ms
+
+Refactor Decoder - 2015.11.15
+For over a year I've wanted to refactor the XML-to-map[string]interface{} decoder to make it more performant. I recently took the time to do that, since we were using github.com/clbanning/mxj in a production system that could be deployed on a Raspberry Pi. Now the decoder is comparable to the stdlib JSON-to-map[string]interface{} decoder in terms of its additional processing overhead relative to decoding to a structure value. As shown by:
+
+ BenchmarkNewMapXml-4 100000 18043 ns/op
+ BenchmarkNewStructXml-4 100000 14892 ns/op
+ BenchmarkNewMapJson-4 300000 4633 ns/op
+ BenchmarkNewStructJson-4 300000 3427 ns/op
+ BenchmarkNewMapXmlBooks-4 20000 82850 ns/op
+ BenchmarkNewStructXmlBooks-4 20000 67822 ns/op
+ BenchmarkNewMapJsonBooks-4 100000 17222 ns/op
+ BenchmarkNewStructJsonBooks-4 100000 15309 ns/op
+
+Notices
+
+ 2021.02.02: v2.5 - add XmlCheckIsValid toggle to force checking that the encoded XML is valid
+ 2020.12.14: v2.4 - add XMLEscapeCharsDecoder to preserve XML escaped characters in Map values
+ 2020.10.28: v2.3 - add TrimWhiteSpace option
+ 2020.05.01: v2.2 - optimize map to XML encoding for large XML docs.
+ 2019.07.04: v2.0 - remove unnecessary methods - mv.XmlWriterRaw, mv.XmlIndentWriterRaw - for Map and MapSeq.
+ 2019.07.04: Add MapSeq type and move associated functions and methods from Map to MapSeq.
+ 2019.01.21: DecodeSimpleValuesAsMap - decode to map[:map["#text":]] rather than map[:]
+ 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc.
+ 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps.
+ 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package.
+ 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing.
+ 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods.
+ 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag().
+ 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc.
+ 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix().
+ 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable.
+ 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars().
+ 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf".
+ To cast them to float64, first set flag with CastNanInf(true).
+ 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure.
+ 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization.
+ 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM).
+ 2015.12.02: XML decoding/encoding that preserves original structure of document. See NewMapXmlSeq()
+ and mv.XmlSeq() / mv.XmlSeqIndent().
+ 2015-05-20: New: mv.StringIndentNoTypeInfo().
+ Also, alphabetically sort map[string]interface{} values by key to prettify output for mv.Xml(),
+ mv.XmlIndent(), mv.StringIndent(), mv.StringIndentNoTypeInfo().
+ 2014-11-09: IncludeTagSeqNum() adds "_seq" key with XML doc positional information.
+ (NOTE: PreserveXmlList() is similar and will be here soon.)
+ 2014-09-18: inspired by NYTimes fork, added PrependAttrWithHyphen() to allow stripping hyphen from attribute tag.
+ 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML.
+ 2014-04-28: ValuesForPath() and NewMap() now accept path with indexed array references.
+
+Basic Unmarshal XML to map[string]interface{}
+type Map map[string]interface{}
+
+Create a `Map` value, 'mv', from any `map[string]interface{}` value, 'v':
+mv := Map(v)
+
+Unmarshal / marshal XML as a `Map` value, 'mv':
+mv, err := NewMapXml(xmlValue) // unmarshal
+xmlValue, err := mv.Xml() // marshal
+
+Unmarshal XML from an `io.Reader` as a `Map` value, 'mv':
+mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream
+mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
+
+Marshal `Map` value, 'mv', to an XML Writer (`io.Writer`):
+err := mv.XmlWriter(xmlWriter)
+raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
+
+Also, for prettified output:
+xmlValue, err := mv.XmlIndent(prefix, indent, ...)
+err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...)
+raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
+
+Bulk process XML with error handling (note: handlers must return a boolean value):
+err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
+err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
+
+Converting XML to JSON: see Examples for `NewMapXml` and `HandleXmlReader`.
+
+There are comparable functions and methods for JSON processing.
+
+Arbitrary structure values can be decoded to / encoded from `Map` values:
+mv, err := NewMapStruct(structVal)
+err := mv.Struct(structPointer)
+
+Extract / modify Map values
+To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON
+or structure to a `Map` value, 'mv', or cast a `map[string]interface{}` value to a `Map` value, 'mv', then:
+paths := mv.PathsForKey(key)
+path := mv.PathForKeyShortest(key)
+values, err := mv.ValuesForKey(key, subkeys)
+values, err := mv.ValuesForPath(path, subkeys)
+count, err := mv.UpdateValuesForPath(newVal, path, subkeys)
+
+Get everything at once, irrespective of path depth:
+leafnodes := mv.LeafNodes()
+leafvalues := mv.LeafValues()
+
+A new `Map` with whatever keys are desired can be created from the current `Map` and then encoded in XML
+or JSON. (Note: keys can use dot-notation.)
+newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
+newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
+newXml, err := newMap.Xml() // for example
+newJson, err := newMap.Json() // ditto
+
+Usage
+
+The package is fairly well [self-documented with examples](http://godoc.org/github.com/clbanning/mxj).
+
+Also, the subdirectory "examples" contains a wide range of examples, several taken from golang-nuts discussions.
+
+XML parsing conventions
+
+Using NewMapXml()
+
+ - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`,
+ to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or
+ `SetAttrPrefix()`.)
+ - If the element is a simple element and has attributes, the element value
+ is given the key `#text` for its `map[string]interface{}` representation. (See
+ the 'atomFeedString.xml' test data, below.)
+ - XML comments, directives, and process instructions are ignored.
+ - If CoerceKeysToLower() has been called, then the resultant keys will be lower case.
+
+Using NewMapXmlSeq()
+
+ - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values
+ where the `` value has "#text" and "#seq" keys - the "#text" key holds the
+ value for ``.
+ - All elements, except for the root, have a "#seq" key.
+ - Comments, directives, and process instructions are unmarshalled into the Map using the
+ keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more
+ specifics.)
+ - Name space syntax is preserved:
+ - `something` parses to `map["ns:key"]interface{}{"something"}`
+ - `xmlns:ns="http://myns.com/ns"` parses to `map["xmlns:ns"]interface{}{"http://myns.com/ns"}`
+
+Both
+
+ - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them
+ to be cast, set a flag to cast them using CastNanInf(true).
+
+XML encoding conventions
+
+ - 'nil' `Map` values, which may represent 'null' JSON values, are encoded as ` `.
+ NOTE: the operation is not symmetric as ` ` elements are decoded as `tag:""` `Map` values,
+ which, then, encode in JSON as `"tag":""` values.
+ - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go
+ randomizes the walk through map[string]interface{} values.) If you plan to re-encode the
+ Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and
+ mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when
+ working with the Map representation.
+
+Running "go test"
+
+Because there are no guarantees on the sequence map elements are retrieved, the tests have been
+written for visual verification in most cases. One advantage is that you can easily use the
+output from running "go test" as examples of calling the various functions and methods.
+
+Motivation
+
+I make extensive use of JSON for messaging and typically unmarshal the messages into
+`map[string]interface{}` values. This is easily done using `json.Unmarshal` from the
+standard Go libraries. Unfortunately, many legacy solutions use structured
+XML messages; in those environments the applications would have to be refactored to
+interoperate with my components.
+
+The better solution is to just provide an alternative HTTP handler that receives
+XML messages and parses it into a `map[string]interface{}` value and then reuse
+all the JSON-based code. The Go `xml.Unmarshal()` function does not provide the same
+option of unmarshaling XML messages into `map[string]interface{}` values. So I wrote
+a couple of small functions to fill this gap and released them as the x2j package.
+
+Over the next year and a half additional features were added, and the companion j2x
+package was released to address XML encoding of arbitrary JSON and `map[string]interface{}`
+values. As part of a refactoring of our production system and looking at how we had been
+using the x2j and j2x packages we found that we rarely performed direct XML-to-JSON or
+JSON-to_XML conversion and that working with the XML or JSON as `map[string]interface{}`
+values was the primary value. Thus, everything was refactored into the mxj package.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/remove.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/remove.go
new file mode 100644
index 000000000000..8362ab17fa4f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/remove.go
@@ -0,0 +1,37 @@
+package mxj
+
+import "strings"
+
+// Removes the path.
+func (mv Map) Remove(path string) error {
+ m := map[string]interface{}(mv)
+ return remove(m, path)
+}
+
+func remove(m interface{}, path string) error {
+ val, err := prevValueByPath(m, path)
+ if err != nil {
+ return err
+ }
+
+ lastKey := lastKey(path)
+ delete(val, lastKey)
+
+ return nil
+}
+
+// returns the last key of the path.
+// lastKey("a.b.c") would had returned "c"
+func lastKey(path string) string {
+ keys := strings.Split(path, ".")
+ key := keys[len(keys)-1]
+ return key
+}
+
+// returns the path without the last key
+// parentPath("a.b.c") whould had returned "a.b"
+func parentPath(path string) string {
+ keys := strings.Split(path, ".")
+ parentPath := strings.Join(keys[0:len(keys)-1], ".")
+ return parentPath
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/rename.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/rename.go
new file mode 100644
index 000000000000..4c655ed5d0ad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/rename.go
@@ -0,0 +1,61 @@
+package mxj
+
+import (
+ "errors"
+ "strings"
+)
+
+// RenameKey renames a key in a Map.
+// It works only for nested maps.
+// It doesn't work for cases when the key is in a list.
+func (mv Map) RenameKey(path string, newName string) error {
+ var v bool
+ var err error
+ if v, err = mv.Exists(path); err == nil && !v {
+ return errors.New("RenameKey: path not found: " + path)
+ } else if err != nil {
+ return err
+ }
+ if v, err = mv.Exists(parentPath(path) + "." + newName); err == nil && v {
+ return errors.New("RenameKey: key already exists: " + newName)
+ } else if err != nil {
+ return err
+ }
+
+ m := map[string]interface{}(mv)
+ return renameKey(m, path, newName)
+}
+
+func renameKey(m interface{}, path string, newName string) error {
+ val, err := prevValueByPath(m, path)
+ if err != nil {
+ return err
+ }
+
+ oldName := lastKey(path)
+ val[newName] = val[oldName]
+ delete(val, oldName)
+
+ return nil
+}
+
+// returns a value which contains a last key in the path
+// For example: prevValueByPath("a.b.c", {a{b{c: 3}}}) returns {c: 3}
+func prevValueByPath(m interface{}, path string) (map[string]interface{}, error) {
+ keys := strings.Split(path, ".")
+
+ switch mValue := m.(type) {
+ case map[string]interface{}:
+ for key, value := range mValue {
+ if key == keys[0] {
+ if len(keys) == 1 {
+ return mValue, nil
+ } else {
+ // keep looking for the full path to the key
+ return prevValueByPath(value, strings.Join(keys[1:], "."))
+ }
+ }
+ }
+ }
+ return nil, errors.New("prevValueByPath: didn't find path – " + path)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/set.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/set.go
new file mode 100644
index 000000000000..a297fc38887a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/set.go
@@ -0,0 +1,26 @@
+package mxj
+
+import (
+ "strings"
+)
+
+// Sets the value for the path
+func (mv Map) SetValueForPath(value interface{}, path string) error {
+ pathAry := strings.Split(path, ".")
+ parentPathAry := pathAry[0 : len(pathAry)-1]
+ parentPath := strings.Join(parentPathAry, ".")
+
+ val, err := mv.ValueForPath(parentPath)
+ if err != nil {
+ return err
+ }
+ if val == nil {
+ return nil // we just ignore the request if there's no val
+ }
+
+ key := pathAry[len(pathAry)-1]
+ cVal := val.(map[string]interface{})
+ cVal[key] = value
+
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/setfieldsep.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/setfieldsep.go
new file mode 100644
index 000000000000..b70715ebc65a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/setfieldsep.go
@@ -0,0 +1,20 @@
+package mxj
+
+// Per: https://github.com/clbanning/mxj/issues/37#issuecomment-278651862
+var fieldSep string = ":"
+
+// SetFieldSeparator changes the default field separator, ":", for the
+// newVal argument in mv.UpdateValuesForPath and the optional 'subkey' arguments
+// in mv.ValuesForKey and mv.ValuesForPath.
+//
+// E.g., if the newVal value is "http://blah/blah", setting the field separator
+// to "|" will allow the newVal specification, "|http://blah/blah" to parse
+// properly. If called with no argument or an empty string value, the field
+// separator is set to the default, ":".
+func SetFieldSeparator(s ...string) {
+ if len(s) == 0 || s[0] == "" {
+ fieldSep = ":" // the default
+ return
+ }
+ fieldSep = s[0]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/songtext.xml b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/songtext.xml
new file mode 100644
index 000000000000..8c0f2becb128
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/songtext.xml
@@ -0,0 +1,29 @@
+
+ help me!
+
+
+
+ Henry was a renegade
+ Didn't like to play it safe
+ One component at a time
+ There's got to be a better way
+ Oh, people came from miles around
+ Searching for a steady job
+ Welcome to the Motor Town
+ Booming like an atom bomb
+
+
+ Oh, Henry was the end of the story
+ Then everything went wrong
+ And we'll return it to its former glory
+ But it just takes so long
+
+
+
+ It's going to take a long time
+ It's going to take it, but we'll make it one day
+ It's going to take a long time
+ It's going to take it, but we'll make it one day
+
+
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/strict.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/strict.go
new file mode 100644
index 000000000000..1e769560ba0b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/strict.go
@@ -0,0 +1,30 @@
+// Copyright 2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// strict.go actually addresses setting xml.Decoder attribute
+// values. This'll let you parse non-standard XML.
+
+package mxj
+
+import (
+ "encoding/xml"
+)
+
+// CustomDecoder can be used to specify xml.Decoder attribute
+// values, e.g., Strict:false, to be used. By default CustomDecoder
+// is nil. If CustomeDecoder != nil, then mxj.XmlCharsetReader variable is
+// ignored and must be set as part of the CustomDecoder value, if needed.
+// Usage:
+// mxj.CustomDecoder = &xml.Decoder{Strict:false}
+var CustomDecoder *xml.Decoder
+
+// useCustomDecoder copy over public attributes from customDecoder
+func useCustomDecoder(d *xml.Decoder) {
+ d.Strict = CustomDecoder.Strict
+ d.AutoClose = CustomDecoder.AutoClose
+ d.Entity = CustomDecoder.Entity
+ d.CharsetReader = CustomDecoder.CharsetReader
+ d.DefaultSpace = CustomDecoder.DefaultSpace
+}
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/struct.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/struct.go
new file mode 100644
index 000000000000..9be636cdcab7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/struct.go
@@ -0,0 +1,54 @@
+// Copyright 2012-2017 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "encoding/json"
+ "errors"
+ "reflect"
+
+ // "github.com/fatih/structs"
+)
+
+// Create a new Map value from a structure. Error returned if argument is not a structure.
+// Only public structure fields are decoded in the Map value. See github.com/fatih/structs#Map
+// for handling of "structs" tags.
+
+// DEPRECATED - import github.com/fatih/structs and cast result of structs.Map to mxj.Map.
+// import "github.com/fatih/structs"
+// ...
+// sm, err := structs.Map()
+// if err != nil {
+// // handle error
+// }
+// m := mxj.Map(sm)
+// Alernatively uncomment the old source and import in struct.go.
+func NewMapStruct(structVal interface{}) (Map, error) {
+ return nil, errors.New("deprecated - see package documentation")
+ /*
+ if !structs.IsStruct(structVal) {
+ return nil, errors.New("NewMapStruct() error: argument is not type Struct")
+ }
+ return structs.Map(structVal), nil
+ */
+}
+
+// Marshal a map[string]interface{} into a structure referenced by 'structPtr'. Error returned
+// if argument is not a pointer or if json.Unmarshal returns an error.
+// json.Unmarshal structure encoding rules are followed to encode public structure fields.
+func (mv Map) Struct(structPtr interface{}) error {
+ // should check that we're getting a pointer.
+ if reflect.ValueOf(structPtr).Kind() != reflect.Ptr {
+ return errors.New("mv.Struct() error: argument is not type Ptr")
+ }
+
+ m := map[string]interface{}(mv)
+ j, err := json.Marshal(m)
+ if err != nil {
+ return err
+ }
+
+ return json.Unmarshal(j, structPtr)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/updatevalues.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/updatevalues.go
new file mode 100644
index 000000000000..9e10d84e8d57
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/updatevalues.go
@@ -0,0 +1,258 @@
+// Copyright 2012-2014, 2017 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// updatevalues.go - modify a value based on path and possibly sub-keys
+// TODO(clb): handle simple elements with attributes and NewMapXmlSeq Map values.
+
+package mxj
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// Update value based on path and possible sub-key values.
+// A count of the number of values changed and any error are returned.
+// If the count == 0, then no path (and subkeys) matched.
+// 'newVal' can be a Map or map[string]interface{} value with a single 'key' that is the key to be modified
+// or a string value "key:value[:type]" where type is "bool" or "num" to cast the value.
+// 'path' is dot-notation list of keys to traverse; last key in path can be newVal key
+// NOTE: 'path' spec does not currently support indexed array references.
+// 'subkeys' are "key:value[:type]" entries that must match for path node
+// - For attributes prefix the label with the attribute prefix character, by default a
+// hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.)
+// - The subkey can be wildcarded - "key:*" - to require that it's there with some value.
+// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an
+// exclusion critera - e.g., "!author:William T. Gaddis".
+//
+// NOTES:
+// 1. Simple elements with attributes need a path terminated as ".#text" to modify the actual value.
+// 2. Values in Maps created using NewMapXmlSeq are map[string]interface{} values with a "#text" key.
+// 3. If values in 'newVal' or 'subkeys' args contain ":", use SetFieldSeparator to an unused symbol,
+// perhaps "|".
+func (mv Map) UpdateValuesForPath(newVal interface{}, path string, subkeys ...string) (int, error) {
+ m := map[string]interface{}(mv)
+
+ // extract the subkeys
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ // extract key and value from newVal
+ var key string
+ var val interface{}
+ switch newVal.(type) {
+ case map[string]interface{}, Map:
+ switch newVal.(type) { // "fallthrough is not permitted in type switch" (Spec)
+ case Map:
+ newVal = newVal.(Map).Old()
+ }
+ if len(newVal.(map[string]interface{})) != 1 {
+ return 0, fmt.Errorf("newVal map can only have len == 1 - %+v", newVal)
+ }
+ for key, val = range newVal.(map[string]interface{}) {
+ }
+ case string: // split it as a key:value pair
+ ss := strings.Split(newVal.(string), fieldSep)
+ n := len(ss)
+ if n < 2 || n > 3 {
+ return 0, fmt.Errorf("unknown newVal spec - %+v", newVal)
+ }
+ key = ss[0]
+ if n == 2 {
+ val = interface{}(ss[1])
+ } else if n == 3 {
+ switch ss[2] {
+ case "bool", "boolean":
+ nv, err := strconv.ParseBool(ss[1])
+ if err != nil {
+ return 0, fmt.Errorf("can't convert newVal to bool - %+v", newVal)
+ }
+ val = interface{}(nv)
+ case "num", "numeric", "float", "int":
+ nv, err := strconv.ParseFloat(ss[1], 64)
+ if err != nil {
+ return 0, fmt.Errorf("can't convert newVal to float64 - %+v", newVal)
+ }
+ val = interface{}(nv)
+ default:
+ return 0, fmt.Errorf("unknown type for newVal value - %+v", newVal)
+ }
+ }
+ default:
+ return 0, fmt.Errorf("invalid newVal type - %+v", newVal)
+ }
+
+ // parse path
+ keys := strings.Split(path, ".")
+
+ var count int
+ updateValuesForKeyPath(key, val, m, keys, subKeyMap, &count)
+
+ return count, nil
+}
+
+// navigate the path
+func updateValuesForKeyPath(key string, value interface{}, m interface{}, keys []string, subkeys map[string]interface{}, cnt *int) {
+ // ----- at end node: looking at possible node to get 'key' ----
+ if len(keys) == 1 {
+ updateValue(key, value, m, keys[0], subkeys, cnt)
+ return
+ }
+
+ // ----- here we are navigating the path thru the penultimate node --------
+ // key of interest is keys[0] - the next in the path
+ switch keys[0] {
+ case "*": // wildcard - scan all values
+ switch m.(type) {
+ case map[string]interface{}:
+ for _, v := range m.(map[string]interface{}) {
+ updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt)
+ }
+ case []interface{}:
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ // flatten out a list of maps - keys are processed
+ case map[string]interface{}:
+ for _, vv := range v.(map[string]interface{}) {
+ updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt)
+ }
+ default:
+ updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt)
+ }
+ }
+ }
+ default: // key - must be map[string]interface{}
+ switch m.(type) {
+ case map[string]interface{}:
+ if v, ok := m.(map[string]interface{})[keys[0]]; ok {
+ updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt)
+ }
+ case []interface{}: // may be buried in list
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}:
+ if vv, ok := v.(map[string]interface{})[keys[0]]; ok {
+ updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt)
+ }
+ }
+ }
+ }
+ }
+}
+
+// change value if key and subkeys are present
+func updateValue(key string, value interface{}, m interface{}, keys0 string, subkeys map[string]interface{}, cnt *int) {
+ // there are two possible options for the value of 'keys0': map[string]interface, []interface{}
+ // and 'key' is a key in the map or is a key in a map in a list.
+ switch m.(type) {
+ case map[string]interface{}: // gotta have the last key
+ if keys0 == "*" {
+ for k := range m.(map[string]interface{}) {
+ updateValue(key, value, m, k, subkeys, cnt)
+ }
+ return
+ }
+ endVal, _ := m.(map[string]interface{})[keys0]
+
+ // if newV key is the end of path, replace the value for path-end
+ // may be []interface{} - means replace just an entry w/ subkeys
+ // otherwise replace the keys0 value if subkeys are there
+ // NOTE: this will replace the subkeys, also
+ if key == keys0 {
+ switch endVal.(type) {
+ case map[string]interface{}:
+ if hasSubKeys(m, subkeys) {
+ (m.(map[string]interface{}))[keys0] = value
+ (*cnt)++
+ }
+ case []interface{}:
+ // without subkeys can't select list member to modify
+ // so key:value spec is it ...
+ if hasSubKeys(m, subkeys) {
+ (m.(map[string]interface{}))[keys0] = value
+ (*cnt)++
+ break
+ }
+ nv := make([]interface{}, 0)
+ var valmodified bool
+ for _, v := range endVal.([]interface{}) {
+ // check entry subkeys
+ if hasSubKeys(v, subkeys) {
+ // replace v with value
+ nv = append(nv, value)
+ valmodified = true
+ (*cnt)++
+ continue
+ }
+ nv = append(nv, v)
+ }
+ if valmodified {
+ (m.(map[string]interface{}))[keys0] = interface{}(nv)
+ }
+ default: // anything else is a strict replacement
+ if hasSubKeys(m, subkeys) {
+ (m.(map[string]interface{}))[keys0] = value
+ (*cnt)++
+ }
+ }
+ return
+ }
+
+ // so value is for an element of endVal
+ // if endVal is a map then 'key' must be there w/ subkeys
+ // if endVal is a list then 'key' must be in a list member w/ subkeys
+ switch endVal.(type) {
+ case map[string]interface{}:
+ if !hasSubKeys(endVal, subkeys) {
+ return
+ }
+ if _, ok := (endVal.(map[string]interface{}))[key]; ok {
+ (endVal.(map[string]interface{}))[key] = value
+ (*cnt)++
+ }
+ case []interface{}: // keys0 points to a list, check subkeys
+ for _, v := range endVal.([]interface{}) {
+ // got to be a map so we can replace value for 'key'
+ vv, vok := v.(map[string]interface{})
+ if !vok {
+ continue
+ }
+ if _, ok := vv[key]; !ok {
+ continue
+ }
+ if !hasSubKeys(vv, subkeys) {
+ continue
+ }
+ vv[key] = value
+ (*cnt)++
+ }
+ }
+ case []interface{}: // key may be in a list member
+ // don't need to handle keys0 == "*"; we're looking at everything, anyway.
+ for _, v := range m.([]interface{}) {
+ // only map values - we're looking for 'key'
+ mm, ok := v.(map[string]interface{})
+ if !ok {
+ continue
+ }
+ if _, ok := mm[key]; !ok {
+ continue
+ }
+ if !hasSubKeys(mm, subkeys) {
+ continue
+ }
+ mm[key] = value
+ (*cnt)++
+ }
+ }
+
+ // return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xml.go
new file mode 100644
index 000000000000..9aa04233924e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xml.go
@@ -0,0 +1,1410 @@
+// Copyright 2012-2016, 2018-2019 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// xml.go - basically the core of X2j for map[string]interface{} values.
+// NewMapXml, NewMapXmlReader, mv.Xml, mv.XmlWriter
+// see x2j and j2x for wrappers to provide end-to-end transformation of XML and JSON messages.
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// ------------------- NewMapXml & NewMapXmlReader ... -------------------------
+
+// If XmlCharsetReader != nil, it will be used to decode the XML, if required.
+// Note: if CustomDecoder != nil, then XmlCharsetReader is ignored;
+// set the CustomDecoder attribute instead.
+// import (
+// charset "code.google.com/p/go-charset/charset"
+// github.com/clbanning/mxj
+// )
+// ...
+// mxj.XmlCharsetReader = charset.NewReader
+// m, merr := mxj.NewMapXml(xmlValue)
+var XmlCharsetReader func(charset string, input io.Reader) (io.Reader, error)
+
+// NewMapXml - convert a XML doc into a Map
+// (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().)
+// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible.
+//
+// Converting XML to JSON is a simple as:
+// ...
+// mapVal, merr := mxj.NewMapXml(xmlVal)
+// if merr != nil {
+// // handle error
+// }
+// jsonVal, jerr := mapVal.Json()
+// if jerr != nil {
+// // handle error
+// }
+//
+// NOTES:
+// 1. Declarations, directives, process instructions and comments are NOT parsed.
+// 2. The 'xmlVal' will be parsed looking for an xml.StartElement, so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 3. If CoerceKeysToLower() has been called, then all key values will be lower case.
+// 4. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+// 5. If DisableTrimWhiteSpace(b bool) has been called, then all values will be trimmed or not. 'true' by default.
+func NewMapXml(xmlVal []byte, cast ...bool) (Map, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ return xmlToMap(xmlVal, r)
+}
+
+// Get next XML doc from an io.Reader as a Map value. Returns Map value.
+// NOTES:
+// 1. Declarations, directives, process instructions and comments are NOT parsed.
+// 2. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 3. If CoerceKeysToLower() has been called, then all key values will be lower case.
+// 4. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXmlReader(xmlReader io.Reader, cast ...bool) (Map, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+
+ // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder
+ // will wrap it in a bufio.Reader and seek on the file beyond where the
+ // xml.Decoder parses!
+ if _, ok := xmlReader.(io.ByteReader); !ok {
+ xmlReader = myByteReader(xmlReader) // see code at EOF
+ }
+
+ // build the map
+ return xmlReaderToMap(xmlReader, r)
+}
+
+// Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML.
+// NOTES:
+// 1. Declarations, directives, process instructions and comments are NOT parsed.
+// 2. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte
+// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact.
+// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large
+// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body
+// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call.
+// 3. The 'raw' return value may be larger than the XML text value.
+// 4. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 5. If CoerceKeysToLower() has been called, then all key values will be lower case.
+// 6. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXmlReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ // create TeeReader so we can retrieve raw XML
+ buf := make([]byte, 0)
+ wb := bytes.NewBuffer(buf)
+ trdr := myTeeReader(xmlReader, wb) // see code at EOF
+
+ m, err := xmlReaderToMap(trdr, r)
+
+ // retrieve the raw XML that was decoded
+ b := wb.Bytes()
+
+ if err != nil {
+ return nil, b, err
+ }
+
+ return m, b, nil
+}
+
+// xmlReaderToMap() - parse a XML io.Reader to a map[string]interface{} value
+func xmlReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) {
+ // parse the Reader
+ p := xml.NewDecoder(rdr)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlToMapParser("", nil, p, r)
+}
+
+// xmlToMap - convert a XML doc into map[string]interface{} value
+func xmlToMap(doc []byte, r bool) (map[string]interface{}, error) {
+ b := bytes.NewReader(doc)
+ p := xml.NewDecoder(b)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlToMapParser("", nil, p, r)
+}
+
+// ===================================== where the work happens =============================
+
+// PrependAttrWithHyphen. Prepend attribute tags with a hyphen.
+// Default is 'true'. (Not applicable to NewMapXmlSeq(), mv.XmlSeq(), etc.)
+// Note:
+// If 'false', unmarshaling and marshaling is not symmetric. Attributes will be
+// marshal'd as attr and may be part of a list.
+func PrependAttrWithHyphen(v bool) {
+ if v {
+ attrPrefix = "-"
+ lenAttrPrefix = len(attrPrefix)
+ return
+ }
+ attrPrefix = ""
+ lenAttrPrefix = len(attrPrefix)
+}
+
+// Include sequence id with inner tags. - per Sean Murphy, murphysean84@gmail.com.
+var includeTagSeqNum bool
+
+// IncludeTagSeqNum - include a "_seq":N key:value pair with each inner tag, denoting
+// its position when parsed. This is of limited usefulness, since list values cannot
+// be tagged with "_seq" without changing their depth in the Map.
+// So THIS SHOULD BE USED WITH CAUTION - see the test cases. Here's a sample of what
+// you get.
+/*
+
+
+
+
+ hello
+
+
+ parses as:
+
+ {
+ Obj:{
+ "-c":"la",
+ "-h":"da",
+ "-x":"dee",
+ "intObj":[
+ {
+ "-id"="3",
+ "_seq":"0" // if mxj.Cast is passed, then: "_seq":0
+ },
+ {
+ "-id"="2",
+ "_seq":"2"
+ }],
+ "intObj1":{
+ "-id":"1",
+ "_seq":"1"
+ },
+ "StrObj":{
+ "#text":"hello", // simple element value gets "#text" tag
+ "_seq":"3"
+ }
+ }
+ }
+*/
+func IncludeTagSeqNum(b ...bool) {
+ if len(b) == 0 {
+ includeTagSeqNum = !includeTagSeqNum
+ } else if len(b) == 1 {
+ includeTagSeqNum = b[0]
+ }
+}
+
+// all keys will be "lower case"
+var lowerCase bool
+
+// Coerce all tag values to keys in lower case. This is useful if you've got sources with variable
+// tag capitalization, and you want to use m.ValuesForKeys(), etc., with the key or path spec
+// in lower case.
+// CoerceKeysToLower() will toggle the coercion flag true|false - on|off
+// CoerceKeysToLower(true|false) will set the coercion flag on|off
+//
+// NOTE: only recognized by NewMapXml, NewMapXmlReader, and NewMapXmlReaderRaw functions as well as
+// the associated HandleXmlReader and HandleXmlReaderRaw.
+func CoerceKeysToLower(b ...bool) {
+ if len(b) == 0 {
+ lowerCase = !lowerCase
+ } else if len(b) == 1 {
+ lowerCase = b[0]
+ }
+}
+
+// disableTrimWhiteSpace sets if the white space should be removed or not
+var disableTrimWhiteSpace bool
+var trimRunes = "\t\r\b\n "
+
+// DisableTrimWhiteSpace set if the white space should be trimmed or not. By default white space is always trimmed. If
+// no argument is provided, trim white space will be disabled.
+func DisableTrimWhiteSpace(b ...bool) {
+ if len(b) == 0 {
+ disableTrimWhiteSpace = true
+ } else {
+ disableTrimWhiteSpace = b[0]
+ }
+
+ if disableTrimWhiteSpace {
+ trimRunes = "\t\r\b\n"
+ } else {
+ trimRunes = "\t\r\b\n "
+ }
+}
+
+// 25jun16: Allow user to specify the "prefix" character for XML attribute key labels.
+// We do this by replacing '`' constant with attrPrefix var, replacing useHyphen with attrPrefix = "",
+// and adding a SetAttrPrefix(s string) function.
+
+var attrPrefix string = `-` // the default
+var lenAttrPrefix int = 1 // the default
+
+// SetAttrPrefix changes the default, "-", to the specified value, s.
+// SetAttrPrefix("") is the same as PrependAttrWithHyphen(false).
+// (Not applicable for NewMapXmlSeq(), mv.XmlSeq(), etc.)
+func SetAttrPrefix(s string) {
+ attrPrefix = s
+ lenAttrPrefix = len(attrPrefix)
+}
+
+// 18jan17: Allows user to specify if the map keys should be in snake case instead
+// of the default hyphenated notation.
+var snakeCaseKeys bool
+
+// CoerceKeysToSnakeCase changes the default, false, to the specified value, b.
+// Note: the attribute prefix will be a hyphen, '-', or what ever string value has
+// been specified using SetAttrPrefix.
+func CoerceKeysToSnakeCase(b ...bool) {
+ if len(b) == 0 {
+ snakeCaseKeys = !snakeCaseKeys
+ } else if len(b) == 1 {
+ snakeCaseKeys = b[0]
+ }
+}
+
+// 10jan19: use of pull request #57 should be conditional - legacy code assumes
+// numeric values are float64.
+var castToInt bool
+
+// CastValuesToInt tries to coerce numeric valus to int64 or uint64 instead of the
+// default float64. Repeated calls with no argument will toggle this on/off, or this
+// handling will be set with the value of 'b'.
+func CastValuesToInt(b ...bool) {
+ if len(b) == 0 {
+ castToInt = !castToInt
+ } else if len(b) == 1 {
+ castToInt = b[0]
+ }
+}
+
+// 05feb17: support processing XMPP streams (issue #36)
+var handleXMPPStreamTag bool
+
+// HandleXMPPStreamTag causes decoder to parse XMPP elements.
+// If called with no argument, XMPP stream element handling is toggled on/off.
+// (See xmppStream_test.go for example.)
+// If called with NewMapXml, NewMapXmlReader, New MapXmlReaderRaw the "stream"
+// element will be returned as:
+// map["stream"]interface{}{map[-]interface{}}.
+// If called with NewMapSeq, NewMapSeqReader, NewMapSeqReaderRaw the "stream"
+// element will be returned as:
+// map["stream:stream"]interface{}{map["#attr"]interface{}{map[string]interface{}}}
+// where the "#attr" values have "#text" and "#seq" keys. (See NewMapXmlSeq.)
+func HandleXMPPStreamTag(b ...bool) {
+ if len(b) == 0 {
+ handleXMPPStreamTag = !handleXMPPStreamTag
+ } else if len(b) == 1 {
+ handleXMPPStreamTag = b[0]
+ }
+}
+
+// 21jan18 - decode all values as map["#text":value] (issue #56)
+var decodeSimpleValuesAsMap bool
+
+// DecodeSimpleValuesAsMap forces all values to be decoded as map["#text":].
+// If called with no argument, the decoding is toggled on/off.
+//
+// By default the NewMapXml functions decode simple values without attributes as
+// map[:]. This function causes simple values without attributes to be
+// decoded the same as simple values with attributes - map[:map["#text":]].
+func DecodeSimpleValuesAsMap(b ...bool) {
+ if len(b) == 0 {
+ decodeSimpleValuesAsMap = !decodeSimpleValuesAsMap
+ } else if len(b) == 1 {
+ decodeSimpleValuesAsMap = b[0]
+ }
+}
+
+// xmlToMapParser (2015.11.12) - load a 'clean' XML doc into a map[string]interface{} directly.
+// A refactoring of xmlToTreeParser(), markDuplicate() and treeToMap() - here, all-in-one.
+// We've removed the intermediate *node tree with the allocation and subsequent rescanning.
+func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) {
+ if lowerCase {
+ skey = strings.ToLower(skey)
+ }
+ if snakeCaseKeys {
+ skey = strings.Replace(skey, "-", "_", -1)
+ }
+
+ // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'.
+ // Unless 'skey' is a simple element w/o attributes, in which case the xml.CharData value is the value.
+ var n, na map[string]interface{}
+ var seq int // for includeTagSeqNum
+
+ // Allocate maps and load attributes, if any.
+ // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through
+ // to get StartElement then recurse with skey==xml.StartElement.Name.Local
+ // where we begin allocating map[string]interface{} values 'n' and 'na'.
+ if skey != "" {
+ n = make(map[string]interface{}) // old n
+ na = make(map[string]interface{}) // old n.nodes
+ if len(a) > 0 {
+ for _, v := range a {
+ if snakeCaseKeys {
+ v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1)
+ }
+ var key string
+ key = attrPrefix + v.Name.Local
+ if lowerCase {
+ key = strings.ToLower(key)
+ }
+ if xmlEscapeCharsDecoder { // per issue#84
+ v.Value = escapeChars(v.Value)
+ }
+ na[key] = cast(v.Value, r, key)
+ }
+ }
+ }
+ // Return XMPP message.
+ if handleXMPPStreamTag && skey == "stream" {
+ n[skey] = na
+ return n, nil
+ }
+
+ for {
+ t, err := p.Token()
+ if err != nil {
+ if err != io.EOF {
+ return nil, errors.New("xml.Decoder.Token() - " + err.Error())
+ }
+ return nil, err
+ }
+ switch t.(type) {
+ case xml.StartElement:
+ tt := t.(xml.StartElement)
+
+ // First call to xmlToMapParser() doesn't pass xml.StartElement - the map key.
+ // So when the loop is first entered, the first token is the root tag along
+ // with any attributes, which we process here.
+ //
+ // Subsequent calls to xmlToMapParser() will pass in tag+attributes for
+ // processing before getting the next token which is the element value,
+ // which is done above.
+ if skey == "" {
+ return xmlToMapParser(tt.Name.Local, tt.Attr, p, r)
+ }
+
+ // If not initializing the map, parse the element.
+ // len(nn) == 1, necessarily - it is just an 'n'.
+ nn, err := xmlToMapParser(tt.Name.Local, tt.Attr, p, r)
+ if err != nil {
+ return nil, err
+ }
+
+ // The nn map[string]interface{} value is a na[nn_key] value.
+ // We need to see if nn_key already exists - means we're parsing a list.
+ // This may require converting na[nn_key] value into []interface{} type.
+ // First, extract the key:val for the map - it's a singleton.
+ // Note:
+ // * if CoerceKeysToLower() called, then key will be lower case.
+ // * if CoerceKeysToSnakeCase() called, then key will be converted to snake case.
+ var key string
+ var val interface{}
+ for key, val = range nn {
+ break
+ }
+
+ // IncludeTagSeqNum requests that the element be augmented with a "_seq" sub-element.
+ // In theory, we don't need this if len(na) == 1. But, we don't know what might
+ // come next - we're only parsing forward. So if you ask for 'includeTagSeqNum' you
+ // get it on every element. (Personally, I never liked this, but I added it on request
+ // and did get a $50 Amazon gift card in return - now we support it for backwards compatibility!)
+ if includeTagSeqNum {
+ switch val.(type) {
+ case []interface{}:
+ // noop - There's no clean way to handle this w/o changing message structure.
+ case map[string]interface{}:
+ val.(map[string]interface{})["_seq"] = seq // will overwrite an "_seq" XML tag
+ seq++
+ case interface{}: // a non-nil simple element: string, float64, bool
+ v := map[string]interface{}{"#text": val}
+ v["_seq"] = seq
+ seq++
+ val = v
+ }
+ }
+
+ // 'na' holding sub-elements of n.
+ // See if 'key' already exists.
+ // If 'key' exists, then this is a list, if not just add key:val to na.
+ if v, ok := na[key]; ok {
+ var a []interface{}
+ switch v.(type) {
+ case []interface{}:
+ a = v.([]interface{})
+ default: // anything else - note: v.(type) != nil
+ a = []interface{}{v}
+ }
+ a = append(a, val)
+ na[key] = a
+ } else {
+ na[key] = val // save it as a singleton
+ }
+ case xml.EndElement:
+ // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case.
+ if len(n) == 0 {
+ // If len(na)==0 we have an empty element == "";
+ // it has no xml.Attr nor xml.CharData.
+ // Note: in original node-tree parser, val defaulted to "";
+ // so we always had the default if len(node.nodes) == 0.
+ if len(na) > 0 {
+ n[skey] = na
+ } else {
+ n[skey] = "" // empty element
+ }
+ } else if len(n) == 1 && len(na) > 0 {
+ // it's a simple element w/ no attributes w/ subelements
+ for _, v := range n {
+ na["#text"] = v
+ }
+ n[skey] = na
+ }
+ return n, nil
+ case xml.CharData:
+ // clean up possible noise
+ tt := strings.Trim(string(t.(xml.CharData)), trimRunes)
+ if xmlEscapeCharsDecoder { // issue#84
+ tt = escapeChars(tt)
+ }
+ if len(tt) > 0 {
+ if len(na) > 0 || decodeSimpleValuesAsMap {
+ na["#text"] = cast(tt, r, "#text")
+ } else if skey != "" {
+ n[skey] = cast(tt, r, skey)
+ } else {
+ // per Adrian (http://www.adrianlungu.com/) catch stray text
+ // in decoder stream -
+ // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374
+ // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get
+ // a p.Token() decoding error when the BOM is UTF-16 or UTF-32.
+ continue
+ }
+ }
+ default:
+ // noop
+ }
+ }
+}
+
+var castNanInf bool
+
+// Cast "Nan", "Inf", "-Inf" XML values to 'float64'.
+// By default, these values will be decoded as 'string'.
+func CastNanInf(b ...bool) {
+ if len(b) == 0 {
+ castNanInf = !castNanInf
+ } else if len(b) == 1 {
+ castNanInf = b[0]
+ }
+}
+
+// cast - try to cast string values to bool or float64
+// 't' is the tag key that can be checked for 'not-casting'
+func cast(s string, r bool, t string) interface{} {
+ if checkTagToSkip != nil && t != "" && checkTagToSkip(t) {
+ // call the check-function here with 't[0]'
+ // if 'true' return s
+ return s
+ }
+
+ if r {
+ // handle nan and inf
+ if !castNanInf {
+ switch strings.ToLower(s) {
+ case "nan", "inf", "-inf":
+ return s
+ }
+ }
+
+ // handle numeric strings ahead of boolean
+ if castToInt {
+ if f, err := strconv.ParseInt(s, 10, 64); err == nil {
+ return f
+ }
+ if f, err := strconv.ParseUint(s, 10, 64); err == nil {
+ return f
+ }
+ }
+
+ if castToFloat {
+ if f, err := strconv.ParseFloat(s, 64); err == nil {
+ return f
+ }
+ }
+
+ // ParseBool treats "1"==true & "0"==false, we've already scanned those
+ // values as float64. See if value has 't' or 'f' as initial screen to
+ // minimize calls to ParseBool; also, see if len(s) < 6.
+ if castToBool {
+ if len(s) > 0 && len(s) < 6 {
+ switch s[:1] {
+ case "t", "T", "f", "F":
+ if b, err := strconv.ParseBool(s); err == nil {
+ return b
+ }
+ }
+ }
+ }
+ }
+ return s
+}
+
+// pull request, #59
+var castToFloat = true
+
+// CastValuesToFloat can be used to skip casting to float64 when
+// "cast" argument is 'true' in NewMapXml, etc.
+// Default is true.
+func CastValuesToFloat(b ...bool) {
+ if len(b) == 0 {
+ castToFloat = !castToFloat
+ } else if len(b) == 1 {
+ castToFloat = b[0]
+ }
+}
+
+var castToBool = true
+
+// CastValuesToBool can be used to skip casting to bool when
+// "cast" argument is 'true' in NewMapXml, etc.
+// Default is true.
+func CastValuesToBool(b ...bool) {
+ if len(b) == 0 {
+ castToBool = !castToBool
+ } else if len(b) == 1 {
+ castToBool = b[0]
+ }
+}
+
+// checkTagToSkip - switch to address Issue #58
+
+var checkTagToSkip func(string) bool
+
+// SetCheckTagToSkipFunc registers function to test whether the value
+// for a tag should be cast to bool or float64 when "cast" argument is 'true'.
+// (Dot tag path notation is not supported.)
+// NOTE: key may be "#text" if it's a simple element with attributes
+// or "decodeSimpleValuesAsMap == true".
+// NOTE: does not apply to NewMapXmlSeq... functions.
+func SetCheckTagToSkipFunc(fn func(string) bool) {
+ checkTagToSkip = fn
+}
+
+// ------------------ END: NewMapXml & NewMapXmlReader -------------------------
+
+// ------------------ mv.Xml & mv.XmlWriter - from j2x ------------------------
+
+const (
+ DefaultRootTag = "doc"
+)
+
+var useGoXmlEmptyElemSyntax bool
+
+// XmlGoEmptyElemSyntax() - rather than .
+// Go's encoding/xml package marshals empty XML elements as . By default this package
+// encodes empty elements as . If you're marshaling Map values that include structures
+// (which are passed to xml.Marshal for encoding), this will let you conform to the standard package.
+func XmlGoEmptyElemSyntax() {
+ useGoXmlEmptyElemSyntax = true
+}
+
+// XmlDefaultEmptyElemSyntax() - rather than .
+// Return XML encoding for empty elements to the default package setting.
+// Reverses effect of XmlGoEmptyElemSyntax().
+func XmlDefaultEmptyElemSyntax() {
+ useGoXmlEmptyElemSyntax = false
+}
+
+// ------- issue #88 ----------
+// xmlCheckIsValid set switch to force decoding the encoded XML to
+// see if it is valid XML.
+var xmlCheckIsValid bool
+
+// XmlCheckIsValid forces the encoded XML to be checked for validity.
+func XmlCheckIsValid(b ...bool) {
+ if len(b) == 1 {
+ xmlCheckIsValid = b[0]
+ return
+ }
+ xmlCheckIsValid = !xmlCheckIsValid
+}
+
+// Encode a Map as XML. The companion of NewMapXml().
+// The following rules apply.
+// - The key label "#text" is treated as the value for a simple element with attributes.
+// - Map keys that begin with a hyphen, '-', are interpreted as attributes.
+// It is an error if the attribute doesn't have a []byte, string, number, or boolean value.
+// - Map value type encoding:
+// > string, bool, float64, int, int32, int64, float32: per "%v" formating
+// > []bool, []uint8: by casting to string
+// > structures, etc.: handed to xml.Marshal() - if there is an error, the element
+// value is "UNKNOWN"
+// - Elements with only attribute values or are null are terminated using "/>".
+// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible.
+// Thus, `{ "key":"value" }` encodes as "value ".
+// - To encode empty elements in a syntax consistent with encoding/xml call UseGoXmlEmptyElementSyntax().
+// The attributes tag=value pairs are alphabetized by "tag". Also, when encoding map[string]interface{} values -
+// complex elements, etc. - the key:value pairs are alphabetized by key so the resulting tags will appear sorted.
+func (mv Map) Xml(rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+ var err error
+ b := new(bytes.Buffer)
+ p := new(pretty) // just a stub
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ for key, value := range m {
+ // if it an array, see if all values are map[string]interface{}
+ // we force a new root tag if we'll end up with no key:value in the list
+ // so: key:[string_val, bool:true] --> string_val true
+ switch value.(type) {
+ case []interface{}:
+ for _, v := range value.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}: // noop
+ default: // anything else
+ err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p)
+ goto done
+ }
+ }
+ }
+ err = marshalMapToXmlIndent(false, b, key, value, p)
+ }
+ } else if len(rootTag) == 1 {
+ err = marshalMapToXmlIndent(false, b, rootTag[0], m, p)
+ } else {
+ err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p)
+ }
+done:
+ if xmlCheckIsValid {
+ d := xml.NewDecoder(bytes.NewReader(b.Bytes()))
+ for {
+ _, err = d.Token()
+ if err == io.EOF {
+ err = nil
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return b.Bytes(), err
+}
+
+// The following implementation is provided only for symmetry with NewMapXmlReader[Raw]
+// The names will also provide a key for the number of return arguments.
+
+// Writes the Map as XML on the Writer.
+// See Xml() for encoding rules.
+func (mv Map) XmlWriter(xmlWriter io.Writer, rootTag ...string) error {
+ x, err := mv.Xml(rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// Writes the Map as XML on the Writer. []byte is the raw XML that was written.
+// See Xml() for encoding rules.
+/*
+func (mv Map) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) {
+ x, err := mv.Xml(rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+*/
+
+// Writes the Map as pretty XML on the Writer.
+// See Xml() for encoding rules.
+func (mv Map) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error {
+ x, err := mv.XmlIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written.
+// See Xml() for encoding rules.
+/*
+func (mv Map) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) {
+ x, err := mv.XmlIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+*/
+
+// -------------------- END: mv.Xml & mv.XmlWriter -------------------------------
+
+// -------------- Handle XML stream by processing Map value --------------------
+
+// Default poll delay to keep Handler from spinning on an open stream
+// like sitting on os.Stdin waiting for imput.
+var xhandlerPollInterval = time.Millisecond
+
+// Bulk process XML using handlers that process a Map value.
+// 'rdr' is an io.Reader for XML (stream)
+// 'mapHandler' is the Map processor. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'.
+func HandleXmlReader(xmlReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error {
+ var n int
+ for {
+ m, merr := NewMapXmlReader(xmlReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ time.Sleep(xhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
+
+// Bulk process XML using handlers that process a Map value and the raw XML.
+// 'rdr' is an io.Reader for XML (stream)
+// 'mapHandler' is the Map and raw XML - []byte - processor. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error and raw XML processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'.
+// See NewMapXmlReaderRaw for comment on performance associated with retrieving raw XML from a Reader.
+func HandleXmlReaderRaw(xmlReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error {
+ var n int
+ for {
+ m, raw, merr := NewMapXmlReaderRaw(xmlReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr, raw); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m, raw); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ time.Sleep(xhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
+
+// ----------------- END: Handle XML stream by processing Map value --------------
+
+// -------- a hack of io.TeeReader ... need one that's an io.ByteReader for xml.NewDecoder() ----------
+
+// This is a clone of io.TeeReader with the additional method t.ReadByte().
+// Thus, this TeeReader is also an io.ByteReader.
+// This is necessary because xml.NewDecoder uses a ByteReader not a Reader. It appears to have been written
+// with bufio.Reader or bytes.Reader in mind ... not a generic io.Reader, which doesn't have to have ReadByte()..
+// If NewDecoder is passed a Reader that does not satisfy ByteReader() it wraps the Reader with
+// bufio.NewReader and uses ReadByte rather than Read that runs the TeeReader pipe logic.
+
+type teeReader struct {
+ r io.Reader
+ w io.Writer
+ b []byte
+}
+
+func myTeeReader(r io.Reader, w io.Writer) io.Reader {
+ b := make([]byte, 1)
+ return &teeReader{r, w, b}
+}
+
+// need for io.Reader - but we don't use it ...
+func (t *teeReader) Read(p []byte) (int, error) {
+ return 0, nil
+}
+
+func (t *teeReader) ReadByte() (byte, error) {
+ n, err := t.r.Read(t.b)
+ if n > 0 {
+ if _, err := t.w.Write(t.b[:1]); err != nil {
+ return t.b[0], err
+ }
+ }
+ return t.b[0], err
+}
+
+// For use with NewMapXmlReader & NewMapXmlSeqReader.
+type byteReader struct {
+ r io.Reader
+ b []byte
+}
+
+func myByteReader(r io.Reader) io.Reader {
+ b := make([]byte, 1)
+ return &byteReader{r, b}
+}
+
+// Need for io.Reader interface ...
+// Needed if reading a malformed http.Request.Body - issue #38.
+func (b *byteReader) Read(p []byte) (int, error) {
+ return b.r.Read(p)
+}
+
+func (b *byteReader) ReadByte() (byte, error) {
+ _, err := b.r.Read(b.b)
+ if len(b.b) > 0 {
+ return b.b[0], nil
+ }
+ var c byte
+ return c, err
+}
+
+// ----------------------- END: io.TeeReader hack -----------------------------------
+
+// ---------------------- XmlIndent - from j2x package ----------------------------
+
+// Encode a map[string]interface{} as a pretty XML string.
+// See Xml for encoding rules.
+func (mv Map) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+
+ var err error
+ b := new(bytes.Buffer)
+ p := new(pretty)
+ p.indent = indent
+ p.padding = prefix
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ // this can extract the key for the single map element
+ // use it if it isn't a key for a list
+ for key, value := range m {
+ if _, ok := value.([]interface{}); ok {
+ err = marshalMapToXmlIndent(true, b, DefaultRootTag, m, p)
+ } else {
+ err = marshalMapToXmlIndent(true, b, key, value, p)
+ }
+ }
+ } else if len(rootTag) == 1 {
+ err = marshalMapToXmlIndent(true, b, rootTag[0], m, p)
+ } else {
+ err = marshalMapToXmlIndent(true, b, DefaultRootTag, m, p)
+ }
+ if xmlCheckIsValid {
+ d := xml.NewDecoder(bytes.NewReader(b.Bytes()))
+ for {
+ _, err = d.Token()
+ if err == io.EOF {
+ err = nil
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return b.Bytes(), err
+}
+
+type pretty struct {
+ indent string
+ cnt int
+ padding string
+ mapDepth int
+ start int
+}
+
+func (p *pretty) Indent() {
+ p.padding += p.indent
+ p.cnt++
+}
+
+func (p *pretty) Outdent() {
+ if p.cnt > 0 {
+ p.padding = p.padding[:len(p.padding)-len(p.indent)]
+ p.cnt--
+ }
+}
+
+// where the work actually happens
+// returns an error if an attribute is not atomic
+// NOTE: 01may20 - replaces mapToXmlIndent(); uses bytes.Buffer instead for string appends.
+func marshalMapToXmlIndent(doIndent bool, b *bytes.Buffer, key string, value interface{}, pp *pretty) error {
+ var err error
+ var endTag bool
+ var isSimple bool
+ var elen int
+ p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start}
+
+ // per issue #48, 18apr18 - try and coerce maps to map[string]interface{}
+ // Don't need for mapToXmlSeqIndent, since maps there are decoded by NewMapXmlSeq().
+ if reflect.ValueOf(value).Kind() == reflect.Map {
+ switch value.(type) {
+ case map[string]interface{}:
+ default:
+ val := make(map[string]interface{})
+ vv := reflect.ValueOf(value)
+ keys := vv.MapKeys()
+ for _, k := range keys {
+ val[fmt.Sprint(k)] = vv.MapIndex(k).Interface()
+ }
+ value = val
+ }
+ }
+
+ // 14jul20. The following block of code has become something of a catch all for odd stuff
+ // that might be passed in as a result of casting an arbitrary map[] to an mxj.Map
+ // value and then call m.Xml or m.XmlIndent. See issue #71 (and #73) for such edge cases.
+ switch value.(type) {
+ // these types are handled during encoding
+ case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32, json.Number:
+ case []map[string]interface{}, []string, []float64, []bool, []int, []int32, []int64, []float32, []json.Number:
+ case []interface{}:
+ case nil:
+ value = ""
+ default:
+ // see if value is a struct, if so marshal using encoding/xml package
+ if reflect.ValueOf(value).Kind() == reflect.Struct {
+ if v, err := xml.Marshal(value); err != nil {
+ return err
+ } else {
+ value = string(v)
+ }
+ } else {
+ // coerce eveything else into a string value
+ value = fmt.Sprint(value)
+ }
+ }
+
+ // start the XML tag with required indentaton and padding
+ if doIndent {
+ if _, err = b.WriteString(p.padding); err != nil {
+ return err
+ }
+ }
+ switch value.(type) {
+ case []interface{}:
+ default:
+ if _, err = b.WriteString(`<` + key); err != nil {
+ return err
+ }
+ }
+
+ switch value.(type) {
+ case map[string]interface{}:
+ vv := value.(map[string]interface{})
+ lenvv := len(vv)
+ // scan out attributes - attribute keys have prepended attrPrefix
+ attrlist := make([][2]string, len(vv))
+ var n int
+ var ss string
+ for k, v := range vv {
+ if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix {
+ switch v.(type) {
+ case string:
+ if xmlEscapeChars {
+ ss = escapeChars(v.(string))
+ } else {
+ ss = v.(string)
+ }
+ attrlist[n][0] = k[lenAttrPrefix:]
+ attrlist[n][1] = ss
+ case float64, bool, int, int32, int64, float32, json.Number:
+ attrlist[n][0] = k[lenAttrPrefix:]
+ attrlist[n][1] = fmt.Sprintf("%v", v)
+ case []byte:
+ if xmlEscapeChars {
+ ss = escapeChars(string(v.([]byte)))
+ } else {
+ ss = string(v.([]byte))
+ }
+ attrlist[n][0] = k[lenAttrPrefix:]
+ attrlist[n][1] = ss
+ default:
+ return fmt.Errorf("invalid attribute value for: %s:<%T>", k, v)
+ }
+ n++
+ }
+ }
+ if n > 0 {
+ attrlist = attrlist[:n]
+ sort.Sort(attrList(attrlist))
+ for _, v := range attrlist {
+ if _, err = b.WriteString(` ` + v[0] + `="` + v[1] + `"`); err != nil {
+ return err
+ }
+ }
+ }
+ // only attributes?
+ if n == lenvv {
+ if useGoXmlEmptyElemSyntax {
+ if _, err = b.WriteString(`` + key + ">"); err != nil {
+ return err
+ }
+ } else {
+ if _, err = b.WriteString(`/>`); err != nil {
+ return err
+ }
+ }
+ break
+ }
+
+ // simple element? Note: '#text" is an invalid XML tag.
+ isComplex := false
+ if v, ok := vv["#text"]; ok && n+1 == lenvv {
+ // just the value and attributes
+ switch v.(type) {
+ case string:
+ if xmlEscapeChars {
+ v = escapeChars(v.(string))
+ } else {
+ v = v.(string)
+ }
+ case []byte:
+ if xmlEscapeChars {
+ v = escapeChars(string(v.([]byte)))
+ } else {
+ v = string(v.([]byte))
+ }
+ }
+ if _, err = b.WriteString(">" + fmt.Sprintf("%v", v)); err != nil {
+ return err
+ }
+ endTag = true
+ elen = 1
+ isSimple = true
+ break
+ } else if ok {
+ // need to handle when there are subelements in addition to the simple element value
+ // issue #90
+ switch v.(type) {
+ case string:
+ if xmlEscapeChars {
+ v = escapeChars(v.(string))
+ } else {
+ v = v.(string)
+ }
+ case []byte:
+ if xmlEscapeChars {
+ v = escapeChars(string(v.([]byte)))
+ } else {
+ v = string(v.([]byte))
+ }
+ }
+ if _, err = b.WriteString(">" + fmt.Sprintf("%v", v)); err != nil {
+ return err
+ }
+ isComplex = true
+ }
+
+ // close tag with possible attributes
+ if !isComplex {
+ if _, err = b.WriteString(">"); err != nil {
+ return err
+ }
+ }
+ if doIndent {
+ // *s += "\n"
+ if _, err = b.WriteString("\n"); err != nil {
+ return err
+ }
+ }
+ // something more complex
+ p.mapDepth++
+ // extract the map k:v pairs and sort on key
+ elemlist := make([][2]interface{}, len(vv))
+ n = 0
+ for k, v := range vv {
+ if k == "#text" {
+ // simple element handled above
+ continue
+ }
+ if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix {
+ continue
+ }
+ elemlist[n][0] = k
+ elemlist[n][1] = v
+ n++
+ }
+ elemlist = elemlist[:n]
+ sort.Sort(elemList(elemlist))
+ var i int
+ for _, v := range elemlist {
+ switch v[1].(type) {
+ case []interface{}:
+ default:
+ if i == 0 && doIndent {
+ p.Indent()
+ }
+ }
+ i++
+ if err := marshalMapToXmlIndent(doIndent, b, v[0].(string), v[1], p); err != nil {
+ return err
+ }
+ switch v[1].(type) {
+ case []interface{}: // handled in []interface{} case
+ default:
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ i--
+ }
+ p.mapDepth--
+ endTag = true
+ elen = 1 // we do have some content ...
+ case []interface{}:
+ // special case - found during implementing Issue #23
+ if len(value.([]interface{})) == 0 {
+ if doIndent {
+ if _, err = b.WriteString(p.padding + p.indent); err != nil {
+ return err
+ }
+ }
+ if _, err = b.WriteString("<" + key); err != nil {
+ return err
+ }
+ elen = 0
+ endTag = true
+ break
+ }
+ for _, v := range value.([]interface{}) {
+ if doIndent {
+ p.Indent()
+ }
+ if err := marshalMapToXmlIndent(doIndent, b, key, v, p); err != nil {
+ return err
+ }
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ return nil
+ case []string:
+ // This was added by https://github.com/slotix ... not a type that
+ // would be encountered if mv generated from NewMapXml, NewMapJson.
+ // Could be encountered in AnyXml(), so we'll let it stay, though
+ // it should be merged with case []interface{}, above.
+ //quick fix for []string type
+ //[]string should be treated exaclty as []interface{}
+ if len(value.([]string)) == 0 {
+ if doIndent {
+ if _, err = b.WriteString(p.padding + p.indent); err != nil {
+ return err
+ }
+ }
+ if _, err = b.WriteString("<" + key); err != nil {
+ return err
+ }
+ elen = 0
+ endTag = true
+ break
+ }
+ for _, v := range value.([]string) {
+ if doIndent {
+ p.Indent()
+ }
+ if err := marshalMapToXmlIndent(doIndent, b, key, v, p); err != nil {
+ return err
+ }
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ return nil
+ case nil:
+ // terminate the tag
+ if doIndent {
+ // *s += p.padding
+ if _, err = b.WriteString(p.padding); err != nil {
+ return err
+ }
+ }
+ if _, err = b.WriteString("<" + key); err != nil {
+ return err
+ }
+ endTag, isSimple = true, true
+ break
+ default: // handle anything - even goofy stuff
+ elen = 0
+ switch value.(type) {
+ case string:
+ v := value.(string)
+ if xmlEscapeChars {
+ v = escapeChars(v)
+ }
+ elen = len(v)
+ if elen > 0 {
+ // *s += ">" + v
+ if _, err = b.WriteString(">" + v); err != nil {
+ return err
+ }
+ }
+ case float64, bool, int, int32, int64, float32, json.Number:
+ v := fmt.Sprintf("%v", value)
+ elen = len(v) // always > 0
+ if _, err = b.WriteString(">" + v); err != nil {
+ return err
+ }
+ case []byte: // NOTE: byte is just an alias for uint8
+ // similar to how xml.Marshal handles []byte structure members
+ v := string(value.([]byte))
+ if xmlEscapeChars {
+ v = escapeChars(v)
+ }
+ elen = len(v)
+ if elen > 0 {
+ // *s += ">" + v
+ if _, err = b.WriteString(">" + v); err != nil {
+ return err
+ }
+ }
+ default:
+ if _, err = b.WriteString(">"); err != nil {
+ return err
+ }
+ var v []byte
+ var err error
+ if doIndent {
+ v, err = xml.MarshalIndent(value, p.padding, p.indent)
+ } else {
+ v, err = xml.Marshal(value)
+ }
+ if err != nil {
+ if _, err = b.WriteString(">UNKNOWN"); err != nil {
+ return err
+ }
+ } else {
+ elen = len(v)
+ if elen > 0 {
+ if _, err = b.Write(v); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ isSimple = true
+ endTag = true
+ }
+ if endTag {
+ if doIndent {
+ if !isSimple {
+ if _, err = b.WriteString(p.padding); err != nil {
+ return err
+ }
+ }
+ }
+ if elen > 0 || useGoXmlEmptyElemSyntax {
+ if elen == 0 {
+ if _, err = b.WriteString(">"); err != nil {
+ return err
+ }
+ }
+ if _, err = b.WriteString(`` + key + ">"); err != nil {
+ return err
+ }
+ } else {
+ if _, err = b.WriteString(`/>`); err != nil {
+ return err
+ }
+ }
+ }
+ if doIndent {
+ if p.cnt > p.start {
+ if _, err = b.WriteString("\n"); err != nil {
+ return err
+ }
+ }
+ p.Outdent()
+ }
+
+ return nil
+}
+
+// ============================ sort interface implementation =================
+
+type attrList [][2]string
+
+func (a attrList) Len() int {
+ return len(a)
+}
+
+func (a attrList) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func (a attrList) Less(i, j int) bool {
+ return a[i][0] <= a[j][0]
+}
+
+type elemList [][2]interface{}
+
+func (e elemList) Len() int {
+ return len(e)
+}
+
+func (e elemList) Swap(i, j int) {
+ e[i], e[j] = e[j], e[i]
+}
+
+func (e elemList) Less(i, j int) bool {
+ return e[i][0].(string) <= e[j][0].(string)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xmlseq.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xmlseq.go
new file mode 100644
index 000000000000..80632bd3c3bc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xmlseq.go
@@ -0,0 +1,877 @@
+// Copyright 2012-2016, 2019 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// xmlseq.go - version of xml.go with sequence # injection on Decoding and sorting on Encoding.
+// Also, handles comments, directives and process instructions.
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "sort"
+ "strings"
+)
+
+// MapSeq is like Map but contains seqencing indices to allow recovering the original order of
+// the XML elements when the map[string]interface{} is marshaled. Element attributes are
+// stored as a map["#attr"]map[]map[string]interface{}{"#text":"", "#seq":}
+// value instead of denoting the keys with a prefix character. Also, comments, directives and
+// process instructions are preserved.
+type MapSeq map[string]interface{}
+
+// NoRoot is returned by NewXmlSeq, etc., when a comment, directive or procinstr element is parsed
+// in the XML data stream and the element is not contained in an XML object with a root element.
+var NoRoot = errors.New("no root key")
+var NO_ROOT = NoRoot // maintain backwards compatibility
+
+// ------------------- NewMapXmlSeq & NewMapXmlSeqReader ... -------------------------
+
+// NewMapXmlSeq converts a XML doc into a MapSeq value with elements id'd with decoding sequence key represented
+// as map["#seq"].
+// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible.
+// NOTE: "#seq" key/value pairs are removed on encoding with msv.Xml() / msv.XmlIndent().
+// • attributes are a map - map["#attr"]map["attr_key"]map[string]interface{}{"#text":, "#seq":}
+// • all simple elements are decoded as map["#text"]interface{} with a "#seq" k:v pair, as well.
+// • lists always decode as map["list_tag"][]map[string]interface{} where the array elements are maps that
+// include a "#seq" k:v pair based on sequence they are decoded. Thus, XML like:
+//
+// value 1
+// value 2
+// value 3
+//
+// is decoded as:
+// doc :
+// ltag :[[]interface{}]
+// [item: 0]
+// #seq :[int] 0
+// #text :[string] value 1
+// [item: 1]
+// #seq :[int] 2
+// #text :[string] value 3
+// newtag :
+// #seq :[int] 1
+// #text :[string] value 2
+// It will encode in proper sequence even though the MapSeq representation merges all "ltag" elements in an array.
+// • comments - "" - are decoded as map["#comment"]map["#text"]"cmnt_text" with a "#seq" k:v pair.
+// • directives - "" - are decoded as map["#directive"]map[#text"]"directive_text" with a "#seq" k:v pair.
+// • process instructions - "" - are decoded as map["#procinst"]interface{} where the #procinst value
+// is of map[string]interface{} type with the following keys: #target, #inst, and #seq.
+// • comments, directives, and procinsts that are NOT part of a document with a root key will be returned as
+// map[string]interface{} and the error value 'NoRoot'.
+// • note: ": tag preserve the
+// ":" notation rather than stripping it as with NewMapXml().
+// 2. Attribute keys for name space prefix declarations preserve "xmlns:" notation.
+//
+// ERRORS:
+// 1. If a NoRoot error, "no root key," is returned, check the initial map key for a "#comment",
+// "#directive" or #procinst" key.
+func NewMapXmlSeq(xmlVal []byte, cast ...bool) (MapSeq, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ return xmlSeqToMap(xmlVal, r)
+}
+
+// NewMpaXmlSeqReader returns next XML doc from an io.Reader as a MapSeq value.
+// NOTES:
+// 1. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 2. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to
+// re-encode the message in its original structure.
+// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+//
+// ERRORS:
+// 1. If a NoRoot error, "no root key," is returned, check the initial map key for a "#comment",
+// "#directive" or #procinst" key.
+func NewMapXmlSeqReader(xmlReader io.Reader, cast ...bool) (MapSeq, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+
+ // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder
+ // will wrap it in a bufio.Reader and seek on the file beyond where the
+ // xml.Decoder parses!
+ if _, ok := xmlReader.(io.ByteReader); !ok {
+ xmlReader = myByteReader(xmlReader) // see code at EOF
+ }
+
+ // build the map
+ return xmlSeqReaderToMap(xmlReader, r)
+}
+
+// NewMapXmlSeqReaderRaw returns the next XML doc from an io.Reader as a MapSeq value.
+// Returns MapSeq value, slice with the raw XML, and any error.
+// NOTES:
+// 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte
+// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact.
+// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large
+// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body
+// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call.
+// 2. The 'raw' return value may be larger than the XML text value.
+// 3. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 4. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to
+// re-encode the message in its original structure.
+// 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+//
+// ERRORS:
+// 1. If a NoRoot error, "no root key," is returned, check if the initial map key is "#comment",
+// "#directive" or #procinst" key.
+func NewMapXmlSeqReaderRaw(xmlReader io.Reader, cast ...bool) (MapSeq, []byte, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ // create TeeReader so we can retrieve raw XML
+ buf := make([]byte, 0)
+ wb := bytes.NewBuffer(buf)
+ trdr := myTeeReader(xmlReader, wb)
+
+ m, err := xmlSeqReaderToMap(trdr, r)
+
+ // retrieve the raw XML that was decoded
+ b := wb.Bytes()
+
+ // err may be NoRoot
+ return m, b, err
+}
+
+// xmlSeqReaderToMap() - parse a XML io.Reader to a map[string]interface{} value
+func xmlSeqReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) {
+ // parse the Reader
+ p := xml.NewDecoder(rdr)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlSeqToMapParser("", nil, p, r)
+}
+
+// xmlSeqToMap - convert a XML doc into map[string]interface{} value
+func xmlSeqToMap(doc []byte, r bool) (map[string]interface{}, error) {
+ b := bytes.NewReader(doc)
+ p := xml.NewDecoder(b)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlSeqToMapParser("", nil, p, r)
+}
+
+// ===================================== where the work happens =============================
+
+// xmlSeqToMapParser - load a 'clean' XML doc into a map[string]interface{} directly.
+// Add #seq tag value for each element decoded - to be used for Encoding later.
+func xmlSeqToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) {
+ if snakeCaseKeys {
+ skey = strings.Replace(skey, "-", "_", -1)
+ }
+
+ // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'.
+ var n, na map[string]interface{}
+ var seq int // for including seq num when decoding
+
+ // Allocate maps and load attributes, if any.
+ // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through
+ // to get StartElement then recurse with skey==xml.StartElement.Name.Local
+ // where we begin allocating map[string]interface{} values 'n' and 'na'.
+ if skey != "" {
+ // 'n' only needs one slot - save call to runtime•hashGrow()
+ // 'na' we don't know
+ n = make(map[string]interface{}, 1)
+ na = make(map[string]interface{})
+ if len(a) > 0 {
+ // xml.Attr is decoded into: map["#attr"]map[]interface{}
+ // where interface{} is map[string]interface{}{"#text":, "#seq":}
+ aa := make(map[string]interface{}, len(a))
+ for i, v := range a {
+ if snakeCaseKeys {
+ v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1)
+ }
+ if xmlEscapeCharsDecoder { // per issue#84
+ v.Value = escapeChars(v.Value)
+ }
+ if len(v.Name.Space) > 0 {
+ aa[v.Name.Space+`:`+v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r, ""), "#seq": i}
+ } else {
+ aa[v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r, ""), "#seq": i}
+ }
+ }
+ na["#attr"] = aa
+ }
+ }
+
+ // Return XMPP message.
+ if handleXMPPStreamTag && skey == "stream:stream" {
+ n[skey] = na
+ return n, nil
+ }
+
+ for {
+ t, err := p.RawToken()
+ if err != nil {
+ if err != io.EOF {
+ return nil, errors.New("xml.Decoder.Token() - " + err.Error())
+ }
+ return nil, err
+ }
+ switch t.(type) {
+ case xml.StartElement:
+ tt := t.(xml.StartElement)
+
+ // First call to xmlSeqToMapParser() doesn't pass xml.StartElement - the map key.
+ // So when the loop is first entered, the first token is the root tag along
+ // with any attributes, which we process here.
+ //
+ // Subsequent calls to xmlSeqToMapParser() will pass in tag+attributes for
+ // processing before getting the next token which is the element value,
+ // which is done above.
+ if skey == "" {
+ if len(tt.Name.Space) > 0 {
+ return xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r)
+ } else {
+ return xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r)
+ }
+ }
+
+ // If not initializing the map, parse the element.
+ // len(nn) == 1, necessarily - it is just an 'n'.
+ var nn map[string]interface{}
+ if len(tt.Name.Space) > 0 {
+ nn, err = xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r)
+ } else {
+ nn, err = xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ // The nn map[string]interface{} value is a na[nn_key] value.
+ // We need to see if nn_key already exists - means we're parsing a list.
+ // This may require converting na[nn_key] value into []interface{} type.
+ // First, extract the key:val for the map - it's a singleton.
+ var key string
+ var val interface{}
+ for key, val = range nn {
+ break
+ }
+
+ // add "#seq" k:v pair -
+ // Sequence number included even in list elements - this should allow us
+ // to properly resequence even something goofy like:
+ // item 1
+ // item 2
+ // item 3
+ // where all the "list" subelements are decoded into an array.
+ switch val.(type) {
+ case map[string]interface{}:
+ val.(map[string]interface{})["#seq"] = seq
+ seq++
+ case interface{}: // a non-nil simple element: string, float64, bool
+ v := map[string]interface{}{"#text": val, "#seq": seq}
+ seq++
+ val = v
+ }
+
+ // 'na' holding sub-elements of n.
+ // See if 'key' already exists.
+ // If 'key' exists, then this is a list, if not just add key:val to na.
+ if v, ok := na[key]; ok {
+ var a []interface{}
+ switch v.(type) {
+ case []interface{}:
+ a = v.([]interface{})
+ default: // anything else - note: v.(type) != nil
+ a = []interface{}{v}
+ }
+ a = append(a, val)
+ na[key] = a
+ } else {
+ na[key] = val // save it as a singleton
+ }
+ case xml.EndElement:
+ if skey != "" {
+ tt := t.(xml.EndElement)
+ if snakeCaseKeys {
+ tt.Name.Local = strings.Replace(tt.Name.Local, "-", "_", -1)
+ }
+ var name string
+ if len(tt.Name.Space) > 0 {
+ name = tt.Name.Space + `:` + tt.Name.Local
+ } else {
+ name = tt.Name.Local
+ }
+ if skey != name {
+ return nil, fmt.Errorf("element %s not properly terminated, got %s at #%d",
+ skey, name, p.InputOffset())
+ }
+ }
+ // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case.
+ if len(n) == 0 {
+ // If len(na)==0 we have an empty element == "";
+ // it has no xml.Attr nor xml.CharData.
+ // Empty element content will be map["etag"]map["#text"]""
+ // after #seq injection - map["etag"]map["#seq"]seq - after return.
+ if len(na) > 0 {
+ n[skey] = na
+ } else {
+ n[skey] = "" // empty element
+ }
+ }
+ return n, nil
+ case xml.CharData:
+ // clean up possible noise
+ tt := strings.Trim(string(t.(xml.CharData)), trimRunes)
+ if xmlEscapeCharsDecoder { // issue#84
+ tt = escapeChars(tt)
+ }
+ if skey == "" {
+ // per Adrian (http://www.adrianlungu.com/) catch stray text
+ // in decoder stream -
+ // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374
+ // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get
+ // a p.Token() decoding error when the BOM is UTF-16 or UTF-32.
+ continue
+ }
+ if len(tt) > 0 {
+ // every simple element is a #text and has #seq associated with it
+ na["#text"] = cast(tt, r, "")
+ na["#seq"] = seq
+ seq++
+ }
+ case xml.Comment:
+ if n == nil { // no root 'key'
+ n = map[string]interface{}{"#comment": string(t.(xml.Comment))}
+ return n, NoRoot
+ }
+ cm := make(map[string]interface{}, 2)
+ cm["#text"] = string(t.(xml.Comment))
+ cm["#seq"] = seq
+ seq++
+ na["#comment"] = cm
+ case xml.Directive:
+ if n == nil { // no root 'key'
+ n = map[string]interface{}{"#directive": string(t.(xml.Directive))}
+ return n, NoRoot
+ }
+ dm := make(map[string]interface{}, 2)
+ dm["#text"] = string(t.(xml.Directive))
+ dm["#seq"] = seq
+ seq++
+ na["#directive"] = dm
+ case xml.ProcInst:
+ if n == nil {
+ na = map[string]interface{}{"#target": t.(xml.ProcInst).Target, "#inst": string(t.(xml.ProcInst).Inst)}
+ n = map[string]interface{}{"#procinst": na}
+ return n, NoRoot
+ }
+ pm := make(map[string]interface{}, 3)
+ pm["#target"] = t.(xml.ProcInst).Target
+ pm["#inst"] = string(t.(xml.ProcInst).Inst)
+ pm["#seq"] = seq
+ seq++
+ na["#procinst"] = pm
+ default:
+ // noop - shouldn't ever get here, now, since we handle all token types
+ }
+ }
+}
+
+// ------------------ END: NewMapXml & NewMapXmlReader -------------------------
+
+// --------------------- mv.XmlSeq & mv.XmlSeqWriter -------------------------
+
+// Xml encodes a MapSeq as XML with elements sorted on #seq. The companion of NewMapXmlSeq().
+// The following rules apply.
+// - The "#seq" key value is used to seqence the subelements or attributes only.
+// - The "#attr" map key identifies the map of attribute map[string]interface{} values with "#text" key.
+// - The "#comment" map key identifies a comment in the value "#text" map entry - .
+// - The "#directive" map key identifies a directive in the value "#text" map entry - .
+// - The "#procinst" map key identifies a process instruction in the value "#target" and "#inst"
+// map entries - .
+// - Value type encoding:
+// > string, bool, float64, int, int32, int64, float32: per "%v" formating
+// > []bool, []uint8: by casting to string
+// > structures, etc.: handed to xml.Marshal() - if there is an error, the element
+// value is "UNKNOWN"
+// - Elements with only attribute values or are null are terminated using "/>" unless XmlGoEmptyElemSystax() called.
+// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible.
+// Thus, `{ "key":"value" }` encodes as "value ".
+func (mv MapSeq) Xml(rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+ var err error
+ s := new(string)
+ p := new(pretty) // just a stub
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ for key, value := range m {
+ // if it's an array, see if all values are map[string]interface{}
+ // we force a new root tag if we'll end up with no key:value in the list
+ // so: key:[string_val, bool:true] --> string_val true
+ switch value.(type) {
+ case []interface{}:
+ for _, v := range value.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}: // noop
+ default: // anything else
+ err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p)
+ goto done
+ }
+ }
+ }
+ err = mapToXmlSeqIndent(false, s, key, value, p)
+ }
+ } else if len(rootTag) == 1 {
+ err = mapToXmlSeqIndent(false, s, rootTag[0], m, p)
+ } else {
+ err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p)
+ }
+done:
+ if xmlCheckIsValid {
+ d := xml.NewDecoder(bytes.NewReader([]byte(*s)))
+ for {
+ _, err = d.Token()
+ if err == io.EOF {
+ err = nil
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return []byte(*s), err
+}
+
+// The following implementation is provided only for symmetry with NewMapXmlReader[Raw]
+// The names will also provide a key for the number of return arguments.
+
+// XmlWriter Writes the MapSeq value as XML on the Writer.
+// See MapSeq.Xml() for encoding rules.
+func (mv MapSeq) XmlWriter(xmlWriter io.Writer, rootTag ...string) error {
+ x, err := mv.Xml(rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// XmlWriteRaw writes the MapSeq value as XML on the Writer. []byte is the raw XML that was written.
+// See Map.XmlSeq() for encoding rules.
+/*
+func (mv MapSeq) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) {
+ x, err := mv.Xml(rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+*/
+
+// XmlIndentWriter writes the MapSeq value as pretty XML on the Writer.
+// See MapSeq.Xml() for encoding rules.
+func (mv MapSeq) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error {
+ x, err := mv.XmlIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// XmlIndentWriterRaw writes the Map as pretty XML on the Writer. []byte is the raw XML that was written.
+// See Map.XmlSeq() for encoding rules.
+/*
+func (mv MapSeq) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) {
+ x, err := mv.XmlSeqIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+*/
+
+// -------------------- END: mv.Xml & mv.XmlWriter -------------------------------
+
+// ---------------------- XmlSeqIndent ----------------------------
+
+// XmlIndent encodes a map[string]interface{} as a pretty XML string.
+// See MapSeq.XmlSeq() for encoding rules.
+func (mv MapSeq) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+
+ var err error
+ s := new(string)
+ p := new(pretty)
+ p.indent = indent
+ p.padding = prefix
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ // this can extract the key for the single map element
+ // use it if it isn't a key for a list
+ for key, value := range m {
+ if _, ok := value.([]interface{}); ok {
+ err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p)
+ } else {
+ err = mapToXmlSeqIndent(true, s, key, value, p)
+ }
+ }
+ } else if len(rootTag) == 1 {
+ err = mapToXmlSeqIndent(true, s, rootTag[0], m, p)
+ } else {
+ err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p)
+ }
+ if xmlCheckIsValid {
+ if _, err = NewMapXml([]byte(*s)); err != nil {
+ return nil, err
+ }
+ d := xml.NewDecoder(bytes.NewReader([]byte(*s)))
+ for {
+ _, err = d.Token()
+ if err == io.EOF {
+ err = nil
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return []byte(*s), err
+}
+
+// where the work actually happens
+// returns an error if an attribute is not atomic
+func mapToXmlSeqIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error {
+ var endTag bool
+ var isSimple bool
+ var noEndTag bool
+ var elen int
+ var ss string
+ p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start}
+
+ switch value.(type) {
+ case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
+ if doIndent {
+ *s += p.padding
+ }
+ if key != "#comment" && key != "#directive" && key != "#procinst" {
+ *s += `<` + key
+ }
+ }
+ switch value.(type) {
+ case map[string]interface{}:
+ val := value.(map[string]interface{})
+
+ if key == "#comment" {
+ *s += ``
+ noEndTag = true
+ break
+ }
+
+ if key == "#directive" {
+ *s += ``
+ noEndTag = true
+ break
+ }
+
+ if key == "#procinst" {
+ *s += `` + val["#target"].(string) + ` ` + val["#inst"].(string) + `?>`
+ noEndTag = true
+ break
+ }
+
+ haveAttrs := false
+ // process attributes first
+ if v, ok := val["#attr"].(map[string]interface{}); ok {
+ // First, unroll the map[string]interface{} into a []keyval array.
+ // Then sequence it.
+ kv := make([]keyval, len(v))
+ n := 0
+ for ak, av := range v {
+ kv[n] = keyval{ak, av}
+ n++
+ }
+ sort.Sort(elemListSeq(kv))
+ // Now encode the attributes in original decoding sequence, using keyval array.
+ for _, a := range kv {
+ vv := a.v.(map[string]interface{})
+ switch vv["#text"].(type) {
+ case string:
+ if xmlEscapeChars {
+ ss = escapeChars(vv["#text"].(string))
+ } else {
+ ss = vv["#text"].(string)
+ }
+ *s += ` ` + a.k + `="` + ss + `"`
+ case float64, bool, int, int32, int64, float32:
+ *s += ` ` + a.k + `="` + fmt.Sprintf("%v", vv["#text"]) + `"`
+ case []byte:
+ if xmlEscapeChars {
+ ss = escapeChars(string(vv["#text"].([]byte)))
+ } else {
+ ss = string(vv["#text"].([]byte))
+ }
+ *s += ` ` + a.k + `="` + ss + `"`
+ default:
+ return fmt.Errorf("invalid attribute value for: %s", a.k)
+ }
+ }
+ haveAttrs = true
+ }
+
+ // simple element?
+ // every map value has, at least, "#seq" and, perhaps, "#text" and/or "#attr"
+ _, seqOK := val["#seq"] // have key
+ if v, ok := val["#text"]; ok && ((len(val) == 3 && haveAttrs) || (len(val) == 2 && !haveAttrs)) && seqOK {
+ if stmp, ok := v.(string); ok && stmp != "" {
+ if xmlEscapeChars {
+ stmp = escapeChars(stmp)
+ }
+ *s += ">" + stmp
+ endTag = true
+ elen = 1
+ }
+ isSimple = true
+ break
+ } else if !ok && ((len(val) == 2 && haveAttrs) || (len(val) == 1 && !haveAttrs)) && seqOK {
+ // here no #text but have #seq or #seq+#attr
+ endTag = false
+ break
+ }
+
+ // we now need to sequence everything except attributes
+ // 'kv' will hold everything that needs to be written
+ kv := make([]keyval, 0)
+ for k, v := range val {
+ if k == "#attr" { // already processed
+ continue
+ }
+ if k == "#seq" { // ignore - just for sorting
+ continue
+ }
+ switch v.(type) {
+ case []interface{}:
+ // unwind the array as separate entries
+ for _, vv := range v.([]interface{}) {
+ kv = append(kv, keyval{k, vv})
+ }
+ default:
+ kv = append(kv, keyval{k, v})
+ }
+ }
+
+ // close tag with possible attributes
+ *s += ">"
+ if doIndent {
+ *s += "\n"
+ }
+ // something more complex
+ p.mapDepth++
+ sort.Sort(elemListSeq(kv))
+ i := 0
+ for _, v := range kv {
+ switch v.v.(type) {
+ case []interface{}:
+ default:
+ if i == 0 && doIndent {
+ p.Indent()
+ }
+ }
+ i++
+ if err := mapToXmlSeqIndent(doIndent, s, v.k, v.v, p); err != nil {
+ return err
+ }
+ switch v.v.(type) {
+ case []interface{}: // handled in []interface{} case
+ default:
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ i--
+ }
+ p.mapDepth--
+ endTag = true
+ elen = 1 // we do have some content other than attrs
+ case []interface{}:
+ for _, v := range value.([]interface{}) {
+ if doIndent {
+ p.Indent()
+ }
+ if err := mapToXmlSeqIndent(doIndent, s, key, v, p); err != nil {
+ return err
+ }
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ return nil
+ case nil:
+ // terminate the tag
+ if doIndent {
+ *s += p.padding
+ }
+ *s += "<" + key
+ endTag, isSimple = true, true
+ break
+ default: // handle anything - even goofy stuff
+ elen = 0
+ switch value.(type) {
+ case string:
+ if xmlEscapeChars {
+ ss = escapeChars(value.(string))
+ } else {
+ ss = value.(string)
+ }
+ elen = len(ss)
+ if elen > 0 {
+ *s += ">" + ss
+ }
+ case float64, bool, int, int32, int64, float32:
+ v := fmt.Sprintf("%v", value)
+ elen = len(v)
+ if elen > 0 {
+ *s += ">" + v
+ }
+ case []byte: // NOTE: byte is just an alias for uint8
+ // similar to how xml.Marshal handles []byte structure members
+ if xmlEscapeChars {
+ ss = escapeChars(string(value.([]byte)))
+ } else {
+ ss = string(value.([]byte))
+ }
+ elen = len(ss)
+ if elen > 0 {
+ *s += ">" + ss
+ }
+ default:
+ var v []byte
+ var err error
+ if doIndent {
+ v, err = xml.MarshalIndent(value, p.padding, p.indent)
+ } else {
+ v, err = xml.Marshal(value)
+ }
+ if err != nil {
+ *s += ">UNKNOWN"
+ } else {
+ elen = len(v)
+ if elen > 0 {
+ *s += string(v)
+ }
+ }
+ }
+ isSimple = true
+ endTag = true
+ }
+ if endTag && !noEndTag {
+ if doIndent {
+ if !isSimple {
+ *s += p.padding
+ }
+ }
+ switch value.(type) {
+ case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
+ if elen > 0 || useGoXmlEmptyElemSyntax {
+ if elen == 0 {
+ *s += ">"
+ }
+ *s += `` + key + ">"
+ } else {
+ *s += `/>`
+ }
+ }
+ } else if !noEndTag {
+ if useGoXmlEmptyElemSyntax {
+ *s += `` + key + ">"
+ // *s += ">" + key + ">"
+ } else {
+ *s += "/>"
+ }
+ }
+ if doIndent {
+ if p.cnt > p.start {
+ *s += "\n"
+ }
+ p.Outdent()
+ }
+
+ return nil
+}
+
+// the element sort implementation
+
+type keyval struct {
+ k string
+ v interface{}
+}
+type elemListSeq []keyval
+
+func (e elemListSeq) Len() int {
+ return len(e)
+}
+
+func (e elemListSeq) Swap(i, j int) {
+ e[i], e[j] = e[j], e[i]
+}
+
+func (e elemListSeq) Less(i, j int) bool {
+ var iseq, jseq int
+ var fiseq, fjseq float64
+ var ok bool
+ if iseq, ok = e[i].v.(map[string]interface{})["#seq"].(int); !ok {
+ if fiseq, ok = e[i].v.(map[string]interface{})["#seq"].(float64); ok {
+ iseq = int(fiseq)
+ } else {
+ iseq = 9999999
+ }
+ }
+
+ if jseq, ok = e[j].v.(map[string]interface{})["#seq"].(int); !ok {
+ if fjseq, ok = e[j].v.(map[string]interface{})["#seq"].(float64); ok {
+ jseq = int(fjseq)
+ } else {
+ jseq = 9999999
+ }
+ }
+
+ return iseq <= jseq
+}
+
+// =============== https://groups.google.com/forum/#!topic/golang-nuts/lHPOHD-8qio
+
+// BeautifyXml (re)formats an XML doc similar to Map.XmlIndent().
+// It preserves comments, directives and process instructions,
+func BeautifyXml(b []byte, prefix, indent string) ([]byte, error) {
+ x, err := NewMapXmlSeq(b)
+ if err != nil {
+ return nil, err
+ }
+ return x.XmlIndent(prefix, indent)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xmlseq2.go b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xmlseq2.go
new file mode 100644
index 000000000000..467fd07697d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/clbanning/mxj/v2/xmlseq2.go
@@ -0,0 +1,18 @@
+// Copyright 2012-2016, 2019 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+// ---------------- expose Map methods to MapSeq type ---------------------------
+
+// Pretty print a Map.
+func (msv MapSeq) StringIndent(offset ...int) string {
+ return writeMap(map[string]interface{}(msv), true, true, offset...)
+}
+
+// Pretty print a Map without the value type information - just key:value entries.
+func (msv MapSeq) StringIndentNoTypeInfo(offset ...int) string {
+ return writeMap(map[string]interface{}(msv), false, true, offset...)
+}
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/LICENSE
new file mode 100644
index 000000000000..ce4fabaf8c21
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Oleg Kovalov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/README.md
new file mode 100644
index 000000000000..f00036667eee
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/README.md
@@ -0,0 +1,113 @@
+# jwt
+
+[![build-img]][build-url]
+[![pkg-img]][pkg-url]
+[![reportcard-img]][reportcard-url]
+[![coverage-img]][coverage-url]
+
+JSON Web Token for Go [RFC 7519](https://tools.ietf.org/html/rfc7519), also see [jwt.io](https://jwt.io) for more.
+
+The latest version is `v3`.
+
+## Rationale
+
+There are many JWT libraries, but many of them are hard to use (unclear or fixed API), not optimal (unneeded allocations + strange API). This library addresses all these issues. It's simple to read, to use, memory and CPU conservative.
+
+## Features
+
+* Simple API.
+* Clean and tested code.
+* Optimized for speed.
+* Concurrent-safe.
+* Dependency-free.
+* All well-known algorithms are supported
+ * HMAC (HS)
+ * RSA (RS)
+ * RSA-PSS (PS)
+ * ECDSA (ES)
+ * EdDSA (EdDSA)
+ * or your own!
+
+## Install
+
+Go version 1.13+
+
+```
+GO111MODULE=on go get github.com/cristalhq/jwt/v3
+```
+
+## Example
+
+Build new token:
+
+```go
+// create a Signer (HMAC in this example)
+key := []byte(`secret`)
+signer, err := jwt.NewSignerHS(jwt.HS256, key)
+checkErr(err)
+
+// create claims (you can create your own, see: Example_BuildUserClaims)
+claims := &jwt.RegisteredClaims{
+ Audience: []string{"admin"},
+ ID: "random-unique-string",
+}
+
+// create a Builder
+builder := jwt.NewBuilder(signer)
+
+// and build a Token
+token, err := builder.Build(claims)
+checkErr(err)
+
+// here is token as byte slice
+var _ []byte = token.Bytes() // or just token.String() for string
+```
+
+Parse and verify token:
+```go
+// create a Verifier (HMAC in this example)
+key := []byte(`secret`)
+verifier, err := jwt.NewVerifierHS(jwt.HS256, key)
+checkErr(err)
+
+// parse a Token (by example received from a request)
+tokenStr := ``
+token, err := jwt.ParseString(tokenStr)
+checkErr(err)
+
+// and verify it's signature
+err = verifier.Verify(token.Payload(), token.Signature())
+checkErr(err)
+
+// also you can parse and verify together
+newToken, err := jwt.ParseAndVerifyString(tokenStr, verifier)
+checkErr(err)
+
+// get standard claims
+var newClaims jwt.StandardClaims
+errClaims := json.Unmarshal(newToken.RawClaims(), &newClaims)
+checkErr(errClaims)
+
+// verify claims as you
+var _ bool = newClaims.IsForAudience("admin")
+var _ bool = newClaims.IsValidAt(time.Now())
+```
+
+Also see examples: [example_test.go](https://github.com/cristalhq/jwt/blob/master/example_test.go).
+
+## Documentation
+
+See [these docs][pkg-url].
+
+## License
+
+[MIT License](LICENSE).
+
+[build-img]: https://github.com/cristalhq/jwt/workflows/build/badge.svg
+[build-url]: https://github.com/cristalhq/jwt/actions
+[pkg-img]: https://pkg.go.dev/badge/cristalhq/jwt/v3
+[pkg-url]: https://pkg.go.dev/github.com/cristalhq/jwt/v3
+[reportcard-img]: https://goreportcard.com/badge/cristalhq/jwt
+[reportcard-url]: https://goreportcard.com/report/cristalhq/jwt
+[coverage-img]: https://codecov.io/gh/cristalhq/jwt/branch/master/graph/badge.svg
+[coverage-url]: https://codecov.io/gh/cristalhq/jwt
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo.go
new file mode 100644
index 000000000000..c812a3c2278d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo.go
@@ -0,0 +1,81 @@
+package jwt
+
+import (
+ "crypto"
+ _ "crypto/sha256" // to register a hash
+ _ "crypto/sha512" // to register a hash
+)
+
+// Signer is used to sign tokens.
+type Signer interface {
+ Algorithm() Algorithm
+ SignSize() int
+ Sign(payload []byte) ([]byte, error)
+}
+
+// Verifier is used to verify tokens.
+type Verifier interface {
+ Algorithm() Algorithm
+ Verify(payload, signature []byte) error
+}
+
+// Algorithm for signing and verifying.
+type Algorithm string
+
+func (a Algorithm) String() string { return string(a) }
+
+// keySize of the algorithm's key (if exist). Is similar to Signer.SignSize.
+func (a Algorithm) keySize() int { return algsKeySize[a] }
+
+var algsKeySize = map[Algorithm]int{
+ // for EdDSA private and public key have different sizes, so 0
+ // for HS there is no limits for key size, so 0
+
+ RS256: 256,
+ RS384: 384,
+ RS512: 512,
+
+ ES256: 64,
+ ES384: 96,
+ ES512: 132,
+
+ PS256: 256,
+ PS384: 384,
+ PS512: 512,
+}
+
+// Algorithm names for signing and verifying.
+const (
+ EdDSA Algorithm = "EdDSA"
+
+ HS256 Algorithm = "HS256"
+ HS384 Algorithm = "HS384"
+ HS512 Algorithm = "HS512"
+
+ RS256 Algorithm = "RS256"
+ RS384 Algorithm = "RS384"
+ RS512 Algorithm = "RS512"
+
+ ES256 Algorithm = "ES256"
+ ES384 Algorithm = "ES384"
+ ES512 Algorithm = "ES512"
+
+ PS256 Algorithm = "PS256"
+ PS384 Algorithm = "PS384"
+ PS512 Algorithm = "PS512"
+)
+
+func hashPayload(hash crypto.Hash, payload []byte) ([]byte, error) {
+ hasher := hash.New()
+
+ _, err := hasher.Write(payload)
+ if err != nil {
+ return nil, err
+ }
+ signed := hasher.Sum(nil)
+ return signed, nil
+}
+
+func constTimeAlgEqual(a, b Algorithm) bool {
+ return constTimeEqual(a.String(), b.String())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_eddsa.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_eddsa.go
new file mode 100644
index 000000000000..1af3d3ffabaf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_eddsa.go
@@ -0,0 +1,65 @@
+package jwt
+
+import (
+ "crypto/ed25519"
+)
+
+// NewSignerEdDSA returns a new ed25519-based signer.
+func NewSignerEdDSA(key ed25519.PrivateKey) (Signer, error) {
+ if len(key) == 0 {
+ return nil, ErrNilKey
+ }
+ if len(key) != ed25519.PrivateKeySize {
+ return nil, ErrInvalidKey
+ }
+ return &edDSAAlg{
+ alg: EdDSA,
+ privateKey: key,
+ }, nil
+}
+
+// NewVerifierEdDSA returns a new ed25519-based verifier.
+func NewVerifierEdDSA(key ed25519.PublicKey) (Verifier, error) {
+ if len(key) == 0 {
+ return nil, ErrNilKey
+ }
+ if len(key) != ed25519.PublicKeySize {
+ return nil, ErrInvalidKey
+ }
+ return &edDSAAlg{
+ alg: EdDSA,
+ publicKey: key,
+ }, nil
+}
+
+type edDSAAlg struct {
+ alg Algorithm
+ publicKey ed25519.PublicKey
+ privateKey ed25519.PrivateKey
+}
+
+func (ed *edDSAAlg) Algorithm() Algorithm {
+ return ed.alg
+}
+
+func (ed *edDSAAlg) SignSize() int {
+ return ed25519.SignatureSize
+}
+
+func (ed *edDSAAlg) Sign(payload []byte) ([]byte, error) {
+ return ed25519.Sign(ed.privateKey, payload), nil
+}
+
+func (ed *edDSAAlg) VerifyToken(token *Token) error {
+ if constTimeAlgEqual(token.Header().Algorithm, ed.alg) {
+ return ed.Verify(token.Payload(), token.Signature())
+ }
+ return ErrAlgorithmMismatch
+}
+
+func (ed *edDSAAlg) Verify(payload, signature []byte) error {
+ if !ed25519.Verify(ed.publicKey, payload, signature) {
+ return ErrInvalidSignature
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_es.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_es.go
new file mode 100644
index 000000000000..2b3126c8a7f8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_es.go
@@ -0,0 +1,132 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rand"
+ "math/big"
+)
+
+// NewSignerES returns a new ECDSA-based signer.
+func NewSignerES(alg Algorithm, key *ecdsa.PrivateKey) (Signer, error) {
+ if key == nil {
+ return nil, ErrNilKey
+ }
+ hash, err := getParamsES(alg, roundBytes(key.PublicKey.Params().BitSize)*2)
+ if err != nil {
+ return nil, err
+ }
+ return &esAlg{
+ alg: alg,
+ hash: hash,
+ privateKey: key,
+ signSize: roundBytes(key.PublicKey.Params().BitSize) * 2,
+ }, nil
+}
+
+// NewVerifierES returns a new ECDSA-based verifier.
+func NewVerifierES(alg Algorithm, key *ecdsa.PublicKey) (Verifier, error) {
+ if key == nil {
+ return nil, ErrNilKey
+ }
+ hash, err := getParamsES(alg, roundBytes(key.Params().BitSize)*2)
+ if err != nil {
+ return nil, err
+ }
+ return &esAlg{
+ alg: alg,
+ hash: hash,
+ publicKey: key,
+ signSize: roundBytes(key.Params().BitSize) * 2,
+ }, nil
+}
+
+func getParamsES(alg Algorithm, size int) (crypto.Hash, error) {
+ var hash crypto.Hash
+ switch alg {
+ case ES256:
+ hash = crypto.SHA256
+ case ES384:
+ hash = crypto.SHA384
+ case ES512:
+ hash = crypto.SHA512
+ default:
+ return 0, ErrUnsupportedAlg
+ }
+
+ if alg.keySize() != size {
+ return 0, ErrInvalidKey
+ }
+ return hash, nil
+}
+
+type esAlg struct {
+ alg Algorithm
+ hash crypto.Hash
+ publicKey *ecdsa.PublicKey
+ privateKey *ecdsa.PrivateKey
+ signSize int
+}
+
+func (es *esAlg) Algorithm() Algorithm {
+ return es.alg
+}
+
+func (es *esAlg) SignSize() int {
+ return es.signSize
+}
+
+func (es *esAlg) Sign(payload []byte) ([]byte, error) {
+ digest, err := hashPayload(es.hash, payload)
+ if err != nil {
+ return nil, err
+ }
+
+ r, s, errSign := ecdsa.Sign(rand.Reader, es.privateKey, digest)
+ if err != nil {
+ return nil, errSign
+ }
+
+ pivot := es.SignSize() / 2
+
+ rBytes, sBytes := r.Bytes(), s.Bytes()
+ signature := make([]byte, es.SignSize())
+ copy(signature[pivot-len(rBytes):], rBytes)
+ copy(signature[pivot*2-len(sBytes):], sBytes)
+ return signature, nil
+}
+
+func (es *esAlg) VerifyToken(token *Token) error {
+ if constTimeAlgEqual(token.Header().Algorithm, es.alg) {
+ return es.Verify(token.Payload(), token.Signature())
+ }
+ return ErrAlgorithmMismatch
+}
+
+func (es *esAlg) Verify(payload, signature []byte) error {
+ if len(signature) != es.SignSize() {
+ return ErrInvalidSignature
+ }
+
+ digest, err := hashPayload(es.hash, payload)
+ if err != nil {
+ return err
+ }
+
+ pivot := es.SignSize() / 2
+ r := big.NewInt(0).SetBytes(signature[:pivot])
+ s := big.NewInt(0).SetBytes(signature[pivot:])
+
+ if !ecdsa.Verify(es.publicKey, digest, r, s) {
+ return ErrInvalidSignature
+ }
+ return nil
+}
+
+func roundBytes(n int) int {
+ res := n / 8
+ if n%8 > 0 {
+ return res + 1
+ }
+ return res
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_hs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_hs.go
new file mode 100644
index 000000000000..9438fbff7f99
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_hs.go
@@ -0,0 +1,111 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/hmac"
+ "hash"
+ "sync"
+)
+
+// NewSignerHS returns a new HMAC-based signer.
+func NewSignerHS(alg Algorithm, key []byte) (Signer, error) {
+ return newHS(alg, key)
+}
+
+// NewVerifierHS returns a new HMAC-based verifier.
+func NewVerifierHS(alg Algorithm, key []byte) (Verifier, error) {
+ return newHS(alg, key)
+}
+
+type hmacAlgo interface {
+ // copy-pasted Signer & Verifier due to older Go versions
+ Algorithm() Algorithm
+ SignSize() int
+ Sign(payload []byte) ([]byte, error)
+ Verify(payload, signature []byte) error
+ VerifyToken(token *Token) error
+}
+
+func newHS(alg Algorithm, key []byte) (hmacAlgo, error) {
+ if len(key) == 0 {
+ return nil, ErrNilKey
+ }
+ hash, ok := getHashHMAC(alg)
+ if !ok {
+ return nil, ErrUnsupportedAlg
+ }
+ return &hsAlg{
+ alg: alg,
+ hash: hash,
+ key: key,
+ hashPool: &sync.Pool{
+ New: func() interface{} {
+ return hmac.New(hash.New, key)
+ },
+ },
+ }, nil
+}
+
+func getHashHMAC(alg Algorithm) (crypto.Hash, bool) {
+ switch alg {
+ case HS256:
+ return crypto.SHA256, true
+ case HS384:
+ return crypto.SHA384, true
+ case HS512:
+ return crypto.SHA512, true
+ default:
+ return 0, false
+ }
+}
+
+type hsAlg struct {
+ alg Algorithm
+ hash crypto.Hash
+ key []byte
+ hashPool *sync.Pool
+}
+
+func (hs *hsAlg) Algorithm() Algorithm {
+ return hs.alg
+}
+
+func (hs *hsAlg) SignSize() int {
+ return hs.hash.Size()
+}
+
+func (hs *hsAlg) Sign(payload []byte) ([]byte, error) {
+ return hs.sign(payload)
+}
+
+func (hs *hsAlg) VerifyToken(token *Token) error {
+ if constTimeAlgEqual(token.Header().Algorithm, hs.alg) {
+ return hs.Verify(token.Payload(), token.Signature())
+ }
+ return ErrAlgorithmMismatch
+}
+
+func (hs *hsAlg) Verify(payload, signature []byte) error {
+ digest, err := hs.sign(payload)
+ if err != nil {
+ return err
+ }
+ if !hmac.Equal(signature, digest) {
+ return ErrInvalidSignature
+ }
+ return nil
+}
+
+func (hs *hsAlg) sign(payload []byte) ([]byte, error) {
+ hasher := hs.hashPool.Get().(hash.Hash)
+ defer func() {
+ hasher.Reset()
+ hs.hashPool.Put(hasher)
+ }()
+
+ _, err := hasher.Write(payload)
+ if err != nil {
+ return nil, err
+ }
+ return hasher.Sum(nil), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_ps.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_ps.go
new file mode 100644
index 000000000000..21d552d37976
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_ps.go
@@ -0,0 +1,127 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+)
+
+// NewSignerPS returns a new RSA-PSS-based signer.
+func NewSignerPS(alg Algorithm, key *rsa.PrivateKey) (Signer, error) {
+ if key == nil {
+ return nil, ErrNilKey
+ }
+ hash, opts, err := getParamsPS(alg, key.Size())
+ if err != nil {
+ return nil, err
+ }
+ return &psAlg{
+ alg: alg,
+ hash: hash,
+ privateKey: key,
+ opts: opts,
+ }, nil
+}
+
+// NewVerifierPS returns a new RSA-PSS-based signer.
+func NewVerifierPS(alg Algorithm, key *rsa.PublicKey) (Verifier, error) {
+ if key == nil {
+ return nil, ErrNilKey
+ }
+ hash, opts, err := getParamsPS(alg, key.Size())
+ if err != nil {
+ return nil, err
+ }
+ return &psAlg{
+ alg: alg,
+ hash: hash,
+ publicKey: key,
+ opts: opts,
+ }, nil
+}
+
+func getParamsPS(alg Algorithm, size int) (crypto.Hash, *rsa.PSSOptions, error) {
+ var hash crypto.Hash
+ var opts *rsa.PSSOptions
+ switch alg {
+ case PS256:
+ hash, opts = crypto.SHA256, optsPS256
+ case PS384:
+ hash, opts = crypto.SHA384, optsPS384
+ case PS512:
+ hash, opts = crypto.SHA512, optsPS512
+ default:
+ return 0, nil, ErrUnsupportedAlg
+ }
+
+ if alg.keySize() != size {
+ return 0, nil, ErrInvalidKey
+ }
+ return hash, opts, nil
+}
+
+var (
+ optsPS256 = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ Hash: crypto.SHA256,
+ }
+
+ optsPS384 = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ Hash: crypto.SHA384,
+ }
+
+ optsPS512 = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ Hash: crypto.SHA512,
+ }
+)
+
+type psAlg struct {
+ alg Algorithm
+ hash crypto.Hash
+ publicKey *rsa.PublicKey
+ privateKey *rsa.PrivateKey
+ opts *rsa.PSSOptions
+}
+
+func (ps *psAlg) SignSize() int {
+ return ps.privateKey.Size()
+}
+
+func (ps *psAlg) Algorithm() Algorithm {
+ return ps.alg
+}
+
+func (ps *psAlg) Sign(payload []byte) ([]byte, error) {
+ digest, err := hashPayload(ps.hash, payload)
+ if err != nil {
+ return nil, err
+ }
+
+ signature, errSign := rsa.SignPSS(rand.Reader, ps.privateKey, ps.hash, digest, ps.opts)
+ if errSign != nil {
+ return nil, errSign
+ }
+ return signature, nil
+}
+
+func (ps *psAlg) VerifyToken(token *Token) error {
+ if constTimeAlgEqual(token.Header().Algorithm, ps.alg) {
+ return ps.Verify(token.Payload(), token.Signature())
+ }
+ return ErrAlgorithmMismatch
+}
+
+func (ps *psAlg) Verify(payload, signature []byte) error {
+ digest, err := hashPayload(ps.hash, payload)
+ if err != nil {
+ return err
+ }
+
+ errVerify := rsa.VerifyPSS(ps.publicKey, ps.hash, digest, signature, ps.opts)
+ if errVerify != nil {
+ return ErrInvalidSignature
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_rs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_rs.go
new file mode 100644
index 000000000000..393e80bea93a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/algo_rs.go
@@ -0,0 +1,102 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+)
+
+// NewSignerRS returns a new RSA-based signer.
+func NewSignerRS(alg Algorithm, key *rsa.PrivateKey) (Signer, error) {
+ if key == nil {
+ return nil, ErrNilKey
+ }
+ hash, err := getHashRS(alg, key.Size())
+ if err != nil {
+ return nil, err
+ }
+ return &rsAlg{
+ alg: alg,
+ hash: hash,
+ privateKey: key,
+ }, nil
+}
+
+// NewVerifierRS returns a new RSA-based verifier.
+func NewVerifierRS(alg Algorithm, key *rsa.PublicKey) (Verifier, error) {
+ if key == nil {
+ return nil, ErrNilKey
+ }
+ hash, err := getHashRS(alg, key.Size())
+ if err != nil {
+ return nil, err
+ }
+ return &rsAlg{
+ alg: alg,
+ hash: hash,
+ publicKey: key,
+ }, nil
+}
+
+func getHashRS(alg Algorithm, size int) (crypto.Hash, error) {
+ var hash crypto.Hash
+ switch alg {
+ case RS256:
+ hash = crypto.SHA256
+ case RS384:
+ hash = crypto.SHA384
+ case RS512:
+ hash = crypto.SHA512
+ default:
+ return 0, ErrUnsupportedAlg
+ }
+ return hash, nil
+}
+
+type rsAlg struct {
+ alg Algorithm
+ hash crypto.Hash
+ publicKey *rsa.PublicKey
+ privateKey *rsa.PrivateKey
+}
+
+func (rs *rsAlg) Algorithm() Algorithm {
+ return rs.alg
+}
+
+func (rs *rsAlg) SignSize() int {
+ return rs.privateKey.Size()
+}
+
+func (rs *rsAlg) Sign(payload []byte) ([]byte, error) {
+ digest, err := hashPayload(rs.hash, payload)
+ if err != nil {
+ return nil, err
+ }
+
+ signature, errSign := rsa.SignPKCS1v15(rand.Reader, rs.privateKey, rs.hash, digest)
+ if errSign != nil {
+ return nil, errSign
+ }
+ return signature, nil
+}
+
+func (rs *rsAlg) VerifyToken(token *Token) error {
+ if constTimeAlgEqual(token.Header().Algorithm, rs.alg) {
+ return rs.Verify(token.Payload(), token.Signature())
+ }
+ return ErrAlgorithmMismatch
+}
+
+func (rs *rsAlg) Verify(payload, signature []byte) error {
+ digest, err := hashPayload(rs.hash, payload)
+ if err != nil {
+ return err
+ }
+
+ errVerify := rsa.VerifyPKCS1v15(rs.publicKey, rs.hash, digest, signature)
+ if errVerify != nil {
+ return ErrInvalidSignature
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/audience.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/audience.go
new file mode 100644
index 000000000000..6b311a033a65
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/audience.go
@@ -0,0 +1,46 @@
+package jwt
+
+import "encoding/json"
+
+// Audience is a special claim that be a single string or an array of strings
+// see RFC 7519.
+type Audience []string
+
+// MarshalJSON implements a marshaling function for "aud" claim.
+func (a Audience) MarshalJSON() ([]byte, error) {
+ switch len(a) {
+ case 0:
+ return []byte(`""`), nil
+ case 1:
+ return json.Marshal(a[0])
+ default:
+ return json.Marshal([]string(a))
+ }
+}
+
+// UnmarshalJSON implements json.Unmarshaler interface.
+func (a *Audience) UnmarshalJSON(b []byte) error {
+ var v interface{}
+ if err := json.Unmarshal(b, &v); err != nil {
+ return ErrAudienceInvalidFormat
+ }
+
+ switch v := v.(type) {
+ case string:
+ *a = Audience{v}
+ return nil
+ case []interface{}:
+ aud := make(Audience, len(v))
+ for i := range v {
+ v, ok := v[i].(string)
+ if !ok {
+ return ErrAudienceInvalidFormat
+ }
+ aud[i] = v
+ }
+ *a = aud
+ return nil
+ default:
+ return ErrAudienceInvalidFormat
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/build.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/build.go
new file mode 100644
index 000000000000..82e292a07bab
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/build.go
@@ -0,0 +1,178 @@
+package jwt
+
+import (
+ "encoding/base64"
+ "encoding/json"
+)
+
+// BuilderOption is used to modify builder properties.
+type BuilderOption func(*Builder)
+
+// WithKeyID sets `kid` header for token.
+func WithKeyID(kid string) BuilderOption {
+ return func(b *Builder) { b.header.KeyID = kid }
+}
+
+// WithContentType sets `cty` header for token.
+func WithContentType(cty string) BuilderOption {
+ return func(b *Builder) { b.header.ContentType = cty }
+}
+
+// Builder is used to create a new token.
+type Builder struct {
+ signer Signer
+ header Header
+ headerRaw []byte
+}
+
+// BuildBytes is used to create and encode JWT with a provided claims.
+func BuildBytes(signer Signer, claims interface{}) ([]byte, error) {
+ return NewBuilder(signer).BuildBytes(claims)
+}
+
+// Build is used to create and encode JWT with a provided claims.
+func Build(signer Signer, claims interface{}) (*Token, error) {
+ return NewBuilder(signer).Build(claims)
+}
+
+// NewBuilder returns new instance of Builder.
+func NewBuilder(signer Signer, opts ...BuilderOption) *Builder {
+ b := &Builder{
+ signer: signer,
+ header: Header{
+ Algorithm: signer.Algorithm(),
+ Type: "JWT",
+ },
+ }
+
+ for _, opt := range opts {
+ opt(b)
+ }
+
+ b.headerRaw = encodeHeader(b.header)
+ return b
+}
+
+// BuildBytes used to create and encode JWT with a provided claims.
+func (b *Builder) BuildBytes(claims interface{}) ([]byte, error) {
+ token, err := b.Build(claims)
+ if err != nil {
+ return nil, err
+ }
+ return token.Raw(), nil
+}
+
+// Build used to create and encode JWT with a provided claims.
+// If claims param is of type []byte or string then it's treated as a marshaled JSON.
+// In other words you can pass already marshaled claims.
+//
+func (b *Builder) Build(claims interface{}) (*Token, error) {
+ rawClaims, errClaims := encodeClaims(claims)
+ if errClaims != nil {
+ return nil, errClaims
+ }
+
+ lenH := len(b.headerRaw)
+ lenC := b64EncodedLen(len(rawClaims))
+ lenS := b64EncodedLen(b.signer.SignSize())
+
+ token := make([]byte, lenH+1+lenC+1+lenS)
+ idx := 0
+ idx = copy(token[idx:], b.headerRaw)
+
+ // add '.' and append encoded claims
+ token[idx] = '.'
+ idx++
+ b64Encode(token[idx:], rawClaims)
+ idx += lenC
+
+ // calculate signature of already written 'header.claims'
+ rawSignature, errSign := b.signer.Sign(token[:idx])
+ if errSign != nil {
+ return nil, errSign
+ }
+
+ // add '.' and append encoded signature
+ token[idx] = '.'
+ idx++
+ b64Encode(token[idx:], rawSignature)
+
+ t := &Token{
+ raw: token,
+ dot1: lenH,
+ dot2: lenH + 1 + lenC,
+ header: b.header,
+ claims: rawClaims,
+ signature: rawSignature,
+ }
+ return t, nil
+}
+
+func encodeClaims(claims interface{}) ([]byte, error) {
+ switch claims := claims.(type) {
+ case []byte:
+ return claims, nil
+ case string:
+ return []byte(claims), nil
+ default:
+ return json.Marshal(claims)
+ }
+}
+
+func encodeHeader(header Header) []byte {
+ if header.Type == "JWT" && header.ContentType == "" && header.KeyID == "" {
+ if h := getPredefinedHeader(header); h != "" {
+ return []byte(h)
+ }
+ // another algorithm? encode below
+ }
+ // returned err is always nil, see *Header.MarshalJSON
+ buf, _ := json.Marshal(header)
+
+ encoded := make([]byte, b64EncodedLen(len(buf)))
+ b64Encode(encoded, buf)
+ return encoded
+}
+
+func getPredefinedHeader(header Header) string {
+ switch header.Algorithm {
+ case EdDSA:
+ return "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9"
+
+ case HS256:
+ return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
+ case HS384:
+ return "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9"
+ case HS512:
+ return "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9"
+
+ case RS256:
+ return "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"
+ case RS384:
+ return "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9"
+ case RS512:
+ return "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9"
+
+ case ES256:
+ return "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9"
+ case ES384:
+ return "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9"
+ case ES512:
+ return "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9"
+
+ case PS256:
+ return "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9"
+ case PS384:
+ return "eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9"
+ case PS512:
+ return "eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9"
+
+ default:
+ return ""
+ }
+}
+
+var (
+ b64Encode = base64.RawURLEncoding.Encode
+ b64EncodedLen = base64.RawURLEncoding.EncodedLen
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/claims.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/claims.go
new file mode 100644
index 000000000000..f0d4a07f27da
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/claims.go
@@ -0,0 +1,90 @@
+package jwt
+
+import (
+ "crypto/subtle"
+ "time"
+)
+
+// RegisteredClaims will replace StandardClaims in v4.
+type RegisteredClaims = StandardClaims
+
+// StandardClaims represents claims for JWT.
+// See: https://tools.ietf.org/html/rfc7519#section-4.1
+//
+type StandardClaims struct {
+ // ID claim provides a unique identifier for the JWT.
+ ID string `json:"jti,omitempty"`
+
+ // Audience claim identifies the recipients that the JWT is intended for.
+ Audience Audience `json:"aud,omitempty"`
+
+ // Issuer claim identifies the principal that issued the JWT.
+ // Use of this claim is OPTIONAL.
+ Issuer string `json:"iss,omitempty"`
+
+ // Subject claim identifies the principal that is the subject of the JWT.
+ // Use of this claim is OPTIONAL.
+ Subject string `json:"sub,omitempty"`
+
+ // ExpiresAt claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.
+ // Use of this claim is OPTIONAL.
+ ExpiresAt *NumericDate `json:"exp,omitempty"`
+
+ // IssuedAt claim identifies the time at which the JWT was issued.
+ // This claim can be used to determine the age of the JWT.
+ // Use of this claim is OPTIONAL.
+ IssuedAt *NumericDate `json:"iat,omitempty"`
+
+ // NotBefore claim identifies the time before which the JWT MUST NOT be accepted for processing.
+ // Use of this claim is OPTIONAL.
+ NotBefore *NumericDate `json:"nbf,omitempty"`
+}
+
+// IsForAudience reports whether token has a given audience.
+func (sc *StandardClaims) IsForAudience(audience string) bool {
+ for _, aud := range sc.Audience {
+ if constTimeEqual(aud, audience) {
+ return true
+ }
+ }
+ return false
+}
+
+// IsIssuer reports whether token has a given issuer.
+func (sc *StandardClaims) IsIssuer(issuer string) bool {
+ return constTimeEqual(sc.Issuer, issuer)
+}
+
+// IsSubject reports whether token has a given subject.
+func (sc *StandardClaims) IsSubject(subject string) bool {
+ return constTimeEqual(sc.Subject, subject)
+}
+
+// IsID reports whether token has a given id.
+func (sc *StandardClaims) IsID(id string) bool {
+ return constTimeEqual(sc.ID, id)
+}
+
+// IsValidExpiresAt reports whether a token isn't expired at a given time.
+func (sc *StandardClaims) IsValidExpiresAt(now time.Time) bool {
+ return sc.ExpiresAt == nil || sc.ExpiresAt.After(now)
+}
+
+// IsValidNotBefore reports whether a token isn't used before a given time.
+func (sc *StandardClaims) IsValidNotBefore(now time.Time) bool {
+ return sc.NotBefore == nil || sc.NotBefore.Before(now)
+}
+
+// IsValidIssuedAt reports whether a token was created before a given time.
+func (sc *StandardClaims) IsValidIssuedAt(now time.Time) bool {
+ return sc.IssuedAt == nil || sc.IssuedAt.Before(now)
+}
+
+// IsValidAt reports whether a token is valid at a given time.
+func (sc *StandardClaims) IsValidAt(now time.Time) bool {
+ return sc.IsValidExpiresAt(now) && sc.IsValidNotBefore(now) && sc.IsValidIssuedAt(now)
+}
+
+func constTimeEqual(a, b string) bool {
+ return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/doc.go
new file mode 100644
index 000000000000..fdfa3651a476
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/doc.go
@@ -0,0 +1,7 @@
+// Package jwt represents JSON Web Token for Go.
+//
+// Builder, all the Signers and Verifiers are safe for use by multiple goroutines simultaneously.
+//
+// See [RFC 7519](https://tools.ietf.org/html/rfc7519) and see [jwt.io](https://jwt.io) for more.
+//
+package jwt
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/errors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/errors.go
new file mode 100644
index 000000000000..83a26c1c5fc1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/errors.go
@@ -0,0 +1,37 @@
+package jwt
+
+// Error represents a JWT error.
+type Error string
+
+func (e Error) Error() string {
+ return string(e)
+}
+
+var _ error = (Error)("")
+
+// Build and parse errors.
+const (
+ // ErrNilKey indicates that key is nil.
+ ErrNilKey = Error("jwt: key is nil")
+
+ // ErrInvalidKey indicates that key is not valid.
+ ErrInvalidKey = Error("jwt: key is not valid")
+
+ // ErrUnsupportedAlg indicates that given algorithm is not supported.
+ ErrUnsupportedAlg = Error("jwt: algorithm is not supported")
+
+ // ErrInvalidFormat indicates that token format is not valid.
+ ErrInvalidFormat = Error("jwt: token format is not valid")
+
+ // ErrAudienceInvalidFormat indicates that audience format is not valid.
+ ErrAudienceInvalidFormat = Error("jwt: audience format is not valid")
+
+ // ErrDateInvalidFormat indicates that date format is not valid.
+ ErrDateInvalidFormat = Error("jwt: date is not valid")
+
+ // ErrAlgorithmMismatch indicates that token is signed by another algorithm.
+ ErrAlgorithmMismatch = Error("jwt: token is signed by another algorithm")
+
+ // ErrInvalidSignature indicates that signature is not valid.
+ ErrInvalidSignature = Error("jwt: signature is not valid")
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/fuzz.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/fuzz.go
new file mode 100644
index 000000000000..5fd1e8c83c79
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/fuzz.go
@@ -0,0 +1,17 @@
+// +build gofuzz
+// To run the fuzzer, run the following commands:
+// $ GO111MODULE=off go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
+// $ cd $GOPATH/src/github.com/cristalhq/jwt/
+// $ go-fuzz-build
+// $ go-fuzz
+// Note: go-fuzz doesn't support go modules, so you must have your local
+// installation of jwt under $GOPATH.
+
+package jwt
+
+func Fuzz(data []byte) int {
+ if _, err := Parse(data); err != nil {
+ return 0
+ }
+ return 1
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/jwt.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/jwt.go
new file mode 100644
index 000000000000..9bd46927b81e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/jwt.go
@@ -0,0 +1,91 @@
+package jwt
+
+import (
+ "bytes"
+ "encoding/json"
+)
+
+// Token represents a JWT token.
+// See: https://tools.ietf.org/html/rfc7519
+//
+type Token struct {
+ raw []byte
+ dot1 int
+ dot2 int
+ signature []byte
+ header Header
+ claims json.RawMessage
+}
+
+func (t *Token) String() string {
+ return string(t.raw)
+}
+
+// SecureString returns token without a signature (replaced with `.`).
+func (t *Token) SecureString() string {
+ dot := bytes.LastIndexByte(t.raw, '.')
+ return string(t.raw[:dot]) + `.`
+}
+
+// Raw returns token's raw bytes.
+func (t *Token) Raw() []byte {
+ return t.raw
+}
+
+// Header returns token's header.
+func (t *Token) Header() Header {
+ return t.header
+}
+
+// RawHeader returns token's header raw bytes.
+func (t *Token) RawHeader() []byte {
+ return t.raw[:t.dot1]
+}
+
+// RawClaims returns token's claims as a raw bytes.
+func (t *Token) RawClaims() []byte {
+ return t.claims
+}
+
+// Payload returns token's payload.
+func (t *Token) Payload() []byte {
+ return t.raw[:t.dot2]
+}
+
+// Signature returns token's signature.
+func (t *Token) Signature() []byte {
+ return t.signature
+}
+
+// Header representa JWT header data.
+// See: https://tools.ietf.org/html/rfc7519#section-5, https://tools.ietf.org/html/rfc7517
+//
+type Header struct {
+ Algorithm Algorithm `json:"alg"`
+ Type string `json:"typ,omitempty"` // only "JWT" can be here
+ ContentType string `json:"cty,omitempty"`
+ KeyID string `json:"kid,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (h *Header) MarshalJSON() ([]byte, error) {
+ buf := bytes.Buffer{}
+ buf.WriteString(`{"alg":"`)
+ buf.WriteString(string(h.Algorithm))
+
+ if h.Type != "" {
+ buf.WriteString(`","typ":"`)
+ buf.WriteString(h.Type)
+ }
+ if h.ContentType != "" {
+ buf.WriteString(`","cty":"`)
+ buf.WriteString(h.ContentType)
+ }
+ if h.KeyID != "" {
+ buf.WriteString(`","kid":"`)
+ buf.WriteString(h.KeyID)
+ }
+ buf.WriteString(`"}`)
+
+ return buf.Bytes(), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/numeric_date.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/numeric_date.go
new file mode 100644
index 000000000000..6bfb0046f4a3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/numeric_date.go
@@ -0,0 +1,44 @@
+package jwt
+
+import (
+ "encoding/json"
+ "math"
+ "strconv"
+ "time"
+)
+
+// NumericDate represents date for StandardClaims
+// See: https://tools.ietf.org/html/rfc7519#section-2
+//
+type NumericDate struct {
+ time.Time
+}
+
+// NewNumericDate creates a new NumericDate value from time.Time.
+func NewNumericDate(t time.Time) *NumericDate {
+ if t.IsZero() {
+ return nil
+ }
+ return &NumericDate{t}
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (t *NumericDate) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatInt(t.Unix(), 10)), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (t *NumericDate) UnmarshalJSON(data []byte) error {
+ var value json.Number
+ if err := json.Unmarshal(data, &value); err != nil {
+ return ErrDateInvalidFormat
+ }
+ f, err := value.Float64()
+ if err != nil {
+ return ErrDateInvalidFormat
+ }
+ sec, dec := math.Modf(f)
+ ts := time.Unix(int64(sec), int64(dec*1e9))
+ *t = NumericDate{ts}
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/parse.go
new file mode 100644
index 000000000000..b339de17419a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/parse.go
@@ -0,0 +1,86 @@
+package jwt
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/json"
+)
+
+// ParseString decodes a token.
+func ParseString(raw string) (*Token, error) {
+ return Parse([]byte(raw))
+}
+
+// Parse decodes a token from a raw bytes.
+func Parse(raw []byte) (*Token, error) {
+ return parse(raw)
+}
+
+// ParseAndVerifyString decodes a token and verifies it's signature.
+func ParseAndVerifyString(raw string, verifier Verifier) (*Token, error) {
+ return ParseAndVerify([]byte(raw), verifier)
+}
+
+// ParseAndVerify decodes a token and verifies it's signature.
+func ParseAndVerify(raw []byte, verifier Verifier) (*Token, error) {
+ token, err := parse(raw)
+ if err != nil {
+ return nil, err
+ }
+ if !constTimeAlgEqual(token.Header().Algorithm, verifier.Algorithm()) {
+ return nil, ErrAlgorithmMismatch
+ }
+ if err := verifier.Verify(token.Payload(), token.Signature()); err != nil {
+ return nil, err
+ }
+ return token, nil
+}
+
+func parse(token []byte) (*Token, error) {
+ // "eyJ" is `{"` which is begin of every JWT token.
+ // Quick check for the invalid input.
+ if !bytes.HasPrefix(token, []byte("eyJ")) {
+ return nil, ErrInvalidFormat
+ }
+
+ dot1 := bytes.IndexByte(token, '.')
+ dot2 := bytes.LastIndexByte(token, '.')
+ if dot2 <= dot1 {
+ return nil, ErrInvalidFormat
+ }
+
+ buf := make([]byte, len(token))
+
+ headerN, err := b64Decode(buf, token[:dot1])
+ if err != nil {
+ return nil, ErrInvalidFormat
+ }
+ var header Header
+ if err := json.Unmarshal(buf[:headerN], &header); err != nil {
+ return nil, ErrInvalidFormat
+ }
+
+ claimsN, err := b64Decode(buf[headerN:], token[dot1+1:dot2])
+ if err != nil {
+ return nil, ErrInvalidFormat
+ }
+ claims := buf[headerN : headerN+claimsN]
+
+ signN, err := b64Decode(buf[headerN+claimsN:], token[dot2+1:])
+ if err != nil {
+ return nil, ErrInvalidFormat
+ }
+ signature := buf[headerN+claimsN : headerN+claimsN+signN]
+
+ tk := &Token{
+ raw: token,
+ dot1: dot1,
+ dot2: dot2,
+ signature: signature,
+ header: header,
+ claims: claims,
+ }
+ return tk, nil
+}
+
+var b64Decode = base64.RawURLEncoding.Decode
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go
deleted file mode 100644
index c4f718e4f1a8..000000000000
--- a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/cristalhq/jwt/v3, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/cristalhq/jwt/v3 (exports: Signer; functions: NewSignerHS,HS256)
-
-// Package jwt is a stub of github.com/cristalhq/jwt/v3, generated by depstubber.
-package jwt
-
-type Algorithm string
-
-func (_ Algorithm) String() string {
- return ""
-}
-
-var HS256 Algorithm = ""
-
-func NewSignerHS(_ Algorithm, _ []byte) (Signer, error) {
- return nil, nil
-}
-
-type Signer interface {
- Algorithm() Algorithm
- Sign(_ []byte) ([]byte, error)
- SignSize() int
-}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/LICENSE
new file mode 100644
index 000000000000..bc52e96f2b0e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2012-2016 Dave Collins
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/bypass.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644
index 000000000000..792994785e36
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/bypass.go
@@ -0,0 +1,145 @@
+// Copyright (c) 2015-2016 Dave Collins
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is not running on Google App Engine, compiled by GopherJS, and
+// "-tags safe" is not added to the go build command line. The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// Go versions prior to 1.4 are disabled because they use a different layout
+// for interfaces which make the implementation of unsafeReflectValue more complex.
+// +build !js,!appengine,!safe,!disableunsafe,go1.4
+
+package spew
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+const (
+ // UnsafeDisabled is a build-time constant which specifies whether or
+ // not access to the unsafe package is available.
+ UnsafeDisabled = false
+
+ // ptrSize is the size of a pointer on the current arch.
+ ptrSize = unsafe.Sizeof((*byte)(nil))
+)
+
+type flag uintptr
+
+var (
+ // flagRO indicates whether the value field of a reflect.Value
+ // is read-only.
+ flagRO flag
+
+ // flagAddr indicates whether the address of the reflect.Value's
+ // value may be taken.
+ flagAddr flag
+)
+
+// flagKindMask holds the bits that make up the kind
+// part of the flags field. In all the supported versions,
+// it is in the lower 5 bits.
+const flagKindMask = flag(0x1f)
+
+// Different versions of Go have used different
+// bit layouts for the flags type. This table
+// records the known combinations.
+var okFlags = []struct {
+ ro, addr flag
+}{{
+ // From Go 1.4 to 1.5
+ ro: 1 << 5,
+ addr: 1 << 7,
+}, {
+ // Up to Go tip.
+ ro: 1<<5 | 1<<6,
+ addr: 1 << 8,
+}}
+
+var flagValOffset = func() uintptr {
+ field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
+ if !ok {
+ panic("reflect.Value has no flag field")
+ }
+ return field.Offset
+}()
+
+// flagField returns a pointer to the flag field of a reflect.Value.
+func flagField(v *reflect.Value) *flag {
+ return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
+}
+
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
+// the typical safety restrictions preventing access to unaddressable and
+// unexported data. It works by digging the raw pointer to the underlying
+// value out of the protected value and generating a new unprotected (unsafe)
+// reflect.Value to it.
+//
+// This allows us to check for implementations of the Stringer and error
+// interfaces to be used for pretty printing ordinarily unaddressable and
+// inaccessible values such as unexported struct fields.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+ if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
+ return v
+ }
+ flagFieldPtr := flagField(&v)
+ *flagFieldPtr &^= flagRO
+ *flagFieldPtr |= flagAddr
+ return v
+}
+
+// Sanity checks against future reflect package changes
+// to the type or semantics of the Value.flag field.
+func init() {
+ field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
+ if !ok {
+ panic("reflect.Value has no flag field")
+ }
+ if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
+ panic("reflect.Value flag field has changed kind")
+ }
+ type t0 int
+ var t struct {
+ A t0
+ // t0 will have flagEmbedRO set.
+ t0
+ // a will have flagStickyRO set
+ a t0
+ }
+ vA := reflect.ValueOf(t).FieldByName("A")
+ va := reflect.ValueOf(t).FieldByName("a")
+ vt0 := reflect.ValueOf(t).FieldByName("t0")
+
+ // Infer flagRO from the difference between the flags
+ // for the (otherwise identical) fields in t.
+ flagPublic := *flagField(&vA)
+ flagWithRO := *flagField(&va) | *flagField(&vt0)
+ flagRO = flagPublic ^ flagWithRO
+
+ // Infer flagAddr from the difference between a value
+ // taken from a pointer and not.
+ vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
+ flagNoPtr := *flagField(&vA)
+ flagPtr := *flagField(&vPtrA)
+ flagAddr = flagNoPtr ^ flagPtr
+
+ // Check that the inferred flags tally with one of the known versions.
+ for _, f := range okFlags {
+ if flagRO == f.ro && flagAddr == f.addr {
+ return
+ }
+ }
+ panic("reflect.Value read-only flag has changed semantics")
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644
index 000000000000..205c28d68c47
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
@@ -0,0 +1,38 @@
+// Copyright (c) 2015-2016 Dave Collins
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is running on Google App Engine, compiled by GopherJS, or
+// "-tags safe" is added to the go build command line. The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// +build js appengine safe disableunsafe !go1.4
+
+package spew
+
+import "reflect"
+
+const (
+ // UnsafeDisabled is a build-time constant which specifies whether or
+ // not access to the unsafe package is available.
+ UnsafeDisabled = true
+)
+
+// unsafeReflectValue typically converts the passed reflect.Value into a one
+// that bypasses the typical safety restrictions preventing access to
+// unaddressable and unexported data. However, doing this relies on access to
+// the unsafe package. This is a stub version which simply returns the passed
+// reflect.Value when the unsafe package is not available.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+ return v
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/common.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/common.go
new file mode 100644
index 000000000000..1be8ce945761
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/common.go
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strconv"
+)
+
+// Some constants in the form of bytes to avoid string overhead. This mirrors
+// the technique used in the fmt package.
+var (
+ panicBytes = []byte("(PANIC=")
+ plusBytes = []byte("+")
+ iBytes = []byte("i")
+ trueBytes = []byte("true")
+ falseBytes = []byte("false")
+ interfaceBytes = []byte("(interface {})")
+ commaNewlineBytes = []byte(",\n")
+ newlineBytes = []byte("\n")
+ openBraceBytes = []byte("{")
+ openBraceNewlineBytes = []byte("{\n")
+ closeBraceBytes = []byte("}")
+ asteriskBytes = []byte("*")
+ colonBytes = []byte(":")
+ colonSpaceBytes = []byte(": ")
+ openParenBytes = []byte("(")
+ closeParenBytes = []byte(")")
+ spaceBytes = []byte(" ")
+ pointerChainBytes = []byte("->")
+ nilAngleBytes = []byte("")
+ maxNewlineBytes = []byte("\n")
+ maxShortBytes = []byte("")
+ circularBytes = []byte("")
+ circularShortBytes = []byte("")
+ invalidAngleBytes = []byte("")
+ openBracketBytes = []byte("[")
+ closeBracketBytes = []byte("]")
+ percentBytes = []byte("%")
+ precisionBytes = []byte(".")
+ openAngleBytes = []byte("<")
+ closeAngleBytes = []byte(">")
+ openMapBytes = []byte("map[")
+ closeMapBytes = []byte("]")
+ lenEqualsBytes = []byte("len=")
+ capEqualsBytes = []byte("cap=")
+)
+
+// hexDigits is used to map a decimal value to a hex digit.
+var hexDigits = "0123456789abcdef"
+
+// catchPanic handles any panics that might occur during the handleMethods
+// calls.
+func catchPanic(w io.Writer, v reflect.Value) {
+ if err := recover(); err != nil {
+ w.Write(panicBytes)
+ fmt.Fprintf(w, "%v", err)
+ w.Write(closeParenBytes)
+ }
+}
+
+// handleMethods attempts to call the Error and String methods on the underlying
+// type the passed reflect.Value represents and outputes the result to Writer w.
+//
+// It handles panics in any called methods by catching and displaying the error
+// as the formatted value.
+func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
+ // We need an interface to check if the type implements the error or
+ // Stringer interface. However, the reflect package won't give us an
+ // interface on certain things like unexported struct fields in order
+ // to enforce visibility rules. We use unsafe, when it's available,
+ // to bypass these restrictions since this package does not mutate the
+ // values.
+ if !v.CanInterface() {
+ if UnsafeDisabled {
+ return false
+ }
+
+ v = unsafeReflectValue(v)
+ }
+
+ // Choose whether or not to do error and Stringer interface lookups against
+ // the base type or a pointer to the base type depending on settings.
+ // Technically calling one of these methods with a pointer receiver can
+ // mutate the value, however, types which choose to satisify an error or
+ // Stringer interface with a pointer receiver should not be mutating their
+ // state inside these interface methods.
+ if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
+ v = unsafeReflectValue(v)
+ }
+ if v.CanAddr() {
+ v = v.Addr()
+ }
+
+ // Is it an error or Stringer?
+ switch iface := v.Interface().(type) {
+ case error:
+ defer catchPanic(w, v)
+ if cs.ContinueOnMethod {
+ w.Write(openParenBytes)
+ w.Write([]byte(iface.Error()))
+ w.Write(closeParenBytes)
+ w.Write(spaceBytes)
+ return false
+ }
+
+ w.Write([]byte(iface.Error()))
+ return true
+
+ case fmt.Stringer:
+ defer catchPanic(w, v)
+ if cs.ContinueOnMethod {
+ w.Write(openParenBytes)
+ w.Write([]byte(iface.String()))
+ w.Write(closeParenBytes)
+ w.Write(spaceBytes)
+ return false
+ }
+ w.Write([]byte(iface.String()))
+ return true
+ }
+ return false
+}
+
+// printBool outputs a boolean value as true or false to Writer w.
+func printBool(w io.Writer, val bool) {
+ if val {
+ w.Write(trueBytes)
+ } else {
+ w.Write(falseBytes)
+ }
+}
+
+// printInt outputs a signed integer value to Writer w.
+func printInt(w io.Writer, val int64, base int) {
+ w.Write([]byte(strconv.FormatInt(val, base)))
+}
+
+// printUint outputs an unsigned integer value to Writer w.
+func printUint(w io.Writer, val uint64, base int) {
+ w.Write([]byte(strconv.FormatUint(val, base)))
+}
+
+// printFloat outputs a floating point value using the specified precision,
+// which is expected to be 32 or 64bit, to Writer w.
+func printFloat(w io.Writer, val float64, precision int) {
+ w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
+}
+
+// printComplex outputs a complex value using the specified float precision
+// for the real and imaginary parts to Writer w.
+func printComplex(w io.Writer, c complex128, floatPrecision int) {
+ r := real(c)
+ w.Write(openParenBytes)
+ w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
+ i := imag(c)
+ if i >= 0 {
+ w.Write(plusBytes)
+ }
+ w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
+ w.Write(iBytes)
+ w.Write(closeParenBytes)
+}
+
+// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
+// prefix to Writer w.
+func printHexPtr(w io.Writer, p uintptr) {
+ // Null pointer.
+ num := uint64(p)
+ if num == 0 {
+ w.Write(nilAngleBytes)
+ return
+ }
+
+ // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
+ buf := make([]byte, 18)
+
+ // It's simpler to construct the hex string right to left.
+ base := uint64(16)
+ i := len(buf) - 1
+ for num >= base {
+ buf[i] = hexDigits[num%base]
+ num /= base
+ i--
+ }
+ buf[i] = hexDigits[num]
+
+ // Add '0x' prefix.
+ i--
+ buf[i] = 'x'
+ i--
+ buf[i] = '0'
+
+ // Strip unused leading bytes.
+ buf = buf[i:]
+ w.Write(buf)
+}
+
+// valuesSorter implements sort.Interface to allow a slice of reflect.Value
+// elements to be sorted.
+type valuesSorter struct {
+ values []reflect.Value
+ strings []string // either nil or same len and values
+ cs *ConfigState
+}
+
+// newValuesSorter initializes a valuesSorter instance, which holds a set of
+// surrogate keys on which the data should be sorted. It uses flags in
+// ConfigState to decide if and how to populate those surrogate keys.
+func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
+ vs := &valuesSorter{values: values, cs: cs}
+ if canSortSimply(vs.values[0].Kind()) {
+ return vs
+ }
+ if !cs.DisableMethods {
+ vs.strings = make([]string, len(values))
+ for i := range vs.values {
+ b := bytes.Buffer{}
+ if !handleMethods(cs, &b, vs.values[i]) {
+ vs.strings = nil
+ break
+ }
+ vs.strings[i] = b.String()
+ }
+ }
+ if vs.strings == nil && cs.SpewKeys {
+ vs.strings = make([]string, len(values))
+ for i := range vs.values {
+ vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
+ }
+ }
+ return vs
+}
+
+// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
+// directly, or whether it should be considered for sorting by surrogate keys
+// (if the ConfigState allows it).
+func canSortSimply(kind reflect.Kind) bool {
+ // This switch parallels valueSortLess, except for the default case.
+ switch kind {
+ case reflect.Bool:
+ return true
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ return true
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ return true
+ case reflect.Float32, reflect.Float64:
+ return true
+ case reflect.String:
+ return true
+ case reflect.Uintptr:
+ return true
+ case reflect.Array:
+ return true
+ }
+ return false
+}
+
+// Len returns the number of values in the slice. It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Len() int {
+ return len(s.values)
+}
+
+// Swap swaps the values at the passed indices. It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Swap(i, j int) {
+ s.values[i], s.values[j] = s.values[j], s.values[i]
+ if s.strings != nil {
+ s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
+ }
+}
+
+// valueSortLess returns whether the first value should sort before the second
+// value. It is used by valueSorter.Less as part of the sort.Interface
+// implementation.
+func valueSortLess(a, b reflect.Value) bool {
+ switch a.Kind() {
+ case reflect.Bool:
+ return !a.Bool() && b.Bool()
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ return a.Int() < b.Int()
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ return a.Uint() < b.Uint()
+ case reflect.Float32, reflect.Float64:
+ return a.Float() < b.Float()
+ case reflect.String:
+ return a.String() < b.String()
+ case reflect.Uintptr:
+ return a.Uint() < b.Uint()
+ case reflect.Array:
+ // Compare the contents of both arrays.
+ l := a.Len()
+ for i := 0; i < l; i++ {
+ av := a.Index(i)
+ bv := b.Index(i)
+ if av.Interface() == bv.Interface() {
+ continue
+ }
+ return valueSortLess(av, bv)
+ }
+ }
+ return a.String() < b.String()
+}
+
+// Less returns whether the value at index i should sort before the
+// value at index j. It is part of the sort.Interface implementation.
+func (s *valuesSorter) Less(i, j int) bool {
+ if s.strings == nil {
+ return valueSortLess(s.values[i], s.values[j])
+ }
+ return s.strings[i] < s.strings[j]
+}
+
+// sortValues is a sort function that handles both native types and any type that
+// can be converted to error or Stringer. Other inputs are sorted according to
+// their Value.String() value to ensure display stability.
+func sortValues(values []reflect.Value, cs *ConfigState) {
+ if len(values) == 0 {
+ return
+ }
+ sort.Sort(newValuesSorter(values, cs))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/config.go
new file mode 100644
index 000000000000..2e3d22f31202
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/config.go
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+)
+
+// ConfigState houses the configuration options used by spew to format and
+// display values. There is a global instance, Config, that is used to control
+// all top-level Formatter and Dump functionality. Each ConfigState instance
+// provides methods equivalent to the top-level functions.
+//
+// The zero value for ConfigState provides no indentation. You would typically
+// want to set it to a space or a tab.
+//
+// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
+// with default settings. See the documentation of NewDefaultConfig for default
+// values.
+type ConfigState struct {
+ // Indent specifies the string to use for each indentation level. The
+ // global config instance that all top-level functions use set this to a
+ // single space by default. If you would like more indentation, you might
+ // set this to a tab with "\t" or perhaps two spaces with " ".
+ Indent string
+
+ // MaxDepth controls the maximum number of levels to descend into nested
+ // data structures. The default, 0, means there is no limit.
+ //
+ // NOTE: Circular data structures are properly detected, so it is not
+ // necessary to set this value unless you specifically want to limit deeply
+ // nested data structures.
+ MaxDepth int
+
+ // DisableMethods specifies whether or not error and Stringer interfaces are
+ // invoked for types that implement them.
+ DisableMethods bool
+
+ // DisablePointerMethods specifies whether or not to check for and invoke
+ // error and Stringer interfaces on types which only accept a pointer
+ // receiver when the current type is not a pointer.
+ //
+ // NOTE: This might be an unsafe action since calling one of these methods
+ // with a pointer receiver could technically mutate the value, however,
+ // in practice, types which choose to satisify an error or Stringer
+ // interface with a pointer receiver should not be mutating their state
+ // inside these interface methods. As a result, this option relies on
+ // access to the unsafe package, so it will not have any effect when
+ // running in environments without access to the unsafe package such as
+ // Google App Engine or with the "safe" build tag specified.
+ DisablePointerMethods bool
+
+ // DisablePointerAddresses specifies whether to disable the printing of
+ // pointer addresses. This is useful when diffing data structures in tests.
+ DisablePointerAddresses bool
+
+ // DisableCapacities specifies whether to disable the printing of capacities
+ // for arrays, slices, maps and channels. This is useful when diffing
+ // data structures in tests.
+ DisableCapacities bool
+
+ // ContinueOnMethod specifies whether or not recursion should continue once
+ // a custom error or Stringer interface is invoked. The default, false,
+ // means it will print the results of invoking the custom error or Stringer
+ // interface and return immediately instead of continuing to recurse into
+ // the internals of the data type.
+ //
+ // NOTE: This flag does not have any effect if method invocation is disabled
+ // via the DisableMethods or DisablePointerMethods options.
+ ContinueOnMethod bool
+
+ // SortKeys specifies map keys should be sorted before being printed. Use
+ // this to have a more deterministic, diffable output. Note that only
+ // native types (bool, int, uint, floats, uintptr and string) and types
+ // that support the error or Stringer interfaces (if methods are
+ // enabled) are supported, with other types sorted according to the
+ // reflect.Value.String() output which guarantees display stability.
+ SortKeys bool
+
+ // SpewKeys specifies that, as a last resort attempt, map keys should
+ // be spewed to strings and sorted by those strings. This is only
+ // considered if SortKeys is true.
+ SpewKeys bool
+}
+
+// Config is the active configuration of the top-level functions.
+// The configuration can be changed by modifying the contents of spew.Config.
+var Config = ConfigState{Indent: " "}
+
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the formatted string as a value that satisfies error. See NewFormatter
+// for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
+ return fmt.Errorf(format, c.convertArgs(a)...)
+}
+
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+ return fmt.Fprint(w, c.convertArgs(a)...)
+}
+
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+ return fmt.Fprintf(w, format, c.convertArgs(a)...)
+}
+
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
+// passed with a Formatter interface returned by c.NewFormatter. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+ return fmt.Fprintln(w, c.convertArgs(a)...)
+}
+
+// Print is a wrapper for fmt.Print that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
+ return fmt.Print(c.convertArgs(a)...)
+}
+
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
+ return fmt.Printf(format, c.convertArgs(a)...)
+}
+
+// Println is a wrapper for fmt.Println that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
+ return fmt.Println(c.convertArgs(a)...)
+}
+
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprint(a ...interface{}) string {
+ return fmt.Sprint(c.convertArgs(a)...)
+}
+
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
+ return fmt.Sprintf(format, c.convertArgs(a)...)
+}
+
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
+// were passed with a Formatter interface returned by c.NewFormatter. It
+// returns the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprintln(a ...interface{}) string {
+ return fmt.Sprintln(c.convertArgs(a)...)
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface. As a result, it integrates cleanly with standard fmt package
+printing functions. The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
+combinations. Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting. In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly. It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+c.Printf, c.Println, or c.Printf.
+*/
+func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
+ return newFormatter(c, v)
+}
+
+// Fdump formats and displays the passed arguments to io.Writer w. It formats
+// exactly the same as Dump.
+func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
+ fdump(c, w, a...)
+}
+
+/*
+Dump displays the passed parameters to standard out with newlines, customizable
+indentation, and additional debug information such as complete types and all
+pointer addresses used to indirect to the final value. It provides the
+following features over the built-in printing facilities provided by the fmt
+package:
+
+ * Pointers are dereferenced and followed
+ * Circular data structures are detected and handled properly
+ * Custom Stringer/error interfaces are optionally invoked, including
+ on unexported types
+ * Custom types which only implement the Stringer/error interfaces via
+ a pointer receiver are optionally invoked when passing non-pointer
+ variables
+ * Byte arrays and slices are dumped like the hexdump -C command which
+ includes offsets, byte values in hex, and ASCII output
+
+The configuration options are controlled by modifying the public members
+of c. See ConfigState for options documentation.
+
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
+get the formatted result as a string.
+*/
+func (c *ConfigState) Dump(a ...interface{}) {
+ fdump(c, os.Stdout, a...)
+}
+
+// Sdump returns a string with the passed arguments formatted exactly the same
+// as Dump.
+func (c *ConfigState) Sdump(a ...interface{}) string {
+ var buf bytes.Buffer
+ fdump(c, &buf, a...)
+ return buf.String()
+}
+
+// convertArgs accepts a slice of arguments and returns a slice of the same
+// length with each argument converted to a spew Formatter interface using
+// the ConfigState associated with s.
+func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
+ formatters = make([]interface{}, len(args))
+ for index, arg := range args {
+ formatters[index] = newFormatter(c, arg)
+ }
+ return formatters
+}
+
+// NewDefaultConfig returns a ConfigState with the following default settings.
+//
+// Indent: " "
+// MaxDepth: 0
+// DisableMethods: false
+// DisablePointerMethods: false
+// ContinueOnMethod: false
+// SortKeys: false
+func NewDefaultConfig() *ConfigState {
+ return &ConfigState{Indent: " "}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/doc.go
new file mode 100644
index 000000000000..aacaac6f1e1e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/doc.go
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Package spew implements a deep pretty printer for Go data structures to aid in
+debugging.
+
+A quick overview of the additional features spew provides over the built-in
+printing facilities for Go data types are as follows:
+
+ * Pointers are dereferenced and followed
+ * Circular data structures are detected and handled properly
+ * Custom Stringer/error interfaces are optionally invoked, including
+ on unexported types
+ * Custom types which only implement the Stringer/error interfaces via
+ a pointer receiver are optionally invoked when passing non-pointer
+ variables
+ * Byte arrays and slices are dumped like the hexdump -C command which
+ includes offsets, byte values in hex, and ASCII output (only when using
+ Dump style)
+
+There are two different approaches spew allows for dumping Go data structures:
+
+ * Dump style which prints with newlines, customizable indentation,
+ and additional debug information such as types and all pointer addresses
+ used to indirect to the final value
+ * A custom Formatter interface that integrates cleanly with the standard fmt
+ package and replaces %v, %+v, %#v, and %#+v to provide inline printing
+ similar to the default %v while providing the additional functionality
+ outlined above and passing unsupported format verbs such as %x and %q
+ along to fmt
+
+Quick Start
+
+This section demonstrates how to quickly get started with spew. See the
+sections below for further details on formatting and configuration options.
+
+To dump a variable with full newlines, indentation, type, and pointer
+information use Dump, Fdump, or Sdump:
+ spew.Dump(myVar1, myVar2, ...)
+ spew.Fdump(someWriter, myVar1, myVar2, ...)
+ str := spew.Sdump(myVar1, myVar2, ...)
+
+Alternatively, if you would prefer to use format strings with a compacted inline
+printing style, use the convenience wrappers Printf, Fprintf, etc with
+%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
+%#+v (adds types and pointer addresses):
+ spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+ spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+
+Configuration Options
+
+Configuration of spew is handled by fields in the ConfigState type. For
+convenience, all of the top-level functions use a global state available
+via the spew.Config global.
+
+It is also possible to create a ConfigState instance that provides methods
+equivalent to the top-level functions. This allows concurrent configuration
+options. See the ConfigState documentation for more details.
+
+The following configuration options are available:
+ * Indent
+ String to use for each indentation level for Dump functions.
+ It is a single space by default. A popular alternative is "\t".
+
+ * MaxDepth
+ Maximum number of levels to descend into nested data structures.
+ There is no limit by default.
+
+ * DisableMethods
+ Disables invocation of error and Stringer interface methods.
+ Method invocation is enabled by default.
+
+ * DisablePointerMethods
+ Disables invocation of error and Stringer interface methods on types
+ which only accept pointer receivers from non-pointer variables.
+ Pointer method invocation is enabled by default.
+
+ * DisablePointerAddresses
+ DisablePointerAddresses specifies whether to disable the printing of
+ pointer addresses. This is useful when diffing data structures in tests.
+
+ * DisableCapacities
+ DisableCapacities specifies whether to disable the printing of
+ capacities for arrays, slices, maps and channels. This is useful when
+ diffing data structures in tests.
+
+ * ContinueOnMethod
+ Enables recursion into types after invoking error and Stringer interface
+ methods. Recursion after method invocation is disabled by default.
+
+ * SortKeys
+ Specifies map keys should be sorted before being printed. Use
+ this to have a more deterministic, diffable output. Note that
+ only native types (bool, int, uint, floats, uintptr and string)
+ and types which implement error or Stringer interfaces are
+ supported with other types sorted according to the
+ reflect.Value.String() output which guarantees display
+ stability. Natural map order is used by default.
+
+ * SpewKeys
+ Specifies that, as a last resort attempt, map keys should be
+ spewed to strings and sorted by those strings. This is only
+ considered if SortKeys is true.
+
+Dump Usage
+
+Simply call spew.Dump with a list of variables you want to dump:
+
+ spew.Dump(myVar1, myVar2, ...)
+
+You may also call spew.Fdump if you would prefer to output to an arbitrary
+io.Writer. For example, to dump to standard error:
+
+ spew.Fdump(os.Stderr, myVar1, myVar2, ...)
+
+A third option is to call spew.Sdump to get the formatted output as a string:
+
+ str := spew.Sdump(myVar1, myVar2, ...)
+
+Sample Dump Output
+
+See the Dump example for details on the setup of the types and variables being
+shown here.
+
+ (main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+ flag: (main.Flag) flagTwo,
+ data: (uintptr)
+ }),
+ ExportedField: (map[interface {}]interface {}) (len=1) {
+ (string) (len=3) "one": (bool) true
+ }
+ }
+
+Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
+command as shown.
+ ([]uint8) (len=32 cap=32) {
+ 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
+ 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
+ 00000020 31 32 |12|
+ }
+
+Custom Formatter
+
+Spew provides a custom formatter that implements the fmt.Formatter interface
+so that it integrates cleanly with standard fmt package printing functions. The
+formatter is useful for inline printing of smaller data types similar to the
+standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations. Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting. In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Custom Formatter Usage
+
+The simplest way to make use of the spew custom formatter is to call one of the
+convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
+functions have syntax you are most likely already familiar with:
+
+ spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+ spew.Println(myVar, myVar2)
+ spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+
+See the Index for the full list convenience functions.
+
+Sample Formatter Output
+
+Double pointer to a uint8:
+ %v: <**>5
+ %+v: <**>(0xf8400420d0->0xf8400420c8)5
+ %#v: (**uint8)5
+ %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
+
+Pointer to circular struct with a uint8 field and a pointer to itself:
+ %v: <*>{1 <*>}
+ %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)}
+ %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)}
+ %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)}
+
+See the Printf example for details on the setup of variables being shown
+here.
+
+Errors
+
+Since it is possible for custom Stringer/error interfaces to panic, spew
+detects them and handles them internally by printing the panic information
+inline with the output. Since spew is intended to provide deep pretty printing
+capabilities on structures, it intentionally does not return any errors.
+*/
+package spew
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/dump.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/dump.go
new file mode 100644
index 000000000000..f78d89fc1f6c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/dump.go
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ // uint8Type is a reflect.Type representing a uint8. It is used to
+ // convert cgo types to uint8 slices for hexdumping.
+ uint8Type = reflect.TypeOf(uint8(0))
+
+ // cCharRE is a regular expression that matches a cgo char.
+ // It is used to detect character arrays to hexdump them.
+ cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
+
+ // cUnsignedCharRE is a regular expression that matches a cgo unsigned
+ // char. It is used to detect unsigned character arrays to hexdump
+ // them.
+ cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
+
+ // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
+ // It is used to detect uint8_t arrays to hexdump them.
+ cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
+)
+
+// dumpState contains information about the state of a dump operation.
+type dumpState struct {
+ w io.Writer
+ depth int
+ pointers map[uintptr]int
+ ignoreNextType bool
+ ignoreNextIndent bool
+ cs *ConfigState
+}
+
+// indent performs indentation according to the depth level and cs.Indent
+// option.
+func (d *dumpState) indent() {
+ if d.ignoreNextIndent {
+ d.ignoreNextIndent = false
+ return
+ }
+ d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
+ if v.Kind() == reflect.Interface && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v
+}
+
+// dumpPtr handles formatting of pointers by indirecting them as necessary.
+func (d *dumpState) dumpPtr(v reflect.Value) {
+ // Remove pointers at or below the current depth from map used to detect
+ // circular refs.
+ for k, depth := range d.pointers {
+ if depth >= d.depth {
+ delete(d.pointers, k)
+ }
+ }
+
+ // Keep list of all dereferenced pointers to show later.
+ pointerChain := make([]uintptr, 0)
+
+ // Figure out how many levels of indirection there are by dereferencing
+ // pointers and unpacking interfaces down the chain while detecting circular
+ // references.
+ nilFound := false
+ cycleFound := false
+ indirects := 0
+ ve := v
+ for ve.Kind() == reflect.Ptr {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ indirects++
+ addr := ve.Pointer()
+ pointerChain = append(pointerChain, addr)
+ if pd, ok := d.pointers[addr]; ok && pd < d.depth {
+ cycleFound = true
+ indirects--
+ break
+ }
+ d.pointers[addr] = d.depth
+
+ ve = ve.Elem()
+ if ve.Kind() == reflect.Interface {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ ve = ve.Elem()
+ }
+ }
+
+ // Display type information.
+ d.w.Write(openParenBytes)
+ d.w.Write(bytes.Repeat(asteriskBytes, indirects))
+ d.w.Write([]byte(ve.Type().String()))
+ d.w.Write(closeParenBytes)
+
+ // Display pointer information.
+ if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
+ d.w.Write(openParenBytes)
+ for i, addr := range pointerChain {
+ if i > 0 {
+ d.w.Write(pointerChainBytes)
+ }
+ printHexPtr(d.w, addr)
+ }
+ d.w.Write(closeParenBytes)
+ }
+
+ // Display dereferenced value.
+ d.w.Write(openParenBytes)
+ switch {
+ case nilFound:
+ d.w.Write(nilAngleBytes)
+
+ case cycleFound:
+ d.w.Write(circularBytes)
+
+ default:
+ d.ignoreNextType = true
+ d.dump(ve)
+ }
+ d.w.Write(closeParenBytes)
+}
+
+// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
+// reflection) arrays and slices are dumped in hexdump -C fashion.
+func (d *dumpState) dumpSlice(v reflect.Value) {
+ // Determine whether this type should be hex dumped or not. Also,
+ // for types which should be hexdumped, try to use the underlying data
+ // first, then fall back to trying to convert them to a uint8 slice.
+ var buf []uint8
+ doConvert := false
+ doHexDump := false
+ numEntries := v.Len()
+ if numEntries > 0 {
+ vt := v.Index(0).Type()
+ vts := vt.String()
+ switch {
+ // C types that need to be converted.
+ case cCharRE.MatchString(vts):
+ fallthrough
+ case cUnsignedCharRE.MatchString(vts):
+ fallthrough
+ case cUint8tCharRE.MatchString(vts):
+ doConvert = true
+
+ // Try to use existing uint8 slices and fall back to converting
+ // and copying if that fails.
+ case vt.Kind() == reflect.Uint8:
+ // We need an addressable interface to convert the type
+ // to a byte slice. However, the reflect package won't
+ // give us an interface on certain things like
+ // unexported struct fields in order to enforce
+ // visibility rules. We use unsafe, when available, to
+ // bypass these restrictions since this package does not
+ // mutate the values.
+ vs := v
+ if !vs.CanInterface() || !vs.CanAddr() {
+ vs = unsafeReflectValue(vs)
+ }
+ if !UnsafeDisabled {
+ vs = vs.Slice(0, numEntries)
+
+ // Use the existing uint8 slice if it can be
+ // type asserted.
+ iface := vs.Interface()
+ if slice, ok := iface.([]uint8); ok {
+ buf = slice
+ doHexDump = true
+ break
+ }
+ }
+
+ // The underlying data needs to be converted if it can't
+ // be type asserted to a uint8 slice.
+ doConvert = true
+ }
+
+ // Copy and convert the underlying type if needed.
+ if doConvert && vt.ConvertibleTo(uint8Type) {
+ // Convert and copy each element into a uint8 byte
+ // slice.
+ buf = make([]uint8, numEntries)
+ for i := 0; i < numEntries; i++ {
+ vv := v.Index(i)
+ buf[i] = uint8(vv.Convert(uint8Type).Uint())
+ }
+ doHexDump = true
+ }
+ }
+
+ // Hexdump the entire slice as needed.
+ if doHexDump {
+ indent := strings.Repeat(d.cs.Indent, d.depth)
+ str := indent + hex.Dump(buf)
+ str = strings.Replace(str, "\n", "\n"+indent, -1)
+ str = strings.TrimRight(str, d.cs.Indent)
+ d.w.Write([]byte(str))
+ return
+ }
+
+ // Recursively call dump for each item.
+ for i := 0; i < numEntries; i++ {
+ d.dump(d.unpackValue(v.Index(i)))
+ if i < (numEntries - 1) {
+ d.w.Write(commaNewlineBytes)
+ } else {
+ d.w.Write(newlineBytes)
+ }
+ }
+}
+
+// dump is the main workhorse for dumping a value. It uses the passed reflect
+// value to figure out what kind of object we are dealing with and formats it
+// appropriately. It is a recursive function, however circular data structures
+// are detected and handled properly.
+func (d *dumpState) dump(v reflect.Value) {
+ // Handle invalid reflect values immediately.
+ kind := v.Kind()
+ if kind == reflect.Invalid {
+ d.w.Write(invalidAngleBytes)
+ return
+ }
+
+ // Handle pointers specially.
+ if kind == reflect.Ptr {
+ d.indent()
+ d.dumpPtr(v)
+ return
+ }
+
+ // Print type information unless already handled elsewhere.
+ if !d.ignoreNextType {
+ d.indent()
+ d.w.Write(openParenBytes)
+ d.w.Write([]byte(v.Type().String()))
+ d.w.Write(closeParenBytes)
+ d.w.Write(spaceBytes)
+ }
+ d.ignoreNextType = false
+
+ // Display length and capacity if the built-in len and cap functions
+ // work with the value's kind and the len/cap itself is non-zero.
+ valueLen, valueCap := 0, 0
+ switch v.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Chan:
+ valueLen, valueCap = v.Len(), v.Cap()
+ case reflect.Map, reflect.String:
+ valueLen = v.Len()
+ }
+ if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
+ d.w.Write(openParenBytes)
+ if valueLen != 0 {
+ d.w.Write(lenEqualsBytes)
+ printInt(d.w, int64(valueLen), 10)
+ }
+ if !d.cs.DisableCapacities && valueCap != 0 {
+ if valueLen != 0 {
+ d.w.Write(spaceBytes)
+ }
+ d.w.Write(capEqualsBytes)
+ printInt(d.w, int64(valueCap), 10)
+ }
+ d.w.Write(closeParenBytes)
+ d.w.Write(spaceBytes)
+ }
+
+ // Call Stringer/error interfaces if they exist and the handle methods flag
+ // is enabled
+ if !d.cs.DisableMethods {
+ if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+ if handled := handleMethods(d.cs, d.w, v); handled {
+ return
+ }
+ }
+ }
+
+ switch kind {
+ case reflect.Invalid:
+ // Do nothing. We should never get here since invalid has already
+ // been handled above.
+
+ case reflect.Bool:
+ printBool(d.w, v.Bool())
+
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ printInt(d.w, v.Int(), 10)
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ printUint(d.w, v.Uint(), 10)
+
+ case reflect.Float32:
+ printFloat(d.w, v.Float(), 32)
+
+ case reflect.Float64:
+ printFloat(d.w, v.Float(), 64)
+
+ case reflect.Complex64:
+ printComplex(d.w, v.Complex(), 32)
+
+ case reflect.Complex128:
+ printComplex(d.w, v.Complex(), 64)
+
+ case reflect.Slice:
+ if v.IsNil() {
+ d.w.Write(nilAngleBytes)
+ break
+ }
+ fallthrough
+
+ case reflect.Array:
+ d.w.Write(openBraceNewlineBytes)
+ d.depth++
+ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+ d.indent()
+ d.w.Write(maxNewlineBytes)
+ } else {
+ d.dumpSlice(v)
+ }
+ d.depth--
+ d.indent()
+ d.w.Write(closeBraceBytes)
+
+ case reflect.String:
+ d.w.Write([]byte(strconv.Quote(v.String())))
+
+ case reflect.Interface:
+ // The only time we should get here is for nil interfaces due to
+ // unpackValue calls.
+ if v.IsNil() {
+ d.w.Write(nilAngleBytes)
+ }
+
+ case reflect.Ptr:
+ // Do nothing. We should never get here since pointers have already
+ // been handled above.
+
+ case reflect.Map:
+ // nil maps should be indicated as different than empty maps
+ if v.IsNil() {
+ d.w.Write(nilAngleBytes)
+ break
+ }
+
+ d.w.Write(openBraceNewlineBytes)
+ d.depth++
+ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+ d.indent()
+ d.w.Write(maxNewlineBytes)
+ } else {
+ numEntries := v.Len()
+ keys := v.MapKeys()
+ if d.cs.SortKeys {
+ sortValues(keys, d.cs)
+ }
+ for i, key := range keys {
+ d.dump(d.unpackValue(key))
+ d.w.Write(colonSpaceBytes)
+ d.ignoreNextIndent = true
+ d.dump(d.unpackValue(v.MapIndex(key)))
+ if i < (numEntries - 1) {
+ d.w.Write(commaNewlineBytes)
+ } else {
+ d.w.Write(newlineBytes)
+ }
+ }
+ }
+ d.depth--
+ d.indent()
+ d.w.Write(closeBraceBytes)
+
+ case reflect.Struct:
+ d.w.Write(openBraceNewlineBytes)
+ d.depth++
+ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+ d.indent()
+ d.w.Write(maxNewlineBytes)
+ } else {
+ vt := v.Type()
+ numFields := v.NumField()
+ for i := 0; i < numFields; i++ {
+ d.indent()
+ vtf := vt.Field(i)
+ d.w.Write([]byte(vtf.Name))
+ d.w.Write(colonSpaceBytes)
+ d.ignoreNextIndent = true
+ d.dump(d.unpackValue(v.Field(i)))
+ if i < (numFields - 1) {
+ d.w.Write(commaNewlineBytes)
+ } else {
+ d.w.Write(newlineBytes)
+ }
+ }
+ }
+ d.depth--
+ d.indent()
+ d.w.Write(closeBraceBytes)
+
+ case reflect.Uintptr:
+ printHexPtr(d.w, uintptr(v.Uint()))
+
+ case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+ printHexPtr(d.w, v.Pointer())
+
+ // There were not any other types at the time this code was written, but
+ // fall back to letting the default fmt package handle it in case any new
+ // types are added.
+ default:
+ if v.CanInterface() {
+ fmt.Fprintf(d.w, "%v", v.Interface())
+ } else {
+ fmt.Fprintf(d.w, "%v", v.String())
+ }
+ }
+}
+
+// fdump is a helper function to consolidate the logic from the various public
+// methods which take varying writers and config states.
+func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
+ for _, arg := range a {
+ if arg == nil {
+ w.Write(interfaceBytes)
+ w.Write(spaceBytes)
+ w.Write(nilAngleBytes)
+ w.Write(newlineBytes)
+ continue
+ }
+
+ d := dumpState{w: w, cs: cs}
+ d.pointers = make(map[uintptr]int)
+ d.dump(reflect.ValueOf(arg))
+ d.w.Write(newlineBytes)
+ }
+}
+
+// Fdump formats and displays the passed arguments to io.Writer w. It formats
+// exactly the same as Dump.
+func Fdump(w io.Writer, a ...interface{}) {
+ fdump(&Config, w, a...)
+}
+
+// Sdump returns a string with the passed arguments formatted exactly the same
+// as Dump.
+func Sdump(a ...interface{}) string {
+ var buf bytes.Buffer
+ fdump(&Config, &buf, a...)
+ return buf.String()
+}
+
+/*
+Dump displays the passed parameters to standard out with newlines, customizable
+indentation, and additional debug information such as complete types and all
+pointer addresses used to indirect to the final value. It provides the
+following features over the built-in printing facilities provided by the fmt
+package:
+
+ * Pointers are dereferenced and followed
+ * Circular data structures are detected and handled properly
+ * Custom Stringer/error interfaces are optionally invoked, including
+ on unexported types
+ * Custom types which only implement the Stringer/error interfaces via
+ a pointer receiver are optionally invoked when passing non-pointer
+ variables
+ * Byte arrays and slices are dumped like the hexdump -C command which
+ includes offsets, byte values in hex, and ASCII output
+
+The configuration options are controlled by an exported package global,
+spew.Config. See ConfigState for options documentation.
+
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
+get the formatted result as a string.
+*/
+func Dump(a ...interface{}) {
+ fdump(&Config, os.Stdout, a...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/format.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/format.go
new file mode 100644
index 000000000000..b04edb7d7ac2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/format.go
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// supportedFlags is a list of all the character flags supported by fmt package.
+const supportedFlags = "0-+# "
+
+// formatState implements the fmt.Formatter interface and contains information
+// about the state of a formatting operation. The NewFormatter function can
+// be used to get a new Formatter which can be used directly as arguments
+// in standard fmt package printing calls.
+type formatState struct {
+ value interface{}
+ fs fmt.State
+ depth int
+ pointers map[uintptr]int
+ ignoreNextType bool
+ cs *ConfigState
+}
+
+// buildDefaultFormat recreates the original format string without precision
+// and width information to pass in to fmt.Sprintf in the case of an
+// unrecognized type. Unless new types are added to the language, this
+// function won't ever be called.
+func (f *formatState) buildDefaultFormat() (format string) {
+ buf := bytes.NewBuffer(percentBytes)
+
+ for _, flag := range supportedFlags {
+ if f.fs.Flag(int(flag)) {
+ buf.WriteRune(flag)
+ }
+ }
+
+ buf.WriteRune('v')
+
+ format = buf.String()
+ return format
+}
+
+// constructOrigFormat recreates the original format string including precision
+// and width information to pass along to the standard fmt package. This allows
+// automatic deferral of all format strings this package doesn't support.
+func (f *formatState) constructOrigFormat(verb rune) (format string) {
+ buf := bytes.NewBuffer(percentBytes)
+
+ for _, flag := range supportedFlags {
+ if f.fs.Flag(int(flag)) {
+ buf.WriteRune(flag)
+ }
+ }
+
+ if width, ok := f.fs.Width(); ok {
+ buf.WriteString(strconv.Itoa(width))
+ }
+
+ if precision, ok := f.fs.Precision(); ok {
+ buf.Write(precisionBytes)
+ buf.WriteString(strconv.Itoa(precision))
+ }
+
+ buf.WriteRune(verb)
+
+ format = buf.String()
+ return format
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible and
+// ensures that types for values which have been unpacked from an interface
+// are displayed when the show types flag is also set.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
+ if v.Kind() == reflect.Interface {
+ f.ignoreNextType = false
+ if !v.IsNil() {
+ v = v.Elem()
+ }
+ }
+ return v
+}
+
+// formatPtr handles formatting of pointers by indirecting them as necessary.
+func (f *formatState) formatPtr(v reflect.Value) {
+ // Display nil if top level pointer is nil.
+ showTypes := f.fs.Flag('#')
+ if v.IsNil() && (!showTypes || f.ignoreNextType) {
+ f.fs.Write(nilAngleBytes)
+ return
+ }
+
+ // Remove pointers at or below the current depth from map used to detect
+ // circular refs.
+ for k, depth := range f.pointers {
+ if depth >= f.depth {
+ delete(f.pointers, k)
+ }
+ }
+
+ // Keep list of all dereferenced pointers to possibly show later.
+ pointerChain := make([]uintptr, 0)
+
+ // Figure out how many levels of indirection there are by derferencing
+ // pointers and unpacking interfaces down the chain while detecting circular
+ // references.
+ nilFound := false
+ cycleFound := false
+ indirects := 0
+ ve := v
+ for ve.Kind() == reflect.Ptr {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ indirects++
+ addr := ve.Pointer()
+ pointerChain = append(pointerChain, addr)
+ if pd, ok := f.pointers[addr]; ok && pd < f.depth {
+ cycleFound = true
+ indirects--
+ break
+ }
+ f.pointers[addr] = f.depth
+
+ ve = ve.Elem()
+ if ve.Kind() == reflect.Interface {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ ve = ve.Elem()
+ }
+ }
+
+ // Display type or indirection level depending on flags.
+ if showTypes && !f.ignoreNextType {
+ f.fs.Write(openParenBytes)
+ f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
+ f.fs.Write([]byte(ve.Type().String()))
+ f.fs.Write(closeParenBytes)
+ } else {
+ if nilFound || cycleFound {
+ indirects += strings.Count(ve.Type().String(), "*")
+ }
+ f.fs.Write(openAngleBytes)
+ f.fs.Write([]byte(strings.Repeat("*", indirects)))
+ f.fs.Write(closeAngleBytes)
+ }
+
+ // Display pointer information depending on flags.
+ if f.fs.Flag('+') && (len(pointerChain) > 0) {
+ f.fs.Write(openParenBytes)
+ for i, addr := range pointerChain {
+ if i > 0 {
+ f.fs.Write(pointerChainBytes)
+ }
+ printHexPtr(f.fs, addr)
+ }
+ f.fs.Write(closeParenBytes)
+ }
+
+ // Display dereferenced value.
+ switch {
+ case nilFound:
+ f.fs.Write(nilAngleBytes)
+
+ case cycleFound:
+ f.fs.Write(circularShortBytes)
+
+ default:
+ f.ignoreNextType = true
+ f.format(ve)
+ }
+}
+
+// format is the main workhorse for providing the Formatter interface. It
+// uses the passed reflect value to figure out what kind of object we are
+// dealing with and formats it appropriately. It is a recursive function,
+// however circular data structures are detected and handled properly.
+func (f *formatState) format(v reflect.Value) {
+ // Handle invalid reflect values immediately.
+ kind := v.Kind()
+ if kind == reflect.Invalid {
+ f.fs.Write(invalidAngleBytes)
+ return
+ }
+
+ // Handle pointers specially.
+ if kind == reflect.Ptr {
+ f.formatPtr(v)
+ return
+ }
+
+ // Print type information unless already handled elsewhere.
+ if !f.ignoreNextType && f.fs.Flag('#') {
+ f.fs.Write(openParenBytes)
+ f.fs.Write([]byte(v.Type().String()))
+ f.fs.Write(closeParenBytes)
+ }
+ f.ignoreNextType = false
+
+ // Call Stringer/error interfaces if they exist and the handle methods
+ // flag is enabled.
+ if !f.cs.DisableMethods {
+ if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+ if handled := handleMethods(f.cs, f.fs, v); handled {
+ return
+ }
+ }
+ }
+
+ switch kind {
+ case reflect.Invalid:
+ // Do nothing. We should never get here since invalid has already
+ // been handled above.
+
+ case reflect.Bool:
+ printBool(f.fs, v.Bool())
+
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ printInt(f.fs, v.Int(), 10)
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ printUint(f.fs, v.Uint(), 10)
+
+ case reflect.Float32:
+ printFloat(f.fs, v.Float(), 32)
+
+ case reflect.Float64:
+ printFloat(f.fs, v.Float(), 64)
+
+ case reflect.Complex64:
+ printComplex(f.fs, v.Complex(), 32)
+
+ case reflect.Complex128:
+ printComplex(f.fs, v.Complex(), 64)
+
+ case reflect.Slice:
+ if v.IsNil() {
+ f.fs.Write(nilAngleBytes)
+ break
+ }
+ fallthrough
+
+ case reflect.Array:
+ f.fs.Write(openBracketBytes)
+ f.depth++
+ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+ f.fs.Write(maxShortBytes)
+ } else {
+ numEntries := v.Len()
+ for i := 0; i < numEntries; i++ {
+ if i > 0 {
+ f.fs.Write(spaceBytes)
+ }
+ f.ignoreNextType = true
+ f.format(f.unpackValue(v.Index(i)))
+ }
+ }
+ f.depth--
+ f.fs.Write(closeBracketBytes)
+
+ case reflect.String:
+ f.fs.Write([]byte(v.String()))
+
+ case reflect.Interface:
+ // The only time we should get here is for nil interfaces due to
+ // unpackValue calls.
+ if v.IsNil() {
+ f.fs.Write(nilAngleBytes)
+ }
+
+ case reflect.Ptr:
+ // Do nothing. We should never get here since pointers have already
+ // been handled above.
+
+ case reflect.Map:
+ // nil maps should be indicated as different than empty maps
+ if v.IsNil() {
+ f.fs.Write(nilAngleBytes)
+ break
+ }
+
+ f.fs.Write(openMapBytes)
+ f.depth++
+ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+ f.fs.Write(maxShortBytes)
+ } else {
+ keys := v.MapKeys()
+ if f.cs.SortKeys {
+ sortValues(keys, f.cs)
+ }
+ for i, key := range keys {
+ if i > 0 {
+ f.fs.Write(spaceBytes)
+ }
+ f.ignoreNextType = true
+ f.format(f.unpackValue(key))
+ f.fs.Write(colonBytes)
+ f.ignoreNextType = true
+ f.format(f.unpackValue(v.MapIndex(key)))
+ }
+ }
+ f.depth--
+ f.fs.Write(closeMapBytes)
+
+ case reflect.Struct:
+ numFields := v.NumField()
+ f.fs.Write(openBraceBytes)
+ f.depth++
+ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+ f.fs.Write(maxShortBytes)
+ } else {
+ vt := v.Type()
+ for i := 0; i < numFields; i++ {
+ if i > 0 {
+ f.fs.Write(spaceBytes)
+ }
+ vtf := vt.Field(i)
+ if f.fs.Flag('+') || f.fs.Flag('#') {
+ f.fs.Write([]byte(vtf.Name))
+ f.fs.Write(colonBytes)
+ }
+ f.format(f.unpackValue(v.Field(i)))
+ }
+ }
+ f.depth--
+ f.fs.Write(closeBraceBytes)
+
+ case reflect.Uintptr:
+ printHexPtr(f.fs, uintptr(v.Uint()))
+
+ case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+ printHexPtr(f.fs, v.Pointer())
+
+ // There were not any other types at the time this code was written, but
+ // fall back to letting the default fmt package handle it if any get added.
+ default:
+ format := f.buildDefaultFormat()
+ if v.CanInterface() {
+ fmt.Fprintf(f.fs, format, v.Interface())
+ } else {
+ fmt.Fprintf(f.fs, format, v.String())
+ }
+ }
+}
+
+// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
+// details.
+func (f *formatState) Format(fs fmt.State, verb rune) {
+ f.fs = fs
+
+ // Use standard formatting for verbs that are not v.
+ if verb != 'v' {
+ format := f.constructOrigFormat(verb)
+ fmt.Fprintf(fs, format, f.value)
+ return
+ }
+
+ if f.value == nil {
+ if fs.Flag('#') {
+ fs.Write(interfaceBytes)
+ }
+ fs.Write(nilAngleBytes)
+ return
+ }
+
+ f.format(reflect.ValueOf(f.value))
+}
+
+// newFormatter is a helper function to consolidate the logic from the various
+// public methods which take varying config states.
+func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
+ fs := &formatState{value: v, cs: cs}
+ fs.pointers = make(map[uintptr]int)
+ return fs
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface. As a result, it integrates cleanly with standard fmt package
+printing functions. The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations. Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting. In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly. It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+Printf, Println, or Fprintf.
+*/
+func NewFormatter(v interface{}) fmt.Formatter {
+ return newFormatter(&Config, v)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/spew.go b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/spew.go
new file mode 100644
index 000000000000..32c0e3388253
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/davecgh/go-spew/spew/spew.go
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "fmt"
+ "io"
+)
+
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the formatted string as a value that satisfies error. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Errorf(format string, a ...interface{}) (err error) {
+ return fmt.Errorf(format, convertArgs(a)...)
+}
+
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
+func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+ return fmt.Fprint(w, convertArgs(a)...)
+}
+
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+ return fmt.Fprintf(w, format, convertArgs(a)...)
+}
+
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
+// passed with a default Formatter interface returned by NewFormatter. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
+func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+ return fmt.Fprintln(w, convertArgs(a)...)
+}
+
+// Print is a wrapper for fmt.Print that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
+func Print(a ...interface{}) (n int, err error) {
+ return fmt.Print(convertArgs(a)...)
+}
+
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Printf(format string, a ...interface{}) (n int, err error) {
+ return fmt.Printf(format, convertArgs(a)...)
+}
+
+// Println is a wrapper for fmt.Println that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
+func Println(a ...interface{}) (n int, err error) {
+ return fmt.Println(convertArgs(a)...)
+}
+
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
+func Sprint(a ...interface{}) string {
+ return fmt.Sprint(convertArgs(a)...)
+}
+
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
+// passed with a default Formatter interface returned by NewFormatter. It
+// returns the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
+func Sprintf(format string, a ...interface{}) string {
+ return fmt.Sprintf(format, convertArgs(a)...)
+}
+
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
+// were passed with a default Formatter interface returned by NewFormatter. It
+// returns the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
+func Sprintln(a ...interface{}) string {
+ return fmt.Sprintln(convertArgs(a)...)
+}
+
+// convertArgs accepts a slice of arguments and returns a slice of the same
+// length with each argument converted to a default spew Formatter interface.
+func convertArgs(args []interface{}) (formatters []interface{}) {
+ formatters = make([]interface{}, len(args))
+ for index, arg := range args {
+ formatters[index] = NewFormatter(arg)
+ }
+ return formatters
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/dgryski/go-rendezvous/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/dgryski/go-rendezvous/LICENSE
new file mode 100644
index 000000000000..22080f736a41
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/dgryski/go-rendezvous/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017-2020 Damian Gryski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/dgryski/go-rendezvous/rdv.go b/go/ql/test/experimental/CWE-321/vendor/github.com/dgryski/go-rendezvous/rdv.go
new file mode 100644
index 000000000000..7a6f8203c678
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/dgryski/go-rendezvous/rdv.go
@@ -0,0 +1,79 @@
+package rendezvous
+
+type Rendezvous struct {
+ nodes map[string]int
+ nstr []string
+ nhash []uint64
+ hash Hasher
+}
+
+type Hasher func(s string) uint64
+
+func New(nodes []string, hash Hasher) *Rendezvous {
+ r := &Rendezvous{
+ nodes: make(map[string]int, len(nodes)),
+ nstr: make([]string, len(nodes)),
+ nhash: make([]uint64, len(nodes)),
+ hash: hash,
+ }
+
+ for i, n := range nodes {
+ r.nodes[n] = i
+ r.nstr[i] = n
+ r.nhash[i] = hash(n)
+ }
+
+ return r
+}
+
+func (r *Rendezvous) Lookup(k string) string {
+ // short-circuit if we're empty
+ if len(r.nodes) == 0 {
+ return ""
+ }
+
+ khash := r.hash(k)
+
+ var midx int
+ var mhash = xorshiftMult64(khash ^ r.nhash[0])
+
+ for i, nhash := range r.nhash[1:] {
+ if h := xorshiftMult64(khash ^ nhash); h > mhash {
+ midx = i + 1
+ mhash = h
+ }
+ }
+
+ return r.nstr[midx]
+}
+
+func (r *Rendezvous) Add(node string) {
+ r.nodes[node] = len(r.nstr)
+ r.nstr = append(r.nstr, node)
+ r.nhash = append(r.nhash, r.hash(node))
+}
+
+func (r *Rendezvous) Remove(node string) {
+ // find index of node to remove
+ nidx := r.nodes[node]
+
+ // remove from the slices
+ l := len(r.nstr)
+ r.nstr[nidx] = r.nstr[l]
+ r.nstr = r.nstr[:l]
+
+ r.nhash[nidx] = r.nhash[l]
+ r.nhash = r.nhash[:l]
+
+ // update the map
+ delete(r.nodes, node)
+ moved := r.nstr[nidx]
+ r.nodes[moved] = nidx
+}
+
+func xorshiftMult64(x uint64) uint64 {
+ x ^= x >> 12 // a
+ x ^= x << 25 // b
+ x ^= x >> 27 // c
+ return x * 2685821657736338717
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/.travis.yml
new file mode 100644
index 000000000000..fa3d8d31c20b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/.travis.yml
@@ -0,0 +1,7 @@
+language: go
+
+go:
+ - tip
+
+script:
+ - go test -v ./...
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/LICENSE
new file mode 100644
index 000000000000..77dfb91cecc1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/LICENSE
@@ -0,0 +1,9 @@
+(The MIT License)
+
+Copyright (c) 2012 Ekin Koc ekin@eknkc.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/README.md
new file mode 100644
index 000000000000..ec0e52fc4ca6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/README.md
@@ -0,0 +1,442 @@
+# amber [![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](http://godoc.org/github.com/eknkc/amber) [![Build Status](https://travis-ci.org/eknkc/amber.svg?branch=master)](https://travis-ci.org/eknkc/amber)
+
+## Notice
+> While Amber is perfectly fine and stable to use, I've been working on a direct Pug.js port for Go. It is somewhat hacky at the moment but take a look at [Pug.go](https://github.com/eknkc/pug) if you are looking for a [Pug.js](https://github.com/pugjs/pug) compatible Go template engine.
+
+### Usage
+```go
+import "github.com/eknkc/amber"
+```
+
+Amber is an elegant templating engine for Go Programming Language
+It is inspired from HAML and Jade
+
+### Tags
+
+A tag is simply a word:
+
+ html
+
+is converted to
+
+```html
+
+```
+
+It is possible to add ID and CLASS attributes to tags:
+
+ div#main
+ span.time
+
+are converted to
+
+```html
+
+
+```
+
+Any arbitrary attribute name / value pair can be added this way:
+
+ a[href="http://www.google.com"]
+
+You can mix multiple attributes together
+
+ a#someid[href="/"][title="Main Page"].main.link Click Link
+
+gets converted to
+
+```html
+Click Link
+```
+
+It is also possible to define these attributes within the block of a tag
+
+ a
+ #someid
+ [href="/"]
+ [title="Main Page"]
+ .main
+ .link
+ | Click Link
+
+### Doctypes
+
+To add a doctype, use `!!!` or `doctype` keywords:
+
+ !!! transitional
+ //
+
+or use `doctype`
+
+ doctype 5
+ //
+
+Available options: `5`, `default`, `xml`, `transitional`, `strict`, `frameset`, `1.1`, `basic`, `mobile`
+
+### Tag Content
+
+For single line tag text, you can just append the text after tag name:
+
+ p Testing!
+
+would yield
+
+ Testing!
+
+For multi line tag text, or nested tags, use indentation:
+
+ html
+ head
+ title Page Title
+ body
+ div#content
+ p
+ | This is a long page content
+ | These lines are all part of the parent p
+
+ a[href="/"] Go To Main Page
+
+### Data
+
+Input template data can be reached by key names directly. For example, assuming the template has been
+executed with following JSON data:
+
+```json
+{
+ "Name": "Ekin",
+ "LastName": "Koc",
+ "Repositories": [
+ "amber",
+ "dateformat"
+ ],
+ "Avatar": "/images/ekin.jpg",
+ "Friends": 17
+}
+```
+
+It is possible to interpolate fields using `#{}`
+
+ p Welcome #{Name}!
+
+would print
+
+```html
+Welcome Ekin!
+```
+
+Attributes can have field names as well
+
+ a[title=Name][href="/ekin.koc"]
+
+would print
+
+```html
+
+```
+
+### Expressions
+
+Amber can expand basic expressions. For example, it is possible to concatenate strings with + operator:
+
+ p Welcome #{Name + " " + LastName}
+
+Arithmetic expressions are also supported:
+
+ p You need #{50 - Friends} more friends to reach 50!
+
+Expressions can be used within attributes
+
+ img[alt=Name + " " + LastName][src=Avatar]
+
+### Variables
+
+It is possible to define dynamic variables within templates,
+all variables must start with a $ character and can be assigned as in the following example:
+
+ div
+ $fullname = Name + " " + LastName
+ p Welcome #{$fullname}
+
+If you need to access the supplied data itself (i.e. the object containing Name, LastName etc fields.) you can use `$` variable
+
+ p $.Name
+
+### Conditions
+
+For conditional blocks, it is possible to use `if `
+
+ div
+ if Friends > 10
+ p You have more than 10 friends
+ else if Friends > 5
+ p You have more than 5 friends
+ else
+ p You need more friends
+
+Again, it is possible to use arithmetic and boolean operators
+
+ div
+ if Name == "Ekin" && LastName == "Koc"
+ p Hey! I know you..
+
+There is a special syntax for conditional attributes. Only block attributes can have conditions;
+
+ div
+ .hasfriends ? Friends > 0
+
+This would yield a div with `hasfriends` class only if the `Friends > 0` condition holds. It is
+perfectly fine to use the same method for other types of attributes:
+
+ div
+ #foo ? Name == "Ekin"
+ [bar=baz] ? len(Repositories) > 0
+
+### Iterations
+
+It is possible to iterate over arrays and maps using `each`:
+
+ each $repo in Repositories
+ p #{$repo}
+
+would print
+
+ p amber
+ p dateformat
+
+It is also possible to iterate over values and indexes at the same time
+
+ each $i, $repo in Repositories
+ p
+ .even ? $i % 2 == 0
+ .odd ? $i % 2 == 1
+
+### Mixins
+
+Mixins (reusable template blocks that accept arguments) can be defined:
+
+ mixin surprise
+ span Surprise!
+ mixin link($href, $title, $text)
+ a[href=$href][title=$title] #{$text}
+
+and then called multiple times within a template (or even within another mixin definition):
+
+ div
+ +surprise
+ +surprise
+ +link("http://google.com", "Google", "Check out Google")
+
+Template data, variables, expressions, etc., can all be passed as arguments:
+
+ +link(GoogleUrl, $googleTitle, "Check out " + $googleTitle)
+
+### Imports
+
+A template can import other templates using `import`:
+
+ a.amber
+ p this is template a
+
+ b.amber
+ p this is template b
+
+ c.amber
+ div
+ import a
+ import b
+
+gets compiled to
+
+ div
+ p this is template a
+ p this is template b
+
+### Inheritance
+
+A template can inherit other templates. In order to inherit another template, an `extends` keyword should be used.
+Parent template can define several named blocks and child template can modify the blocks.
+
+ master.amber
+ !!! 5
+ html
+ head
+ block meta
+ meta[name="description"][content="This is a great website"]
+
+ title
+ block title
+ | Default title
+ body
+ block content
+
+ subpage.amber
+ extends master
+
+ block title
+ | Some sub page!
+
+ block append meta
+ // This will be added after the description meta tag. It is also possible
+ // to prepend someting to an existing block
+ meta[name="keywords"][content="foo bar"]
+
+ block content
+ div#main
+ p Some content here
+
+### License
+(The MIT License)
+
+Copyright (c) 2012 Ekin Koc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+## Usage
+
+```go
+var DefaultOptions = Options{true, false}
+var DefaultDirOptions = DirOptions{".amber", true}
+```
+
+#### func Compile
+
+```go
+func Compile(input string, options Options) (*template.Template, error)
+```
+Parses and compiles the supplied amber template string. Returns corresponding Go
+Template (html/templates) instance. Necessary runtime functions will be injected
+and the template will be ready to be executed.
+
+#### func CompileFile
+
+```go
+func CompileFile(filename string, options Options) (*template.Template, error)
+```
+Parses and compiles the contents of supplied filename. Returns corresponding Go
+Template (html/templates) instance. Necessary runtime functions will be injected
+and the template will be ready to be executed.
+
+#### func CompileDir
+```go
+func CompileDir(dirname string, dopt DirOptions, opt Options) (map[string]*template.Template, error)
+```
+Parses and compiles the contents of a supplied directory name. Returns a mapping of template name (extension stripped) to corresponding Go Template (html/template) instance. Necessary runtime functions will be injected and the template will be ready to be executed.
+
+If there are templates in subdirectories, its key in the map will be it's path relative to `dirname`. For example:
+```
+templates/
+ |-- index.amber
+ |-- layouts/
+ |-- base.amber
+```
+```go
+templates, err := amber.CompileDir("templates/", amber.DefaultDirOptions, amber.DefaultOptions)
+templates["index"] // index.amber Go Template
+templates["layouts/base"] // base.amber Go Template
+```
+By default, the search will be recursive and will match only files ending in ".amber". If recursive is turned off, it will only search the top level of the directory. Specified extension must start with a period.
+
+#### type Compiler
+
+```go
+type Compiler struct {
+ // Compiler options
+ Options
+}
+```
+
+Compiler is the main interface of Amber Template Engine. In order to use an
+Amber template, it is required to create a Compiler and compile an Amber source
+to native Go template.
+
+ compiler := amber.New()
+ // Parse the input file
+ err := compiler.ParseFile("./input.amber")
+ if err == nil {
+ // Compile input file to Go template
+ tpl, err := compiler.Compile()
+ if err == nil {
+ // Check built in html/template documentation for further details
+ tpl.Execute(os.Stdout, somedata)
+ }
+ }
+
+#### func New
+
+```go
+func New() *Compiler
+```
+Create and initialize a new Compiler
+
+#### func (*Compiler) Compile
+
+```go
+func (c *Compiler) Compile() (*template.Template, error)
+```
+Compile amber and create a Go Template (html/templates) instance. Necessary
+runtime functions will be injected and the template will be ready to be
+executed.
+
+#### func (*Compiler) CompileString
+
+```go
+func (c *Compiler) CompileString() (string, error)
+```
+Compile template and return the Go Template source You would not be using this
+unless debugging / checking the output. Please use Compile method to obtain a
+template instance directly.
+
+#### func (*Compiler) CompileWriter
+
+```go
+func (c *Compiler) CompileWriter(out io.Writer) (err error)
+```
+Compile amber and write the Go Template source into given io.Writer instance You
+would not be using this unless debugging / checking the output. Please use
+Compile method to obtain a template instance directly.
+
+#### func (*Compiler) Parse
+
+```go
+func (c *Compiler) Parse(input string) (err error)
+```
+Parse given raw amber template string.
+
+#### func (*Compiler) ParseFile
+
+```go
+func (c *Compiler) ParseFile(filename string) (err error)
+```
+Parse the amber template file in given path
+
+#### type Options
+
+```go
+type Options struct {
+ // Setting if pretty printing is enabled.
+ // Pretty printing ensures that the output html is properly indented and in human readable form.
+ // If disabled, produced HTML is compact. This might be more suitable in production environments.
+ // Defaukt: true
+ PrettyPrint bool
+ // Setting if line number emitting is enabled
+ // In this form, Amber emits line number comments in the output template. It is usable in debugging environments.
+ // Default: false
+ LineNumbers bool
+}
+```
+
+#### type DirOptions
+
+```go
+// Used to provide options to directory compilation
+type DirOptions struct {
+ // File extension to match for compilation
+ Ext string
+ // Whether or not to walk subdirectories
+ Recursive bool
+}
+```
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/compiler.go b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/compiler.go
new file mode 100644
index 000000000000..bec57b72f267
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/compiler.go
@@ -0,0 +1,844 @@
+package amber
+
+import (
+ "bytes"
+ "container/list"
+ "errors"
+ "fmt"
+ "go/ast"
+ gp "go/parser"
+ gt "go/token"
+ "html/template"
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+ "reflect"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/eknkc/amber/parser"
+)
+
+var builtinFunctions = [...]string{
+ "len",
+ "print",
+ "printf",
+ "println",
+ "urlquery",
+ "js",
+ "json",
+ "index",
+ "html",
+ "unescaped",
+}
+
+const (
+ dollar = "__DOLLAR__"
+)
+
+// Compiler is the main interface of Amber Template Engine.
+// In order to use an Amber template, it is required to create a Compiler and
+// compile an Amber source to native Go template.
+// compiler := amber.New()
+// // Parse the input file
+// err := compiler.ParseFile("./input.amber")
+// if err == nil {
+// // Compile input file to Go template
+// tpl, err := compiler.Compile()
+// if err == nil {
+// // Check built in html/template documentation for further details
+// tpl.Execute(os.Stdout, somedata)
+// }
+// }
+type Compiler struct {
+ // Compiler options
+ Options
+ filename string
+ node parser.Node
+ indentLevel int
+ newline bool
+ buffer *bytes.Buffer
+ tempvarIndex int
+ mixins map[string]*parser.Mixin
+}
+
+// New creates and initialize a new Compiler.
+func New() *Compiler {
+ compiler := new(Compiler)
+ compiler.filename = ""
+ compiler.tempvarIndex = 0
+ compiler.PrettyPrint = true
+ compiler.Options = DefaultOptions
+ compiler.mixins = make(map[string]*parser.Mixin)
+
+ return compiler
+}
+
+// Options defines template output behavior.
+type Options struct {
+ // Setting if pretty printing is enabled.
+ // Pretty printing ensures that the output html is properly indented and in human readable form.
+ // If disabled, produced HTML is compact. This might be more suitable in production environments.
+ // Default: true
+ PrettyPrint bool
+ // Setting if line number emitting is enabled
+ // In this form, Amber emits line number comments in the output template. It is usable in debugging environments.
+ // Default: false
+ LineNumbers bool
+ // Setting the virtual filesystem to use
+ // If set, will attempt to use a virtual filesystem provided instead of os.
+ // Default: nil
+ VirtualFilesystem http.FileSystem
+}
+
+// DirOptions is used to provide options to directory compilation.
+type DirOptions struct {
+ // File extension to match for compilation
+ Ext string
+ // Whether or not to walk subdirectories
+ Recursive bool
+}
+
+// DefaultOptions sets pretty-printing to true and line numbering to false.
+var DefaultOptions = Options{true, false, nil}
+
+// DefaultDirOptions sets expected file extension to ".amber" and recursive search for templates within a directory to true.
+var DefaultDirOptions = DirOptions{".amber", true}
+
+// Compile parses and compiles the supplied amber template string. Returns corresponding Go Template (html/templates) instance.
+// Necessary runtime functions will be injected and the template will be ready to be executed.
+func Compile(input string, options Options) (*template.Template, error) {
+ comp := New()
+ comp.Options = options
+
+ err := comp.Parse(input)
+ if err != nil {
+ return nil, err
+ }
+
+ return comp.Compile()
+}
+
+// Compile parses and compiles the supplied amber template []byte.
+// Returns corresponding Go Template (html/templates) instance.
+// Necessary runtime functions will be injected and the template will be ready to be executed.
+func CompileData(input []byte, filename string, options Options) (*template.Template, error) {
+ comp := New()
+ comp.Options = options
+
+ err := comp.ParseData(input, filename)
+ if err != nil {
+ return nil, err
+ }
+
+ return comp.Compile()
+}
+
+// MustCompile is the same as Compile, except the input is assumed error free. If else, panic.
+func MustCompile(input string, options Options) *template.Template {
+ t, err := Compile(input, options)
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// CompileFile parses and compiles the contents of supplied filename. Returns corresponding Go Template (html/templates) instance.
+// Necessary runtime functions will be injected and the template will be ready to be executed.
+func CompileFile(filename string, options Options) (*template.Template, error) {
+ comp := New()
+ comp.Options = options
+
+ err := comp.ParseFile(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ return comp.Compile()
+}
+
+// MustCompileFile is the same as CompileFile, except the input is assumed error free. If else, panic.
+func MustCompileFile(filename string, options Options) *template.Template {
+ t, err := CompileFile(filename, options)
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// CompileDir parses and compiles the contents of a supplied directory path, with options.
+// Returns a map of a template identifier (key) to a Go Template instance.
+// Ex: if the dirname="templates/" had a file "index.amber" the key would be "index"
+// If option for recursive is True, this parses every file of relevant extension
+// in all subdirectories. The key then is the path e.g: "layouts/layout"
+func CompileDir(dirname string, dopt DirOptions, opt Options) (map[string]*template.Template, error) {
+ dir, err := os.Open(dirname)
+ if err != nil && opt.VirtualFilesystem != nil {
+ vdir, err := opt.VirtualFilesystem.Open(dirname)
+ if err != nil {
+ return nil, err
+ }
+ dir = vdir.(*os.File)
+ } else if err != nil {
+ return nil, err
+ }
+ defer dir.Close()
+
+ files, err := dir.Readdir(0)
+ if err != nil {
+ return nil, err
+ }
+
+ compiled := make(map[string]*template.Template)
+ for _, file := range files {
+ // filename is for example "index.amber"
+ filename := file.Name()
+ fileext := filepath.Ext(filename)
+
+ // If recursive is true and there's a subdirectory, recurse
+ if dopt.Recursive && file.IsDir() {
+ dirpath := filepath.Join(dirname, filename)
+ subcompiled, err := CompileDir(dirpath, dopt, opt)
+ if err != nil {
+ return nil, err
+ }
+ // Copy templates from subdirectory into parent template mapping
+ for k, v := range subcompiled {
+ // Concat with parent directory name for unique paths
+ key := filepath.Join(filename, k)
+ compiled[key] = v
+ }
+ } else if fileext == dopt.Ext {
+ // Otherwise compile the file and add to mapping
+ fullpath := filepath.Join(dirname, filename)
+ tmpl, err := CompileFile(fullpath, opt)
+ if err != nil {
+ return nil, err
+ }
+ // Strip extension
+ key := filename[0 : len(filename)-len(fileext)]
+ compiled[key] = tmpl
+ }
+ }
+
+ return compiled, nil
+}
+
+// MustCompileDir is the same as CompileDir, except input is assumed error free. If else, panic.
+func MustCompileDir(dirname string, dopt DirOptions, opt Options) map[string]*template.Template {
+ m, err := CompileDir(dirname, dopt, opt)
+ if err != nil {
+ panic(err)
+ }
+ return m
+}
+
+// Parse given raw amber template string.
+func (c *Compiler) Parse(input string) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = errors.New(r.(string))
+ }
+ }()
+
+ parser, err := parser.StringParser(input)
+
+ if err != nil {
+ return
+ }
+
+ c.node = parser.Parse()
+ return
+}
+
+// Parse given raw amber template bytes, and the filename that belongs with it
+func (c *Compiler) ParseData(input []byte, filename string) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = errors.New(r.(string))
+ }
+ }()
+
+ parser, err := parser.ByteParser(input)
+ parser.SetFilename(filename)
+ if c.VirtualFilesystem != nil {
+ parser.SetVirtualFilesystem(c.VirtualFilesystem)
+ }
+
+ if err != nil {
+ return
+ }
+
+ c.node = parser.Parse()
+ return
+}
+
+// ParseFile parses the amber template file in given path.
+func (c *Compiler) ParseFile(filename string) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = errors.New(r.(string))
+ }
+ }()
+
+ p, err := parser.FileParser(filename)
+ if err != nil && c.VirtualFilesystem != nil {
+ p, err = parser.VirtualFileParser(filename, c.VirtualFilesystem)
+ }
+ if err != nil {
+ return
+ }
+
+ c.node = p.Parse()
+ c.filename = filename
+ return
+}
+
+// Compile amber and create a Go Template (html/templates) instance.
+// Necessary runtime functions will be injected and the template will be ready to be executed.
+func (c *Compiler) Compile() (*template.Template, error) {
+ return c.CompileWithName(filepath.Base(c.filename))
+}
+
+// CompileWithName is the same as Compile, but allows to specify a name for the template.
+func (c *Compiler) CompileWithName(name string) (*template.Template, error) {
+ return c.CompileWithTemplate(template.New(name))
+}
+
+// CompileWithTemplate is the same as Compile but allows to specify a template.
+func (c *Compiler) CompileWithTemplate(t *template.Template) (*template.Template, error) {
+ data, err := c.CompileString()
+
+ if err != nil {
+ return nil, err
+ }
+
+ tpl, err := t.Funcs(FuncMap).Parse(data)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return tpl, nil
+}
+
+// CompileWriter compiles amber and writes the Go Template source into given io.Writer instance.
+// You would not be using this unless debugging / checking the output. Please use Compile
+// method to obtain a template instance directly.
+func (c *Compiler) CompileWriter(out io.Writer) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = errors.New(r.(string))
+ }
+ }()
+
+ c.buffer = new(bytes.Buffer)
+ c.visit(c.node)
+
+ if c.buffer.Len() > 0 {
+ c.write("\n")
+ }
+
+ _, err = c.buffer.WriteTo(out)
+ return
+}
+
+// CompileString compiles the template and returns the Go Template source.
+// You would not be using this unless debugging / checking the output. Please use Compile
+// method to obtain a template instance directly.
+func (c *Compiler) CompileString() (string, error) {
+ var buf bytes.Buffer
+
+ if err := c.CompileWriter(&buf); err != nil {
+ return "", err
+ }
+
+ result := buf.String()
+
+ return result, nil
+}
+
+func (c *Compiler) visit(node parser.Node) {
+ defer func() {
+ if r := recover(); r != nil {
+ if rs, ok := r.(string); ok && rs[:len("Amber Error")] == "Amber Error" {
+ panic(r)
+ }
+
+ pos := node.Pos()
+
+ if len(pos.Filename) > 0 {
+ panic(fmt.Sprintf("Amber Error in <%s>: %v - Line: %d, Column: %d, Length: %d", pos.Filename, r, pos.LineNum, pos.ColNum, pos.TokenLength))
+ } else {
+ panic(fmt.Sprintf("Amber Error: %v - Line: %d, Column: %d, Length: %d", r, pos.LineNum, pos.ColNum, pos.TokenLength))
+ }
+ }
+ }()
+
+ switch node.(type) {
+ case *parser.Block:
+ c.visitBlock(node.(*parser.Block))
+ case *parser.Doctype:
+ c.visitDoctype(node.(*parser.Doctype))
+ case *parser.Comment:
+ c.visitComment(node.(*parser.Comment))
+ case *parser.Tag:
+ c.visitTag(node.(*parser.Tag))
+ case *parser.Text:
+ c.visitText(node.(*parser.Text))
+ case *parser.Condition:
+ c.visitCondition(node.(*parser.Condition))
+ case *parser.Each:
+ c.visitEach(node.(*parser.Each))
+ case *parser.Assignment:
+ c.visitAssignment(node.(*parser.Assignment))
+ case *parser.Mixin:
+ c.visitMixin(node.(*parser.Mixin))
+ case *parser.MixinCall:
+ c.visitMixinCall(node.(*parser.MixinCall))
+ }
+}
+
+func (c *Compiler) write(value string) {
+ c.buffer.WriteString(value)
+}
+
+func (c *Compiler) indent(offset int, newline bool) {
+ if !c.PrettyPrint {
+ return
+ }
+
+ if newline && c.buffer.Len() > 0 {
+ c.write("\n")
+ }
+
+ for i := 0; i < c.indentLevel+offset; i++ {
+ c.write("\t")
+ }
+}
+
+func (c *Compiler) tempvar() string {
+ c.tempvarIndex++
+ return "$__amber_" + strconv.Itoa(c.tempvarIndex)
+}
+
+func (c *Compiler) escape(input string) string {
+ return strings.Replace(strings.Replace(input, `\`, `\\`, -1), `"`, `\"`, -1)
+}
+
+func (c *Compiler) visitBlock(block *parser.Block) {
+ for _, node := range block.Children {
+ if _, ok := node.(*parser.Text); !block.CanInline() && ok {
+ c.indent(0, true)
+ }
+
+ c.visit(node)
+ }
+}
+
+func (c *Compiler) visitDoctype(doctype *parser.Doctype) {
+ c.write(doctype.String())
+}
+
+func (c *Compiler) visitComment(comment *parser.Comment) {
+ if comment.Silent {
+ return
+ }
+
+ c.indent(0, false)
+
+ if comment.Block == nil {
+ c.write(`{{unescaped ""}}`)
+ } else {
+ c.write(``)
+ }
+}
+
+func (c *Compiler) visitCondition(condition *parser.Condition) {
+ c.write(`{{if ` + c.visitRawInterpolation(condition.Expression) + `}}`)
+ c.visitBlock(condition.Positive)
+ if condition.Negative != nil {
+ c.write(`{{else}}`)
+ c.visitBlock(condition.Negative)
+ }
+ c.write(`{{end}}`)
+}
+
+func (c *Compiler) visitEach(each *parser.Each) {
+ if each.Block == nil {
+ return
+ }
+
+ if len(each.Y) == 0 {
+ c.write(`{{range ` + each.X + ` := ` + c.visitRawInterpolation(each.Expression) + `}}`)
+ } else {
+ c.write(`{{range ` + each.X + `, ` + each.Y + ` := ` + c.visitRawInterpolation(each.Expression) + `}}`)
+ }
+ c.visitBlock(each.Block)
+ c.write(`{{end}}`)
+}
+
+func (c *Compiler) visitAssignment(assgn *parser.Assignment) {
+ c.write(`{{` + assgn.X + ` := ` + c.visitRawInterpolation(assgn.Expression) + `}}`)
+}
+
+func (c *Compiler) visitTag(tag *parser.Tag) {
+ type attrib struct {
+ name string
+ value func() string
+ condition string
+ }
+
+ attribs := make(map[string]*attrib)
+
+ for _, item := range tag.Attributes {
+ attritem := item
+ attr := new(attrib)
+ attr.name = item.Name
+
+ attr.value = func() string {
+ if !attritem.IsRaw {
+ return c.visitInterpolation(attritem.Value)
+ } else if attritem.Value == "" {
+ return ""
+ } else {
+ return attritem.Value
+ }
+ }
+
+ if len(attritem.Condition) != 0 {
+ attr.condition = c.visitRawInterpolation(attritem.Condition)
+ }
+
+ if attr.name == "class" && attribs["class"] != nil {
+ prevclass := attribs["class"]
+ prevvalue := prevclass.value
+
+ prevclass.value = func() string {
+ aval := attr.value()
+
+ if len(attr.condition) > 0 {
+ aval = `{{if ` + attr.condition + `}}` + aval + `{{end}}`
+ }
+
+ if len(prevclass.condition) > 0 {
+ return `{{if ` + prevclass.condition + `}}` + prevvalue() + `{{end}} ` + aval
+ }
+
+ return prevvalue() + " " + aval
+ }
+ } else {
+ attribs[attritem.Name] = attr
+ }
+ }
+
+ keys := make([]string, 0, len(attribs))
+ for key := range attribs {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+
+ c.indent(0, true)
+ c.write("<" + tag.Name)
+
+ for _, name := range keys {
+ value := attribs[name]
+
+ if len(value.condition) > 0 {
+ c.write(`{{if ` + value.condition + `}}`)
+ }
+
+ val := value.value()
+
+ if val == "" {
+ c.write(` ` + name)
+ } else {
+ c.write(` ` + name + `="` + val + `"`)
+ }
+
+ if len(value.condition) > 0 {
+ c.write(`{{end}}`)
+ }
+ }
+
+ if tag.IsSelfClosing() {
+ c.write(` />`)
+ } else {
+ c.write(`>`)
+
+ if tag.Block != nil {
+ if !tag.Block.CanInline() {
+ c.indentLevel++
+ }
+
+ c.visitBlock(tag.Block)
+
+ if !tag.Block.CanInline() {
+ c.indentLevel--
+ c.indent(0, true)
+ }
+ }
+
+ c.write(`` + tag.Name + `>`)
+ }
+}
+
+var textInterpolateRegexp = regexp.MustCompile(`#\{(.*?)\}`)
+var textEscapeRegexp = regexp.MustCompile(`\{\{(.*?)\}\}`)
+
+func (c *Compiler) visitText(txt *parser.Text) {
+ value := textEscapeRegexp.ReplaceAllStringFunc(txt.Value, func(value string) string {
+ return `{{"{{"}}` + value[2:len(value)-2] + `{{"}}"}}`
+ })
+
+ value = textInterpolateRegexp.ReplaceAllStringFunc(value, func(value string) string {
+ return c.visitInterpolation(value[2 : len(value)-1])
+ })
+
+ lines := strings.Split(value, "\n")
+ for i := 0; i < len(lines); i++ {
+ c.write(lines[i])
+
+ if i < len(lines)-1 {
+ c.write("\n")
+ c.indent(0, false)
+ }
+ }
+}
+
+func (c *Compiler) visitInterpolation(value string) string {
+ return `{{` + c.visitRawInterpolation(value) + `}}`
+}
+
+func (c *Compiler) visitRawInterpolation(value string) string {
+ if value == "" {
+ value = "\"\""
+ }
+
+ value = strings.Replace(value, "$", dollar, -1)
+ expr, err := gp.ParseExpr(value)
+ if err != nil {
+ panic("Unable to parse expression.")
+ }
+ value = strings.Replace(c.visitExpression(expr), dollar, "$", -1)
+ return value
+}
+
+func (c *Compiler) visitExpression(outerexpr ast.Expr) string {
+ stack := list.New()
+
+ pop := func() string {
+ if stack.Front() == nil {
+ return ""
+ }
+
+ val := stack.Front().Value.(string)
+ stack.Remove(stack.Front())
+ return val
+ }
+
+ var exec func(ast.Expr)
+
+ exec = func(expr ast.Expr) {
+ switch expr := expr.(type) {
+ case *ast.BinaryExpr:
+ {
+ be := expr
+
+ exec(be.Y)
+ exec(be.X)
+
+ negate := false
+ name := c.tempvar()
+ c.write(`{{` + name + ` := `)
+
+ switch be.Op {
+ case gt.ADD:
+ c.write("__amber_add ")
+ case gt.SUB:
+ c.write("__amber_sub ")
+ case gt.MUL:
+ c.write("__amber_mul ")
+ case gt.QUO:
+ c.write("__amber_quo ")
+ case gt.REM:
+ c.write("__amber_rem ")
+ case gt.LAND:
+ c.write("and ")
+ case gt.LOR:
+ c.write("or ")
+ case gt.EQL:
+ c.write("__amber_eql ")
+ case gt.NEQ:
+ c.write("__amber_eql ")
+ negate = true
+ case gt.LSS:
+ c.write("__amber_lss ")
+ case gt.GTR:
+ c.write("__amber_gtr ")
+ case gt.LEQ:
+ c.write("__amber_gtr ")
+ negate = true
+ case gt.GEQ:
+ c.write("__amber_lss ")
+ negate = true
+ default:
+ panic("Unexpected operator!")
+ }
+
+ c.write(pop() + ` ` + pop() + `}}`)
+
+ if !negate {
+ stack.PushFront(name)
+ } else {
+ negname := c.tempvar()
+ c.write(`{{` + negname + ` := not ` + name + `}}`)
+ stack.PushFront(negname)
+ }
+ }
+ case *ast.UnaryExpr:
+ {
+ ue := expr
+
+ exec(ue.X)
+
+ name := c.tempvar()
+ c.write(`{{` + name + ` := `)
+
+ switch ue.Op {
+ case gt.SUB:
+ c.write("__amber_minus ")
+ case gt.ADD:
+ c.write("__amber_plus ")
+ case gt.NOT:
+ c.write("not ")
+ default:
+ panic("Unexpected operator!")
+ }
+
+ c.write(pop() + `}}`)
+ stack.PushFront(name)
+ }
+ case *ast.ParenExpr:
+ exec(expr.X)
+ case *ast.BasicLit:
+ stack.PushFront(strings.Replace(expr.Value, dollar, "$", -1))
+ case *ast.Ident:
+ name := expr.Name
+ if len(name) >= len(dollar) && name[:len(dollar)] == dollar {
+ if name == dollar {
+ stack.PushFront(`.`)
+ } else {
+ stack.PushFront(`$` + expr.Name[len(dollar):])
+ }
+ } else {
+ stack.PushFront(`.` + expr.Name)
+ }
+ case *ast.SelectorExpr:
+ se := expr
+ exec(se.X)
+ x := pop()
+
+ if x == "." {
+ x = ""
+ }
+
+ name := c.tempvar()
+ c.write(`{{` + name + ` := ` + x + `.` + se.Sel.Name + `}}`)
+ stack.PushFront(name)
+ case *ast.CallExpr:
+ ce := expr
+
+ for i := len(ce.Args) - 1; i >= 0; i-- {
+ exec(ce.Args[i])
+ }
+
+ name := c.tempvar()
+ builtin := false
+
+ if ident, ok := ce.Fun.(*ast.Ident); ok {
+ for _, fname := range builtinFunctions {
+ if fname == ident.Name {
+ builtin = true
+ break
+ }
+ }
+ for fname, _ := range FuncMap {
+ if fname == ident.Name {
+ builtin = true
+ break
+ }
+ }
+ }
+
+ if builtin {
+ stack.PushFront(ce.Fun.(*ast.Ident).Name)
+ c.write(`{{` + name + ` := ` + pop())
+ } else if se, ok := ce.Fun.(*ast.SelectorExpr); ok {
+ exec(se.X)
+ x := pop()
+
+ if x == "." {
+ x = ""
+ }
+ stack.PushFront(se.Sel.Name)
+ c.write(`{{` + name + ` := ` + x + `.` + pop())
+ } else {
+ exec(ce.Fun)
+ c.write(`{{` + name + ` := call ` + pop())
+ }
+
+ for i := 0; i < len(ce.Args); i++ {
+ c.write(` `)
+ c.write(pop())
+ }
+
+ c.write(`}}`)
+
+ stack.PushFront(name)
+ default:
+ panic("Unable to parse expression. Unsupported: " + reflect.TypeOf(expr).String())
+ }
+ }
+
+ exec(outerexpr)
+ return pop()
+}
+
+func (c *Compiler) visitMixin(mixin *parser.Mixin) {
+ c.mixins[mixin.Name] = mixin
+}
+
+func (c *Compiler) visitMixinCall(mixinCall *parser.MixinCall) {
+ mixin := c.mixins[mixinCall.Name]
+
+ switch {
+ case mixin == nil:
+ panic(fmt.Sprintf("unknown mixin %q", mixinCall.Name))
+
+ case len(mixinCall.Args) < len(mixin.Args):
+ panic(fmt.Sprintf(
+ "not enough arguments in call to mixin %q (have: %d, want: %d)",
+ mixinCall.Name,
+ len(mixinCall.Args),
+ len(mixin.Args),
+ ))
+ case len(mixinCall.Args) > len(mixin.Args):
+ panic(fmt.Sprintf(
+ "too many arguments in call to mixin %q (have: %d, want: %d)",
+ mixinCall.Name,
+ len(mixinCall.Args),
+ len(mixin.Args),
+ ))
+ }
+
+ for i, arg := range mixin.Args {
+ c.write(fmt.Sprintf(`{{%s := %s}}`, arg, c.visitRawInterpolation(mixinCall.Args[i])))
+ }
+ c.visitBlock(mixin.Block)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/doc.go
new file mode 100644
index 000000000000..76ee96a82027
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/doc.go
@@ -0,0 +1,257 @@
+/*
+Package amber is an elegant templating engine for Go Programming Language.
+It is inspired from HAML and Jade.
+
+Tags
+
+A tag is simply a word:
+
+ html
+
+is converted to
+
+
+
+It is possible to add ID and CLASS attributes to tags:
+
+ div#main
+ span.time
+
+are converted to
+
+
+
+
+Any arbitrary attribute name / value pair can be added this way:
+
+ a[href="http://www.google.com"]
+
+You can mix multiple attributes together
+
+ a#someid[href="/"][title="Main Page"].main.link Click Link
+
+gets converted to
+
+ Click Link
+
+It is also possible to define these attributes within the block of a tag
+
+ a
+ #someid
+ [href="/"]
+ [title="Main Page"]
+ .main
+ .link
+ | Click Link
+
+Doctypes
+
+To add a doctype, use `!!!` or `doctype` keywords:
+
+ !!! transitional
+ //
+
+or use `doctype`
+
+ doctype 5
+ //
+
+Available options: `5`, `default`, `xml`, `transitional`, `strict`, `frameset`, `1.1`, `basic`, `mobile`
+
+Tag Content
+
+For single line tag text, you can just append the text after tag name:
+
+ p Testing!
+
+would yield
+
+ Testing!
+
+For multi line tag text, or nested tags, use indentation:
+
+ html
+ head
+ title Page Title
+ body
+ div#content
+ p
+ | This is a long page content
+ | These lines are all part of the parent p
+
+ a[href="/"] Go To Main Page
+
+Data
+
+Input template data can be reached by key names directly. For example, assuming the template has been
+executed with following JSON data:
+
+ {
+ "Name": "Ekin",
+ "LastName": "Koc",
+ "Repositories": [
+ "amber",
+ "dateformat"
+ ],
+ "Avatar": "/images/ekin.jpg",
+ "Friends": 17
+ }
+
+It is possible to interpolate fields using `#{}`
+
+ p Welcome #{Name}!
+
+would print
+
+ Welcome Ekin!
+
+Attributes can have field names as well
+
+ a[title=Name][href="/ekin.koc"]
+
+would print
+
+
+
+Expressions
+
+Amber can expand basic expressions. For example, it is possible to concatenate strings with + operator:
+
+ p Welcome #{Name + " " + LastName}
+
+Arithmetic expressions are also supported:
+
+ p You need #{50 - Friends} more friends to reach 50!
+
+Expressions can be used within attributes
+
+ img[alt=Name + " " + LastName][src=Avatar]
+
+Variables
+
+It is possible to define dynamic variables within templates,
+all variables must start with a $ character and can be assigned as in the following example:
+
+ div
+ $fullname = Name + " " + LastName
+ p Welcome #{$fullname}
+
+If you need to access the supplied data itself (i.e. the object containing Name, LastName etc fields.) you can use `$` variable
+
+ p $.Name
+
+Conditions
+
+For conditional blocks, it is possible to use `if `
+
+ div
+ if Friends > 10
+ p You have more than 10 friends
+ else if Friends > 5
+ p You have more than 5 friends
+ else
+ p You need more friends
+
+Again, it is possible to use arithmetic and boolean operators
+
+ div
+ if Name == "Ekin" && LastName == "Koc"
+ p Hey! I know you..
+
+There is a special syntax for conditional attributes. Only block attributes can have conditions;
+
+ div
+ .hasfriends ? Friends > 0
+
+This would yield a div with `hasfriends` class only if the `Friends > 0` condition holds. It is
+perfectly fine to use the same method for other types of attributes:
+
+ div
+ #foo ? Name == "Ekin"
+ [bar=baz] ? len(Repositories) > 0
+
+Iterations
+
+It is possible to iterate over arrays and maps using `each`:
+
+ each $repo in Repositories
+ p #{$repo}
+
+would print
+
+ p amber
+ p dateformat
+
+It is also possible to iterate over values and indexes at the same time
+
+ each $i, $repo in Repositories
+ p
+ .even ? $i % 2 == 0
+ .odd ? $i % 2 == 1
+
+Includes
+
+A template can include other templates using `include`:
+
+ a.amber
+ p this is template a
+
+ b.amber
+ p this is template b
+
+ c.amber
+ div
+ include a
+ include b
+
+gets compiled to
+
+ div
+ p this is template a
+ p this is template b
+
+Inheritance
+
+A template can inherit other templates. In order to inherit another template, an `extends` keyword should be used.
+Parent template can define several named blocks and child template can modify the blocks.
+
+ master.amber
+ !!! 5
+ html
+ head
+ block meta
+ meta[name="description"][content="This is a great website"]
+
+ title
+ block title
+ | Default title
+ body
+ block content
+
+ subpage.amber
+ extends master
+
+ block title
+ | Some sub page!
+
+ block append meta
+ // This will be added after the description meta tag. It is also possible
+ // to prepend something to an existing block
+ meta[name="keywords"][content="foo bar"]
+
+ block content
+ div#main
+ p Some content here
+
+License
+(The MIT License)
+
+Copyright (c) 2012 Ekin Koc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+package amber
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/nodes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/nodes.go
new file mode 100644
index 000000000000..2f75ddddbc24
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/nodes.go
@@ -0,0 +1,285 @@
+package parser
+
+import (
+ "regexp"
+ "strings"
+)
+
+var selfClosingTags = [...]string{
+ "meta",
+ "img",
+ "link",
+ "input",
+ "source",
+ "area",
+ "base",
+ "col",
+ "br",
+ "hr",
+}
+
+var doctypes = map[string]string{
+ "5": ``,
+ "default": ``,
+ "xml": ``,
+ "transitional": ``,
+ "strict": ``,
+ "frameset": ``,
+ "1.1": ``,
+ "basic": ``,
+ "mobile": ``,
+}
+
+type Node interface {
+ Pos() SourcePosition
+}
+
+type SourcePosition struct {
+ LineNum int
+ ColNum int
+ TokenLength int
+ Filename string
+}
+
+func (s *SourcePosition) Pos() SourcePosition {
+ return *s
+}
+
+type Doctype struct {
+ SourcePosition
+ Value string
+}
+
+func newDoctype(value string) *Doctype {
+ dt := new(Doctype)
+ dt.Value = value
+ return dt
+}
+
+func (d *Doctype) String() string {
+ if defined := doctypes[d.Value]; len(defined) != 0 {
+ return defined
+ }
+
+ return ``
+}
+
+type Comment struct {
+ SourcePosition
+ Value string
+ Block *Block
+ Silent bool
+}
+
+func newComment(value string) *Comment {
+ dt := new(Comment)
+ dt.Value = value
+ dt.Block = nil
+ dt.Silent = false
+ return dt
+}
+
+type Text struct {
+ SourcePosition
+ Value string
+ Raw bool
+}
+
+func newText(value string, raw bool) *Text {
+ dt := new(Text)
+ dt.Value = value
+ dt.Raw = raw
+ return dt
+}
+
+type Block struct {
+ SourcePosition
+ Children []Node
+}
+
+func newBlock() *Block {
+ block := new(Block)
+ block.Children = make([]Node, 0)
+ return block
+}
+
+func (b *Block) push(node Node) {
+ b.Children = append(b.Children, node)
+}
+
+func (b *Block) pushFront(node Node) {
+ b.Children = append([]Node{node}, b.Children...)
+}
+
+func (b *Block) CanInline() bool {
+ if len(b.Children) == 0 {
+ return true
+ }
+
+ allText := true
+
+ for _, child := range b.Children {
+ if txt, ok := child.(*Text); !ok || txt.Raw {
+ allText = false
+ break
+ }
+ }
+
+ return allText
+}
+
+const (
+ NamedBlockDefault = iota
+ NamedBlockAppend
+ NamedBlockPrepend
+)
+
+type NamedBlock struct {
+ Block
+ Name string
+ Modifier int
+}
+
+func newNamedBlock(name string) *NamedBlock {
+ bb := new(NamedBlock)
+ bb.Name = name
+ bb.Block.Children = make([]Node, 0)
+ bb.Modifier = NamedBlockDefault
+ return bb
+}
+
+type Attribute struct {
+ SourcePosition
+ Name string
+ Value string
+ IsRaw bool
+ Condition string
+}
+
+type Tag struct {
+ SourcePosition
+ Block *Block
+ Name string
+ IsInterpolated bool
+ Attributes []Attribute
+}
+
+func newTag(name string) *Tag {
+ tag := new(Tag)
+ tag.Block = nil
+ tag.Name = name
+ tag.Attributes = make([]Attribute, 0)
+ tag.IsInterpolated = false
+ return tag
+
+}
+
+func (t *Tag) IsSelfClosing() bool {
+ for _, tag := range selfClosingTags {
+ if tag == t.Name {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (t *Tag) IsRawText() bool {
+ return t.Name == "style" || t.Name == "script"
+}
+
+type Condition struct {
+ SourcePosition
+ Positive *Block
+ Negative *Block
+ Expression string
+}
+
+func newCondition(exp string) *Condition {
+ cond := new(Condition)
+ cond.Expression = exp
+ return cond
+}
+
+type Each struct {
+ SourcePosition
+ X string
+ Y string
+ Expression string
+ Block *Block
+}
+
+func newEach(exp string) *Each {
+ each := new(Each)
+ each.Expression = exp
+ return each
+}
+
+type Assignment struct {
+ SourcePosition
+ X string
+ Expression string
+}
+
+func newAssignment(x, expression string) *Assignment {
+ assgn := new(Assignment)
+ assgn.X = x
+ assgn.Expression = expression
+ return assgn
+}
+
+type Mixin struct {
+ SourcePosition
+ Block *Block
+ Name string
+ Args []string
+}
+
+func newMixin(name, args string) *Mixin {
+ mixin := new(Mixin)
+ mixin.Name = name
+
+ delExp := regexp.MustCompile(`,\s`)
+ mixin.Args = delExp.Split(args, -1)
+
+ for i := 0; i < len(mixin.Args); i++ {
+ mixin.Args[i] = strings.TrimSpace(mixin.Args[i])
+ if mixin.Args[i] == "" {
+ mixin.Args = append(mixin.Args[:i], mixin.Args[i+1:]...)
+ i--
+ }
+ }
+
+ return mixin
+}
+
+type MixinCall struct {
+ SourcePosition
+ Name string
+ Args []string
+}
+
+func newMixinCall(name, args string) *MixinCall {
+ mixinCall := new(MixinCall)
+ mixinCall.Name = name
+
+ if args != "" {
+ const t = "%s"
+ quoteExp := regexp.MustCompile(`"(.*?)"`)
+ delExp := regexp.MustCompile(`,\s`)
+
+ quotes := quoteExp.FindAllString(args, -1)
+ replaced := quoteExp.ReplaceAllString(args, t)
+ mixinCall.Args = delExp.Split(replaced, -1)
+
+ qi := 0
+ for i, arg := range mixinCall.Args {
+ if arg == t {
+ mixinCall.Args[i] = quotes[qi]
+ qi++
+ }
+ }
+ }
+
+ return mixinCall
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/parser.go b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/parser.go
new file mode 100644
index 000000000000..9769f0b288a8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/parser.go
@@ -0,0 +1,482 @@
+package parser
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "path/filepath"
+ "strings"
+)
+
+type Parser struct {
+ scanner *scanner
+ filename string
+ fs http.FileSystem
+ currenttoken *token
+ namedBlocks map[string]*NamedBlock
+ parent *Parser
+ result *Block
+}
+
+func newParser(rdr io.Reader) *Parser {
+ p := new(Parser)
+ p.scanner = newScanner(rdr)
+ p.namedBlocks = make(map[string]*NamedBlock)
+ return p
+}
+
+func StringParser(input string) (*Parser, error) {
+ return newParser(bytes.NewReader([]byte(input))), nil
+}
+
+func ByteParser(input []byte) (*Parser, error) {
+ return newParser(bytes.NewReader(input)), nil
+}
+
+func (p *Parser) SetFilename(filename string) {
+ p.filename = filename
+}
+
+func (p *Parser) SetVirtualFilesystem(fs http.FileSystem) {
+ p.fs = fs
+}
+
+func FileParser(filename string) (*Parser, error) {
+ data, err := ioutil.ReadFile(filename)
+
+ if err != nil {
+ return nil, err
+ }
+
+ parser := newParser(bytes.NewReader(data))
+ parser.filename = filename
+ return parser, nil
+}
+
+func VirtualFileParser(filename string, fs http.FileSystem) (*Parser, error) {
+ file, err := fs.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := ioutil.ReadAll(file)
+ if err != nil {
+ return nil, err
+ }
+
+ parser := newParser(bytes.NewReader(data))
+ parser.filename = filename
+ parser.fs = fs
+ return parser, nil
+}
+
+func (p *Parser) Parse() *Block {
+ if p.result != nil {
+ return p.result
+ }
+
+ defer func() {
+ if r := recover(); r != nil {
+ if rs, ok := r.(string); ok && rs[:len("Amber Error")] == "Amber Error" {
+ panic(r)
+ }
+
+ pos := p.pos()
+
+ if len(pos.Filename) > 0 {
+ panic(fmt.Sprintf("Amber Error in <%s>: %v - Line: %d, Column: %d, Length: %d", pos.Filename, r, pos.LineNum, pos.ColNum, pos.TokenLength))
+ } else {
+ panic(fmt.Sprintf("Amber Error: %v - Line: %d, Column: %d, Length: %d", r, pos.LineNum, pos.ColNum, pos.TokenLength))
+ }
+ }
+ }()
+
+ block := newBlock()
+ p.advance()
+
+ for {
+ if p.currenttoken == nil || p.currenttoken.Kind == tokEOF {
+ break
+ }
+
+ if p.currenttoken.Kind == tokBlank {
+ p.advance()
+ continue
+ }
+
+ block.push(p.parse())
+ }
+
+ if p.parent != nil {
+ p.parent.Parse()
+
+ for _, prev := range p.parent.namedBlocks {
+ ours := p.namedBlocks[prev.Name]
+
+ if ours == nil {
+ // Put a copy of the named block into current context, so that sub-templates can use the block
+ p.namedBlocks[prev.Name] = prev
+ continue
+ }
+
+ top := findTopmostParentWithNamedBlock(p, prev.Name)
+ nb := top.namedBlocks[prev.Name]
+ switch ours.Modifier {
+ case NamedBlockAppend:
+ for i := 0; i < len(ours.Children); i++ {
+ nb.push(ours.Children[i])
+ }
+ case NamedBlockPrepend:
+ for i := len(ours.Children) - 1; i >= 0; i-- {
+ nb.pushFront(ours.Children[i])
+ }
+ default:
+ nb.Children = ours.Children
+ }
+ }
+
+ block = p.parent.result
+ }
+
+ p.result = block
+ return block
+}
+
+func (p *Parser) pos() SourcePosition {
+ pos := p.scanner.Pos()
+ pos.Filename = p.filename
+ return pos
+}
+
+func (p *Parser) parseRelativeFile(filename string) *Parser {
+ if len(p.filename) == 0 {
+ panic("Unable to import or extend " + filename + " in a non filesystem based parser.")
+ }
+
+ filename = filepath.Join(filepath.Dir(p.filename), filename)
+
+ if strings.IndexRune(filepath.Base(filename), '.') < 0 {
+ filename = filename + ".amber"
+ }
+
+ parser, err := FileParser(filename)
+ if err != nil && p.fs != nil {
+ parser, err = VirtualFileParser(filename, p.fs)
+ }
+ if err != nil {
+ panic("Unable to read " + filename + ", Error: " + string(err.Error()))
+ }
+
+ return parser
+}
+
+func (p *Parser) parse() Node {
+ switch p.currenttoken.Kind {
+ case tokDoctype:
+ return p.parseDoctype()
+ case tokComment:
+ return p.parseComment()
+ case tokText:
+ return p.parseText()
+ case tokIf:
+ return p.parseIf()
+ case tokEach:
+ return p.parseEach()
+ case tokImport:
+ return p.parseImport()
+ case tokTag:
+ return p.parseTag()
+ case tokAssignment:
+ return p.parseAssignment()
+ case tokNamedBlock:
+ return p.parseNamedBlock()
+ case tokExtends:
+ return p.parseExtends()
+ case tokIndent:
+ return p.parseBlock(nil)
+ case tokMixin:
+ return p.parseMixin()
+ case tokMixinCall:
+ return p.parseMixinCall()
+ }
+
+ panic(fmt.Sprintf("Unexpected token: %d", p.currenttoken.Kind))
+}
+
+func (p *Parser) expect(typ rune) *token {
+ if p.currenttoken.Kind != typ {
+ panic("Unexpected token!")
+ }
+ curtok := p.currenttoken
+ p.advance()
+ return curtok
+}
+
+func (p *Parser) advance() {
+ p.currenttoken = p.scanner.Next()
+}
+
+func (p *Parser) parseExtends() *Block {
+ if p.parent != nil {
+ panic("Unable to extend multiple parent templates.")
+ }
+
+ tok := p.expect(tokExtends)
+ parser := p.parseRelativeFile(tok.Value)
+ parser.Parse()
+ p.parent = parser
+ return newBlock()
+}
+
+func (p *Parser) parseBlock(parent Node) *Block {
+ p.expect(tokIndent)
+ block := newBlock()
+ block.SourcePosition = p.pos()
+
+ for {
+ if p.currenttoken == nil || p.currenttoken.Kind == tokEOF || p.currenttoken.Kind == tokOutdent {
+ break
+ }
+
+ if p.currenttoken.Kind == tokBlank {
+ p.advance()
+ continue
+ }
+
+ if p.currenttoken.Kind == tokId ||
+ p.currenttoken.Kind == tokClassName ||
+ p.currenttoken.Kind == tokAttribute {
+
+ if tag, ok := parent.(*Tag); ok {
+ attr := p.expect(p.currenttoken.Kind)
+ cond := attr.Data["Condition"]
+
+ switch attr.Kind {
+ case tokId:
+ tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "id", attr.Value, true, cond})
+ case tokClassName:
+ tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "class", attr.Value, true, cond})
+ case tokAttribute:
+ tag.Attributes = append(tag.Attributes, Attribute{p.pos(), attr.Value, attr.Data["Content"], attr.Data["Mode"] == "raw", cond})
+ }
+
+ continue
+ } else {
+ panic("Conditional attributes must be placed immediately within a parent tag.")
+ }
+ }
+
+ block.push(p.parse())
+ }
+
+ p.expect(tokOutdent)
+
+ return block
+}
+
+func (p *Parser) parseIf() *Condition {
+ tok := p.expect(tokIf)
+ cnd := newCondition(tok.Value)
+ cnd.SourcePosition = p.pos()
+
+readmore:
+ switch p.currenttoken.Kind {
+ case tokIndent:
+ cnd.Positive = p.parseBlock(cnd)
+ goto readmore
+ case tokElse:
+ p.expect(tokElse)
+ if p.currenttoken.Kind == tokIf {
+ cnd.Negative = newBlock()
+ cnd.Negative.push(p.parseIf())
+ } else if p.currenttoken.Kind == tokIndent {
+ cnd.Negative = p.parseBlock(cnd)
+ } else {
+ panic("Unexpected token!")
+ }
+ goto readmore
+ }
+
+ return cnd
+}
+
+func (p *Parser) parseEach() *Each {
+ tok := p.expect(tokEach)
+ ech := newEach(tok.Value)
+ ech.SourcePosition = p.pos()
+ ech.X = tok.Data["X"]
+ ech.Y = tok.Data["Y"]
+
+ if p.currenttoken.Kind == tokIndent {
+ ech.Block = p.parseBlock(ech)
+ }
+
+ return ech
+}
+
+func (p *Parser) parseImport() *Block {
+ tok := p.expect(tokImport)
+ node := p.parseRelativeFile(tok.Value).Parse()
+ node.SourcePosition = p.pos()
+ return node
+}
+
+func (p *Parser) parseNamedBlock() *Block {
+ tok := p.expect(tokNamedBlock)
+
+ if p.namedBlocks[tok.Value] != nil {
+ panic("Multiple definitions of named blocks are not permitted. Block " + tok.Value + " has been re defined.")
+ }
+
+ block := newNamedBlock(tok.Value)
+ block.SourcePosition = p.pos()
+
+ if tok.Data["Modifier"] == "append" {
+ block.Modifier = NamedBlockAppend
+ } else if tok.Data["Modifier"] == "prepend" {
+ block.Modifier = NamedBlockPrepend
+ }
+
+ if p.currenttoken.Kind == tokIndent {
+ block.Block = *(p.parseBlock(nil))
+ }
+
+ p.namedBlocks[block.Name] = block
+
+ if block.Modifier == NamedBlockDefault {
+ return &block.Block
+ }
+
+ return newBlock()
+}
+
+func (p *Parser) parseDoctype() *Doctype {
+ tok := p.expect(tokDoctype)
+ node := newDoctype(tok.Value)
+ node.SourcePosition = p.pos()
+ return node
+}
+
+func (p *Parser) parseComment() *Comment {
+ tok := p.expect(tokComment)
+ cmnt := newComment(tok.Value)
+ cmnt.SourcePosition = p.pos()
+ cmnt.Silent = tok.Data["Mode"] == "silent"
+
+ if p.currenttoken.Kind == tokIndent {
+ cmnt.Block = p.parseBlock(cmnt)
+ }
+
+ return cmnt
+}
+
+func (p *Parser) parseText() *Text {
+ tok := p.expect(tokText)
+ node := newText(tok.Value, tok.Data["Mode"] == "raw")
+ node.SourcePosition = p.pos()
+ return node
+}
+
+func (p *Parser) parseAssignment() *Assignment {
+ tok := p.expect(tokAssignment)
+ node := newAssignment(tok.Data["X"], tok.Value)
+ node.SourcePosition = p.pos()
+ return node
+}
+
+func (p *Parser) parseTag() *Tag {
+ tok := p.expect(tokTag)
+ tag := newTag(tok.Value)
+ tag.SourcePosition = p.pos()
+
+ ensureBlock := func() {
+ if tag.Block == nil {
+ tag.Block = newBlock()
+ }
+ }
+
+readmore:
+ switch p.currenttoken.Kind {
+ case tokIndent:
+ if tag.IsRawText() {
+ p.scanner.readRaw = true
+ }
+
+ block := p.parseBlock(tag)
+ if tag.Block == nil {
+ tag.Block = block
+ } else {
+ for _, c := range block.Children {
+ tag.Block.push(c)
+ }
+ }
+ case tokId:
+ id := p.expect(tokId)
+ if len(id.Data["Condition"]) > 0 {
+ panic("Conditional attributes must be placed in a block within a tag.")
+ }
+ tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "id", id.Value, true, ""})
+ goto readmore
+ case tokClassName:
+ cls := p.expect(tokClassName)
+ if len(cls.Data["Condition"]) > 0 {
+ panic("Conditional attributes must be placed in a block within a tag.")
+ }
+ tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "class", cls.Value, true, ""})
+ goto readmore
+ case tokAttribute:
+ attr := p.expect(tokAttribute)
+ if len(attr.Data["Condition"]) > 0 {
+ panic("Conditional attributes must be placed in a block within a tag.")
+ }
+ tag.Attributes = append(tag.Attributes, Attribute{p.pos(), attr.Value, attr.Data["Content"], attr.Data["Mode"] == "raw", ""})
+ goto readmore
+ case tokText:
+ if p.currenttoken.Data["Mode"] != "piped" {
+ ensureBlock()
+ tag.Block.pushFront(p.parseText())
+ goto readmore
+ }
+ }
+
+ return tag
+}
+
+func (p *Parser) parseMixin() *Mixin {
+ tok := p.expect(tokMixin)
+ mixin := newMixin(tok.Value, tok.Data["Args"])
+ mixin.SourcePosition = p.pos()
+
+ if p.currenttoken.Kind == tokIndent {
+ mixin.Block = p.parseBlock(mixin)
+ }
+
+ return mixin
+}
+
+func (p *Parser) parseMixinCall() *MixinCall {
+ tok := p.expect(tokMixinCall)
+ mixinCall := newMixinCall(tok.Value, tok.Data["Args"])
+ mixinCall.SourcePosition = p.pos()
+ return mixinCall
+}
+
+func findTopmostParentWithNamedBlock(p *Parser, name string) *Parser {
+ top := p
+
+ for {
+ if top.namedBlocks[name] == nil {
+ return nil
+ }
+ if top.parent == nil {
+ return top
+ }
+ if top.parent.namedBlocks[name] != nil {
+ top = top.parent
+ } else {
+ return top
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/scanner.go b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/scanner.go
new file mode 100644
index 000000000000..70e0203512cd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/parser/scanner.go
@@ -0,0 +1,501 @@
+package parser
+
+import (
+ "bufio"
+ "container/list"
+ "fmt"
+ "io"
+ "regexp"
+)
+
+const (
+ tokEOF = -(iota + 1)
+ tokDoctype
+ tokComment
+ tokIndent
+ tokOutdent
+ tokBlank
+ tokId
+ tokClassName
+ tokTag
+ tokText
+ tokAttribute
+ tokIf
+ tokElse
+ tokEach
+ tokAssignment
+ tokImport
+ tokNamedBlock
+ tokExtends
+ tokMixin
+ tokMixinCall
+)
+
+const (
+ scnNewLine = iota
+ scnLine
+ scnEOF
+)
+
+type scanner struct {
+ reader *bufio.Reader
+ indentStack *list.List
+ stash *list.List
+
+ state int32
+ buffer string
+
+ line int
+ col int
+ lastTokenLine int
+ lastTokenCol int
+ lastTokenSize int
+
+ readRaw bool
+}
+
+type token struct {
+ Kind rune
+ Value string
+ Data map[string]string
+}
+
+func newScanner(r io.Reader) *scanner {
+ s := new(scanner)
+ s.reader = bufio.NewReader(r)
+ s.indentStack = list.New()
+ s.stash = list.New()
+ s.state = scnNewLine
+ s.line = -1
+ s.col = 0
+
+ return s
+}
+
+func (s *scanner) Pos() SourcePosition {
+ return SourcePosition{s.lastTokenLine + 1, s.lastTokenCol + 1, s.lastTokenSize, ""}
+}
+
+// Returns next token found in buffer
+func (s *scanner) Next() *token {
+ if s.readRaw {
+ s.readRaw = false
+ return s.NextRaw()
+ }
+
+ s.ensureBuffer()
+
+ if stashed := s.stash.Front(); stashed != nil {
+ tok := stashed.Value.(*token)
+ s.stash.Remove(stashed)
+ return tok
+ }
+
+ switch s.state {
+ case scnEOF:
+ if outdent := s.indentStack.Back(); outdent != nil {
+ s.indentStack.Remove(outdent)
+ return &token{tokOutdent, "", nil}
+ }
+
+ return &token{tokEOF, "", nil}
+ case scnNewLine:
+ s.state = scnLine
+
+ if tok := s.scanIndent(); tok != nil {
+ return tok
+ }
+
+ return s.Next()
+ case scnLine:
+ if tok := s.scanMixin(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanMixinCall(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanDoctype(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanCondition(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanEach(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanImport(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanExtends(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanBlock(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanAssignment(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanTag(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanId(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanClassName(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanAttribute(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanComment(); tok != nil {
+ return tok
+ }
+
+ if tok := s.scanText(); tok != nil {
+ return tok
+ }
+ }
+
+ return nil
+}
+
+func (s *scanner) NextRaw() *token {
+ result := ""
+ level := 0
+
+ for {
+ s.ensureBuffer()
+
+ switch s.state {
+ case scnEOF:
+ return &token{tokText, result, map[string]string{"Mode": "raw"}}
+ case scnNewLine:
+ s.state = scnLine
+
+ if tok := s.scanIndent(); tok != nil {
+ if tok.Kind == tokIndent {
+ level++
+ } else if tok.Kind == tokOutdent {
+ level--
+ } else {
+ result = result + "\n"
+ continue
+ }
+
+ if level < 0 {
+ s.stash.PushBack(&token{tokOutdent, "", nil})
+
+ if len(result) > 0 && result[len(result)-1] == '\n' {
+ result = result[:len(result)-1]
+ }
+
+ return &token{tokText, result, map[string]string{"Mode": "raw"}}
+ }
+ }
+ case scnLine:
+ if len(result) > 0 {
+ result = result + "\n"
+ }
+ for i := 0; i < level; i++ {
+ result += "\t"
+ }
+ result = result + s.buffer
+ s.consume(len(s.buffer))
+ }
+ }
+
+ return nil
+}
+
+var rgxIndent = regexp.MustCompile(`^(\s+)`)
+
+func (s *scanner) scanIndent() *token {
+ if len(s.buffer) == 0 {
+ return &token{tokBlank, "", nil}
+ }
+
+ var head *list.Element
+ for head = s.indentStack.Front(); head != nil; head = head.Next() {
+ value := head.Value.(*regexp.Regexp)
+
+ if match := value.FindString(s.buffer); len(match) != 0 {
+ s.consume(len(match))
+ } else {
+ break
+ }
+ }
+
+ newIndent := rgxIndent.FindString(s.buffer)
+
+ if len(newIndent) != 0 && head == nil {
+ s.indentStack.PushBack(regexp.MustCompile(regexp.QuoteMeta(newIndent)))
+ s.consume(len(newIndent))
+ return &token{tokIndent, newIndent, nil}
+ }
+
+ if len(newIndent) == 0 && head != nil {
+ for head != nil {
+ next := head.Next()
+ s.indentStack.Remove(head)
+ if next == nil {
+ return &token{tokOutdent, "", nil}
+ } else {
+ s.stash.PushBack(&token{tokOutdent, "", nil})
+ }
+ head = next
+ }
+ }
+
+ if len(newIndent) != 0 && head != nil {
+ panic("Mismatching indentation. Please use a coherent indent schema.")
+ }
+
+ return nil
+}
+
+var rgxDoctype = regexp.MustCompile(`^(!!!|doctype)\s*(.*)`)
+
+func (s *scanner) scanDoctype() *token {
+ if sm := rgxDoctype.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ if len(sm[2]) == 0 {
+ sm[2] = "html"
+ }
+
+ s.consume(len(sm[0]))
+ return &token{tokDoctype, sm[2], nil}
+ }
+
+ return nil
+}
+
+var rgxIf = regexp.MustCompile(`^if\s+(.+)$`)
+var rgxElse = regexp.MustCompile(`^else\s*`)
+
+func (s *scanner) scanCondition() *token {
+ if sm := rgxIf.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokIf, sm[1], nil}
+ }
+
+ if sm := rgxElse.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokElse, "", nil}
+ }
+
+ return nil
+}
+
+var rgxEach = regexp.MustCompile(`^each\s+(\$[\w0-9\-_]*)(?:\s*,\s*(\$[\w0-9\-_]*))?\s+in\s+(.+)$`)
+
+func (s *scanner) scanEach() *token {
+ if sm := rgxEach.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokEach, sm[3], map[string]string{"X": sm[1], "Y": sm[2]}}
+ }
+
+ return nil
+}
+
+var rgxAssignment = regexp.MustCompile(`^(\$[\w0-9\-_]*)?\s*=\s*(.+)$`)
+
+func (s *scanner) scanAssignment() *token {
+ if sm := rgxAssignment.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokAssignment, sm[2], map[string]string{"X": sm[1]}}
+ }
+
+ return nil
+}
+
+var rgxComment = regexp.MustCompile(`^\/\/(-)?\s*(.*)$`)
+
+func (s *scanner) scanComment() *token {
+ if sm := rgxComment.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ mode := "embed"
+ if len(sm[1]) != 0 {
+ mode = "silent"
+ }
+
+ s.consume(len(sm[0]))
+ return &token{tokComment, sm[2], map[string]string{"Mode": mode}}
+ }
+
+ return nil
+}
+
+var rgxId = regexp.MustCompile(`^#([\w-]+)(?:\s*\?\s*(.*)$)?`)
+
+func (s *scanner) scanId() *token {
+ if sm := rgxId.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokId, sm[1], map[string]string{"Condition": sm[2]}}
+ }
+
+ return nil
+}
+
+var rgxClassName = regexp.MustCompile(`^\.([\w-]+)(?:\s*\?\s*(.*)$)?`)
+
+func (s *scanner) scanClassName() *token {
+ if sm := rgxClassName.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokClassName, sm[1], map[string]string{"Condition": sm[2]}}
+ }
+
+ return nil
+}
+
+var rgxAttribute = regexp.MustCompile(`^\[([\w\-:@\.]+)\s*(?:=\s*(\"([^\"\\]*)\"|([^\]]+)))?\](?:\s*\?\s*(.*)$)?`)
+
+func (s *scanner) scanAttribute() *token {
+ if sm := rgxAttribute.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+
+ if len(sm[3]) != 0 || sm[2] == "" {
+ return &token{tokAttribute, sm[1], map[string]string{"Content": sm[3], "Mode": "raw", "Condition": sm[5]}}
+ }
+
+ return &token{tokAttribute, sm[1], map[string]string{"Content": sm[4], "Mode": "expression", "Condition": sm[5]}}
+ }
+
+ return nil
+}
+
+var rgxImport = regexp.MustCompile(`^import\s+([0-9a-zA-Z_\-\. \/]*)$`)
+
+func (s *scanner) scanImport() *token {
+ if sm := rgxImport.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokImport, sm[1], nil}
+ }
+
+ return nil
+}
+
+var rgxExtends = regexp.MustCompile(`^extends\s+([0-9a-zA-Z_\-\. \/]*)$`)
+
+func (s *scanner) scanExtends() *token {
+ if sm := rgxExtends.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokExtends, sm[1], nil}
+ }
+
+ return nil
+}
+
+var rgxBlock = regexp.MustCompile(`^block\s+(?:(append|prepend)\s+)?([0-9a-zA-Z_\-\. \/]*)$`)
+
+func (s *scanner) scanBlock() *token {
+ if sm := rgxBlock.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokNamedBlock, sm[2], map[string]string{"Modifier": sm[1]}}
+ }
+
+ return nil
+}
+
+var rgxTag = regexp.MustCompile(`^(\w[-:\w]*)`)
+
+func (s *scanner) scanTag() *token {
+ if sm := rgxTag.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokTag, sm[1], nil}
+ }
+
+ return nil
+}
+
+var rgxMixin = regexp.MustCompile(`^mixin ([a-zA-Z_-]+\w*)(\(((\$\w*(,\s)?)*)\))?$`)
+
+func (s *scanner) scanMixin() *token {
+ if sm := rgxMixin.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokMixin, sm[1], map[string]string{"Args": sm[3]}}
+ }
+
+ return nil
+}
+
+var rgxMixinCall = regexp.MustCompile(`^\+([A-Za-z_-]+\w*)(\((.+(,\s)?)*\))?$`)
+
+func (s *scanner) scanMixinCall() *token {
+ if sm := rgxMixinCall.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+ return &token{tokMixinCall, sm[1], map[string]string{"Args": sm[3]}}
+ }
+
+ return nil
+}
+
+var rgxText = regexp.MustCompile(`^(\|)? ?(.*)$`)
+
+func (s *scanner) scanText() *token {
+ if sm := rgxText.FindStringSubmatch(s.buffer); len(sm) != 0 {
+ s.consume(len(sm[0]))
+
+ mode := "inline"
+ if sm[1] == "|" {
+ mode = "piped"
+ }
+
+ return &token{tokText, sm[2], map[string]string{"Mode": mode}}
+ }
+
+ return nil
+}
+
+// Moves position forward, and removes beginning of s.buffer (len bytes)
+func (s *scanner) consume(runes int) {
+ if len(s.buffer) < runes {
+ panic(fmt.Sprintf("Unable to consume %d runes from buffer.", runes))
+ }
+
+ s.lastTokenLine = s.line
+ s.lastTokenCol = s.col
+ s.lastTokenSize = runes
+
+ s.buffer = s.buffer[runes:]
+ s.col += runes
+}
+
+// Reads string into s.buffer
+func (s *scanner) ensureBuffer() {
+ if len(s.buffer) > 0 {
+ return
+ }
+
+ buf, err := s.reader.ReadString('\n')
+
+ if err != nil && err != io.EOF {
+ panic(err)
+ } else if err != nil && len(buf) == 0 {
+ s.state = scnEOF
+ } else {
+ // endline "LF only" or "\n" use Unix, Linux, modern MacOS X, FreeBSD, BeOS, RISC OS
+ if buf[len(buf)-1] == '\n' {
+ buf = buf[:len(buf)-1]
+ }
+ // endline "CR+LF" or "\r\n" use internet protocols, DEC RT-11, Windows, CP/M, MS-DOS, OS/2, Symbian OS
+ if len(buf) > 0 && buf[len(buf)-1] == '\r' {
+ buf = buf[:len(buf)-1]
+ }
+
+ s.state = scnNewLine
+ s.buffer = buf
+ s.line += 1
+ s.col = 0
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/runtime.go b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/runtime.go
new file mode 100644
index 000000000000..6438fd1fc29b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/eknkc/amber/runtime.go
@@ -0,0 +1,287 @@
+package amber
+
+import (
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "reflect"
+)
+
+var FuncMap = template.FuncMap{
+ "__amber_add": runtime_add,
+ "__amber_sub": runtime_sub,
+ "__amber_mul": runtime_mul,
+ "__amber_quo": runtime_quo,
+ "__amber_rem": runtime_rem,
+ "__amber_minus": runtime_minus,
+ "__amber_plus": runtime_plus,
+ "__amber_eql": runtime_eql,
+ "__amber_gtr": runtime_gtr,
+ "__amber_lss": runtime_lss,
+
+ "json": runtime_json,
+ "unescaped": runtime_unescaped,
+}
+
+func runtime_add(x, y interface{}) interface{} {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() + vy.Int()
+ case reflect.Float32, reflect.Float64:
+ return float64(vx.Int()) + vy.Float()
+ case reflect.String:
+ return fmt.Sprintf("%d%s", vx.Int(), vy.String())
+ }
+ }
+ case reflect.Float32, reflect.Float64:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Float() + float64(vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.Float() + vy.Float()
+ case reflect.String:
+ return fmt.Sprintf("%f%s", vx.Float(), vy.String())
+ }
+ }
+ case reflect.String:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return fmt.Sprintf("%s%d", vx.String(), vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return fmt.Sprintf("%s%f", vx.String(), vy.Float())
+ case reflect.String:
+ return fmt.Sprintf("%s%s", vx.String(), vy.String())
+ }
+ }
+ }
+
+ return ""
+}
+
+func runtime_sub(x, y interface{}) interface{} {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() - vy.Int()
+ case reflect.Float32, reflect.Float64:
+ return float64(vx.Int()) - vy.Float()
+ }
+ }
+ case reflect.Float32, reflect.Float64:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Float() - float64(vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.Float() - vy.Float()
+ }
+ }
+ }
+
+ return ""
+}
+
+func runtime_mul(x, y interface{}) interface{} {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() * vy.Int()
+ case reflect.Float32, reflect.Float64:
+ return float64(vx.Int()) * vy.Float()
+ }
+ }
+ case reflect.Float32, reflect.Float64:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Float() * float64(vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.Float() * vy.Float()
+ }
+ }
+ }
+
+ return ""
+}
+
+func runtime_quo(x, y interface{}) interface{} {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() / vy.Int()
+ case reflect.Float32, reflect.Float64:
+ return float64(vx.Int()) / vy.Float()
+ }
+ }
+ case reflect.Float32, reflect.Float64:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Float() / float64(vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.Float() / vy.Float()
+ }
+ }
+ }
+
+ return ""
+}
+
+func runtime_rem(x, y interface{}) interface{} {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() % vy.Int()
+ }
+ }
+ }
+
+ return ""
+}
+
+func runtime_minus(x interface{}) interface{} {
+ vx := reflect.ValueOf(x)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return -vx.Int()
+ case reflect.Float32, reflect.Float64:
+ return -vx.Float()
+ }
+
+ return ""
+}
+
+func runtime_plus(x interface{}) interface{} {
+ vx := reflect.ValueOf(x)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return +vx.Int()
+ case reflect.Float32, reflect.Float64:
+ return +vx.Float()
+ }
+
+ return ""
+}
+
+func runtime_eql(x, y interface{}) bool {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() == vy.Int()
+ case reflect.Float32, reflect.Float64:
+ return float64(vx.Int()) == vy.Float()
+ case reflect.String:
+ return fmt.Sprintf("%d", vx.Int()) == vy.String()
+ }
+ }
+ case reflect.Float32, reflect.Float64:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Float() == float64(vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.Float() == vy.Float()
+ case reflect.String:
+ return fmt.Sprintf("%f", vx.Float()) == vy.String()
+ }
+ }
+ case reflect.String:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.String() == fmt.Sprintf("%d", vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.String() == fmt.Sprintf("%f", vy.Float())
+ case reflect.String:
+ return vx.String() == fmt.Sprintf("%s", vy.String())
+ }
+ }
+ case reflect.Bool:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Bool() && vy.Int() != 0
+ case reflect.Bool:
+ return vx.Bool() == vy.Bool()
+ }
+ }
+ }
+
+ return false
+}
+
+func runtime_lss(x, y interface{}) bool {
+ vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
+ switch vx.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Int() < vy.Int()
+ case reflect.Float32, reflect.Float64:
+ return float64(vx.Int()) < vy.Float()
+ case reflect.String:
+ return fmt.Sprintf("%d", vx.Int()) < vy.String()
+ }
+ }
+ case reflect.Float32, reflect.Float64:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.Float() < float64(vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.Float() < vy.Float()
+ case reflect.String:
+ return fmt.Sprintf("%f", vx.Float()) < vy.String()
+ }
+ }
+ case reflect.String:
+ {
+ switch vy.Kind() {
+ case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
+ return vx.String() < fmt.Sprintf("%d", vy.Int())
+ case reflect.Float32, reflect.Float64:
+ return vx.String() < fmt.Sprintf("%f", vy.Float())
+ case reflect.String:
+ return vx.String() < vy.String()
+ }
+ }
+ }
+
+ return false
+}
+
+func runtime_gtr(x, y interface{}) bool {
+ return !runtime_lss(x, y) && !runtime_eql(x, y)
+}
+
+func runtime_json(x interface{}) (res string, err error) {
+ bres, err := json.Marshal(x)
+ res = string(bres)
+ return
+}
+
+func runtime_unescaped(x string) interface{} {
+ return template.HTML(x)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/LICENSE.md b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/LICENSE.md
new file mode 100644
index 000000000000..25fdaf639dfc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/LICENSE.md
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Fatih Arslan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/README.md
new file mode 100644
index 000000000000..5152bf59bf8e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/README.md
@@ -0,0 +1,178 @@
+# color [![](https://github.com/fatih/color/workflows/build/badge.svg)](https://github.com/fatih/color/actions) [![PkgGoDev](https://pkg.go.dev/badge/github.com/fatih/color)](https://pkg.go.dev/github.com/fatih/color)
+
+Color lets you use colorized outputs in terms of [ANSI Escape
+Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
+has support for Windows too! The API can be used in several ways, pick one that
+suits you.
+
+![Color](https://user-images.githubusercontent.com/438920/96832689-03b3e000-13f4-11eb-9803-46f4c4de3406.jpg)
+
+
+## Install
+
+```bash
+go get github.com/fatih/color
+```
+
+## Examples
+
+### Standard colors
+
+```go
+// Print with default helper functions
+color.Cyan("Prints text in cyan.")
+
+// A newline will be appended automatically
+color.Blue("Prints %s in blue.", "text")
+
+// These are using the default foreground colors
+color.Red("We have red")
+color.Magenta("And many others ..")
+
+```
+
+### Mix and reuse colors
+
+```go
+// Create a new color object
+c := color.New(color.FgCyan).Add(color.Underline)
+c.Println("Prints cyan text with an underline.")
+
+// Or just add them to New()
+d := color.New(color.FgCyan, color.Bold)
+d.Printf("This prints bold cyan %s\n", "too!.")
+
+// Mix up foreground and background colors, create new mixes!
+red := color.New(color.FgRed)
+
+boldRed := red.Add(color.Bold)
+boldRed.Println("This will print text in bold red.")
+
+whiteBackground := red.Add(color.BgWhite)
+whiteBackground.Println("Red text with white background.")
+```
+
+### Use your own output (io.Writer)
+
+```go
+// Use your own io.Writer output
+color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
+
+blue := color.New(color.FgBlue)
+blue.Fprint(writer, "This will print text in blue.")
+```
+
+### Custom print functions (PrintFunc)
+
+```go
+// Create a custom print function for convenience
+red := color.New(color.FgRed).PrintfFunc()
+red("Warning")
+red("Error: %s", err)
+
+// Mix up multiple attributes
+notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+notice("Don't forget this...")
+```
+
+### Custom fprint functions (FprintFunc)
+
+```go
+blue := color.New(color.FgBlue).FprintfFunc()
+blue(myWriter, "important notice: %s", stars)
+
+// Mix up with multiple attributes
+success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
+success(myWriter, "Don't forget this...")
+```
+
+### Insert into noncolor strings (SprintFunc)
+
+```go
+// Create SprintXxx functions to mix strings with other non-colorized strings:
+yellow := color.New(color.FgYellow).SprintFunc()
+red := color.New(color.FgRed).SprintFunc()
+fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
+fmt.Printf("This %s rocks!\n", info("package"))
+
+// Use helper functions
+fmt.Println("This", color.RedString("warning"), "should be not neglected.")
+fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
+
+// Windows supported too! Just don't forget to change the output to color.Output
+fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+```
+
+### Plug into existing code
+
+```go
+// Use handy standard colors
+color.Set(color.FgYellow)
+
+fmt.Println("Existing text will now be in yellow")
+fmt.Printf("This one %s\n", "too")
+
+color.Unset() // Don't forget to unset
+
+// You can mix up parameters
+color.Set(color.FgMagenta, color.Bold)
+defer color.Unset() // Use it in your function
+
+fmt.Println("All text will now be bold magenta.")
+```
+
+### Disable/Enable color
+
+There might be a case where you want to explicitly disable/enable color output. the
+`go-isatty` package will automatically disable color output for non-tty output streams
+(for example if the output were piped directly to `less`).
+
+The `color` package also disables color output if the [`NO_COLOR`](https://no-color.org) environment
+variable is set (regardless of its value).
+
+`Color` has support to disable/enable colors programatically both globally and
+for single color definitions. For example suppose you have a CLI app and a
+`--no-color` bool flag. You can easily disable the color output with:
+
+```go
+var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+if *flagNoColor {
+ color.NoColor = true // disables colorized output
+}
+```
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+```go
+c := color.New(color.FgCyan)
+c.Println("Prints cyan text")
+
+c.DisableColor()
+c.Println("This is printed without any color")
+
+c.EnableColor()
+c.Println("This prints again cyan...")
+```
+
+## GitHub Actions
+
+To output color in GitHub Actions (or other CI systems that support ANSI colors), make sure to set `color.NoColor = false` so that it bypasses the check for non-tty output streams.
+
+## Todo
+
+* Save/Return previous values
+* Evaluate fmt.Formatter interface
+
+
+## Credits
+
+ * [Fatih Arslan](https://github.com/fatih)
+ * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
+
+## License
+
+The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/color.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/color.go
new file mode 100644
index 000000000000..98a60f3c88d6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/color.go
@@ -0,0 +1,618 @@
+package color
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/mattn/go-colorable"
+ "github.com/mattn/go-isatty"
+)
+
+var (
+ // NoColor defines if the output is colorized or not. It's dynamically set to
+ // false or true based on the stdout's file descriptor referring to a terminal
+ // or not. It's also set to true if the NO_COLOR environment variable is
+ // set (regardless of its value). This is a global option and affects all
+ // colors. For more control over each color block use the methods
+ // DisableColor() individually.
+ NoColor = noColorExists() || os.Getenv("TERM") == "dumb" ||
+ (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
+
+ // Output defines the standard output of the print functions. By default
+ // os.Stdout is used.
+ Output = colorable.NewColorableStdout()
+
+ // Error defines a color supporting writer for os.Stderr.
+ Error = colorable.NewColorableStderr()
+
+ // colorsCache is used to reduce the count of created Color objects and
+ // allows to reuse already created objects with required Attribute.
+ colorsCache = make(map[Attribute]*Color)
+ colorsCacheMu sync.Mutex // protects colorsCache
+)
+
+// noColorExists returns true if the environment variable NO_COLOR exists.
+func noColorExists() bool {
+ _, exists := os.LookupEnv("NO_COLOR")
+ return exists
+}
+
+// Color defines a custom color object which is defined by SGR parameters.
+type Color struct {
+ params []Attribute
+ noColor *bool
+}
+
+// Attribute defines a single SGR Code
+type Attribute int
+
+const escape = "\x1b"
+
+// Base attributes
+const (
+ Reset Attribute = iota
+ Bold
+ Faint
+ Italic
+ Underline
+ BlinkSlow
+ BlinkRapid
+ ReverseVideo
+ Concealed
+ CrossedOut
+)
+
+// Foreground text colors
+const (
+ FgBlack Attribute = iota + 30
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta
+ FgCyan
+ FgWhite
+)
+
+// Foreground Hi-Intensity text colors
+const (
+ FgHiBlack Attribute = iota + 90
+ FgHiRed
+ FgHiGreen
+ FgHiYellow
+ FgHiBlue
+ FgHiMagenta
+ FgHiCyan
+ FgHiWhite
+)
+
+// Background text colors
+const (
+ BgBlack Attribute = iota + 40
+ BgRed
+ BgGreen
+ BgYellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+)
+
+// Background Hi-Intensity text colors
+const (
+ BgHiBlack Attribute = iota + 100
+ BgHiRed
+ BgHiGreen
+ BgHiYellow
+ BgHiBlue
+ BgHiMagenta
+ BgHiCyan
+ BgHiWhite
+)
+
+// New returns a newly created color object.
+func New(value ...Attribute) *Color {
+ c := &Color{
+ params: make([]Attribute, 0),
+ }
+
+ if noColorExists() {
+ c.noColor = boolPtr(true)
+ }
+
+ c.Add(value...)
+ return c
+}
+
+// Set sets the given parameters immediately. It will change the color of
+// output with the given SGR parameters until color.Unset() is called.
+func Set(p ...Attribute) *Color {
+ c := New(p...)
+ c.Set()
+ return c
+}
+
+// Unset resets all escape attributes and clears the output. Usually should
+// be called after Set().
+func Unset() {
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(Output, "%s[%dm", escape, Reset)
+}
+
+// Set sets the SGR sequence.
+func (c *Color) Set() *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(Output, c.format())
+ return c
+}
+
+func (c *Color) unset() {
+ if c.isNoColorSet() {
+ return
+ }
+
+ Unset()
+}
+
+func (c *Color) setWriter(w io.Writer) *Color {
+ if c.isNoColorSet() {
+ return c
+ }
+
+ fmt.Fprintf(w, c.format())
+ return c
+}
+
+func (c *Color) unsetWriter(w io.Writer) {
+ if c.isNoColorSet() {
+ return
+ }
+
+ if NoColor {
+ return
+ }
+
+ fmt.Fprintf(w, "%s[%dm", escape, Reset)
+}
+
+// Add is used to chain SGR parameters. Use as many as parameters to combine
+// and create custom color objects. Example: Add(color.FgRed, color.Underline).
+func (c *Color) Add(value ...Attribute) *Color {
+ c.params = append(c.params, value...)
+ return c
+}
+
+func (c *Color) prepend(value Attribute) {
+ c.params = append(c.params, 0)
+ copy(c.params[1:], c.params[0:])
+ c.params[0] = value
+}
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprint(w, a...)
+}
+
+// Print formats using the default formats for its operands and writes to
+// standard output. Spaces are added between operands when neither is a
+// string. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Print(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprint(Output, a...)
+}
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprintf(w, format, a...)
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+// This is the standard fmt.Printf() method wrapped with the given color.
+func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintf(Output, format, a...)
+}
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+ c.setWriter(w)
+ defer c.unsetWriter(w)
+
+ return fmt.Fprintln(w, a...)
+}
+
+// Println formats using the default formats for its operands and writes to
+// standard output. Spaces are always added between operands and a newline is
+// appended. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Println(a ...interface{}) (n int, err error) {
+ c.Set()
+ defer c.unset()
+
+ return fmt.Fprintln(Output, a...)
+}
+
+// Sprint is just like Print, but returns a string instead of printing it.
+func (c *Color) Sprint(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+}
+
+// Sprintln is just like Println, but returns a string instead of printing it.
+func (c *Color) Sprintln(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+}
+
+// Sprintf is just like Printf, but returns a string instead of printing it.
+func (c *Color) Sprintf(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+}
+
+// FprintFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprint().
+func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
+ return func(w io.Writer, a ...interface{}) {
+ c.Fprint(w, a...)
+ }
+}
+
+// PrintFunc returns a new function that prints the passed arguments as
+// colorized with color.Print().
+func (c *Color) PrintFunc() func(a ...interface{}) {
+ return func(a ...interface{}) {
+ c.Print(a...)
+ }
+}
+
+// FprintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintf().
+func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
+ return func(w io.Writer, format string, a ...interface{}) {
+ c.Fprintf(w, format, a...)
+ }
+}
+
+// PrintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Printf().
+func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
+ return func(format string, a ...interface{}) {
+ c.Printf(format, a...)
+ }
+}
+
+// FprintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintln().
+func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
+ return func(w io.Writer, a ...interface{}) {
+ c.Fprintln(w, a...)
+ }
+}
+
+// PrintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Println().
+func (c *Color) PrintlnFunc() func(a ...interface{}) {
+ return func(a ...interface{}) {
+ c.Println(a...)
+ }
+}
+
+// SprintFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprint(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output, example:
+//
+// put := New(FgYellow).SprintFunc()
+// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
+func (c *Color) SprintFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprint(a...))
+ }
+}
+
+// SprintfFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintf(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
+ return func(format string, a ...interface{}) string {
+ return c.wrap(fmt.Sprintf(format, a...))
+ }
+}
+
+// SprintlnFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintln(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintlnFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return c.wrap(fmt.Sprintln(a...))
+ }
+}
+
+// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m"
+// an example output might be: "1;36" -> bold cyan
+func (c *Color) sequence() string {
+ format := make([]string, len(c.params))
+ for i, v := range c.params {
+ format[i] = strconv.Itoa(int(v))
+ }
+
+ return strings.Join(format, ";")
+}
+
+// wrap wraps the s string with the colors attributes. The string is ready to
+// be printed.
+func (c *Color) wrap(s string) string {
+ if c.isNoColorSet() {
+ return s
+ }
+
+ return c.format() + s + c.unformat()
+}
+
+func (c *Color) format() string {
+ return fmt.Sprintf("%s[%sm", escape, c.sequence())
+}
+
+func (c *Color) unformat() string {
+ return fmt.Sprintf("%s[%dm", escape, Reset)
+}
+
+// DisableColor disables the color output. Useful to not change any existing
+// code and still being able to output. Can be used for flags like
+// "--no-color". To enable back use EnableColor() method.
+func (c *Color) DisableColor() {
+ c.noColor = boolPtr(true)
+}
+
+// EnableColor enables the color output. Use it in conjunction with
+// DisableColor(). Otherwise this method has no side effects.
+func (c *Color) EnableColor() {
+ c.noColor = boolPtr(false)
+}
+
+func (c *Color) isNoColorSet() bool {
+ // check first if we have user set action
+ if c.noColor != nil {
+ return *c.noColor
+ }
+
+ // if not return the global option, which is disabled by default
+ return NoColor
+}
+
+// Equals returns a boolean value indicating whether two colors are equal.
+func (c *Color) Equals(c2 *Color) bool {
+ if len(c.params) != len(c2.params) {
+ return false
+ }
+
+ for _, attr := range c.params {
+ if !c2.attrExists(attr) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (c *Color) attrExists(a Attribute) bool {
+ for _, attr := range c.params {
+ if attr == a {
+ return true
+ }
+ }
+
+ return false
+}
+
+func boolPtr(v bool) *bool {
+ return &v
+}
+
+func getCachedColor(p Attribute) *Color {
+ colorsCacheMu.Lock()
+ defer colorsCacheMu.Unlock()
+
+ c, ok := colorsCache[p]
+ if !ok {
+ c = New(p)
+ colorsCache[p] = c
+ }
+
+ return c
+}
+
+func colorPrint(format string, p Attribute, a ...interface{}) {
+ c := getCachedColor(p)
+
+ if !strings.HasSuffix(format, "\n") {
+ format += "\n"
+ }
+
+ if len(a) == 0 {
+ c.Print(format)
+ } else {
+ c.Printf(format, a...)
+ }
+}
+
+func colorString(format string, p Attribute, a ...interface{}) string {
+ c := getCachedColor(p)
+
+ if len(a) == 0 {
+ return c.SprintFunc()(format)
+ }
+
+ return c.SprintfFunc()(format, a...)
+}
+
+// Black is a convenient helper function to print with black foreground. A
+// newline is appended to format by default.
+func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
+
+// Red is a convenient helper function to print with red foreground. A
+// newline is appended to format by default.
+func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
+
+// Green is a convenient helper function to print with green foreground. A
+// newline is appended to format by default.
+func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
+
+// Yellow is a convenient helper function to print with yellow foreground.
+// A newline is appended to format by default.
+func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
+
+// Blue is a convenient helper function to print with blue foreground. A
+// newline is appended to format by default.
+func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
+
+// Magenta is a convenient helper function to print with magenta foreground.
+// A newline is appended to format by default.
+func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
+
+// Cyan is a convenient helper function to print with cyan foreground. A
+// newline is appended to format by default.
+func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
+
+// White is a convenient helper function to print with white foreground. A
+// newline is appended to format by default.
+func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
+
+// BlackString is a convenient helper function to return a string with black
+// foreground.
+func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
+
+// RedString is a convenient helper function to return a string with red
+// foreground.
+func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
+
+// GreenString is a convenient helper function to return a string with green
+// foreground.
+func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
+
+// YellowString is a convenient helper function to return a string with yellow
+// foreground.
+func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
+
+// BlueString is a convenient helper function to return a string with blue
+// foreground.
+func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
+
+// MagentaString is a convenient helper function to return a string with magenta
+// foreground.
+func MagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgMagenta, a...)
+}
+
+// CyanString is a convenient helper function to return a string with cyan
+// foreground.
+func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
+
+// WhiteString is a convenient helper function to return a string with white
+// foreground.
+func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
+
+// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
+// newline is appended to format by default.
+func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
+
+// HiRed is a convenient helper function to print with hi-intensity red foreground. A
+// newline is appended to format by default.
+func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
+
+// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
+// newline is appended to format by default.
+func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
+
+// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
+// A newline is appended to format by default.
+func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
+
+// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
+// newline is appended to format by default.
+func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
+
+// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
+// A newline is appended to format by default.
+func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
+
+// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
+// newline is appended to format by default.
+func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
+
+// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
+// newline is appended to format by default.
+func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
+
+// HiBlackString is a convenient helper function to return a string with hi-intensity black
+// foreground.
+func HiBlackString(format string, a ...interface{}) string {
+ return colorString(format, FgHiBlack, a...)
+}
+
+// HiRedString is a convenient helper function to return a string with hi-intensity red
+// foreground.
+func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
+
+// HiGreenString is a convenient helper function to return a string with hi-intensity green
+// foreground.
+func HiGreenString(format string, a ...interface{}) string {
+ return colorString(format, FgHiGreen, a...)
+}
+
+// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
+// foreground.
+func HiYellowString(format string, a ...interface{}) string {
+ return colorString(format, FgHiYellow, a...)
+}
+
+// HiBlueString is a convenient helper function to return a string with hi-intensity blue
+// foreground.
+func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
+
+// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
+// foreground.
+func HiMagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgHiMagenta, a...)
+}
+
+// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
+// foreground.
+func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
+
+// HiWhiteString is a convenient helper function to return a string with hi-intensity white
+// foreground.
+func HiWhiteString(format string, a ...interface{}) string {
+ return colorString(format, FgHiWhite, a...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/doc.go
new file mode 100644
index 000000000000..04541de786f3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/color/doc.go
@@ -0,0 +1,135 @@
+/*
+Package color is an ANSI color package to output colorized or SGR defined
+output to the standard output. The API can be used in several way, pick one
+that suits you.
+
+Use simple and default helper functions with predefined foreground colors:
+
+ color.Cyan("Prints text in cyan.")
+
+ // a newline will be appended automatically
+ color.Blue("Prints %s in blue.", "text")
+
+ // More default foreground colors..
+ color.Red("We have red")
+ color.Yellow("Yellow color too!")
+ color.Magenta("And many others ..")
+
+ // Hi-intensity colors
+ color.HiGreen("Bright green color.")
+ color.HiBlack("Bright black means gray..")
+ color.HiWhite("Shiny white color!")
+
+However there are times where custom color mixes are required. Below are some
+examples to create custom color objects and use the print functions of each
+separate color object.
+
+ // Create a new color object
+ c := color.New(color.FgCyan).Add(color.Underline)
+ c.Println("Prints cyan text with an underline.")
+
+ // Or just add them to New()
+ d := color.New(color.FgCyan, color.Bold)
+ d.Printf("This prints bold cyan %s\n", "too!.")
+
+
+ // Mix up foreground and background colors, create new mixes!
+ red := color.New(color.FgRed)
+
+ boldRed := red.Add(color.Bold)
+ boldRed.Println("This will print text in bold red.")
+
+ whiteBackground := red.Add(color.BgWhite)
+ whiteBackground.Println("Red text with White background.")
+
+ // Use your own io.Writer output
+ color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
+
+ blue := color.New(color.FgBlue)
+ blue.Fprint(myWriter, "This will print text in blue.")
+
+You can create PrintXxx functions to simplify even more:
+
+ // Create a custom print function for convenient
+ red := color.New(color.FgRed).PrintfFunc()
+ red("warning")
+ red("error: %s", err)
+
+ // Mix up multiple attributes
+ notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+ notice("don't forget this...")
+
+You can also FprintXxx functions to pass your own io.Writer:
+
+ blue := color.New(FgBlue).FprintfFunc()
+ blue(myWriter, "important notice: %s", stars)
+
+ // Mix up with multiple attributes
+ success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
+ success(myWriter, don't forget this...")
+
+
+Or create SprintXxx functions to mix strings with other non-colorized strings:
+
+ yellow := New(FgYellow).SprintFunc()
+ red := New(FgRed).SprintFunc()
+
+ fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Printf("this %s rocks!\n", info("package"))
+
+Windows support is enabled by default. All Print functions work as intended.
+However only for color.SprintXXX functions, user should use fmt.FprintXXX and
+set the output to color.Output:
+
+ fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+
+ info := New(FgWhite, BgGreen).SprintFunc()
+ fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
+
+Using with existing code is possible. Just use the Set() method to set the
+standard output to the given parameters. That way a rewrite of an existing
+code is not required.
+
+ // Use handy standard colors.
+ color.Set(color.FgYellow)
+
+ fmt.Println("Existing text will be now in Yellow")
+ fmt.Printf("This one %s\n", "too")
+
+ color.Unset() // don't forget to unset
+
+ // You can mix up parameters
+ color.Set(color.FgMagenta, color.Bold)
+ defer color.Unset() // use it in your function
+
+ fmt.Println("All text will be now bold magenta.")
+
+There might be a case where you want to disable color output (for example to
+pipe the standard output of your app to somewhere else). `Color` has support to
+disable colors both globally and for single color definition. For example
+suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
+the color output with:
+
+ var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+ if *flagNoColor {
+ color.NoColor = true // disables colorized output
+ }
+
+You can also disable the color by setting the NO_COLOR environment variable to any value.
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+ c := color.New(color.FgCyan)
+ c.Println("Prints cyan text")
+
+ c.DisableColor()
+ c.Println("This is printed without any color")
+
+ c.EnableColor()
+ c.Println("This prints again cyan...")
+*/
+package color
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/.gitignore
new file mode 100644
index 000000000000..836562412fe8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/.gitignore
@@ -0,0 +1,23 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/.travis.yml
new file mode 100644
index 000000000000..a08df798127a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/.travis.yml
@@ -0,0 +1,13 @@
+language: go
+go:
+ - 1.7.x
+ - 1.8.x
+ - 1.9.x
+ - tip
+sudo: false
+before_install:
+- go get github.com/axw/gocov/gocov
+- go get github.com/mattn/goveralls
+- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
+script:
+- $HOME/gopath/bin/goveralls -service=travis-ci
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/LICENSE
new file mode 100644
index 000000000000..34504e4b3efb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Fatih Arslan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/README.md
new file mode 100644
index 000000000000..a75eabf37bbc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/README.md
@@ -0,0 +1,163 @@
+# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs)
+
+Structs contains various utilities to work with Go (Golang) structs. It was
+initially used by me to convert a struct into a `map[string]interface{}`. With
+time I've added other utilities for structs. It's basically a high level
+package based on primitives from the reflect package. Feel free to add new
+functions or improve the existing code.
+
+## Install
+
+```bash
+go get github.com/fatih/structs
+```
+
+## Usage and Examples
+
+Just like the standard lib `strings`, `bytes` and co packages, `structs` has
+many global functions to manipulate or organize your struct data. Lets define
+and declare a struct:
+
+```go
+type Server struct {
+ Name string `json:"name,omitempty"`
+ ID int
+ Enabled bool
+ users []string // not exported
+ http.Server // embedded
+}
+
+server := &Server{
+ Name: "gopher",
+ ID: 123456,
+ Enabled: true,
+}
+```
+
+```go
+// Convert a struct to a map[string]interface{}
+// => {"Name":"gopher", "ID":123456, "Enabled":true}
+m := structs.Map(server)
+
+// Convert the values of a struct to a []interface{}
+// => ["gopher", 123456, true]
+v := structs.Values(server)
+
+// Convert the names of a struct to a []string
+// (see "Names methods" for more info about fields)
+n := structs.Names(server)
+
+// Convert the values of a struct to a []*Field
+// (see "Field methods" for more info about fields)
+f := structs.Fields(server)
+
+// Return the struct name => "Server"
+n := structs.Name(server)
+
+// Check if any field of a struct is initialized or not.
+h := structs.HasZero(server)
+
+// Check if all fields of a struct is initialized or not.
+z := structs.IsZero(server)
+
+// Check if server is a struct or a pointer to struct
+i := structs.IsStruct(server)
+```
+
+### Struct methods
+
+The structs functions can be also used as independent methods by creating a new
+`*structs.Struct`. This is handy if you want to have more control over the
+structs (such as retrieving a single Field).
+
+```go
+// Create a new struct type:
+s := structs.New(server)
+
+m := s.Map() // Get a map[string]interface{}
+v := s.Values() // Get a []interface{}
+f := s.Fields() // Get a []*Field
+n := s.Names() // Get a []string
+f := s.Field(name) // Get a *Field based on the given field name
+f, ok := s.FieldOk(name) // Get a *Field based on the given field name
+n := s.Name() // Get the struct name
+h := s.HasZero() // Check if any field is uninitialized
+z := s.IsZero() // Check if all fields are uninitialized
+```
+
+### Field methods
+
+We can easily examine a single Field for more detail. Below you can see how we
+get and interact with various field methods:
+
+
+```go
+s := structs.New(server)
+
+// Get the Field struct for the "Name" field
+name := s.Field("Name")
+
+// Get the underlying value, value => "gopher"
+value := name.Value().(string)
+
+// Set the field's value
+name.Set("another gopher")
+
+// Get the field's kind, kind => "string"
+name.Kind()
+
+// Check if the field is exported or not
+if name.IsExported() {
+ fmt.Println("Name field is exported")
+}
+
+// Check if the value is a zero value, such as "" for string, 0 for int
+if !name.IsZero() {
+ fmt.Println("Name is initialized")
+}
+
+// Check if the field is an anonymous (embedded) field
+if !name.IsEmbedded() {
+ fmt.Println("Name is not an embedded field")
+}
+
+// Get the Field's tag value for tag name "json", tag value => "name,omitempty"
+tagValue := name.Tag("json")
+```
+
+Nested structs are supported too:
+
+```go
+addrField := s.Field("Server").Field("Addr")
+
+// Get the value for addr
+a := addrField.Value().(string)
+
+// Or get all fields
+httpServer := s.Field("Server").Fields()
+```
+
+We can also get a slice of Fields from the Struct type to iterate over all
+fields. This is handy if you wish to examine all fields:
+
+```go
+s := structs.New(server)
+
+for _, f := range s.Fields() {
+ fmt.Printf("field name: %+v\n", f.Name())
+
+ if f.IsExported() {
+ fmt.Printf("value : %+v\n", f.Value())
+ fmt.Printf("is zero : %+v\n", f.IsZero())
+ }
+}
+```
+
+## Credits
+
+ * [Fatih Arslan](https://github.com/fatih)
+ * [Cihangir Savas](https://github.com/cihangir)
+
+## License
+
+The MIT License (MIT) - see LICENSE.md for more details
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/field.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/field.go
new file mode 100644
index 000000000000..e69783230b4e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/field.go
@@ -0,0 +1,141 @@
+package structs
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+)
+
+var (
+ errNotExported = errors.New("field is not exported")
+ errNotSettable = errors.New("field is not settable")
+)
+
+// Field represents a single struct field that encapsulates high level
+// functions around the field.
+type Field struct {
+ value reflect.Value
+ field reflect.StructField
+ defaultTag string
+}
+
+// Tag returns the value associated with key in the tag string. If there is no
+// such key in the tag, Tag returns the empty string.
+func (f *Field) Tag(key string) string {
+ return f.field.Tag.Get(key)
+}
+
+// Value returns the underlying value of the field. It panics if the field
+// is not exported.
+func (f *Field) Value() interface{} {
+ return f.value.Interface()
+}
+
+// IsEmbedded returns true if the given field is an anonymous field (embedded)
+func (f *Field) IsEmbedded() bool {
+ return f.field.Anonymous
+}
+
+// IsExported returns true if the given field is exported.
+func (f *Field) IsExported() bool {
+ return f.field.PkgPath == ""
+}
+
+// IsZero returns true if the given field is not initialized (has a zero value).
+// It panics if the field is not exported.
+func (f *Field) IsZero() bool {
+ zero := reflect.Zero(f.value.Type()).Interface()
+ current := f.Value()
+
+ return reflect.DeepEqual(current, zero)
+}
+
+// Name returns the name of the given field
+func (f *Field) Name() string {
+ return f.field.Name
+}
+
+// Kind returns the fields kind, such as "string", "map", "bool", etc ..
+func (f *Field) Kind() reflect.Kind {
+ return f.value.Kind()
+}
+
+// Set sets the field to given value v. It returns an error if the field is not
+// settable (not addressable or not exported) or if the given value's type
+// doesn't match the fields type.
+func (f *Field) Set(val interface{}) error {
+ // we can't set unexported fields, so be sure this field is exported
+ if !f.IsExported() {
+ return errNotExported
+ }
+
+ // do we get here? not sure...
+ if !f.value.CanSet() {
+ return errNotSettable
+ }
+
+ given := reflect.ValueOf(val)
+
+ if f.value.Kind() != given.Kind() {
+ return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
+ }
+
+ f.value.Set(given)
+ return nil
+}
+
+// Zero sets the field to its zero value. It returns an error if the field is not
+// settable (not addressable or not exported).
+func (f *Field) Zero() error {
+ zero := reflect.Zero(f.value.Type()).Interface()
+ return f.Set(zero)
+}
+
+// Fields returns a slice of Fields. This is particular handy to get the fields
+// of a nested struct . A struct tag with the content of "-" ignores the
+// checking of that particular field. Example:
+//
+// // Field is ignored by this package.
+// Field *http.Request `structs:"-"`
+//
+// It panics if field is not exported or if field's kind is not struct
+func (f *Field) Fields() []*Field {
+ return getFields(f.value, f.defaultTag)
+}
+
+// Field returns the field from a nested struct. It panics if the nested struct
+// is not exported or if the field was not found.
+func (f *Field) Field(name string) *Field {
+ field, ok := f.FieldOk(name)
+ if !ok {
+ panic("field not found")
+ }
+
+ return field
+}
+
+// FieldOk returns the field from a nested struct. The boolean returns whether
+// the field was found (true) or not (false).
+func (f *Field) FieldOk(name string) (*Field, bool) {
+ value := &f.value
+ // value must be settable so we need to make sure it holds the address of the
+ // variable and not a copy, so we can pass the pointer to strctVal instead of a
+ // copy (which is not assigned to any variable, hence not settable).
+ // see "https://blog.golang.org/laws-of-reflection#TOC_8."
+ if f.value.Kind() != reflect.Ptr {
+ a := f.value.Addr()
+ value = &a
+ }
+ v := strctVal(value.Interface())
+ t := v.Type()
+
+ field, ok := t.FieldByName(name)
+ if !ok {
+ return nil, false
+ }
+
+ return &Field{
+ field: field,
+ value: v.FieldByName(name),
+ }, true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/structs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/structs.go
new file mode 100644
index 000000000000..3a87706525f7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/structs.go
@@ -0,0 +1,584 @@
+// Package structs contains various utilities functions to work with structs.
+package structs
+
+import (
+ "fmt"
+
+ "reflect"
+)
+
+var (
+ // DefaultTagName is the default tag name for struct fields which provides
+ // a more granular to tweak certain structs. Lookup the necessary functions
+ // for more info.
+ DefaultTagName = "structs" // struct's field default tag name
+)
+
+// Struct encapsulates a struct type to provide several high level functions
+// around the struct.
+type Struct struct {
+ raw interface{}
+ value reflect.Value
+ TagName string
+}
+
+// New returns a new *Struct with the struct s. It panics if the s's kind is
+// not struct.
+func New(s interface{}) *Struct {
+ return &Struct{
+ raw: s,
+ value: strctVal(s),
+ TagName: DefaultTagName,
+ }
+}
+
+// Map converts the given struct to a map[string]interface{}, where the keys
+// of the map are the field names and the values of the map the associated
+// values of the fields. The default key string is the struct field name but
+// can be changed in the struct field's tag value. The "structs" key in the
+// struct's field tag value is the key name. Example:
+//
+// // Field appears in map as key "myName".
+// Name string `structs:"myName"`
+//
+// A tag value with the content of "-" ignores that particular field. Example:
+//
+// // Field is ignored by this package.
+// Field bool `structs:"-"`
+//
+// A tag value with the content of "string" uses the stringer to get the value. Example:
+//
+// // The value will be output of Animal's String() func.
+// // Map will panic if Animal does not implement String().
+// Field *Animal `structs:"field,string"`
+//
+// A tag value with the option of "flatten" used in a struct field is to flatten its fields
+// in the output map. Example:
+//
+// // The FieldStruct's fields will be flattened into the output map.
+// FieldStruct time.Time `structs:",flatten"`
+//
+// A tag value with the option of "omitnested" stops iterating further if the type
+// is a struct. Example:
+//
+// // Field is not processed further by this package.
+// Field time.Time `structs:"myName,omitnested"`
+// Field *http.Request `structs:",omitnested"`
+//
+// A tag value with the option of "omitempty" ignores that particular field if
+// the field value is empty. Example:
+//
+// // Field appears in map as key "myName", but the field is
+// // skipped if empty.
+// Field string `structs:"myName,omitempty"`
+//
+// // Field appears in map as key "Field" (the default), but
+// // the field is skipped if empty.
+// Field string `structs:",omitempty"`
+//
+// Note that only exported fields of a struct can be accessed, non exported
+// fields will be neglected.
+func (s *Struct) Map() map[string]interface{} {
+ out := make(map[string]interface{})
+ s.FillMap(out)
+ return out
+}
+
+// FillMap is the same as Map. Instead of returning the output, it fills the
+// given map.
+func (s *Struct) FillMap(out map[string]interface{}) {
+ if out == nil {
+ return
+ }
+
+ fields := s.structFields()
+
+ for _, field := range fields {
+ name := field.Name
+ val := s.value.FieldByName(name)
+ isSubStruct := false
+ var finalVal interface{}
+
+ tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
+ if tagName != "" {
+ name = tagName
+ }
+
+ // if the value is a zero value and the field is marked as omitempty do
+ // not include
+ if tagOpts.Has("omitempty") {
+ zero := reflect.Zero(val.Type()).Interface()
+ current := val.Interface()
+
+ if reflect.DeepEqual(current, zero) {
+ continue
+ }
+ }
+
+ if !tagOpts.Has("omitnested") {
+ finalVal = s.nested(val)
+
+ v := reflect.ValueOf(val.Interface())
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ switch v.Kind() {
+ case reflect.Map, reflect.Struct:
+ isSubStruct = true
+ }
+ } else {
+ finalVal = val.Interface()
+ }
+
+ if tagOpts.Has("string") {
+ s, ok := val.Interface().(fmt.Stringer)
+ if ok {
+ out[name] = s.String()
+ }
+ continue
+ }
+
+ if isSubStruct && (tagOpts.Has("flatten")) {
+ for k := range finalVal.(map[string]interface{}) {
+ out[k] = finalVal.(map[string]interface{})[k]
+ }
+ } else {
+ out[name] = finalVal
+ }
+ }
+}
+
+// Values converts the given s struct's field values to a []interface{}. A
+// struct tag with the content of "-" ignores the that particular field.
+// Example:
+//
+// // Field is ignored by this package.
+// Field int `structs:"-"`
+//
+// A value with the option of "omitnested" stops iterating further if the type
+// is a struct. Example:
+//
+// // Fields is not processed further by this package.
+// Field time.Time `structs:",omitnested"`
+// Field *http.Request `structs:",omitnested"`
+//
+// A tag value with the option of "omitempty" ignores that particular field and
+// is not added to the values if the field value is empty. Example:
+//
+// // Field is skipped if empty
+// Field string `structs:",omitempty"`
+//
+// Note that only exported fields of a struct can be accessed, non exported
+// fields will be neglected.
+func (s *Struct) Values() []interface{} {
+ fields := s.structFields()
+
+ var t []interface{}
+
+ for _, field := range fields {
+ val := s.value.FieldByName(field.Name)
+
+ _, tagOpts := parseTag(field.Tag.Get(s.TagName))
+
+ // if the value is a zero value and the field is marked as omitempty do
+ // not include
+ if tagOpts.Has("omitempty") {
+ zero := reflect.Zero(val.Type()).Interface()
+ current := val.Interface()
+
+ if reflect.DeepEqual(current, zero) {
+ continue
+ }
+ }
+
+ if tagOpts.Has("string") {
+ s, ok := val.Interface().(fmt.Stringer)
+ if ok {
+ t = append(t, s.String())
+ }
+ continue
+ }
+
+ if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
+ // look out for embedded structs, and convert them to a
+ // []interface{} to be added to the final values slice
+ t = append(t, Values(val.Interface())...)
+ } else {
+ t = append(t, val.Interface())
+ }
+ }
+
+ return t
+}
+
+// Fields returns a slice of Fields. A struct tag with the content of "-"
+// ignores the checking of that particular field. Example:
+//
+// // Field is ignored by this package.
+// Field bool `structs:"-"`
+//
+// It panics if s's kind is not struct.
+func (s *Struct) Fields() []*Field {
+ return getFields(s.value, s.TagName)
+}
+
+// Names returns a slice of field names. A struct tag with the content of "-"
+// ignores the checking of that particular field. Example:
+//
+// // Field is ignored by this package.
+// Field bool `structs:"-"`
+//
+// It panics if s's kind is not struct.
+func (s *Struct) Names() []string {
+ fields := getFields(s.value, s.TagName)
+
+ names := make([]string, len(fields))
+
+ for i, field := range fields {
+ names[i] = field.Name()
+ }
+
+ return names
+}
+
+func getFields(v reflect.Value, tagName string) []*Field {
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ t := v.Type()
+
+ var fields []*Field
+
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+
+ if tag := field.Tag.Get(tagName); tag == "-" {
+ continue
+ }
+
+ f := &Field{
+ field: field,
+ value: v.FieldByName(field.Name),
+ }
+
+ fields = append(fields, f)
+
+ }
+
+ return fields
+}
+
+// Field returns a new Field struct that provides several high level functions
+// around a single struct field entity. It panics if the field is not found.
+func (s *Struct) Field(name string) *Field {
+ f, ok := s.FieldOk(name)
+ if !ok {
+ panic("field not found")
+ }
+
+ return f
+}
+
+// FieldOk returns a new Field struct that provides several high level functions
+// around a single struct field entity. The boolean returns true if the field
+// was found.
+func (s *Struct) FieldOk(name string) (*Field, bool) {
+ t := s.value.Type()
+
+ field, ok := t.FieldByName(name)
+ if !ok {
+ return nil, false
+ }
+
+ return &Field{
+ field: field,
+ value: s.value.FieldByName(name),
+ defaultTag: s.TagName,
+ }, true
+}
+
+// IsZero returns true if all fields in a struct is a zero value (not
+// initialized) A struct tag with the content of "-" ignores the checking of
+// that particular field. Example:
+//
+// // Field is ignored by this package.
+// Field bool `structs:"-"`
+//
+// A value with the option of "omitnested" stops iterating further if the type
+// is a struct. Example:
+//
+// // Field is not processed further by this package.
+// Field time.Time `structs:"myName,omitnested"`
+// Field *http.Request `structs:",omitnested"`
+//
+// Note that only exported fields of a struct can be accessed, non exported
+// fields will be neglected. It panics if s's kind is not struct.
+func (s *Struct) IsZero() bool {
+ fields := s.structFields()
+
+ for _, field := range fields {
+ val := s.value.FieldByName(field.Name)
+
+ _, tagOpts := parseTag(field.Tag.Get(s.TagName))
+
+ if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
+ ok := IsZero(val.Interface())
+ if !ok {
+ return false
+ }
+
+ continue
+ }
+
+ // zero value of the given field, such as "" for string, 0 for int
+ zero := reflect.Zero(val.Type()).Interface()
+
+ // current value of the given field
+ current := val.Interface()
+
+ if !reflect.DeepEqual(current, zero) {
+ return false
+ }
+ }
+
+ return true
+}
+
+// HasZero returns true if a field in a struct is not initialized (zero value).
+// A struct tag with the content of "-" ignores the checking of that particular
+// field. Example:
+//
+// // Field is ignored by this package.
+// Field bool `structs:"-"`
+//
+// A value with the option of "omitnested" stops iterating further if the type
+// is a struct. Example:
+//
+// // Field is not processed further by this package.
+// Field time.Time `structs:"myName,omitnested"`
+// Field *http.Request `structs:",omitnested"`
+//
+// Note that only exported fields of a struct can be accessed, non exported
+// fields will be neglected. It panics if s's kind is not struct.
+func (s *Struct) HasZero() bool {
+ fields := s.structFields()
+
+ for _, field := range fields {
+ val := s.value.FieldByName(field.Name)
+
+ _, tagOpts := parseTag(field.Tag.Get(s.TagName))
+
+ if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
+ ok := HasZero(val.Interface())
+ if ok {
+ return true
+ }
+
+ continue
+ }
+
+ // zero value of the given field, such as "" for string, 0 for int
+ zero := reflect.Zero(val.Type()).Interface()
+
+ // current value of the given field
+ current := val.Interface()
+
+ if reflect.DeepEqual(current, zero) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Name returns the structs's type name within its package. For more info refer
+// to Name() function.
+func (s *Struct) Name() string {
+ return s.value.Type().Name()
+}
+
+// structFields returns the exported struct fields for a given s struct. This
+// is a convenient helper method to avoid duplicate code in some of the
+// functions.
+func (s *Struct) structFields() []reflect.StructField {
+ t := s.value.Type()
+
+ var f []reflect.StructField
+
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ // we can't access the value of unexported fields
+ if field.PkgPath != "" {
+ continue
+ }
+
+ // don't check if it's omitted
+ if tag := field.Tag.Get(s.TagName); tag == "-" {
+ continue
+ }
+
+ f = append(f, field)
+ }
+
+ return f
+}
+
+func strctVal(s interface{}) reflect.Value {
+ v := reflect.ValueOf(s)
+
+ // if pointer get the underlying element≤
+ for v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ if v.Kind() != reflect.Struct {
+ panic("not struct")
+ }
+
+ return v
+}
+
+// Map converts the given struct to a map[string]interface{}. For more info
+// refer to Struct types Map() method. It panics if s's kind is not struct.
+func Map(s interface{}) map[string]interface{} {
+ return New(s).Map()
+}
+
+// FillMap is the same as Map. Instead of returning the output, it fills the
+// given map.
+func FillMap(s interface{}, out map[string]interface{}) {
+ New(s).FillMap(out)
+}
+
+// Values converts the given struct to a []interface{}. For more info refer to
+// Struct types Values() method. It panics if s's kind is not struct.
+func Values(s interface{}) []interface{} {
+ return New(s).Values()
+}
+
+// Fields returns a slice of *Field. For more info refer to Struct types
+// Fields() method. It panics if s's kind is not struct.
+func Fields(s interface{}) []*Field {
+ return New(s).Fields()
+}
+
+// Names returns a slice of field names. For more info refer to Struct types
+// Names() method. It panics if s's kind is not struct.
+func Names(s interface{}) []string {
+ return New(s).Names()
+}
+
+// IsZero returns true if all fields is equal to a zero value. For more info
+// refer to Struct types IsZero() method. It panics if s's kind is not struct.
+func IsZero(s interface{}) bool {
+ return New(s).IsZero()
+}
+
+// HasZero returns true if any field is equal to a zero value. For more info
+// refer to Struct types HasZero() method. It panics if s's kind is not struct.
+func HasZero(s interface{}) bool {
+ return New(s).HasZero()
+}
+
+// IsStruct returns true if the given variable is a struct or a pointer to
+// struct.
+func IsStruct(s interface{}) bool {
+ v := reflect.ValueOf(s)
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ // uninitialized zero value of a struct
+ if v.Kind() == reflect.Invalid {
+ return false
+ }
+
+ return v.Kind() == reflect.Struct
+}
+
+// Name returns the structs's type name within its package. It returns an
+// empty string for unnamed types. It panics if s's kind is not struct.
+func Name(s interface{}) string {
+ return New(s).Name()
+}
+
+// nested retrieves recursively all types for the given value and returns the
+// nested value.
+func (s *Struct) nested(val reflect.Value) interface{} {
+ var finalVal interface{}
+
+ v := reflect.ValueOf(val.Interface())
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+
+ switch v.Kind() {
+ case reflect.Struct:
+ n := New(val.Interface())
+ n.TagName = s.TagName
+ m := n.Map()
+
+ // do not add the converted value if there are no exported fields, ie:
+ // time.Time
+ if len(m) == 0 {
+ finalVal = val.Interface()
+ } else {
+ finalVal = m
+ }
+ case reflect.Map:
+ // get the element type of the map
+ mapElem := val.Type()
+ switch val.Type().Kind() {
+ case reflect.Ptr, reflect.Array, reflect.Map,
+ reflect.Slice, reflect.Chan:
+ mapElem = val.Type().Elem()
+ if mapElem.Kind() == reflect.Ptr {
+ mapElem = mapElem.Elem()
+ }
+ }
+
+ // only iterate over struct types, ie: map[string]StructType,
+ // map[string][]StructType,
+ if mapElem.Kind() == reflect.Struct ||
+ (mapElem.Kind() == reflect.Slice &&
+ mapElem.Elem().Kind() == reflect.Struct) {
+ m := make(map[string]interface{}, val.Len())
+ for _, k := range val.MapKeys() {
+ m[k.String()] = s.nested(val.MapIndex(k))
+ }
+ finalVal = m
+ break
+ }
+
+ // TODO(arslan): should this be optional?
+ finalVal = val.Interface()
+ case reflect.Slice, reflect.Array:
+ if val.Type().Kind() == reflect.Interface {
+ finalVal = val.Interface()
+ break
+ }
+
+ // TODO(arslan): should this be optional?
+ // do not iterate of non struct types, just pass the value. Ie: []int,
+ // []string, co... We only iterate further if it's a struct.
+ // i.e []foo or []*foo
+ if val.Type().Elem().Kind() != reflect.Struct &&
+ !(val.Type().Elem().Kind() == reflect.Ptr &&
+ val.Type().Elem().Elem().Kind() == reflect.Struct) {
+ finalVal = val.Interface()
+ break
+ }
+
+ slices := make([]interface{}, val.Len())
+ for x := 0; x < val.Len(); x++ {
+ slices[x] = s.nested(val.Index(x))
+ }
+ finalVal = slices
+ default:
+ finalVal = val.Interface()
+ }
+
+ return finalVal
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/tags.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/tags.go
new file mode 100644
index 000000000000..136a31eba9a9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fatih/structs/tags.go
@@ -0,0 +1,32 @@
+package structs
+
+import "strings"
+
+// tagOptions contains a slice of tag options
+type tagOptions []string
+
+// Has returns true if the given option is available in tagOptions
+func (t tagOptions) Has(opt string) bool {
+ for _, tagOpt := range t {
+ if tagOpt == opt {
+ return true
+ }
+ }
+
+ return false
+}
+
+// parseTag splits a struct field's tag into its name and a list of options
+// which comes after a name. A tag is in the form of: "name,option1,option2".
+// The name can be neglectected.
+func parseTag(tag string) (string, tagOptions) {
+ // tag is one of followings:
+ // ""
+ // "name"
+ // "name,opt"
+ // "name,opt,opt2"
+ // ",opt"
+
+ res := strings.Split(tag, ",")
+ return res[0], res[1:]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.gitattributes b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.gitattributes
new file mode 100644
index 000000000000..fcadb2cf9791
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.gitattributes
@@ -0,0 +1 @@
+* text eol=lf
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.gitignore
new file mode 100644
index 000000000000..1346be5512f8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.gitignore
@@ -0,0 +1,41 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+.idea
+.vscode
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+.project
+EBNF.txt
+test1.tpl
+pongo2_internal_test.go
+tpl-error.out
+/count.out
+/cover.out
+*.swp
+*.iml
+/cpu.out
+/mem.out
+/pongo2.test
+*.error
+/profile
+/coverage.out
+/pongo2_internal_test.ignore
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.travis.yml
new file mode 100644
index 000000000000..28eeff66c067
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/.travis.yml
@@ -0,0 +1,11 @@
+language: go
+arch:
+ - AMD64
+ - ppc64le
+os:
+ - linux
+ - osx
+go:
+ - 1.12
+script:
+ - go test -v
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/AUTHORS b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/AUTHORS
new file mode 100644
index 000000000000..601697cfa91a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/AUTHORS
@@ -0,0 +1,11 @@
+Main author and maintainer of pongo2:
+
+* Florian Schlachter
+
+Contributors (in no specific order):
+
+* @romanoaugusto88
+* @vitalbh
+* @blaubaer
+
+Feel free to add yourself to the list or to modify your entry if you did a contribution.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/LICENSE
new file mode 100644
index 000000000000..e876f869054c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2014 Florian Schlachter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/README.md
new file mode 100644
index 000000000000..d684034b85b7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/README.md
@@ -0,0 +1,170 @@
+# [pongo](https://en.wikipedia.org/wiki/Pongo_%28genus%29)2
+
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/flosch/pongo2)](https://pkg.go.dev/github.com/flosch/pongo2)
+[![Build Status](https://travis-ci.org/flosch/pongo2.svg?branch=master)](https://travis-ci.org/flosch/pongo2)
+
+pongo2 is a Django-syntax like templating-language ([official website](https://www.schlachter.tech/solutions/pongo2-template-engine/)).
+
+Install/update using `go get` (no dependencies required by pongo2):
+
+```sh
+go get -u github.com/flosch/pongo2/v4
+```
+
+Please use the [issue tracker](https://github.com/flosch/pongo2/issues) if you're encountering any problems with pongo2 or if you need help with implementing tags or filters ([create a ticket!](https://github.com/flosch/pongo2/issues/new)).
+
+## First impression of a template
+
+```django
+
+
+ Our admins and users
+
+ {# This is a short example to give you a quick overview of pongo2's syntax. #}
+ {% macro user_details(user, is_admin=false) %}
+
+
+
+ = 40) || (user.karma > calc_avg_karma(userlist)+5) %} class="karma-good"{%
+ endif %}>
+
+
+ {{ user }}
+
+
+
+
This user registered {{ user.register_date|naturaltime }}.
+
+
+
The user's biography:
+
+ {{ user.biography|markdown|truncatewords_html:15 }}
+ read more
+
+
+ {% if is_admin %}
+
This user is an admin!
+ {% endif %}
+
+ {% endmacro %}
+
+
+
+
+ Our admins
+ {% for admin in adminlist %} {{ user_details(admin, true) }} {% endfor %}
+
+ Our members
+ {% for user in userlist %} {{ user_details(user) }} {% endfor %}
+
+
+```
+
+## Features
+
+- Syntax- and feature-set-compatible with [Django 1.7](https://django.readthedocs.io/en/1.7.x/topics/templates.html)
+- [Advanced C-like expressions](https://github.com/flosch/pongo2/blob/master/template_tests/expressions.tpl).
+- [Complex function calls within expressions](https://github.com/flosch/pongo2/blob/master/template_tests/function_calls_wrapper.tpl).
+- [Easy API to create new filters and tags](http://godoc.org/github.com/flosch/pongo2#RegisterFilter) ([including parsing arguments](http://godoc.org/github.com/flosch/pongo2#Parser))
+- Additional features:
+ - Macros including importing macros from other files (see [template_tests/macro.tpl](https://github.com/flosch/pongo2/blob/master/template_tests/macro.tpl))
+ - [Template sandboxing](https://godoc.org/github.com/flosch/pongo2#TemplateSet) ([directory patterns](http://golang.org/pkg/path/filepath/#Match), banned tags/filters)
+
+## Caveats
+
+### Filters
+
+- **date** / **time**: The `date` and `time` filter are taking the Golang specific time- and date-format (not Django's one) currently. [Take a look on the format here](http://golang.org/pkg/time/#Time.Format).
+- **stringformat**: `stringformat` does **not** take Python's string format syntax as a parameter, instead it takes Go's. Essentially `{{ 3.14|stringformat:"pi is %.2f" }}` is `fmt.Sprintf("pi is %.2f", 3.14)`.
+- **escape** / **force_escape**: Unlike Django's behaviour, the `escape`-filter is applied immediately. Therefore there is no need for a `force_escape`-filter yet.
+
+### Tags
+
+- **for**: All the `forloop` fields (like `forloop.counter`) are written with a capital letter at the beginning. For example, the `counter` can be accessed by `forloop.Counter` and the parentloop by `forloop.Parentloop`.
+- **now**: takes Go's time format (see **date** and **time**-filter).
+
+### Misc
+
+- **not in-operator**: You can check whether a map/struct/string contains a key/field/substring by using the in-operator (or the negation of it):
+ `{% if key in map %}Key is in map{% else %}Key not in map{% endif %}` or `{% if !(key in map) %}Key is NOT in map{% else %}Key is in map{% endif %}`.
+
+## Add-ons, libraries and helpers
+
+### Official
+
+- [pongo2-addons](https://github.com/flosch/pongo2-addons) - Official additional filters/tags for pongo2 (for example a **markdown**-filter). They are in their own repository because they're relying on 3rd-party-libraries.
+
+### 3rd-party
+
+- [beego-pongo2](https://github.com/oal/beego-pongo2) - A tiny little helper for using Pongo2 with [Beego](https://github.com/astaxie/beego).
+- [beego-pongo2.v2](https://github.com/ipfans/beego-pongo2.v2) - Same as `beego-pongo2`, but for pongo2 v2.
+- [macaron-pongo2](https://github.com/macaron-contrib/pongo2) - pongo2 support for [Macaron](https://github.com/Unknwon/macaron), a modular web framework.
+- [ginpongo2](https://github.com/ngerakines/ginpongo2) - middleware for [gin](github.com/gin-gonic/gin) to use pongo2 templates
+- [Build'n support for Iris' template engine](https://github.com/kataras/iris)
+- [pongo2gin](https://gitlab.com/go-box/pongo2gin) - alternative renderer for [gin](github.com/gin-gonic/gin) to use pongo2 templates
+- [pongo2-trans](https://github.com/digitalcrab/pongo2trans) - `trans`-tag implementation for internationalization
+- [tpongo2](https://github.com/tango-contrib/tpongo2) - pongo2 support for [Tango](https://github.com/lunny/tango), a micro-kernel & pluggable web framework.
+- [p2cli](https://github.com/wrouesnel/p2cli) - command line templating utility based on pongo2
+- [Pongo2echo](https://github.com/stnc/pongo2echo) - pongo2 echo framework stability renderer [stnc]
+- [Pongo2gin](https://github.com/stnc/pongo2gin) - pongo2 gin minimal framework stability renderer [stnc]
+
+
+Please add your project to this list and send me a pull request when you've developed something nice for pongo2.
+
+## Who's using pongo2
+
+[I'm compiling a list of pongo2 users](https://github.com/flosch/pongo2/issues/241). Add your project or company!
+
+## API-usage examples
+
+Please see the documentation for a full list of provided API methods.
+
+### A tiny example (template string)
+
+```go
+// Compile the template first (i. e. creating the AST)
+tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
+if err != nil {
+ panic(err)
+}
+// Now you can render the template with the given
+// pongo2.Context how often you want to.
+out, err := tpl.Execute(pongo2.Context{"name": "florian"})
+if err != nil {
+ panic(err)
+}
+fmt.Println(out) // Output: Hello Florian!
+```
+
+## Example server-usage (template file)
+
+```go
+package main
+
+import (
+ "github.com/flosch/pongo2/v4"
+ "net/http"
+)
+
+// Pre-compiling the templates at application startup using the
+// little Must()-helper function (Must() will panic if FromFile()
+// or FromString() will return with an error - that's it).
+// It's faster to pre-compile it anywhere at startup and only
+// execute the template later.
+var tplExample = pongo2.Must(pongo2.FromFile("example.html"))
+
+func examplePage(w http.ResponseWriter, r *http.Request) {
+ // Execute the template per HTTP request
+ err := tplExample.ExecuteWriter(pongo2.Context{"query": r.FormValue("query")}, w)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+}
+
+func main() {
+ http.HandleFunc("/", examplePage)
+ http.ListenAndServe(":8080", nil)
+}
+```
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/context.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/context.go
new file mode 100644
index 000000000000..dbc5e3e375ae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/context.go
@@ -0,0 +1,137 @@
+package pongo2
+
+import (
+ "fmt"
+ "regexp"
+
+ "errors"
+)
+
+var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
+
+var autoescape = true
+
+func SetAutoescape(newValue bool) {
+ autoescape = newValue
+}
+
+// A Context type provides constants, variables, instances or functions to a template.
+//
+// pongo2 automatically provides meta-information or functions through the "pongo2"-key.
+// Currently, context["pongo2"] contains the following keys:
+// 1. version: returns the version string
+//
+// Template examples for accessing items from your context:
+// {{ myconstant }}
+// {{ myfunc("test", 42) }}
+// {{ user.name }}
+// {{ pongo2.version }}
+type Context map[string]interface{}
+
+func (c Context) checkForValidIdentifiers() *Error {
+ for k, v := range c {
+ if !reIdentifiers.MatchString(k) {
+ return &Error{
+ Sender: "checkForValidIdentifiers",
+ OrigError: fmt.Errorf("context-key '%s' (value: '%+v') is not a valid identifier", k, v),
+ }
+ }
+ }
+ return nil
+}
+
+// Update updates this context with the key/value-pairs from another context.
+func (c Context) Update(other Context) Context {
+ for k, v := range other {
+ c[k] = v
+ }
+ return c
+}
+
+// ExecutionContext contains all data important for the current rendering state.
+//
+// If you're writing a custom tag, your tag's Execute()-function will
+// have access to the ExecutionContext. This struct stores anything
+// about the current rendering process's Context including
+// the Context provided by the user (field Public).
+// You can safely use the Private context to provide data to the user's
+// template (like a 'forloop'-information). The Shared-context is used
+// to share data between tags. All ExecutionContexts share this context.
+//
+// Please be careful when accessing the Public data.
+// PLEASE DO NOT MODIFY THE PUBLIC CONTEXT (read-only).
+//
+// To create your own execution context within tags, use the
+// NewChildExecutionContext(parent) function.
+type ExecutionContext struct {
+ template *Template
+
+ Autoescape bool
+ Public Context
+ Private Context
+ Shared Context
+}
+
+var pongo2MetaContext = Context{
+ "version": Version,
+}
+
+func newExecutionContext(tpl *Template, ctx Context) *ExecutionContext {
+ privateCtx := make(Context)
+
+ // Make the pongo2-related funcs/vars available to the context
+ privateCtx["pongo2"] = pongo2MetaContext
+
+ return &ExecutionContext{
+ template: tpl,
+
+ Public: ctx,
+ Private: privateCtx,
+ Autoescape: autoescape,
+ }
+}
+
+func NewChildExecutionContext(parent *ExecutionContext) *ExecutionContext {
+ newctx := &ExecutionContext{
+ template: parent.template,
+
+ Public: parent.Public,
+ Private: make(Context),
+ Autoescape: parent.Autoescape,
+ }
+ newctx.Shared = parent.Shared
+
+ // Copy all existing private items
+ newctx.Private.Update(parent.Private)
+
+ return newctx
+}
+
+func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
+ return ctx.OrigError(errors.New(msg), token)
+}
+
+func (ctx *ExecutionContext) OrigError(err error, token *Token) *Error {
+ filename := ctx.template.name
+ var line, col int
+ if token != nil {
+ // No tokens available
+ // TODO: Add location (from where?)
+ filename = token.Filename
+ line = token.Line
+ col = token.Col
+ }
+ return &Error{
+ Template: ctx.template,
+ Filename: filename,
+ Line: line,
+ Column: col,
+ Token: token,
+ Sender: "execution",
+ OrigError: err,
+ }
+}
+
+func (ctx *ExecutionContext) Logf(format string, args ...interface{}) {
+ ctx.template.set.logf(format, args...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/doc.go
new file mode 100644
index 000000000000..0a161deec123
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/doc.go
@@ -0,0 +1,31 @@
+// Package pongo2 is a Django-syntax like template-engine
+//
+// Blog posts about pongo2 (including introduction and migration):
+// https://www.florian-schlachter.de/?tag=pongo2
+//
+// Complete documentation on the template language:
+// https://docs.djangoproject.com/en/dev/topics/templates/
+//
+// Try out pongo2 live in the pongo2 playground:
+// https://www.florian-schlachter.de/pongo2/
+//
+// Make sure to read README.md in the repository as well.
+//
+// A tiny example with template strings:
+//
+// (Snippet on playground: https://www.florian-schlachter.de/pongo2/?id=1206546277)
+//
+// // Compile the template first (i. e. creating the AST)
+// tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
+// if err != nil {
+// panic(err)
+// }
+// // Now you can render the template with the given
+// // pongo2.Context how often you want to.
+// out, err := tpl.Execute(pongo2.Context{"name": "fred"})
+// if err != nil {
+// panic(err)
+// }
+// fmt.Println(out) // Output: Hello Fred!
+//
+package pongo2
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/error.go
new file mode 100644
index 000000000000..8aec8c10034d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/error.go
@@ -0,0 +1,91 @@
+package pongo2
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+)
+
+// The Error type is being used to address an error during lexing, parsing or
+// execution. If you want to return an error object (for example in your own
+// tag or filter) fill this object with as much information as you have.
+// Make sure "Sender" is always given (if you're returning an error within
+// a filter, make Sender equals 'filter:yourfilter'; same goes for tags: 'tag:mytag').
+// It's okay if you only fill in ErrorMsg if you don't have any other details at hand.
+type Error struct {
+ Template *Template
+ Filename string
+ Line int
+ Column int
+ Token *Token
+ Sender string
+ OrigError error
+}
+
+func (e *Error) updateFromTokenIfNeeded(template *Template, t *Token) *Error {
+ if e.Template == nil {
+ e.Template = template
+ }
+
+ if e.Token == nil {
+ e.Token = t
+ if e.Line <= 0 {
+ e.Line = t.Line
+ e.Column = t.Col
+ }
+ }
+
+ return e
+}
+
+// Returns a nice formatted error string.
+func (e *Error) Error() string {
+ s := "[Error"
+ if e.Sender != "" {
+ s += " (where: " + e.Sender + ")"
+ }
+ if e.Filename != "" {
+ s += " in " + e.Filename
+ }
+ if e.Line > 0 {
+ s += fmt.Sprintf(" | Line %d Col %d", e.Line, e.Column)
+ if e.Token != nil {
+ s += fmt.Sprintf(" near '%s'", e.Token.Val)
+ }
+ }
+ s += "] "
+ s += e.OrigError.Error()
+ return s
+}
+
+// RawLine returns the affected line from the original template, if available.
+func (e *Error) RawLine() (line string, available bool, outErr error) {
+ if e.Line <= 0 || e.Filename == "" {
+ return "", false, nil
+ }
+
+ filename := e.Filename
+ if e.Template != nil {
+ filename = e.Template.set.resolveFilename(e.Template, e.Filename)
+ }
+ file, err := os.Open(filename)
+ if err != nil {
+ return "", false, err
+ }
+ defer func() {
+ err := file.Close()
+ if err != nil && outErr == nil {
+ outErr = err
+ }
+ }()
+
+ scanner := bufio.NewScanner(file)
+ l := 0
+ for scanner.Scan() {
+ l++
+ if l == e.Line {
+ return scanner.Text(), true, nil
+ }
+ }
+ return "", false, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/filters.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/filters.go
new file mode 100644
index 000000000000..8d4c89e22f76
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/filters.go
@@ -0,0 +1,141 @@
+package pongo2
+
+import (
+ "fmt"
+)
+
+// FilterFunction is the type filter functions must fulfil
+type FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
+
+var filters map[string]FilterFunction
+
+func init() {
+ filters = make(map[string]FilterFunction)
+}
+
+// FilterExists returns true if the given filter is already registered
+func FilterExists(name string) bool {
+ _, existing := filters[name]
+ return existing
+}
+
+// RegisterFilter registers a new filter. If there's already a filter with the same
+// name, RegisterFilter will panic. You usually want to call this
+// function in the filter's init() function:
+// http://golang.org/doc/effective_go.html#init
+//
+// See http://www.florian-schlachter.de/post/pongo2/ for more about
+// writing filters and tags.
+func RegisterFilter(name string, fn FilterFunction) error {
+ if FilterExists(name) {
+ return fmt.Errorf("filter with name '%s' is already registered", name)
+ }
+ filters[name] = fn
+ return nil
+}
+
+// ReplaceFilter replaces an already registered filter with a new implementation. Use this
+// function with caution since it allows you to change existing filter behaviour.
+func ReplaceFilter(name string, fn FilterFunction) error {
+ if !FilterExists(name) {
+ return fmt.Errorf("filter with name '%s' does not exist (therefore cannot be overridden)", name)
+ }
+ filters[name] = fn
+ return nil
+}
+
+// MustApplyFilter behaves like ApplyFilter, but panics on an error.
+func MustApplyFilter(name string, value *Value, param *Value) *Value {
+ val, err := ApplyFilter(name, value, param)
+ if err != nil {
+ panic(err)
+ }
+ return val
+}
+
+// ApplyFilter applies a filter to a given value using the given parameters.
+// Returns a *pongo2.Value or an error.
+func ApplyFilter(name string, value *Value, param *Value) (*Value, *Error) {
+ fn, existing := filters[name]
+ if !existing {
+ return nil, &Error{
+ Sender: "applyfilter",
+ OrigError: fmt.Errorf("Filter with name '%s' not found.", name),
+ }
+ }
+
+ // Make sure param is a *Value
+ if param == nil {
+ param = AsValue(nil)
+ }
+
+ return fn(value, param)
+}
+
+type filterCall struct {
+ token *Token
+
+ name string
+ parameter IEvaluator
+
+ filterFunc FilterFunction
+}
+
+func (fc *filterCall) Execute(v *Value, ctx *ExecutionContext) (*Value, *Error) {
+ var param *Value
+ var err *Error
+
+ if fc.parameter != nil {
+ param, err = fc.parameter.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ param = AsValue(nil)
+ }
+
+ filteredValue, err := fc.filterFunc(v, param)
+ if err != nil {
+ return nil, err.updateFromTokenIfNeeded(ctx.template, fc.token)
+ }
+ return filteredValue, nil
+}
+
+// Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
+func (p *Parser) parseFilter() (*filterCall, *Error) {
+ identToken := p.MatchType(TokenIdentifier)
+
+ // Check filter ident
+ if identToken == nil {
+ return nil, p.Error("Filter name must be an identifier.", nil)
+ }
+
+ filter := &filterCall{
+ token: identToken,
+ name: identToken.Val,
+ }
+
+ // Get the appropriate filter function and bind it
+ filterFn, exists := filters[identToken.Val]
+ if !exists {
+ return nil, p.Error(fmt.Sprintf("Filter '%s' does not exist.", identToken.Val), identToken)
+ }
+
+ filter.filterFunc = filterFn
+
+ // Check for filter-argument (2 tokens needed: ':' ARG)
+ if p.Match(TokenSymbol, ":") != nil {
+ if p.Peek(TokenSymbol, "}}") != nil {
+ return nil, p.Error("Filter parameter required after ':'.", nil)
+ }
+
+ // Get filter argument expression
+ v, err := p.parseVariableOrLiteral()
+ if err != nil {
+ return nil, err
+ }
+ filter.parameter = v
+ }
+
+ return filter, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/filters_builtin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/filters_builtin.go
new file mode 100644
index 000000000000..c0ec6161401d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/filters_builtin.go
@@ -0,0 +1,927 @@
+package pongo2
+
+/* Filters that are provided through github.com/flosch/pongo2-addons:
+ ------------------------------------------------------------------
+
+ filesizeformat
+ slugify
+ timesince
+ timeuntil
+
+ Filters that won't be added:
+ ----------------------------
+
+ get_static_prefix (reason: web-framework specific)
+ pprint (reason: python-specific)
+ static (reason: web-framework specific)
+
+ Reconsideration (not implemented yet):
+ --------------------------------------
+
+ force_escape (reason: not yet needed since this is the behaviour of pongo2's escape filter)
+ safeseq (reason: same reason as `force_escape`)
+ unordered_list (python-specific; not sure whether needed or not)
+ dictsort (python-specific; maybe one could add a filter to sort a list of structs by a specific field name)
+ dictsortreversed (see dictsort)
+*/
+
+import (
+ "bytes"
+ "fmt"
+ "math/rand"
+ "net/url"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+
+ "errors"
+)
+
+func init() {
+ rand.Seed(time.Now().Unix())
+
+ RegisterFilter("escape", filterEscape)
+ RegisterFilter("safe", filterSafe)
+ RegisterFilter("escapejs", filterEscapejs)
+
+ RegisterFilter("add", filterAdd)
+ RegisterFilter("addslashes", filterAddslashes)
+ RegisterFilter("capfirst", filterCapfirst)
+ RegisterFilter("center", filterCenter)
+ RegisterFilter("cut", filterCut)
+ RegisterFilter("date", filterDate)
+ RegisterFilter("default", filterDefault)
+ RegisterFilter("default_if_none", filterDefaultIfNone)
+ RegisterFilter("divisibleby", filterDivisibleby)
+ RegisterFilter("first", filterFirst)
+ RegisterFilter("floatformat", filterFloatformat)
+ RegisterFilter("get_digit", filterGetdigit)
+ RegisterFilter("iriencode", filterIriencode)
+ RegisterFilter("join", filterJoin)
+ RegisterFilter("last", filterLast)
+ RegisterFilter("length", filterLength)
+ RegisterFilter("length_is", filterLengthis)
+ RegisterFilter("linebreaks", filterLinebreaks)
+ RegisterFilter("linebreaksbr", filterLinebreaksbr)
+ RegisterFilter("linenumbers", filterLinenumbers)
+ RegisterFilter("ljust", filterLjust)
+ RegisterFilter("lower", filterLower)
+ RegisterFilter("make_list", filterMakelist)
+ RegisterFilter("phone2numeric", filterPhone2numeric)
+ RegisterFilter("pluralize", filterPluralize)
+ RegisterFilter("random", filterRandom)
+ RegisterFilter("removetags", filterRemovetags)
+ RegisterFilter("rjust", filterRjust)
+ RegisterFilter("slice", filterSlice)
+ RegisterFilter("split", filterSplit)
+ RegisterFilter("stringformat", filterStringformat)
+ RegisterFilter("striptags", filterStriptags)
+ RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
+ RegisterFilter("title", filterTitle)
+ RegisterFilter("truncatechars", filterTruncatechars)
+ RegisterFilter("truncatechars_html", filterTruncatecharsHTML)
+ RegisterFilter("truncatewords", filterTruncatewords)
+ RegisterFilter("truncatewords_html", filterTruncatewordsHTML)
+ RegisterFilter("upper", filterUpper)
+ RegisterFilter("urlencode", filterUrlencode)
+ RegisterFilter("urlize", filterUrlize)
+ RegisterFilter("urlizetrunc", filterUrlizetrunc)
+ RegisterFilter("wordcount", filterWordcount)
+ RegisterFilter("wordwrap", filterWordwrap)
+ RegisterFilter("yesno", filterYesno)
+
+ RegisterFilter("float", filterFloat) // pongo-specific
+ RegisterFilter("integer", filterInteger) // pongo-specific
+}
+
+func filterTruncatecharsHelper(s string, newLen int) string {
+ runes := []rune(s)
+ if newLen < len(runes) {
+ if newLen >= 3 {
+ return fmt.Sprintf("%s...", string(runes[:newLen-3]))
+ }
+ // Not enough space for the ellipsis
+ return string(runes[:newLen])
+ }
+ return string(runes)
+}
+
+func filterTruncateHTMLHelper(value string, newOutput *bytes.Buffer, cond func() bool, fn func(c rune, s int, idx int) int, finalize func()) {
+ vLen := len(value)
+ var tagStack []string
+ idx := 0
+
+ for idx < vLen && !cond() {
+ c, s := utf8.DecodeRuneInString(value[idx:])
+ if c == utf8.RuneError {
+ idx += s
+ continue
+ }
+
+ if c == '<' {
+ newOutput.WriteRune(c)
+ idx += s // consume "<"
+
+ if idx+1 < vLen {
+ if value[idx] == '/' {
+ // Close tag
+
+ newOutput.WriteString("/")
+
+ tag := ""
+ idx++ // consume "/"
+
+ for idx < vLen {
+ c2, size2 := utf8.DecodeRuneInString(value[idx:])
+ if c2 == utf8.RuneError {
+ idx += size2
+ continue
+ }
+
+ // End of tag found
+ if c2 == '>' {
+ idx++ // consume ">"
+ break
+ }
+ tag += string(c2)
+ idx += size2
+ }
+
+ if len(tagStack) > 0 {
+ // Ideally, the close tag is TOP of tag stack
+ // In malformed HTML, it must not be, so iterate through the stack and remove the tag
+ for i := len(tagStack) - 1; i >= 0; i-- {
+ if tagStack[i] == tag {
+ // Found the tag
+ tagStack[i] = tagStack[len(tagStack)-1]
+ tagStack = tagStack[:len(tagStack)-1]
+ break
+ }
+ }
+ }
+
+ newOutput.WriteString(tag)
+ newOutput.WriteString(">")
+ } else {
+ // Open tag
+
+ tag := ""
+
+ params := false
+ for idx < vLen {
+ c2, size2 := utf8.DecodeRuneInString(value[idx:])
+ if c2 == utf8.RuneError {
+ idx += size2
+ continue
+ }
+
+ newOutput.WriteRune(c2)
+
+ // End of tag found
+ if c2 == '>' {
+ idx++ // consume ">"
+ break
+ }
+
+ if !params {
+ if c2 == ' ' {
+ params = true
+ } else {
+ tag += string(c2)
+ }
+ }
+
+ idx += size2
+ }
+
+ // Add tag to stack
+ tagStack = append(tagStack, tag)
+ }
+ }
+ } else {
+ idx = fn(c, s, idx)
+ }
+ }
+
+ finalize()
+
+ for i := len(tagStack) - 1; i >= 0; i-- {
+ tag := tagStack[i]
+ // Close everything from the regular tag stack
+ newOutput.WriteString(fmt.Sprintf("%s>", tag))
+ }
+}
+
+func filterTruncatechars(in *Value, param *Value) (*Value, *Error) {
+ s := in.String()
+ newLen := param.Integer()
+ return AsValue(filterTruncatecharsHelper(s, newLen)), nil
+}
+
+func filterTruncatecharsHTML(in *Value, param *Value) (*Value, *Error) {
+ value := in.String()
+ newLen := max(param.Integer()-3, 0)
+
+ newOutput := bytes.NewBuffer(nil)
+
+ textcounter := 0
+
+ filterTruncateHTMLHelper(value, newOutput, func() bool {
+ return textcounter >= newLen
+ }, func(c rune, s int, idx int) int {
+ textcounter++
+ newOutput.WriteRune(c)
+
+ return idx + s
+ }, func() {
+ if textcounter >= newLen && textcounter < len(value) {
+ newOutput.WriteString("...")
+ }
+ })
+
+ return AsSafeValue(newOutput.String()), nil
+}
+
+func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
+ words := strings.Fields(in.String())
+ n := param.Integer()
+ if n <= 0 {
+ return AsValue(""), nil
+ }
+ nlen := min(len(words), n)
+ out := make([]string, 0, nlen)
+ for i := 0; i < nlen; i++ {
+ out = append(out, words[i])
+ }
+
+ if n < len(words) {
+ out = append(out, "...")
+ }
+
+ return AsValue(strings.Join(out, " ")), nil
+}
+
+func filterTruncatewordsHTML(in *Value, param *Value) (*Value, *Error) {
+ value := in.String()
+ newLen := max(param.Integer(), 0)
+
+ newOutput := bytes.NewBuffer(nil)
+
+ wordcounter := 0
+
+ filterTruncateHTMLHelper(value, newOutput, func() bool {
+ return wordcounter >= newLen
+ }, func(_ rune, _ int, idx int) int {
+ // Get next word
+ wordFound := false
+
+ for idx < len(value) {
+ c2, size2 := utf8.DecodeRuneInString(value[idx:])
+ if c2 == utf8.RuneError {
+ idx += size2
+ continue
+ }
+
+ if c2 == '<' {
+ // HTML tag start, don't consume it
+ return idx
+ }
+
+ newOutput.WriteRune(c2)
+ idx += size2
+
+ if c2 == ' ' || c2 == '.' || c2 == ',' || c2 == ';' {
+ // Word ends here, stop capturing it now
+ break
+ } else {
+ wordFound = true
+ }
+ }
+
+ if wordFound {
+ wordcounter++
+ }
+
+ return idx
+ }, func() {
+ if wordcounter >= newLen {
+ newOutput.WriteString("...")
+ }
+ })
+
+ return AsSafeValue(newOutput.String()), nil
+}
+
+func filterEscape(in *Value, param *Value) (*Value, *Error) {
+ output := strings.Replace(in.String(), "&", "&", -1)
+ output = strings.Replace(output, ">", ">", -1)
+ output = strings.Replace(output, "<", "<", -1)
+ output = strings.Replace(output, "\"", """, -1)
+ output = strings.Replace(output, "'", "'", -1)
+ return AsValue(output), nil
+}
+
+func filterSafe(in *Value, param *Value) (*Value, *Error) {
+ return in, nil // nothing to do here, just to keep track of the safe application
+}
+
+func filterEscapejs(in *Value, param *Value) (*Value, *Error) {
+ sin := in.String()
+
+ var b bytes.Buffer
+
+ idx := 0
+ for idx < len(sin) {
+ c, size := utf8.DecodeRuneInString(sin[idx:])
+ if c == utf8.RuneError {
+ idx += size
+ continue
+ }
+
+ if c == '\\' {
+ // Escape seq?
+ if idx+1 < len(sin) {
+ switch sin[idx+1] {
+ case 'r':
+ b.WriteString(fmt.Sprintf(`\u%04X`, '\r'))
+ idx += 2
+ continue
+ case 'n':
+ b.WriteString(fmt.Sprintf(`\u%04X`, '\n'))
+ idx += 2
+ continue
+ /*case '\'':
+ b.WriteString(fmt.Sprintf(`\u%04X`, '\''))
+ idx += 2
+ continue
+ case '"':
+ b.WriteString(fmt.Sprintf(`\u%04X`, '"'))
+ idx += 2
+ continue*/
+ }
+ }
+ }
+
+ if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == ' ' || c == '/' {
+ b.WriteRune(c)
+ } else {
+ b.WriteString(fmt.Sprintf(`\u%04X`, c))
+ }
+
+ idx += size
+ }
+
+ return AsValue(b.String()), nil
+}
+
+func filterAdd(in *Value, param *Value) (*Value, *Error) {
+ if in.IsNumber() && param.IsNumber() {
+ if in.IsFloat() || param.IsFloat() {
+ return AsValue(in.Float() + param.Float()), nil
+ }
+ return AsValue(in.Integer() + param.Integer()), nil
+ }
+ // If in/param is not a number, we're relying on the
+ // Value's String() conversion and just add them both together
+ return AsValue(in.String() + param.String()), nil
+}
+
+func filterAddslashes(in *Value, param *Value) (*Value, *Error) {
+ output := strings.Replace(in.String(), "\\", "\\\\", -1)
+ output = strings.Replace(output, "\"", "\\\"", -1)
+ output = strings.Replace(output, "'", "\\'", -1)
+ return AsValue(output), nil
+}
+
+func filterCut(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(strings.Replace(in.String(), param.String(), "", -1)), nil
+}
+
+func filterLength(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(in.Len()), nil
+}
+
+func filterLengthis(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(in.Len() == param.Integer()), nil
+}
+
+func filterDefault(in *Value, param *Value) (*Value, *Error) {
+ if !in.IsTrue() {
+ return param, nil
+ }
+ return in, nil
+}
+
+func filterDefaultIfNone(in *Value, param *Value) (*Value, *Error) {
+ if in.IsNil() {
+ return param, nil
+ }
+ return in, nil
+}
+
+func filterDivisibleby(in *Value, param *Value) (*Value, *Error) {
+ if param.Integer() == 0 {
+ return AsValue(false), nil
+ }
+ return AsValue(in.Integer()%param.Integer() == 0), nil
+}
+
+func filterFirst(in *Value, param *Value) (*Value, *Error) {
+ if in.CanSlice() && in.Len() > 0 {
+ return in.Index(0), nil
+ }
+ return AsValue(""), nil
+}
+
+func filterFloatformat(in *Value, param *Value) (*Value, *Error) {
+ val := in.Float()
+
+ decimals := -1
+ if !param.IsNil() {
+ // Any argument provided?
+ decimals = param.Integer()
+ }
+
+ // if the argument is not a number (e. g. empty), the default
+ // behaviour is trim the result
+ trim := !param.IsNumber()
+
+ if decimals <= 0 {
+ // argument is negative or zero, so we
+ // want the output being trimmed
+ decimals = -decimals
+ trim = true
+ }
+
+ if trim {
+ // Remove zeroes
+ if float64(int(val)) == val {
+ return AsValue(in.Integer()), nil
+ }
+ }
+
+ return AsValue(strconv.FormatFloat(val, 'f', decimals, 64)), nil
+}
+
+func filterGetdigit(in *Value, param *Value) (*Value, *Error) {
+ i := param.Integer()
+ l := len(in.String()) // do NOT use in.Len() here!
+ if i <= 0 || i > l {
+ return in, nil
+ }
+ return AsValue(in.String()[l-i] - 48), nil
+}
+
+const filterIRIChars = "/#%[]=:;$&()+,!?*@'~"
+
+func filterIriencode(in *Value, param *Value) (*Value, *Error) {
+ var b bytes.Buffer
+
+ sin := in.String()
+ for _, r := range sin {
+ if strings.IndexRune(filterIRIChars, r) >= 0 {
+ b.WriteRune(r)
+ } else {
+ b.WriteString(url.QueryEscape(string(r)))
+ }
+ }
+
+ return AsValue(b.String()), nil
+}
+
+func filterJoin(in *Value, param *Value) (*Value, *Error) {
+ if !in.CanSlice() {
+ return in, nil
+ }
+ sep := param.String()
+ sl := make([]string, 0, in.Len())
+ for i := 0; i < in.Len(); i++ {
+ sl = append(sl, in.Index(i).String())
+ }
+ return AsValue(strings.Join(sl, sep)), nil
+}
+
+func filterLast(in *Value, param *Value) (*Value, *Error) {
+ if in.CanSlice() && in.Len() > 0 {
+ return in.Index(in.Len() - 1), nil
+ }
+ return AsValue(""), nil
+}
+
+func filterUpper(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(strings.ToUpper(in.String())), nil
+}
+
+func filterLower(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(strings.ToLower(in.String())), nil
+}
+
+func filterMakelist(in *Value, param *Value) (*Value, *Error) {
+ s := in.String()
+ result := make([]string, 0, len(s))
+ for _, c := range s {
+ result = append(result, string(c))
+ }
+ return AsValue(result), nil
+}
+
+func filterCapfirst(in *Value, param *Value) (*Value, *Error) {
+ if in.Len() <= 0 {
+ return AsValue(""), nil
+ }
+ t := in.String()
+ r, size := utf8.DecodeRuneInString(t)
+ return AsValue(strings.ToUpper(string(r)) + t[size:]), nil
+}
+
+func filterCenter(in *Value, param *Value) (*Value, *Error) {
+ width := param.Integer()
+ slen := in.Len()
+ if width <= slen {
+ return in, nil
+ }
+
+ spaces := width - slen
+ left := spaces/2 + spaces%2
+ right := spaces / 2
+
+ return AsValue(fmt.Sprintf("%s%s%s", strings.Repeat(" ", left),
+ in.String(), strings.Repeat(" ", right))), nil
+}
+
+func filterDate(in *Value, param *Value) (*Value, *Error) {
+ t, isTime := in.Interface().(time.Time)
+ if !isTime {
+ return nil, &Error{
+ Sender: "filter:date",
+ OrigError: errors.New("filter input argument must be of type 'time.Time'"),
+ }
+ }
+ return AsValue(t.Format(param.String())), nil
+}
+
+func filterFloat(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(in.Float()), nil
+}
+
+func filterInteger(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(in.Integer()), nil
+}
+
+func filterLinebreaks(in *Value, param *Value) (*Value, *Error) {
+ if in.Len() == 0 {
+ return in, nil
+ }
+
+ var b bytes.Buffer
+
+ // Newline =
+ // Double newline = ...
+ lines := strings.Split(in.String(), "\n")
+ lenlines := len(lines)
+
+ opened := false
+
+ for idx, line := range lines {
+
+ if !opened {
+ b.WriteString("")
+ opened = true
+ }
+
+ b.WriteString(line)
+
+ if idx < lenlines-1 && strings.TrimSpace(lines[idx]) != "" {
+ // We've not reached the end
+ if strings.TrimSpace(lines[idx+1]) == "" {
+ // Next line is empty
+ if opened {
+ b.WriteString("
")
+ opened = false
+ }
+ } else {
+ b.WriteString(" ")
+ }
+ }
+ }
+
+ if opened {
+ b.WriteString("
")
+ }
+
+ return AsValue(b.String()), nil
+}
+
+func filterSplit(in *Value, param *Value) (*Value, *Error) {
+ chunks := strings.Split(in.String(), param.String())
+
+ return AsValue(chunks), nil
+}
+
+func filterLinebreaksbr(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(strings.Replace(in.String(), "\n", " ", -1)), nil
+}
+
+func filterLinenumbers(in *Value, param *Value) (*Value, *Error) {
+ lines := strings.Split(in.String(), "\n")
+ output := make([]string, 0, len(lines))
+ for idx, line := range lines {
+ output = append(output, fmt.Sprintf("%d. %s", idx+1, line))
+ }
+ return AsValue(strings.Join(output, "\n")), nil
+}
+
+func filterLjust(in *Value, param *Value) (*Value, *Error) {
+ times := param.Integer() - in.Len()
+ if times < 0 {
+ times = 0
+ }
+ return AsValue(fmt.Sprintf("%s%s", in.String(), strings.Repeat(" ", times))), nil
+}
+
+func filterUrlencode(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(url.QueryEscape(in.String())), nil
+}
+
+// TODO: This regexp could do some work
+var filterUrlizeURLRegexp = regexp.MustCompile(`((((http|https)://)|www\.|((^|[ ])[0-9A-Za-z_\-]+(\.com|\.net|\.org|\.info|\.biz|\.de))))(?U:.*)([ ]+|$)`)
+var filterUrlizeEmailRegexp = regexp.MustCompile(`(\w+@\w+\.\w{2,4})`)
+
+func filterUrlizeHelper(input string, autoescape bool, trunc int) (string, error) {
+ var soutErr error
+ sout := filterUrlizeURLRegexp.ReplaceAllStringFunc(input, func(raw_url string) string {
+ var prefix string
+ var suffix string
+ if strings.HasPrefix(raw_url, " ") {
+ prefix = " "
+ }
+ if strings.HasSuffix(raw_url, " ") {
+ suffix = " "
+ }
+
+ raw_url = strings.TrimSpace(raw_url)
+
+ t, err := ApplyFilter("iriencode", AsValue(raw_url), nil)
+ if err != nil {
+ soutErr = err
+ return ""
+ }
+ url := t.String()
+
+ if !strings.HasPrefix(url, "http") {
+ url = fmt.Sprintf("http://%s", url)
+ }
+
+ title := raw_url
+
+ if trunc > 3 && len(title) > trunc {
+ title = fmt.Sprintf("%s...", title[:trunc-3])
+ }
+
+ if autoescape {
+ t, err := ApplyFilter("escape", AsValue(title), nil)
+ if err != nil {
+ soutErr = err
+ return ""
+ }
+ title = t.String()
+ }
+
+ return fmt.Sprintf(`%s%s %s`, prefix, url, title, suffix)
+ })
+ if soutErr != nil {
+ return "", soutErr
+ }
+
+ sout = filterUrlizeEmailRegexp.ReplaceAllStringFunc(sout, func(mail string) string {
+ title := mail
+
+ if trunc > 3 && len(title) > trunc {
+ title = fmt.Sprintf("%s...", title[:trunc-3])
+ }
+
+ return fmt.Sprintf(`%s `, mail, title)
+ })
+
+ return sout, nil
+}
+
+func filterUrlize(in *Value, param *Value) (*Value, *Error) {
+ autoescape := true
+ if param.IsBool() {
+ autoescape = param.Bool()
+ }
+
+ s, err := filterUrlizeHelper(in.String(), autoescape, -1)
+ if err != nil {
+
+ }
+
+ return AsValue(s), nil
+}
+
+func filterUrlizetrunc(in *Value, param *Value) (*Value, *Error) {
+ s, err := filterUrlizeHelper(in.String(), true, param.Integer())
+ if err != nil {
+ return nil, &Error{
+ Sender: "filter:urlizetrunc",
+ OrigError: errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"),
+ }
+ }
+ return AsValue(s), nil
+}
+
+func filterStringformat(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(fmt.Sprintf(param.String(), in.Interface())), nil
+}
+
+var reStriptags = regexp.MustCompile("<[^>]*?>")
+
+func filterStriptags(in *Value, param *Value) (*Value, *Error) {
+ s := in.String()
+
+ // Strip all tags
+ s = reStriptags.ReplaceAllString(s, "")
+
+ return AsValue(strings.TrimSpace(s)), nil
+}
+
+// https://en.wikipedia.org/wiki/Phoneword
+var filterPhone2numericMap = map[string]string{
+ "a": "2", "b": "2", "c": "2", "d": "3", "e": "3", "f": "3", "g": "4", "h": "4", "i": "4", "j": "5", "k": "5",
+ "l": "5", "m": "6", "n": "6", "o": "6", "p": "7", "q": "7", "r": "7", "s": "7", "t": "8", "u": "8", "v": "8",
+ "w": "9", "x": "9", "y": "9", "z": "9",
+}
+
+func filterPhone2numeric(in *Value, param *Value) (*Value, *Error) {
+ sin := in.String()
+ for k, v := range filterPhone2numericMap {
+ sin = strings.Replace(sin, k, v, -1)
+ sin = strings.Replace(sin, strings.ToUpper(k), v, -1)
+ }
+ return AsValue(sin), nil
+}
+
+func filterPluralize(in *Value, param *Value) (*Value, *Error) {
+ if in.IsNumber() {
+ // Works only on numbers
+ if param.Len() > 0 {
+ endings := strings.Split(param.String(), ",")
+ if len(endings) > 2 {
+ return nil, &Error{
+ Sender: "filter:pluralize",
+ OrigError: errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"),
+ }
+ }
+ if len(endings) == 1 {
+ // 1 argument
+ if in.Integer() != 1 {
+ return AsValue(endings[0]), nil
+ }
+ } else {
+ if in.Integer() != 1 {
+ // 2 arguments
+ return AsValue(endings[1]), nil
+ }
+ return AsValue(endings[0]), nil
+ }
+ } else {
+ if in.Integer() != 1 {
+ // return default 's'
+ return AsValue("s"), nil
+ }
+ }
+
+ return AsValue(""), nil
+ }
+ return nil, &Error{
+ Sender: "filter:pluralize",
+ OrigError: errors.New("filter 'pluralize' does only work on numbers"),
+ }
+}
+
+func filterRandom(in *Value, param *Value) (*Value, *Error) {
+ if !in.CanSlice() || in.Len() <= 0 {
+ return in, nil
+ }
+ i := rand.Intn(in.Len())
+ return in.Index(i), nil
+}
+
+func filterRemovetags(in *Value, param *Value) (*Value, *Error) {
+ s := in.String()
+ tags := strings.Split(param.String(), ",")
+
+ // Strip only specific tags
+ for _, tag := range tags {
+ re := regexp.MustCompile(fmt.Sprintf("?%s/?>", tag))
+ s = re.ReplaceAllString(s, "")
+ }
+
+ return AsValue(strings.TrimSpace(s)), nil
+}
+
+func filterRjust(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(fmt.Sprintf(fmt.Sprintf("%%%ds", param.Integer()), in.String())), nil
+}
+
+func filterSlice(in *Value, param *Value) (*Value, *Error) {
+ comp := strings.Split(param.String(), ":")
+ if len(comp) != 2 {
+ return nil, &Error{
+ Sender: "filter:slice",
+ OrigError: errors.New("Slice string must have the format 'from:to' [from/to can be omitted, but the ':' is required]"),
+ }
+ }
+
+ if !in.CanSlice() {
+ return in, nil
+ }
+
+ from := AsValue(comp[0]).Integer()
+ to := in.Len()
+
+ if from > to {
+ from = to
+ }
+
+ vto := AsValue(comp[1]).Integer()
+ if vto >= from && vto <= in.Len() {
+ to = vto
+ }
+
+ return in.Slice(from, to), nil
+}
+
+func filterTitle(in *Value, param *Value) (*Value, *Error) {
+ if !in.IsString() {
+ return AsValue(""), nil
+ }
+ return AsValue(strings.Title(strings.ToLower(in.String()))), nil
+}
+
+func filterWordcount(in *Value, param *Value) (*Value, *Error) {
+ return AsValue(len(strings.Fields(in.String()))), nil
+}
+
+func filterWordwrap(in *Value, param *Value) (*Value, *Error) {
+ words := strings.Fields(in.String())
+ wordsLen := len(words)
+ wrapAt := param.Integer()
+ if wrapAt <= 0 {
+ return in, nil
+ }
+
+ linecount := wordsLen/wrapAt + wordsLen%wrapAt
+ lines := make([]string, 0, linecount)
+ for i := 0; i < linecount; i++ {
+ lines = append(lines, strings.Join(words[wrapAt*i:min(wrapAt*(i+1), wordsLen)], " "))
+ }
+ return AsValue(strings.Join(lines, "\n")), nil
+}
+
+func filterYesno(in *Value, param *Value) (*Value, *Error) {
+ choices := map[int]string{
+ 0: "yes",
+ 1: "no",
+ 2: "maybe",
+ }
+ paramString := param.String()
+ customChoices := strings.Split(paramString, ",")
+ if len(paramString) > 0 {
+ if len(customChoices) > 3 {
+ return nil, &Error{
+ Sender: "filter:yesno",
+ OrigError: fmt.Errorf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", paramString),
+ }
+ }
+ if len(customChoices) < 2 {
+ return nil, &Error{
+ Sender: "filter:yesno",
+ OrigError: fmt.Errorf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", paramString),
+ }
+ }
+
+ // Map to the options now
+ choices[0] = customChoices[0]
+ choices[1] = customChoices[1]
+ if len(customChoices) == 3 {
+ choices[2] = customChoices[2]
+ }
+ }
+
+ // maybe
+ if in.IsNil() {
+ return AsValue(choices[2]), nil
+ }
+
+ // yes
+ if in.IsTrue() {
+ return AsValue(choices[0]), nil
+ }
+
+ // no
+ return AsValue(choices[1]), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/helpers.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/helpers.go
new file mode 100644
index 000000000000..880dbc044435
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/helpers.go
@@ -0,0 +1,15 @@
+package pongo2
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/lexer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/lexer.go
new file mode 100644
index 000000000000..f1897984a98b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/lexer.go
@@ -0,0 +1,432 @@
+package pongo2
+
+import (
+ "fmt"
+ "strings"
+ "unicode/utf8"
+
+ "errors"
+)
+
+const (
+ TokenError = iota
+ EOF
+
+ TokenHTML
+
+ TokenKeyword
+ TokenIdentifier
+ TokenString
+ TokenNumber
+ TokenSymbol
+)
+
+var (
+ tokenSpaceChars = " \n\r\t"
+ tokenIdentifierChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
+ tokenIdentifierCharsWithDigits = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"
+ tokenDigits = "0123456789"
+
+ // Available symbols in pongo2 (within filters/tag)
+ TokenSymbols = []string{
+ // 3-Char symbols
+ "{{-", "-}}", "{%-", "-%}",
+
+ // 2-Char symbols
+ "==", ">=", "<=", "&&", "||", "{{", "}}", "{%", "%}", "!=", "<>",
+
+ // 1-Char symbol
+ "(", ")", "+", "-", "*", "<", ">", "/", "^", ",", ".", "!", "|", ":", "=", "%",
+ }
+
+ // Available keywords in pongo2
+ TokenKeywords = []string{"in", "and", "or", "not", "true", "false", "as", "export"}
+)
+
+type TokenType int
+type Token struct {
+ Filename string
+ Typ TokenType
+ Val string
+ Line int
+ Col int
+ TrimWhitespaces bool
+}
+
+type lexerStateFn func() lexerStateFn
+type lexer struct {
+ name string
+ input string
+ start int // start pos of the item
+ pos int // current pos
+ width int // width of last rune
+ tokens []*Token
+ errored bool
+ startline int
+ startcol int
+ line int
+ col int
+
+ inVerbatim bool
+ verbatimName string
+}
+
+func (t *Token) String() string {
+ val := t.Val
+ if len(val) > 1000 {
+ val = fmt.Sprintf("%s...%s", val[:10], val[len(val)-5:])
+ }
+
+ typ := ""
+ switch t.Typ {
+ case TokenHTML:
+ typ = "HTML"
+ case TokenError:
+ typ = "Error"
+ case TokenIdentifier:
+ typ = "Identifier"
+ case TokenKeyword:
+ typ = "Keyword"
+ case TokenNumber:
+ typ = "Number"
+ case TokenString:
+ typ = "String"
+ case TokenSymbol:
+ typ = "Symbol"
+ default:
+ typ = "Unknown"
+ }
+
+ return fmt.Sprintf("",
+ typ, t.Typ, val, t.Line, t.Col, t.TrimWhitespaces)
+}
+
+func lex(name string, input string) ([]*Token, *Error) {
+ l := &lexer{
+ name: name,
+ input: input,
+ tokens: make([]*Token, 0, 100),
+ line: 1,
+ col: 1,
+ startline: 1,
+ startcol: 1,
+ }
+ l.run()
+ if l.errored {
+ errtoken := l.tokens[len(l.tokens)-1]
+ return nil, &Error{
+ Filename: name,
+ Line: errtoken.Line,
+ Column: errtoken.Col,
+ Sender: "lexer",
+ OrigError: errors.New(errtoken.Val),
+ }
+ }
+ return l.tokens, nil
+}
+
+func (l *lexer) value() string {
+ return l.input[l.start:l.pos]
+}
+
+func (l *lexer) length() int {
+ return l.pos - l.start
+}
+
+func (l *lexer) emit(t TokenType) {
+ tok := &Token{
+ Filename: l.name,
+ Typ: t,
+ Val: l.value(),
+ Line: l.startline,
+ Col: l.startcol,
+ }
+
+ if t == TokenString {
+ // Escape sequence \" in strings
+ tok.Val = strings.Replace(tok.Val, `\"`, `"`, -1)
+ tok.Val = strings.Replace(tok.Val, `\\`, `\`, -1)
+ }
+
+ if t == TokenSymbol && len(tok.Val) == 3 && (strings.HasSuffix(tok.Val, "-") || strings.HasPrefix(tok.Val, "-")) {
+ tok.TrimWhitespaces = true
+ tok.Val = strings.Replace(tok.Val, "-", "", -1)
+ }
+
+ l.tokens = append(l.tokens, tok)
+ l.start = l.pos
+ l.startline = l.line
+ l.startcol = l.col
+}
+
+func (l *lexer) next() rune {
+ if l.pos >= len(l.input) {
+ l.width = 0
+ return EOF
+ }
+ r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+ l.width = w
+ l.pos += l.width
+ l.col += l.width
+ return r
+}
+
+func (l *lexer) backup() {
+ l.pos -= l.width
+ l.col -= l.width
+}
+
+func (l *lexer) peek() rune {
+ r := l.next()
+ l.backup()
+ return r
+}
+
+func (l *lexer) ignore() {
+ l.start = l.pos
+ l.startline = l.line
+ l.startcol = l.col
+}
+
+func (l *lexer) accept(what string) bool {
+ if strings.IndexRune(what, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+func (l *lexer) acceptRun(what string) {
+ for strings.IndexRune(what, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+func (l *lexer) errorf(format string, args ...interface{}) lexerStateFn {
+ t := &Token{
+ Filename: l.name,
+ Typ: TokenError,
+ Val: fmt.Sprintf(format, args...),
+ Line: l.startline,
+ Col: l.startcol,
+ }
+ l.tokens = append(l.tokens, t)
+ l.errored = true
+ l.startline = l.line
+ l.startcol = l.col
+ return nil
+}
+
+func (l *lexer) eof() bool {
+ return l.start >= len(l.input)-1
+}
+
+func (l *lexer) run() {
+ for {
+ // TODO: Support verbatim tag names
+ // https://docs.djangoproject.com/en/dev/ref/templates/builtins/#verbatim
+ if l.inVerbatim {
+ name := l.verbatimName
+ if name != "" {
+ name += " "
+ }
+ if strings.HasPrefix(l.input[l.pos:], fmt.Sprintf("{%% endverbatim %s%%}", name)) { // end verbatim
+ if l.pos > l.start {
+ l.emit(TokenHTML)
+ }
+ w := len("{% endverbatim %}")
+ l.pos += w
+ l.col += w
+ l.ignore()
+ l.inVerbatim = false
+ }
+ } else if strings.HasPrefix(l.input[l.pos:], "{% verbatim %}") { // tag
+ if l.pos > l.start {
+ l.emit(TokenHTML)
+ }
+ l.inVerbatim = true
+ w := len("{% verbatim %}")
+ l.pos += w
+ l.col += w
+ l.ignore()
+ }
+
+ if !l.inVerbatim {
+ // Ignore single-line comments {# ... #}
+ if strings.HasPrefix(l.input[l.pos:], "{#") {
+ if l.pos > l.start {
+ l.emit(TokenHTML)
+ }
+
+ l.pos += 2 // pass '{#'
+ l.col += 2
+
+ for {
+ switch l.peek() {
+ case EOF:
+ l.errorf("Single-line comment not closed.")
+ return
+ case '\n':
+ l.errorf("Newline not permitted in a single-line comment.")
+ return
+ }
+
+ if strings.HasPrefix(l.input[l.pos:], "#}") {
+ l.pos += 2 // pass '#}'
+ l.col += 2
+ break
+ }
+
+ l.next()
+ }
+ l.ignore() // ignore whole comment
+
+ // Comment skipped
+ continue // next token
+ }
+
+ if strings.HasPrefix(l.input[l.pos:], "{{") || // variable
+ strings.HasPrefix(l.input[l.pos:], "{%") { // tag
+ if l.pos > l.start {
+ l.emit(TokenHTML)
+ }
+ l.tokenize()
+ if l.errored {
+ return
+ }
+ continue
+ }
+ }
+
+ switch l.peek() {
+ case '\n':
+ l.line++
+ l.col = 0
+ }
+ if l.next() == EOF {
+ break
+ }
+ }
+
+ if l.pos > l.start {
+ l.emit(TokenHTML)
+ }
+
+ if l.inVerbatim {
+ l.errorf("verbatim-tag not closed, got EOF.")
+ }
+}
+
+func (l *lexer) tokenize() {
+ for state := l.stateCode; state != nil; {
+ state = state()
+ }
+}
+
+func (l *lexer) stateCode() lexerStateFn {
+outer_loop:
+ for {
+ switch {
+ case l.accept(tokenSpaceChars):
+ if l.value() == "\n" {
+ return l.errorf("Newline not allowed within tag/variable.")
+ }
+ l.ignore()
+ continue
+ case l.accept(tokenIdentifierChars):
+ return l.stateIdentifier
+ case l.accept(tokenDigits):
+ return l.stateNumber
+ case l.accept(`"'`):
+ return l.stateString
+ }
+
+ // Check for symbol
+ for _, sym := range TokenSymbols {
+ if strings.HasPrefix(l.input[l.start:], sym) {
+ l.pos += len(sym)
+ l.col += l.length()
+ l.emit(TokenSymbol)
+
+ if sym == "%}" || sym == "-%}" || sym == "}}" || sym == "-}}" {
+ // Tag/variable end, return after emit
+ return nil
+ }
+
+ continue outer_loop
+ }
+ }
+
+ break
+ }
+
+ // Normal shut down
+ return nil
+}
+
+func (l *lexer) stateIdentifier() lexerStateFn {
+ l.acceptRun(tokenIdentifierChars)
+ l.acceptRun(tokenIdentifierCharsWithDigits)
+ for _, kw := range TokenKeywords {
+ if kw == l.value() {
+ l.emit(TokenKeyword)
+ return l.stateCode
+ }
+ }
+ l.emit(TokenIdentifier)
+ return l.stateCode
+}
+
+func (l *lexer) stateNumber() lexerStateFn {
+ l.acceptRun(tokenDigits)
+ if l.accept(tokenIdentifierCharsWithDigits) {
+ // This seems to be an identifier starting with a number.
+ // See https://github.com/flosch/pongo2/issues/151
+ return l.stateIdentifier()
+ }
+ /*
+ Maybe context-sensitive number lexing?
+ * comments.0.Text // first comment
+ * usercomments.1.0 // second user, first comment
+ * if (score >= 8.5) // 8.5 as a number
+
+ if l.peek() == '.' {
+ l.accept(".")
+ if !l.accept(tokenDigits) {
+ return l.errorf("Malformed number.")
+ }
+ l.acceptRun(tokenDigits)
+ }
+ */
+ l.emit(TokenNumber)
+ return l.stateCode
+}
+
+func (l *lexer) stateString() lexerStateFn {
+ quotationMark := l.value()
+ l.ignore()
+ l.startcol-- // we're starting the position at the first "
+ for !l.accept(quotationMark) {
+ switch l.next() {
+ case '\\':
+ // escape sequence
+ switch l.peek() {
+ case '"', '\\':
+ l.next()
+ default:
+ return l.errorf("Unknown escape sequence: \\%c", l.peek())
+ }
+ case EOF:
+ return l.errorf("Unexpected EOF, string not closed.")
+ case '\n':
+ return l.errorf("Newline in string is not allowed.")
+ }
+ }
+ l.backup()
+ l.emit(TokenString)
+
+ l.next()
+ l.ignore()
+
+ return l.stateCode
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes.go
new file mode 100644
index 000000000000..5b039cdf40ca
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes.go
@@ -0,0 +1,16 @@
+package pongo2
+
+// The root document
+type nodeDocument struct {
+ Nodes []INode
+}
+
+func (doc *nodeDocument) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ for _, n := range doc.Nodes {
+ err := n.Execute(ctx, writer)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes_html.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes_html.go
new file mode 100644
index 000000000000..b980a3a5cf97
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes_html.go
@@ -0,0 +1,23 @@
+package pongo2
+
+import (
+ "strings"
+)
+
+type nodeHTML struct {
+ token *Token
+ trimLeft bool
+ trimRight bool
+}
+
+func (n *nodeHTML) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ res := n.token.Val
+ if n.trimLeft {
+ res = strings.TrimLeft(res, tokenSpaceChars)
+ }
+ if n.trimRight {
+ res = strings.TrimRight(res, tokenSpaceChars)
+ }
+ writer.WriteString(res)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes_wrapper.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes_wrapper.go
new file mode 100644
index 000000000000..d1bcb8d851ff
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/nodes_wrapper.go
@@ -0,0 +1,16 @@
+package pongo2
+
+type NodeWrapper struct {
+ Endtag string
+ nodes []INode
+}
+
+func (wrapper *NodeWrapper) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ for _, n := range wrapper.nodes {
+ err := n.Execute(ctx, writer)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/options.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/options.go
new file mode 100644
index 000000000000..9c39e467ef66
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/options.go
@@ -0,0 +1,26 @@
+package pongo2
+
+// Options allow you to change the behavior of template-engine.
+// You can change the options before calling the Execute method.
+type Options struct {
+ // If this is set to true the first newline after a block is removed (block, not variable tag!). Defaults to false.
+ TrimBlocks bool
+
+ // If this is set to true leading spaces and tabs are stripped from the start of a line to a block. Defaults to false
+ LStripBlocks bool
+}
+
+func newOptions() *Options {
+ return &Options{
+ TrimBlocks: false,
+ LStripBlocks: false,
+ }
+}
+
+// Update updates this options from another options.
+func (opt *Options) Update(other *Options) *Options {
+ opt.TrimBlocks = other.TrimBlocks
+ opt.LStripBlocks = other.LStripBlocks
+
+ return opt
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser.go
new file mode 100644
index 000000000000..19553f1716d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser.go
@@ -0,0 +1,309 @@
+package pongo2
+
+import (
+ "fmt"
+ "strings"
+
+ "errors"
+)
+
+type INode interface {
+ Execute(*ExecutionContext, TemplateWriter) *Error
+}
+
+type IEvaluator interface {
+ INode
+ GetPositionToken() *Token
+ Evaluate(*ExecutionContext) (*Value, *Error)
+ FilterApplied(name string) bool
+}
+
+// The parser provides you a comprehensive and easy tool to
+// work with the template document and arguments provided by
+// the user for your custom tag.
+//
+// The parser works on a token list which will be provided by pongo2.
+// A token is a unit you can work with. Tokens are either of type identifier,
+// string, number, keyword, HTML or symbol.
+//
+// (See Token's documentation for more about tokens)
+type Parser struct {
+ name string
+ idx int
+ tokens []*Token
+ lastToken *Token
+
+ // if the parser parses a template document, here will be
+ // a reference to it (needed to access the template through Tags)
+ template *Template
+}
+
+// Creates a new parser to parse tokens.
+// Used inside pongo2 to parse documents and to provide an easy-to-use
+// parser for tag authors
+func newParser(name string, tokens []*Token, template *Template) *Parser {
+ p := &Parser{
+ name: name,
+ tokens: tokens,
+ template: template,
+ }
+ if len(tokens) > 0 {
+ p.lastToken = tokens[len(tokens)-1]
+ }
+ return p
+}
+
+// Consume one token. It will be gone forever.
+func (p *Parser) Consume() {
+ p.ConsumeN(1)
+}
+
+// Consume N tokens. They will be gone forever.
+func (p *Parser) ConsumeN(count int) {
+ p.idx += count
+}
+
+// Returns the current token.
+func (p *Parser) Current() *Token {
+ return p.Get(p.idx)
+}
+
+// Returns the CURRENT token if the given type matches.
+// Consumes this token on success.
+func (p *Parser) MatchType(typ TokenType) *Token {
+ if t := p.PeekType(typ); t != nil {
+ p.Consume()
+ return t
+ }
+ return nil
+}
+
+// Returns the CURRENT token if the given type AND value matches.
+// Consumes this token on success.
+func (p *Parser) Match(typ TokenType, val string) *Token {
+ if t := p.Peek(typ, val); t != nil {
+ p.Consume()
+ return t
+ }
+ return nil
+}
+
+// Returns the CURRENT token if the given type AND *one* of
+// the given values matches.
+// Consumes this token on success.
+func (p *Parser) MatchOne(typ TokenType, vals ...string) *Token {
+ for _, val := range vals {
+ if t := p.Peek(typ, val); t != nil {
+ p.Consume()
+ return t
+ }
+ }
+ return nil
+}
+
+// Returns the CURRENT token if the given type matches.
+// It DOES NOT consume the token.
+func (p *Parser) PeekType(typ TokenType) *Token {
+ return p.PeekTypeN(0, typ)
+}
+
+// Returns the CURRENT token if the given type AND value matches.
+// It DOES NOT consume the token.
+func (p *Parser) Peek(typ TokenType, val string) *Token {
+ return p.PeekN(0, typ, val)
+}
+
+// Returns the CURRENT token if the given type AND *one* of
+// the given values matches.
+// It DOES NOT consume the token.
+func (p *Parser) PeekOne(typ TokenType, vals ...string) *Token {
+ for _, v := range vals {
+ t := p.PeekN(0, typ, v)
+ if t != nil {
+ return t
+ }
+ }
+ return nil
+}
+
+// Returns the tokens[current position + shift] token if the
+// given type AND value matches for that token.
+// DOES NOT consume the token.
+func (p *Parser) PeekN(shift int, typ TokenType, val string) *Token {
+ t := p.Get(p.idx + shift)
+ if t != nil {
+ if t.Typ == typ && t.Val == val {
+ return t
+ }
+ }
+ return nil
+}
+
+// Returns the tokens[current position + shift] token if the given type matches.
+// DOES NOT consume the token for that token.
+func (p *Parser) PeekTypeN(shift int, typ TokenType) *Token {
+ t := p.Get(p.idx + shift)
+ if t != nil {
+ if t.Typ == typ {
+ return t
+ }
+ }
+ return nil
+}
+
+// Returns the UNCONSUMED token count.
+func (p *Parser) Remaining() int {
+ return len(p.tokens) - p.idx
+}
+
+// Returns the total token count.
+func (p *Parser) Count() int {
+ return len(p.tokens)
+}
+
+// Returns tokens[i] or NIL (if i >= len(tokens))
+func (p *Parser) Get(i int) *Token {
+ if i < len(p.tokens) && i >= 0 {
+ return p.tokens[i]
+ }
+ return nil
+}
+
+// Returns tokens[current-position + shift] or NIL
+// (if (current-position + i) >= len(tokens))
+func (p *Parser) GetR(shift int) *Token {
+ i := p.idx + shift
+ return p.Get(i)
+}
+
+// Error produces a nice error message and returns an error-object.
+// The 'token'-argument is optional. If provided, it will take
+// the token's position information. If not provided, it will
+// automatically use the CURRENT token's position information.
+func (p *Parser) Error(msg string, token *Token) *Error {
+ if token == nil {
+ // Set current token
+ token = p.Current()
+ if token == nil {
+ // Set to last token
+ if len(p.tokens) > 0 {
+ token = p.tokens[len(p.tokens)-1]
+ }
+ }
+ }
+ var line, col int
+ if token != nil {
+ line = token.Line
+ col = token.Col
+ }
+ return &Error{
+ Template: p.template,
+ Filename: p.name,
+ Sender: "parser",
+ Line: line,
+ Column: col,
+ Token: token,
+ OrigError: errors.New(msg),
+ }
+}
+
+// Wraps all nodes between starting tag and "{% endtag %}" and provides
+// one simple interface to execute the wrapped nodes.
+// It returns a parser to process provided arguments to the tag.
+func (p *Parser) WrapUntilTag(names ...string) (*NodeWrapper, *Parser, *Error) {
+ wrapper := &NodeWrapper{}
+
+ var tagArgs []*Token
+
+ for p.Remaining() > 0 {
+ // New tag, check whether we have to stop wrapping here
+ if p.Peek(TokenSymbol, "{%") != nil {
+ tagIdent := p.PeekTypeN(1, TokenIdentifier)
+
+ if tagIdent != nil {
+ // We've found a (!) end-tag
+
+ found := false
+ for _, n := range names {
+ if tagIdent.Val == n {
+ found = true
+ break
+ }
+ }
+
+ // We only process the tag if we've found an end tag
+ if found {
+ // Okay, endtag found.
+ p.ConsumeN(2) // '{%' tagname
+
+ for {
+ if p.Match(TokenSymbol, "%}") != nil {
+ // Okay, end the wrapping here
+ wrapper.Endtag = tagIdent.Val
+ return wrapper, newParser(p.template.name, tagArgs, p.template), nil
+ }
+ t := p.Current()
+ p.Consume()
+ if t == nil {
+ return nil, nil, p.Error("Unexpected EOF.", p.lastToken)
+ }
+ tagArgs = append(tagArgs, t)
+ }
+ }
+ }
+
+ }
+
+ // Otherwise process next element to be wrapped
+ node, err := p.parseDocElement()
+ if err != nil {
+ return nil, nil, err
+ }
+ wrapper.nodes = append(wrapper.nodes, node)
+ }
+
+ return nil, nil, p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")),
+ p.lastToken)
+}
+
+// Skips all nodes between starting tag and "{% endtag %}"
+func (p *Parser) SkipUntilTag(names ...string) *Error {
+ for p.Remaining() > 0 {
+ // New tag, check whether we have to stop wrapping here
+ if p.Peek(TokenSymbol, "{%") != nil {
+ tagIdent := p.PeekTypeN(1, TokenIdentifier)
+
+ if tagIdent != nil {
+ // We've found a (!) end-tag
+
+ found := false
+ for _, n := range names {
+ if tagIdent.Val == n {
+ found = true
+ break
+ }
+ }
+
+ // We only process the tag if we've found an end tag
+ if found {
+ // Okay, endtag found.
+ p.ConsumeN(2) // '{%' tagname
+
+ for {
+ if p.Match(TokenSymbol, "%}") != nil {
+ // Done skipping, exit.
+ return nil
+ }
+ }
+ }
+ }
+ }
+ t := p.Current()
+ p.Consume()
+ if t == nil {
+ return p.Error("Unexpected EOF.", p.lastToken)
+ }
+ }
+
+ return p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")), p.lastToken)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser_document.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser_document.go
new file mode 100644
index 000000000000..e3ac2c8e9d89
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser_document.go
@@ -0,0 +1,59 @@
+package pongo2
+
+// Doc = { ( Filter | Tag | HTML ) }
+func (p *Parser) parseDocElement() (INode, *Error) {
+ t := p.Current()
+
+ switch t.Typ {
+ case TokenHTML:
+ n := &nodeHTML{token: t}
+ left := p.PeekTypeN(-1, TokenSymbol)
+ right := p.PeekTypeN(1, TokenSymbol)
+ n.trimLeft = left != nil && left.TrimWhitespaces
+ n.trimRight = right != nil && right.TrimWhitespaces
+ p.Consume() // consume HTML element
+ return n, nil
+ case TokenSymbol:
+ switch t.Val {
+ case "{{":
+ // parse variable
+ variable, err := p.parseVariableElement()
+ if err != nil {
+ return nil, err
+ }
+ return variable, nil
+ case "{%":
+ // parse tag
+ tag, err := p.parseTagElement()
+ if err != nil {
+ return nil, err
+ }
+ return tag, nil
+ }
+ }
+ return nil, p.Error("Unexpected token (only HTML/tags/filters in templates allowed)", t)
+}
+
+func (tpl *Template) parse() *Error {
+ tpl.parser = newParser(tpl.name, tpl.tokens, tpl)
+ doc, err := tpl.parser.parseDocument()
+ if err != nil {
+ return err
+ }
+ tpl.root = doc
+ return nil
+}
+
+func (p *Parser) parseDocument() (*nodeDocument, *Error) {
+ doc := &nodeDocument{}
+
+ for p.Remaining() > 0 {
+ node, err := p.parseDocElement()
+ if err != nil {
+ return nil, err
+ }
+ doc.Nodes = append(doc.Nodes, node)
+ }
+
+ return doc, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser_expression.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser_expression.go
new file mode 100644
index 000000000000..215b0afb10a2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/parser_expression.go
@@ -0,0 +1,517 @@
+package pongo2
+
+import (
+ "fmt"
+ "math"
+)
+
+type Expression struct {
+ // TODO: Add location token?
+ expr1 IEvaluator
+ expr2 IEvaluator
+ opToken *Token
+}
+
+type relationalExpression struct {
+ // TODO: Add location token?
+ expr1 IEvaluator
+ expr2 IEvaluator
+ opToken *Token
+}
+
+type simpleExpression struct {
+ negate bool
+ negativeSign bool
+ term1 IEvaluator
+ term2 IEvaluator
+ opToken *Token
+}
+
+type term struct {
+ // TODO: Add location token?
+ factor1 IEvaluator
+ factor2 IEvaluator
+ opToken *Token
+}
+
+type power struct {
+ // TODO: Add location token?
+ power1 IEvaluator
+ power2 IEvaluator
+}
+
+func (expr *Expression) FilterApplied(name string) bool {
+ return expr.expr1.FilterApplied(name) && (expr.expr2 == nil ||
+ (expr.expr2 != nil && expr.expr2.FilterApplied(name)))
+}
+
+func (expr *relationalExpression) FilterApplied(name string) bool {
+ return expr.expr1.FilterApplied(name) && (expr.expr2 == nil ||
+ (expr.expr2 != nil && expr.expr2.FilterApplied(name)))
+}
+
+func (expr *simpleExpression) FilterApplied(name string) bool {
+ return expr.term1.FilterApplied(name) && (expr.term2 == nil ||
+ (expr.term2 != nil && expr.term2.FilterApplied(name)))
+}
+
+func (expr *term) FilterApplied(name string) bool {
+ return expr.factor1.FilterApplied(name) && (expr.factor2 == nil ||
+ (expr.factor2 != nil && expr.factor2.FilterApplied(name)))
+}
+
+func (expr *power) FilterApplied(name string) bool {
+ return expr.power1.FilterApplied(name) && (expr.power2 == nil ||
+ (expr.power2 != nil && expr.power2.FilterApplied(name)))
+}
+
+func (expr *Expression) GetPositionToken() *Token {
+ return expr.expr1.GetPositionToken()
+}
+
+func (expr *relationalExpression) GetPositionToken() *Token {
+ return expr.expr1.GetPositionToken()
+}
+
+func (expr *simpleExpression) GetPositionToken() *Token {
+ return expr.term1.GetPositionToken()
+}
+
+func (expr *term) GetPositionToken() *Token {
+ return expr.factor1.GetPositionToken()
+}
+
+func (expr *power) GetPositionToken() *Token {
+ return expr.power1.GetPositionToken()
+}
+
+func (expr *Expression) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (expr *relationalExpression) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (expr *simpleExpression) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (expr *term) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (expr *power) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (expr *Expression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ v1, err := expr.expr1.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if expr.expr2 != nil {
+ switch expr.opToken.Val {
+ case "and", "&&":
+ if !v1.IsTrue() {
+ return AsValue(false), nil
+ } else {
+ v2, err := expr.expr2.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return AsValue(v2.IsTrue()), nil
+ }
+ case "or", "||":
+ if v1.IsTrue() {
+ return AsValue(true), nil
+ } else {
+ v2, err := expr.expr2.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return AsValue(v2.IsTrue()), nil
+ }
+ default:
+ return nil, ctx.Error(fmt.Sprintf("unimplemented: %s", expr.opToken.Val), expr.opToken)
+ }
+ } else {
+ return v1, nil
+ }
+}
+
+func (expr *relationalExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ v1, err := expr.expr1.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if expr.expr2 != nil {
+ v2, err := expr.expr2.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ switch expr.opToken.Val {
+ case "<=":
+ if v1.IsFloat() || v2.IsFloat() {
+ return AsValue(v1.Float() <= v2.Float()), nil
+ }
+ if v1.IsTime() && v2.IsTime() {
+ tm1, tm2 := v1.Time(), v2.Time()
+ return AsValue(tm1.Before(tm2) || tm1.Equal(tm2)), nil
+ }
+ return AsValue(v1.Integer() <= v2.Integer()), nil
+ case ">=":
+ if v1.IsFloat() || v2.IsFloat() {
+ return AsValue(v1.Float() >= v2.Float()), nil
+ }
+ if v1.IsTime() && v2.IsTime() {
+ tm1, tm2 := v1.Time(), v2.Time()
+ return AsValue(tm1.After(tm2) || tm1.Equal(tm2)), nil
+ }
+ return AsValue(v1.Integer() >= v2.Integer()), nil
+ case "==":
+ return AsValue(v1.EqualValueTo(v2)), nil
+ case ">":
+ if v1.IsFloat() || v2.IsFloat() {
+ return AsValue(v1.Float() > v2.Float()), nil
+ }
+ if v1.IsTime() && v2.IsTime() {
+ return AsValue(v1.Time().After(v2.Time())), nil
+ }
+ return AsValue(v1.Integer() > v2.Integer()), nil
+ case "<":
+ if v1.IsFloat() || v2.IsFloat() {
+ return AsValue(v1.Float() < v2.Float()), nil
+ }
+ if v1.IsTime() && v2.IsTime() {
+ return AsValue(v1.Time().Before(v2.Time())), nil
+ }
+ return AsValue(v1.Integer() < v2.Integer()), nil
+ case "!=", "<>":
+ return AsValue(!v1.EqualValueTo(v2)), nil
+ case "in":
+ return AsValue(v2.Contains(v1)), nil
+ default:
+ return nil, ctx.Error(fmt.Sprintf("unimplemented: %s", expr.opToken.Val), expr.opToken)
+ }
+ } else {
+ return v1, nil
+ }
+}
+
+func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ t1, err := expr.term1.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ result := t1
+
+ if expr.negate {
+ result = result.Negate()
+ }
+
+ if expr.negativeSign {
+ if result.IsNumber() {
+ switch {
+ case result.IsFloat():
+ result = AsValue(-1 * result.Float())
+ case result.IsInteger():
+ result = AsValue(-1 * result.Integer())
+ default:
+ return nil, ctx.Error("Operation between a number and a non-(float/integer) is not possible", nil)
+ }
+ } else {
+ return nil, ctx.Error("Negative sign on a non-number expression", expr.GetPositionToken())
+ }
+ }
+
+ if expr.term2 != nil {
+ t2, err := expr.term2.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ switch expr.opToken.Val {
+ case "+":
+ if result.IsFloat() || t2.IsFloat() {
+ // Result will be a float
+ return AsValue(result.Float() + t2.Float()), nil
+ }
+ // Result will be an integer
+ return AsValue(result.Integer() + t2.Integer()), nil
+ case "-":
+ if result.IsFloat() || t2.IsFloat() {
+ // Result will be a float
+ return AsValue(result.Float() - t2.Float()), nil
+ }
+ // Result will be an integer
+ return AsValue(result.Integer() - t2.Integer()), nil
+ default:
+ return nil, ctx.Error("Unimplemented", expr.GetPositionToken())
+ }
+ }
+
+ return result, nil
+}
+
+func (expr *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ f1, err := expr.factor1.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if expr.factor2 != nil {
+ f2, err := expr.factor2.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ switch expr.opToken.Val {
+ case "*":
+ if f1.IsFloat() || f2.IsFloat() {
+ // Result will be float
+ return AsValue(f1.Float() * f2.Float()), nil
+ }
+ // Result will be int
+ return AsValue(f1.Integer() * f2.Integer()), nil
+ case "/":
+ if f1.IsFloat() || f2.IsFloat() {
+ // Result will be float
+ return AsValue(f1.Float() / f2.Float()), nil
+ }
+ // Result will be int
+ return AsValue(f1.Integer() / f2.Integer()), nil
+ case "%":
+ // Result will be int
+ return AsValue(f1.Integer() % f2.Integer()), nil
+ default:
+ return nil, ctx.Error("unimplemented", expr.opToken)
+ }
+ } else {
+ return f1, nil
+ }
+}
+
+func (expr *power) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ p1, err := expr.power1.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if expr.power2 != nil {
+ p2, err := expr.power2.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return AsValue(math.Pow(p1.Float(), p2.Float())), nil
+ }
+ return p1, nil
+}
+
+func (p *Parser) parseFactor() (IEvaluator, *Error) {
+ if p.Match(TokenSymbol, "(") != nil {
+ expr, err := p.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ if p.Match(TokenSymbol, ")") == nil {
+ return nil, p.Error("Closing bracket expected after expression", nil)
+ }
+ return expr, nil
+ }
+
+ return p.parseVariableOrLiteralWithFilter()
+}
+
+func (p *Parser) parsePower() (IEvaluator, *Error) {
+ pw := new(power)
+
+ power1, err := p.parseFactor()
+ if err != nil {
+ return nil, err
+ }
+ pw.power1 = power1
+
+ if p.Match(TokenSymbol, "^") != nil {
+ power2, err := p.parsePower()
+ if err != nil {
+ return nil, err
+ }
+ pw.power2 = power2
+ }
+
+ if pw.power2 == nil {
+ // Shortcut for faster evaluation
+ return pw.power1, nil
+ }
+
+ return pw, nil
+}
+
+func (p *Parser) parseTerm() (IEvaluator, *Error) {
+ returnTerm := new(term)
+
+ factor1, err := p.parsePower()
+ if err != nil {
+ return nil, err
+ }
+ returnTerm.factor1 = factor1
+
+ for p.PeekOne(TokenSymbol, "*", "/", "%") != nil {
+ if returnTerm.opToken != nil {
+ // Create new sub-term
+ returnTerm = &term{
+ factor1: returnTerm,
+ }
+ }
+
+ op := p.Current()
+ p.Consume()
+
+ factor2, err := p.parsePower()
+ if err != nil {
+ return nil, err
+ }
+
+ returnTerm.opToken = op
+ returnTerm.factor2 = factor2
+ }
+
+ if returnTerm.opToken == nil {
+ // Shortcut for faster evaluation
+ return returnTerm.factor1, nil
+ }
+
+ return returnTerm, nil
+}
+
+func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
+ expr := new(simpleExpression)
+
+ if sign := p.MatchOne(TokenSymbol, "+", "-"); sign != nil {
+ if sign.Val == "-" {
+ expr.negativeSign = true
+ }
+ }
+
+ if p.Match(TokenSymbol, "!") != nil || p.Match(TokenKeyword, "not") != nil {
+ expr.negate = true
+ }
+
+ term1, err := p.parseTerm()
+ if err != nil {
+ return nil, err
+ }
+ expr.term1 = term1
+
+ for p.PeekOne(TokenSymbol, "+", "-") != nil {
+ if expr.opToken != nil {
+ // New sub expr
+ expr = &simpleExpression{
+ term1: expr,
+ }
+ }
+
+ op := p.Current()
+ p.Consume()
+
+ term2, err := p.parseTerm()
+ if err != nil {
+ return nil, err
+ }
+
+ expr.term2 = term2
+ expr.opToken = op
+ }
+
+ if expr.negate == false && expr.negativeSign == false && expr.term2 == nil {
+ // Shortcut for faster evaluation
+ return expr.term1, nil
+ }
+
+ return expr, nil
+}
+
+func (p *Parser) parseRelationalExpression() (IEvaluator, *Error) {
+ expr1, err := p.parseSimpleExpression()
+ if err != nil {
+ return nil, err
+ }
+
+ expr := &relationalExpression{
+ expr1: expr1,
+ }
+
+ if t := p.MatchOne(TokenSymbol, "==", "<=", ">=", "!=", "<>", ">", "<"); t != nil {
+ expr2, err := p.parseRelationalExpression()
+ if err != nil {
+ return nil, err
+ }
+ expr.opToken = t
+ expr.expr2 = expr2
+ } else if t := p.MatchOne(TokenKeyword, "in"); t != nil {
+ expr2, err := p.parseSimpleExpression()
+ if err != nil {
+ return nil, err
+ }
+ expr.opToken = t
+ expr.expr2 = expr2
+ }
+
+ if expr.expr2 == nil {
+ // Shortcut for faster evaluation
+ return expr.expr1, nil
+ }
+
+ return expr, nil
+}
+
+func (p *Parser) ParseExpression() (IEvaluator, *Error) {
+ rexpr1, err := p.parseRelationalExpression()
+ if err != nil {
+ return nil, err
+ }
+
+ exp := &Expression{
+ expr1: rexpr1,
+ }
+
+ if p.PeekOne(TokenSymbol, "&&", "||") != nil || p.PeekOne(TokenKeyword, "and", "or") != nil {
+ op := p.Current()
+ p.Consume()
+ expr2, err := p.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ exp.expr2 = expr2
+ exp.opToken = op
+ }
+
+ if exp.expr2 == nil {
+ // Shortcut for faster evaluation
+ return exp.expr1, nil
+ }
+
+ return exp, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/pongo2.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/pongo2.go
new file mode 100644
index 000000000000..8e222139aebd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/pongo2.go
@@ -0,0 +1,14 @@
+package pongo2
+
+// Version string
+const Version = "4.0.2"
+
+// Must panics, if a Template couldn't successfully parsed. This is how you
+// would use it:
+// var baseTemplate = pongo2.Must(pongo2.FromFile("templates/base.html"))
+func Must(tpl *Template, err error) *Template {
+ if err != nil {
+ panic(err)
+ }
+ return tpl
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags.go
new file mode 100644
index 000000000000..710ee2527ba6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags.go
@@ -0,0 +1,133 @@
+package pongo2
+
+/* Incomplete:
+ -----------
+
+ verbatim (only the "name" argument is missing for verbatim)
+
+ Reconsideration:
+ ----------------
+
+ debug (reason: not sure what to output yet)
+ regroup / Grouping on other properties (reason: maybe too python-specific; not sure how useful this would be in Go)
+
+ Following built-in tags wont be added:
+ --------------------------------------
+
+ csrf_token (reason: web-framework specific)
+ load (reason: python-specific)
+ url (reason: web-framework specific)
+*/
+
+import (
+ "fmt"
+)
+
+type INodeTag interface {
+ INode
+}
+
+// This is the function signature of the tag's parser you will have
+// to implement in order to create a new tag.
+//
+// 'doc' is providing access to the whole document while 'arguments'
+// is providing access to the user's arguments to the tag:
+//
+// {% your_tag_name some "arguments" 123 %}
+//
+// start_token will be the *Token with the tag's name in it (here: your_tag_name).
+//
+// Please see the Parser documentation on how to use the parser.
+// See RegisterTag()'s documentation for more information about
+// writing a tag as well.
+type TagParser func(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error)
+
+type tag struct {
+ name string
+ parser TagParser
+}
+
+var tags map[string]*tag
+
+func init() {
+ tags = make(map[string]*tag)
+}
+
+// Registers a new tag. You usually want to call this
+// function in the tag's init() function:
+// http://golang.org/doc/effective_go.html#init
+//
+// See http://www.florian-schlachter.de/post/pongo2/ for more about
+// writing filters and tags.
+func RegisterTag(name string, parserFn TagParser) error {
+ _, existing := tags[name]
+ if existing {
+ return fmt.Errorf("tag with name '%s' is already registered", name)
+ }
+ tags[name] = &tag{
+ name: name,
+ parser: parserFn,
+ }
+ return nil
+}
+
+// Replaces an already registered tag with a new implementation. Use this
+// function with caution since it allows you to change existing tag behaviour.
+func ReplaceTag(name string, parserFn TagParser) error {
+ _, existing := tags[name]
+ if !existing {
+ return fmt.Errorf("tag with name '%s' does not exist (therefore cannot be overridden)", name)
+ }
+ tags[name] = &tag{
+ name: name,
+ parser: parserFn,
+ }
+ return nil
+}
+
+// Tag = "{%" IDENT ARGS "%}"
+func (p *Parser) parseTagElement() (INodeTag, *Error) {
+ p.Consume() // consume "{%"
+ tokenName := p.MatchType(TokenIdentifier)
+
+ // Check for identifier
+ if tokenName == nil {
+ return nil, p.Error("Tag name must be an identifier.", nil)
+ }
+
+ // Check for the existing tag
+ tag, exists := tags[tokenName.Val]
+ if !exists {
+ // Does not exists
+ return nil, p.Error(fmt.Sprintf("Tag '%s' not found (or beginning tag not provided)", tokenName.Val), tokenName)
+ }
+
+ // Check sandbox tag restriction
+ if _, isBanned := p.template.set.bannedTags[tokenName.Val]; isBanned {
+ return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
+ }
+
+ var argsToken []*Token
+ for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
+ // Add token to args
+ argsToken = append(argsToken, p.Current())
+ p.Consume() // next token
+ }
+
+ // EOF?
+ if p.Remaining() == 0 {
+ return nil, p.Error("Unexpectedly reached EOF, no tag end found.", p.lastToken)
+ }
+
+ p.Match(TokenSymbol, "%}")
+
+ argParser := newParser(p.name, argsToken, p.template)
+ if len(argsToken) == 0 {
+ // This is done to have nice EOF error messages
+ argParser.lastToken = tokenName
+ }
+
+ p.template.level++
+ defer func() { p.template.level-- }()
+ return tag.parser(p, tokenName, argParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_autoescape.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_autoescape.go
new file mode 100644
index 000000000000..590a1db3506e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_autoescape.go
@@ -0,0 +1,52 @@
+package pongo2
+
+type tagAutoescapeNode struct {
+ wrapper *NodeWrapper
+ autoescape bool
+}
+
+func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ old := ctx.Autoescape
+ ctx.Autoescape = node.autoescape
+
+ err := node.wrapper.Execute(ctx, writer)
+ if err != nil {
+ return err
+ }
+
+ ctx.Autoescape = old
+
+ return nil
+}
+
+func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ autoescapeNode := &tagAutoescapeNode{}
+
+ wrapper, _, err := doc.WrapUntilTag("endautoescape")
+ if err != nil {
+ return nil, err
+ }
+ autoescapeNode.wrapper = wrapper
+
+ modeToken := arguments.MatchType(TokenIdentifier)
+ if modeToken == nil {
+ return nil, arguments.Error("A mode is required for autoescape-tag.", nil)
+ }
+ if modeToken.Val == "on" {
+ autoescapeNode.autoescape = true
+ } else if modeToken.Val == "off" {
+ autoescapeNode.autoescape = false
+ } else {
+ return nil, arguments.Error("Only 'on' or 'off' is valid as an autoescape-mode.", nil)
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed autoescape-tag arguments.", nil)
+ }
+
+ return autoescapeNode, nil
+}
+
+func init() {
+ RegisterTag("autoescape", tagAutoescapeParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_block.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_block.go
new file mode 100644
index 000000000000..86145f329aef
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_block.go
@@ -0,0 +1,129 @@
+package pongo2
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type tagBlockNode struct {
+ name string
+}
+
+func (node *tagBlockNode) getBlockWrappers(tpl *Template) []*NodeWrapper {
+ nodeWrappers := make([]*NodeWrapper, 0)
+ var t *NodeWrapper
+
+ for tpl != nil {
+ t = tpl.blocks[node.name]
+ if t != nil {
+ nodeWrappers = append(nodeWrappers, t)
+ }
+ tpl = tpl.child
+ }
+
+ return nodeWrappers
+}
+
+func (node *tagBlockNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ tpl := ctx.template
+ if tpl == nil {
+ panic("internal error: tpl == nil")
+ }
+
+ // Determine the block to execute
+ blockWrappers := node.getBlockWrappers(tpl)
+ lenBlockWrappers := len(blockWrappers)
+
+ if lenBlockWrappers == 0 {
+ return ctx.Error("internal error: len(block_wrappers) == 0 in tagBlockNode.Execute()", nil)
+ }
+
+ blockWrapper := blockWrappers[lenBlockWrappers-1]
+ ctx.Private["block"] = tagBlockInformation{
+ ctx: ctx,
+ wrappers: blockWrappers[0 : lenBlockWrappers-1],
+ }
+ err := blockWrapper.Execute(ctx, writer)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+type tagBlockInformation struct {
+ ctx *ExecutionContext
+ wrappers []*NodeWrapper
+}
+
+func (t tagBlockInformation) Super() string {
+ lenWrappers := len(t.wrappers)
+
+ if lenWrappers == 0 {
+ return ""
+ }
+
+ superCtx := NewChildExecutionContext(t.ctx)
+ superCtx.Private["block"] = tagBlockInformation{
+ ctx: t.ctx,
+ wrappers: t.wrappers[0 : lenWrappers-1],
+ }
+
+ blockWrapper := t.wrappers[lenWrappers-1]
+ buf := bytes.NewBufferString("")
+ err := blockWrapper.Execute(superCtx, &templateWriter{buf})
+ if err != nil {
+ return ""
+ }
+ return buf.String()
+}
+
+func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ if arguments.Count() == 0 {
+ return nil, arguments.Error("Tag 'block' requires an identifier.", nil)
+ }
+
+ nameToken := arguments.MatchType(TokenIdentifier)
+ if nameToken == nil {
+ return nil, arguments.Error("First argument for tag 'block' must be an identifier.", nil)
+ }
+
+ if arguments.Remaining() != 0 {
+ return nil, arguments.Error("Tag 'block' takes exactly 1 argument (an identifier).", nil)
+ }
+
+ wrapper, endtagargs, err := doc.WrapUntilTag("endblock")
+ if err != nil {
+ return nil, err
+ }
+ if endtagargs.Remaining() > 0 {
+ endtagnameToken := endtagargs.MatchType(TokenIdentifier)
+ if endtagnameToken != nil {
+ if endtagnameToken.Val != nameToken.Val {
+ return nil, endtagargs.Error(fmt.Sprintf("Name for 'endblock' must equal to 'block'-tag's name ('%s' != '%s').",
+ nameToken.Val, endtagnameToken.Val), nil)
+ }
+ }
+
+ if endtagnameToken == nil || endtagargs.Remaining() > 0 {
+ return nil, endtagargs.Error("Either no or only one argument (identifier) allowed for 'endblock'.", nil)
+ }
+ }
+
+ tpl := doc.template
+ if tpl == nil {
+ panic("internal error: tpl == nil")
+ }
+ _, hasBlock := tpl.blocks[nameToken.Val]
+ if !hasBlock {
+ tpl.blocks[nameToken.Val] = wrapper
+ } else {
+ return nil, arguments.Error(fmt.Sprintf("Block named '%s' already defined", nameToken.Val), nil)
+ }
+
+ return &tagBlockNode{name: nameToken.Val}, nil
+}
+
+func init() {
+ RegisterTag("block", tagBlockParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_comment.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_comment.go
new file mode 100644
index 000000000000..56a02ed99db4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_comment.go
@@ -0,0 +1,27 @@
+package pongo2
+
+type tagCommentNode struct{}
+
+func (node *tagCommentNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ return nil
+}
+
+func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ commentNode := &tagCommentNode{}
+
+ // TODO: Process the endtag's arguments (see django 'comment'-tag documentation)
+ err := doc.SkipUntilTag("endcomment")
+ if err != nil {
+ return nil, err
+ }
+
+ if arguments.Count() != 0 {
+ return nil, arguments.Error("Tag 'comment' does not take any argument.", nil)
+ }
+
+ return commentNode, nil
+}
+
+func init() {
+ RegisterTag("comment", tagCommentParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_cycle.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_cycle.go
new file mode 100644
index 000000000000..ffbd254eea8b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_cycle.go
@@ -0,0 +1,106 @@
+package pongo2
+
+type tagCycleValue struct {
+ node *tagCycleNode
+ value *Value
+}
+
+type tagCycleNode struct {
+ position *Token
+ args []IEvaluator
+ idx int
+ asName string
+ silent bool
+}
+
+func (cv *tagCycleValue) String() string {
+ return cv.value.String()
+}
+
+func (node *tagCycleNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ item := node.args[node.idx%len(node.args)]
+ node.idx++
+
+ val, err := item.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ if t, ok := val.Interface().(*tagCycleValue); ok {
+ // {% cycle "test1" "test2"
+ // {% cycle cycleitem %}
+
+ // Update the cycle value with next value
+ item := t.node.args[t.node.idx%len(t.node.args)]
+ t.node.idx++
+
+ val, err := item.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ t.value = val
+
+ if !t.node.silent {
+ writer.WriteString(val.String())
+ }
+ } else {
+ // Regular call
+
+ cycleValue := &tagCycleValue{
+ node: node,
+ value: val,
+ }
+
+ if node.asName != "" {
+ ctx.Private[node.asName] = cycleValue
+ }
+ if !node.silent {
+ writer.WriteString(val.String())
+ }
+ }
+
+ return nil
+}
+
+// HINT: We're not supporting the old comma-separated list of expressions argument-style
+func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ cycleNode := &tagCycleNode{
+ position: start,
+ }
+
+ for arguments.Remaining() > 0 {
+ node, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ cycleNode.args = append(cycleNode.args, node)
+
+ if arguments.MatchOne(TokenKeyword, "as") != nil {
+ // as
+
+ nameToken := arguments.MatchType(TokenIdentifier)
+ if nameToken == nil {
+ return nil, arguments.Error("Name (identifier) expected after 'as'.", nil)
+ }
+ cycleNode.asName = nameToken.Val
+
+ if arguments.MatchOne(TokenIdentifier, "silent") != nil {
+ cycleNode.silent = true
+ }
+
+ // Now we're finished
+ break
+ }
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed cycle-tag.", nil)
+ }
+
+ return cycleNode, nil
+}
+
+func init() {
+ RegisterTag("cycle", tagCycleParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_extends.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_extends.go
new file mode 100644
index 000000000000..5771020a0661
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_extends.go
@@ -0,0 +1,52 @@
+package pongo2
+
+type tagExtendsNode struct {
+ filename string
+}
+
+func (node *tagExtendsNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ return nil
+}
+
+func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ extendsNode := &tagExtendsNode{}
+
+ if doc.template.level > 1 {
+ return nil, arguments.Error("The 'extends' tag can only defined on root level.", start)
+ }
+
+ if doc.template.parent != nil {
+ // Already one parent
+ return nil, arguments.Error("This template has already one parent.", start)
+ }
+
+ if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
+ // prepared, static template
+
+ // Get parent's filename
+ parentFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
+
+ // Parse the parent
+ parentTemplate, err := doc.template.set.FromFile(parentFilename)
+ if err != nil {
+ return nil, err.(*Error)
+ }
+
+ // Keep track of things
+ parentTemplate.child = doc.template
+ doc.template.parent = parentTemplate
+ extendsNode.filename = parentFilename
+ } else {
+ return nil, arguments.Error("Tag 'extends' requires a template filename as string.", nil)
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Tag 'extends' does only take 1 argument.", nil)
+ }
+
+ return extendsNode, nil
+}
+
+func init() {
+ RegisterTag("extends", tagExtendsParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_filter.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_filter.go
new file mode 100644
index 000000000000..b38fd929821d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_filter.go
@@ -0,0 +1,95 @@
+package pongo2
+
+import (
+ "bytes"
+)
+
+type nodeFilterCall struct {
+ name string
+ paramExpr IEvaluator
+}
+
+type tagFilterNode struct {
+ position *Token
+ bodyWrapper *NodeWrapper
+ filterChain []*nodeFilterCall
+}
+
+func (node *tagFilterNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ temp := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB size
+
+ err := node.bodyWrapper.Execute(ctx, temp)
+ if err != nil {
+ return err
+ }
+
+ value := AsValue(temp.String())
+
+ for _, call := range node.filterChain {
+ var param *Value
+ if call.paramExpr != nil {
+ param, err = call.paramExpr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ } else {
+ param = AsValue(nil)
+ }
+ value, err = ApplyFilter(call.name, value, param)
+ if err != nil {
+ return ctx.Error(err.Error(), node.position)
+ }
+ }
+
+ writer.WriteString(value.String())
+
+ return nil
+}
+
+func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ filterNode := &tagFilterNode{
+ position: start,
+ }
+
+ wrapper, _, err := doc.WrapUntilTag("endfilter")
+ if err != nil {
+ return nil, err
+ }
+ filterNode.bodyWrapper = wrapper
+
+ for arguments.Remaining() > 0 {
+ filterCall := &nodeFilterCall{}
+
+ nameToken := arguments.MatchType(TokenIdentifier)
+ if nameToken == nil {
+ return nil, arguments.Error("Expected a filter name (identifier).", nil)
+ }
+ filterCall.name = nameToken.Val
+
+ if arguments.MatchOne(TokenSymbol, ":") != nil {
+ // Filter parameter
+ // NOTICE: we can't use ParseExpression() here, because it would parse the next filter "|..." as well in the argument list
+ expr, err := arguments.parseVariableOrLiteral()
+ if err != nil {
+ return nil, err
+ }
+ filterCall.paramExpr = expr
+ }
+
+ filterNode.filterChain = append(filterNode.filterChain, filterCall)
+
+ if arguments.MatchOne(TokenSymbol, "|") == nil {
+ break
+ }
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed filter-tag arguments.", nil)
+ }
+
+ return filterNode, nil
+}
+
+func init() {
+ RegisterTag("filter", tagFilterParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_firstof.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_firstof.go
new file mode 100644
index 000000000000..5b2888e2be5d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_firstof.go
@@ -0,0 +1,49 @@
+package pongo2
+
+type tagFirstofNode struct {
+ position *Token
+ args []IEvaluator
+}
+
+func (node *tagFirstofNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ for _, arg := range node.args {
+ val, err := arg.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ if val.IsTrue() {
+ if ctx.Autoescape && !arg.FilterApplied("safe") {
+ val, err = ApplyFilter("escape", val, nil)
+ if err != nil {
+ return err
+ }
+ }
+
+ writer.WriteString(val.String())
+ return nil
+ }
+ }
+
+ return nil
+}
+
+func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ firstofNode := &tagFirstofNode{
+ position: start,
+ }
+
+ for arguments.Remaining() > 0 {
+ node, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ firstofNode.args = append(firstofNode.args, node)
+ }
+
+ return firstofNode, nil
+}
+
+func init() {
+ RegisterTag("firstof", tagFirstofParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_for.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_for.go
new file mode 100644
index 000000000000..5b0b5554c83f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_for.go
@@ -0,0 +1,159 @@
+package pongo2
+
+type tagForNode struct {
+ key string
+ value string // only for maps: for key, value in map
+ objectEvaluator IEvaluator
+ reversed bool
+ sorted bool
+
+ bodyWrapper *NodeWrapper
+ emptyWrapper *NodeWrapper
+}
+
+type tagForLoopInformation struct {
+ Counter int
+ Counter0 int
+ Revcounter int
+ Revcounter0 int
+ First bool
+ Last bool
+ Parentloop *tagForLoopInformation
+}
+
+func (node *tagForNode) Execute(ctx *ExecutionContext, writer TemplateWriter) (forError *Error) {
+ // Backup forloop (as parentloop in public context), key-name and value-name
+ forCtx := NewChildExecutionContext(ctx)
+ parentloop := forCtx.Private["forloop"]
+
+ // Create loop struct
+ loopInfo := &tagForLoopInformation{
+ First: true,
+ }
+
+ // Is it a loop in a loop?
+ if parentloop != nil {
+ loopInfo.Parentloop = parentloop.(*tagForLoopInformation)
+ }
+
+ // Register loopInfo in public context
+ forCtx.Private["forloop"] = loopInfo
+
+ obj, err := node.objectEvaluator.Evaluate(forCtx)
+ if err != nil {
+ return err
+ }
+
+ obj.IterateOrder(func(idx, count int, key, value *Value) bool {
+ // There's something to iterate over (correct type and at least 1 item)
+
+ // Update loop infos and public context
+ forCtx.Private[node.key] = key
+ if value != nil {
+ forCtx.Private[node.value] = value
+ }
+ loopInfo.Counter = idx + 1
+ loopInfo.Counter0 = idx
+ if idx == 1 {
+ loopInfo.First = false
+ }
+ if idx+1 == count {
+ loopInfo.Last = true
+ }
+ loopInfo.Revcounter = count - idx // TODO: Not sure about this, have to look it up
+ loopInfo.Revcounter0 = count - (idx + 1) // TODO: Not sure about this, have to look it up
+
+ // Render elements with updated context
+ err := node.bodyWrapper.Execute(forCtx, writer)
+ if err != nil {
+ forError = err
+ return false
+ }
+ return true
+ }, func() {
+ // Nothing to iterate over (maybe wrong type or no items)
+ if node.emptyWrapper != nil {
+ err := node.emptyWrapper.Execute(forCtx, writer)
+ if err != nil {
+ forError = err
+ }
+ }
+ }, node.reversed, node.sorted)
+
+ return forError
+}
+
+func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ forNode := &tagForNode{}
+
+ // Arguments parsing
+ var valueToken *Token
+ keyToken := arguments.MatchType(TokenIdentifier)
+ if keyToken == nil {
+ return nil, arguments.Error("Expected an key identifier as first argument for 'for'-tag", nil)
+ }
+
+ if arguments.Match(TokenSymbol, ",") != nil {
+ // Value name is provided
+ valueToken = arguments.MatchType(TokenIdentifier)
+ if valueToken == nil {
+ return nil, arguments.Error("Value name must be an identifier.", nil)
+ }
+ }
+
+ if arguments.Match(TokenKeyword, "in") == nil {
+ return nil, arguments.Error("Expected keyword 'in'.", nil)
+ }
+
+ objectEvaluator, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ forNode.objectEvaluator = objectEvaluator
+ forNode.key = keyToken.Val
+ if valueToken != nil {
+ forNode.value = valueToken.Val
+ }
+
+ if arguments.MatchOne(TokenIdentifier, "reversed") != nil {
+ forNode.reversed = true
+ }
+
+ if arguments.MatchOne(TokenIdentifier, "sorted") != nil {
+ forNode.sorted = true
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed for-loop arguments.", nil)
+ }
+
+ // Body wrapping
+ wrapper, endargs, err := doc.WrapUntilTag("empty", "endfor")
+ if err != nil {
+ return nil, err
+ }
+ forNode.bodyWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+
+ if wrapper.Endtag == "empty" {
+ // if there's an else in the if-statement, we need the else-Block as well
+ wrapper, endargs, err = doc.WrapUntilTag("endfor")
+ if err != nil {
+ return nil, err
+ }
+ forNode.emptyWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+ }
+
+ return forNode, nil
+}
+
+func init() {
+ RegisterTag("for", tagForParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_if.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_if.go
new file mode 100644
index 000000000000..3eeaf3b49983
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_if.go
@@ -0,0 +1,76 @@
+package pongo2
+
+type tagIfNode struct {
+ conditions []IEvaluator
+ wrappers []*NodeWrapper
+}
+
+func (node *tagIfNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ for i, condition := range node.conditions {
+ result, err := condition.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ if result.IsTrue() {
+ return node.wrappers[i].Execute(ctx, writer)
+ }
+ // Last condition?
+ if len(node.conditions) == i+1 && len(node.wrappers) > i+1 {
+ return node.wrappers[i+1].Execute(ctx, writer)
+ }
+ }
+ return nil
+}
+
+func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ ifNode := &tagIfNode{}
+
+ // Parse first and main IF condition
+ condition, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ ifNode.conditions = append(ifNode.conditions, condition)
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("If-condition is malformed.", nil)
+ }
+
+ // Check the rest
+ for {
+ wrapper, tagArgs, err := doc.WrapUntilTag("elif", "else", "endif")
+ if err != nil {
+ return nil, err
+ }
+ ifNode.wrappers = append(ifNode.wrappers, wrapper)
+
+ if wrapper.Endtag == "elif" {
+ // elif can take a condition
+ condition, err = tagArgs.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ ifNode.conditions = append(ifNode.conditions, condition)
+
+ if tagArgs.Remaining() > 0 {
+ return nil, tagArgs.Error("Elif-condition is malformed.", nil)
+ }
+ } else {
+ if tagArgs.Count() > 0 {
+ // else/endif can't take any conditions
+ return nil, tagArgs.Error("Arguments not allowed here.", nil)
+ }
+ }
+
+ if wrapper.Endtag == "endif" {
+ break
+ }
+ }
+
+ return ifNode, nil
+}
+
+func init() {
+ RegisterTag("if", tagIfParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifchanged.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifchanged.go
new file mode 100644
index 000000000000..45296a0a3459
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifchanged.go
@@ -0,0 +1,116 @@
+package pongo2
+
+import (
+ "bytes"
+)
+
+type tagIfchangedNode struct {
+ watchedExpr []IEvaluator
+ lastValues []*Value
+ lastContent []byte
+ thenWrapper *NodeWrapper
+ elseWrapper *NodeWrapper
+}
+
+func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ if len(node.watchedExpr) == 0 {
+ // Check against own rendered body
+
+ buf := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
+ err := node.thenWrapper.Execute(ctx, buf)
+ if err != nil {
+ return err
+ }
+
+ bufBytes := buf.Bytes()
+ if !bytes.Equal(node.lastContent, bufBytes) {
+ // Rendered content changed, output it
+ writer.Write(bufBytes)
+ node.lastContent = bufBytes
+ }
+ } else {
+ nowValues := make([]*Value, 0, len(node.watchedExpr))
+ for _, expr := range node.watchedExpr {
+ val, err := expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ nowValues = append(nowValues, val)
+ }
+
+ // Compare old to new values now
+ changed := len(node.lastValues) == 0
+
+ for idx, oldVal := range node.lastValues {
+ if !oldVal.EqualValueTo(nowValues[idx]) {
+ changed = true
+ break // we can stop here because ONE value changed
+ }
+ }
+
+ node.lastValues = nowValues
+
+ if changed {
+ // Render thenWrapper
+ err := node.thenWrapper.Execute(ctx, writer)
+ if err != nil {
+ return err
+ }
+ } else {
+ // Render elseWrapper
+ err := node.elseWrapper.Execute(ctx, writer)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ ifchangedNode := &tagIfchangedNode{}
+
+ for arguments.Remaining() > 0 {
+ // Parse condition
+ expr, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ ifchangedNode.watchedExpr = append(ifchangedNode.watchedExpr, expr)
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Ifchanged-arguments are malformed.", nil)
+ }
+
+ // Wrap then/else-blocks
+ wrapper, endargs, err := doc.WrapUntilTag("else", "endifchanged")
+ if err != nil {
+ return nil, err
+ }
+ ifchangedNode.thenWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+
+ if wrapper.Endtag == "else" {
+ // if there's an else in the if-statement, we need the else-Block as well
+ wrapper, endargs, err = doc.WrapUntilTag("endifchanged")
+ if err != nil {
+ return nil, err
+ }
+ ifchangedNode.elseWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+ }
+
+ return ifchangedNode, nil
+}
+
+func init() {
+ RegisterTag("ifchanged", tagIfchangedParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifequal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifequal.go
new file mode 100644
index 000000000000..103f1c7ba6ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifequal.go
@@ -0,0 +1,78 @@
+package pongo2
+
+type tagIfEqualNode struct {
+ var1, var2 IEvaluator
+ thenWrapper *NodeWrapper
+ elseWrapper *NodeWrapper
+}
+
+func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ r1, err := node.var1.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ r2, err := node.var2.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ result := r1.EqualValueTo(r2)
+
+ if result {
+ return node.thenWrapper.Execute(ctx, writer)
+ }
+ if node.elseWrapper != nil {
+ return node.elseWrapper.Execute(ctx, writer)
+ }
+ return nil
+}
+
+func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ ifequalNode := &tagIfEqualNode{}
+
+ // Parse two expressions
+ var1, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ var2, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ ifequalNode.var1 = var1
+ ifequalNode.var2 = var2
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
+ }
+
+ // Wrap then/else-blocks
+ wrapper, endargs, err := doc.WrapUntilTag("else", "endifequal")
+ if err != nil {
+ return nil, err
+ }
+ ifequalNode.thenWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+
+ if wrapper.Endtag == "else" {
+ // if there's an else in the if-statement, we need the else-Block as well
+ wrapper, endargs, err = doc.WrapUntilTag("endifequal")
+ if err != nil {
+ return nil, err
+ }
+ ifequalNode.elseWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+ }
+
+ return ifequalNode, nil
+}
+
+func init() {
+ RegisterTag("ifequal", tagIfEqualParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifnotequal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifnotequal.go
new file mode 100644
index 000000000000..0d287d349d00
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ifnotequal.go
@@ -0,0 +1,78 @@
+package pongo2
+
+type tagIfNotEqualNode struct {
+ var1, var2 IEvaluator
+ thenWrapper *NodeWrapper
+ elseWrapper *NodeWrapper
+}
+
+func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ r1, err := node.var1.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ r2, err := node.var2.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ result := !r1.EqualValueTo(r2)
+
+ if result {
+ return node.thenWrapper.Execute(ctx, writer)
+ }
+ if node.elseWrapper != nil {
+ return node.elseWrapper.Execute(ctx, writer)
+ }
+ return nil
+}
+
+func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ ifnotequalNode := &tagIfNotEqualNode{}
+
+ // Parse two expressions
+ var1, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ var2, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ ifnotequalNode.var1 = var1
+ ifnotequalNode.var2 = var2
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
+ }
+
+ // Wrap then/else-blocks
+ wrapper, endargs, err := doc.WrapUntilTag("else", "endifnotequal")
+ if err != nil {
+ return nil, err
+ }
+ ifnotequalNode.thenWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+
+ if wrapper.Endtag == "else" {
+ // if there's an else in the if-statement, we need the else-Block as well
+ wrapper, endargs, err = doc.WrapUntilTag("endifnotequal")
+ if err != nil {
+ return nil, err
+ }
+ ifnotequalNode.elseWrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+ }
+
+ return ifnotequalNode, nil
+}
+
+func init() {
+ RegisterTag("ifnotequal", tagIfNotEqualParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_import.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_import.go
new file mode 100644
index 000000000000..7e0d6a01a51f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_import.go
@@ -0,0 +1,84 @@
+package pongo2
+
+import (
+ "fmt"
+)
+
+type tagImportNode struct {
+ position *Token
+ filename string
+ macros map[string]*tagMacroNode // alias/name -> macro instance
+}
+
+func (node *tagImportNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ for name, macro := range node.macros {
+ func(name string, macro *tagMacroNode) {
+ ctx.Private[name] = func(args ...*Value) *Value {
+ return macro.call(ctx, args...)
+ }
+ }(name, macro)
+ }
+ return nil
+}
+
+func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ importNode := &tagImportNode{
+ position: start,
+ macros: make(map[string]*tagMacroNode),
+ }
+
+ filenameToken := arguments.MatchType(TokenString)
+ if filenameToken == nil {
+ return nil, arguments.Error("Import-tag needs a filename as string.", nil)
+ }
+
+ importNode.filename = doc.template.set.resolveFilename(doc.template, filenameToken.Val)
+
+ if arguments.Remaining() == 0 {
+ return nil, arguments.Error("You must at least specify one macro to import.", nil)
+ }
+
+ // Compile the given template
+ tpl, err := doc.template.set.FromFile(importNode.filename)
+ if err != nil {
+ return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, start)
+ }
+
+ for arguments.Remaining() > 0 {
+ macroNameToken := arguments.MatchType(TokenIdentifier)
+ if macroNameToken == nil {
+ return nil, arguments.Error("Expected macro name (identifier).", nil)
+ }
+
+ asName := macroNameToken.Val
+ if arguments.Match(TokenKeyword, "as") != nil {
+ aliasToken := arguments.MatchType(TokenIdentifier)
+ if aliasToken == nil {
+ return nil, arguments.Error("Expected macro alias name (identifier).", nil)
+ }
+ asName = aliasToken.Val
+ }
+
+ macroInstance, has := tpl.exportedMacros[macroNameToken.Val]
+ if !has {
+ return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
+ importNode.filename), macroNameToken)
+ }
+
+ importNode.macros[asName] = macroInstance
+
+ if arguments.Remaining() == 0 {
+ break
+ }
+
+ if arguments.Match(TokenSymbol, ",") == nil {
+ return nil, arguments.Error("Expected ','.", nil)
+ }
+ }
+
+ return importNode, nil
+}
+
+func init() {
+ RegisterTag("import", tagImportParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_include.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_include.go
new file mode 100644
index 000000000000..6d619fdabebc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_include.go
@@ -0,0 +1,146 @@
+package pongo2
+
+type tagIncludeNode struct {
+ tpl *Template
+ filenameEvaluator IEvaluator
+ lazy bool
+ only bool
+ filename string
+ withPairs map[string]IEvaluator
+ ifExists bool
+}
+
+func (node *tagIncludeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ // Building the context for the template
+ includeCtx := make(Context)
+
+ // Fill the context with all data from the parent
+ if !node.only {
+ includeCtx.Update(ctx.Public)
+ includeCtx.Update(ctx.Private)
+ }
+
+ // Put all custom with-pairs into the context
+ for key, value := range node.withPairs {
+ val, err := value.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ includeCtx[key] = val
+ }
+
+ // Execute the template
+ if node.lazy {
+ // Evaluate the filename
+ filename, err := node.filenameEvaluator.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ if filename.String() == "" {
+ return ctx.Error("Filename for 'include'-tag evaluated to an empty string.", nil)
+ }
+
+ // Get include-filename
+ includedFilename := ctx.template.set.resolveFilename(ctx.template, filename.String())
+
+ includedTpl, err2 := ctx.template.set.FromFile(includedFilename)
+ if err2 != nil {
+ // if this is ReadFile error, and "if_exists" flag is enabled
+ if node.ifExists && err2.(*Error).Sender == "fromfile" {
+ return nil
+ }
+ return err2.(*Error)
+ }
+ err2 = includedTpl.ExecuteWriter(includeCtx, writer)
+ if err2 != nil {
+ return err2.(*Error)
+ }
+ return nil
+ }
+ // Template is already parsed with static filename
+ err := node.tpl.ExecuteWriter(includeCtx, writer)
+ if err != nil {
+ return err.(*Error)
+ }
+ return nil
+}
+
+type tagIncludeEmptyNode struct{}
+
+func (node *tagIncludeEmptyNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ return nil
+}
+
+func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ includeNode := &tagIncludeNode{
+ withPairs: make(map[string]IEvaluator),
+ }
+
+ if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
+ // prepared, static template
+
+ // "if_exists" flag
+ ifExists := arguments.Match(TokenIdentifier, "if_exists") != nil
+
+ // Get include-filename
+ includedFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
+
+ // Parse the parent
+ includeNode.filename = includedFilename
+ includedTpl, err := doc.template.set.FromFile(includedFilename)
+ if err != nil {
+ // if this is ReadFile error, and "if_exists" token presents we should create and empty node
+ if err.(*Error).Sender == "fromfile" && ifExists {
+ return &tagIncludeEmptyNode{}, nil
+ }
+ return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filenameToken)
+ }
+ includeNode.tpl = includedTpl
+ } else {
+ // No String, then the user wants to use lazy-evaluation (slower, but possible)
+ filenameEvaluator, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err.updateFromTokenIfNeeded(doc.template, filenameToken)
+ }
+ includeNode.filenameEvaluator = filenameEvaluator
+ includeNode.lazy = true
+ includeNode.ifExists = arguments.Match(TokenIdentifier, "if_exists") != nil // "if_exists" flag
+ }
+
+ // After having parsed the filename we're gonna parse the with+only options
+ if arguments.Match(TokenIdentifier, "with") != nil {
+ for arguments.Remaining() > 0 {
+ // We have at least one key=expr pair (because of starting "with")
+ keyToken := arguments.MatchType(TokenIdentifier)
+ if keyToken == nil {
+ return nil, arguments.Error("Expected an identifier", nil)
+ }
+ if arguments.Match(TokenSymbol, "=") == nil {
+ return nil, arguments.Error("Expected '='.", nil)
+ }
+ valueExpr, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err.updateFromTokenIfNeeded(doc.template, keyToken)
+ }
+
+ includeNode.withPairs[keyToken.Val] = valueExpr
+
+ // Only?
+ if arguments.Match(TokenIdentifier, "only") != nil {
+ includeNode.only = true
+ break // stop parsing arguments because it's the last option
+ }
+ }
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed 'include'-tag arguments.", nil)
+ }
+
+ return includeNode, nil
+}
+
+func init() {
+ RegisterTag("include", tagIncludeParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_lorem.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_lorem.go
new file mode 100644
index 000000000000..7794f6c126ff
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_lorem.go
@@ -0,0 +1,132 @@
+package pongo2
+
+import (
+ "fmt"
+ "math/rand"
+ "strings"
+ "time"
+)
+
+var (
+ tagLoremParagraphs = strings.Split(tagLoremText, "\n")
+ tagLoremWords = strings.Fields(tagLoremText)
+)
+
+type tagLoremNode struct {
+ position *Token
+ count int // number of paragraphs
+ method string // w = words, p = HTML paragraphs, b = plain-text (default is b)
+ random bool // does not use the default paragraph "Lorem ipsum dolor sit amet, ..."
+}
+
+func (node *tagLoremNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ switch node.method {
+ case "b":
+ if node.random {
+ for i := 0; i < node.count; i++ {
+ if i > 0 {
+ writer.WriteString("\n")
+ }
+ par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
+ writer.WriteString(par)
+ }
+ } else {
+ for i := 0; i < node.count; i++ {
+ if i > 0 {
+ writer.WriteString("\n")
+ }
+ par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
+ writer.WriteString(par)
+ }
+ }
+ case "w":
+ if node.random {
+ for i := 0; i < node.count; i++ {
+ if i > 0 {
+ writer.WriteString(" ")
+ }
+ word := tagLoremWords[rand.Intn(len(tagLoremWords))]
+ writer.WriteString(word)
+ }
+ } else {
+ for i := 0; i < node.count; i++ {
+ if i > 0 {
+ writer.WriteString(" ")
+ }
+ word := tagLoremWords[i%len(tagLoremWords)]
+ writer.WriteString(word)
+ }
+ }
+ case "p":
+ if node.random {
+ for i := 0; i < node.count; i++ {
+ if i > 0 {
+ writer.WriteString("\n")
+ }
+ writer.WriteString("")
+ par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
+ writer.WriteString(par)
+ writer.WriteString("
")
+ }
+ } else {
+ for i := 0; i < node.count; i++ {
+ if i > 0 {
+ writer.WriteString("\n")
+ }
+ writer.WriteString("")
+ par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
+ writer.WriteString(par)
+ writer.WriteString("
")
+
+ }
+ }
+ default:
+ return ctx.OrigError(fmt.Errorf("unsupported method: %s", node.method), nil)
+ }
+
+ return nil
+}
+
+func tagLoremParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ loremNode := &tagLoremNode{
+ position: start,
+ count: 1,
+ method: "b",
+ }
+
+ if countToken := arguments.MatchType(TokenNumber); countToken != nil {
+ loremNode.count = AsValue(countToken.Val).Integer()
+ }
+
+ if methodToken := arguments.MatchType(TokenIdentifier); methodToken != nil {
+ if methodToken.Val != "w" && methodToken.Val != "p" && methodToken.Val != "b" {
+ return nil, arguments.Error("lorem-method must be either 'w', 'p' or 'b'.", nil)
+ }
+
+ loremNode.method = methodToken.Val
+ }
+
+ if arguments.MatchOne(TokenIdentifier, "random") != nil {
+ loremNode.random = true
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed lorem-tag arguments.", nil)
+ }
+
+ return loremNode, nil
+}
+
+func init() {
+ rand.Seed(time.Now().Unix())
+
+ RegisterTag("lorem", tagLoremParser)
+}
+
+const tagLoremText = `Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
+Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
+At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.
+Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.`
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_macro.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_macro.go
new file mode 100644
index 000000000000..dd3e0bf48a35
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_macro.go
@@ -0,0 +1,149 @@
+package pongo2
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type tagMacroNode struct {
+ position *Token
+ name string
+ argsOrder []string
+ args map[string]IEvaluator
+ exported bool
+
+ wrapper *NodeWrapper
+}
+
+func (node *tagMacroNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ ctx.Private[node.name] = func(args ...*Value) *Value {
+ return node.call(ctx, args...)
+ }
+
+ return nil
+}
+
+func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
+ argsCtx := make(Context)
+
+ for k, v := range node.args {
+ if v == nil {
+ // User did not provided a default value
+ argsCtx[k] = nil
+ } else {
+ // Evaluate the default value
+ valueExpr, err := v.Evaluate(ctx)
+ if err != nil {
+ ctx.Logf(err.Error())
+ return AsSafeValue(err.Error())
+ }
+
+ argsCtx[k] = valueExpr
+ }
+ }
+
+ if len(args) > len(node.argsOrder) {
+ // Too many arguments, we're ignoring them and just logging into debug mode.
+ err := ctx.Error(fmt.Sprintf("Macro '%s' called with too many arguments (%d instead of %d).",
+ node.name, len(args), len(node.argsOrder)), nil).updateFromTokenIfNeeded(ctx.template, node.position)
+
+ ctx.Logf(err.Error()) // TODO: This is a workaround, because the error is not returned yet to the Execution()-methods
+ return AsSafeValue(err.Error())
+ }
+
+ // Make a context for the macro execution
+ macroCtx := NewChildExecutionContext(ctx)
+
+ // Register all arguments in the private context
+ macroCtx.Private.Update(argsCtx)
+
+ for idx, argValue := range args {
+ macroCtx.Private[node.argsOrder[idx]] = argValue.Interface()
+ }
+
+ var b bytes.Buffer
+ err := node.wrapper.Execute(macroCtx, &b)
+ if err != nil {
+ return AsSafeValue(err.updateFromTokenIfNeeded(ctx.template, node.position).Error())
+ }
+
+ return AsSafeValue(b.String())
+}
+
+func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ macroNode := &tagMacroNode{
+ position: start,
+ args: make(map[string]IEvaluator),
+ }
+
+ nameToken := arguments.MatchType(TokenIdentifier)
+ if nameToken == nil {
+ return nil, arguments.Error("Macro-tag needs at least an identifier as name.", nil)
+ }
+ macroNode.name = nameToken.Val
+
+ if arguments.MatchOne(TokenSymbol, "(") == nil {
+ return nil, arguments.Error("Expected '('.", nil)
+ }
+
+ for arguments.Match(TokenSymbol, ")") == nil {
+ argNameToken := arguments.MatchType(TokenIdentifier)
+ if argNameToken == nil {
+ return nil, arguments.Error("Expected argument name as identifier.", nil)
+ }
+ macroNode.argsOrder = append(macroNode.argsOrder, argNameToken.Val)
+
+ if arguments.Match(TokenSymbol, "=") != nil {
+ // Default expression follows
+ argDefaultExpr, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ macroNode.args[argNameToken.Val] = argDefaultExpr
+ } else {
+ // No default expression
+ macroNode.args[argNameToken.Val] = nil
+ }
+
+ if arguments.Match(TokenSymbol, ")") != nil {
+ break
+ }
+ if arguments.Match(TokenSymbol, ",") == nil {
+ return nil, arguments.Error("Expected ',' or ')'.", nil)
+ }
+ }
+
+ if arguments.Match(TokenKeyword, "export") != nil {
+ macroNode.exported = true
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed macro-tag.", nil)
+ }
+
+ // Body wrapping
+ wrapper, endargs, err := doc.WrapUntilTag("endmacro")
+ if err != nil {
+ return nil, err
+ }
+ macroNode.wrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+
+ if macroNode.exported {
+ // Now register the macro if it wants to be exported
+ _, has := doc.template.exportedMacros[macroNode.name]
+ if has {
+ return nil, doc.Error(fmt.Sprintf("another macro with name '%s' already exported", macroNode.name), start)
+ }
+ doc.template.exportedMacros[macroNode.name] = macroNode
+ }
+
+ return macroNode, nil
+}
+
+func init() {
+ RegisterTag("macro", tagMacroParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_now.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_now.go
new file mode 100644
index 000000000000..d9fa4a371134
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_now.go
@@ -0,0 +1,50 @@
+package pongo2
+
+import (
+ "time"
+)
+
+type tagNowNode struct {
+ position *Token
+ format string
+ fake bool
+}
+
+func (node *tagNowNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ var t time.Time
+ if node.fake {
+ t = time.Date(2014, time.February, 05, 18, 31, 45, 00, time.UTC)
+ } else {
+ t = time.Now()
+ }
+
+ writer.WriteString(t.Format(node.format))
+
+ return nil
+}
+
+func tagNowParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ nowNode := &tagNowNode{
+ position: start,
+ }
+
+ formatToken := arguments.MatchType(TokenString)
+ if formatToken == nil {
+ return nil, arguments.Error("Expected a format string.", nil)
+ }
+ nowNode.format = formatToken.Val
+
+ if arguments.MatchOne(TokenIdentifier, "fake") != nil {
+ nowNode.fake = true
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed now-tag arguments.", nil)
+ }
+
+ return nowNode, nil
+}
+
+func init() {
+ RegisterTag("now", tagNowParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_set.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_set.go
new file mode 100644
index 000000000000..be121c12ac4f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_set.go
@@ -0,0 +1,50 @@
+package pongo2
+
+type tagSetNode struct {
+ name string
+ expression IEvaluator
+}
+
+func (node *tagSetNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ // Evaluate expression
+ value, err := node.expression.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ ctx.Private[node.name] = value
+ return nil
+}
+
+func tagSetParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ node := &tagSetNode{}
+
+ // Parse variable name
+ typeToken := arguments.MatchType(TokenIdentifier)
+ if typeToken == nil {
+ return nil, arguments.Error("Expected an identifier.", nil)
+ }
+ node.name = typeToken.Val
+
+ if arguments.Match(TokenSymbol, "=") == nil {
+ return nil, arguments.Error("Expected '='.", nil)
+ }
+
+ // Variable expression
+ keyExpression, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ node.expression = keyExpression
+
+ // Remaining arguments
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed 'set'-tag arguments.", nil)
+ }
+
+ return node, nil
+}
+
+func init() {
+ RegisterTag("set", tagSetParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_spaceless.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_spaceless.go
new file mode 100644
index 000000000000..4fa851ba45ba
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_spaceless.go
@@ -0,0 +1,54 @@
+package pongo2
+
+import (
+ "bytes"
+ "regexp"
+)
+
+type tagSpacelessNode struct {
+ wrapper *NodeWrapper
+}
+
+var tagSpacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)
+
+func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ b := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
+
+ err := node.wrapper.Execute(ctx, b)
+ if err != nil {
+ return err
+ }
+
+ s := b.String()
+ // Repeat this recursively
+ changed := true
+ for changed {
+ s2 := tagSpacelessRegexp.ReplaceAllString(s, "$1$3")
+ changed = s != s2
+ s = s2
+ }
+
+ writer.WriteString(s)
+
+ return nil
+}
+
+func tagSpacelessParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ spacelessNode := &tagSpacelessNode{}
+
+ wrapper, _, err := doc.WrapUntilTag("endspaceless")
+ if err != nil {
+ return nil, err
+ }
+ spacelessNode.wrapper = wrapper
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed spaceless-tag arguments.", nil)
+ }
+
+ return spacelessNode, nil
+}
+
+func init() {
+ RegisterTag("spaceless", tagSpacelessParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ssi.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ssi.go
new file mode 100644
index 000000000000..c33858d5f1bd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_ssi.go
@@ -0,0 +1,68 @@
+package pongo2
+
+import (
+ "io/ioutil"
+)
+
+type tagSSINode struct {
+ filename string
+ content string
+ template *Template
+}
+
+func (node *tagSSINode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ if node.template != nil {
+ // Execute the template within the current context
+ includeCtx := make(Context)
+ includeCtx.Update(ctx.Public)
+ includeCtx.Update(ctx.Private)
+
+ err := node.template.execute(includeCtx, writer)
+ if err != nil {
+ return err.(*Error)
+ }
+ } else {
+ // Just print out the content
+ writer.WriteString(node.content)
+ }
+ return nil
+}
+
+func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ SSINode := &tagSSINode{}
+
+ if fileToken := arguments.MatchType(TokenString); fileToken != nil {
+ SSINode.filename = fileToken.Val
+
+ if arguments.Match(TokenIdentifier, "parsed") != nil {
+ // parsed
+ temporaryTpl, err := doc.template.set.FromFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
+ if err != nil {
+ return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, fileToken)
+ }
+ SSINode.template = temporaryTpl
+ } else {
+ // plaintext
+ buf, err := ioutil.ReadFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
+ if err != nil {
+ return nil, (&Error{
+ Sender: "tag:ssi",
+ OrigError: err,
+ }).updateFromTokenIfNeeded(doc.template, fileToken)
+ }
+ SSINode.content = string(buf)
+ }
+ } else {
+ return nil, arguments.Error("First argument must be a string.", nil)
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed SSI-tag argument.", nil)
+ }
+
+ return SSINode, nil
+}
+
+func init() {
+ RegisterTag("ssi", tagSSIParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_templatetag.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_templatetag.go
new file mode 100644
index 000000000000..164b4dc3d07e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_templatetag.go
@@ -0,0 +1,45 @@
+package pongo2
+
+type tagTemplateTagNode struct {
+ content string
+}
+
+var templateTagMapping = map[string]string{
+ "openblock": "{%",
+ "closeblock": "%}",
+ "openvariable": "{{",
+ "closevariable": "}}",
+ "openbrace": "{",
+ "closebrace": "}",
+ "opencomment": "{#",
+ "closecomment": "#}",
+}
+
+func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ writer.WriteString(node.content)
+ return nil
+}
+
+func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ ttNode := &tagTemplateTagNode{}
+
+ if argToken := arguments.MatchType(TokenIdentifier); argToken != nil {
+ output, found := templateTagMapping[argToken.Val]
+ if !found {
+ return nil, arguments.Error("Argument not found", argToken)
+ }
+ ttNode.content = output
+ } else {
+ return nil, arguments.Error("Identifier expected.", nil)
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed templatetag-tag argument.", nil)
+ }
+
+ return ttNode, nil
+}
+
+func init() {
+ RegisterTag("templatetag", tagTemplateTagParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_widthratio.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_widthratio.go
new file mode 100644
index 000000000000..70c9c3e8af2e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_widthratio.go
@@ -0,0 +1,83 @@
+package pongo2
+
+import (
+ "fmt"
+ "math"
+)
+
+type tagWidthratioNode struct {
+ position *Token
+ current, max IEvaluator
+ width IEvaluator
+ ctxName string
+}
+
+func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ current, err := node.current.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ max, err := node.max.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ width, err := node.width.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ value := int(math.Ceil(current.Float()/max.Float()*width.Float() + 0.5))
+
+ if node.ctxName == "" {
+ writer.WriteString(fmt.Sprintf("%d", value))
+ } else {
+ ctx.Private[node.ctxName] = value
+ }
+
+ return nil
+}
+
+func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ widthratioNode := &tagWidthratioNode{
+ position: start,
+ }
+
+ current, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ widthratioNode.current = current
+
+ max, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ widthratioNode.max = max
+
+ width, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ widthratioNode.width = width
+
+ if arguments.MatchOne(TokenKeyword, "as") != nil {
+ // Name follows
+ nameToken := arguments.MatchType(TokenIdentifier)
+ if nameToken == nil {
+ return nil, arguments.Error("Expected name (identifier).", nil)
+ }
+ widthratioNode.ctxName = nameToken.Val
+ }
+
+ if arguments.Remaining() > 0 {
+ return nil, arguments.Error("Malformed widthratio-tag arguments.", nil)
+ }
+
+ return widthratioNode, nil
+}
+
+func init() {
+ RegisterTag("widthratio", tagWidthratioParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_with.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_with.go
new file mode 100644
index 000000000000..32b3c1c42812
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/tags_with.go
@@ -0,0 +1,88 @@
+package pongo2
+
+type tagWithNode struct {
+ withPairs map[string]IEvaluator
+ wrapper *NodeWrapper
+}
+
+func (node *tagWithNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ //new context for block
+ withctx := NewChildExecutionContext(ctx)
+
+ // Put all custom with-pairs into the context
+ for key, value := range node.withPairs {
+ val, err := value.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ withctx.Private[key] = val
+ }
+
+ return node.wrapper.Execute(withctx, writer)
+}
+
+func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
+ withNode := &tagWithNode{
+ withPairs: make(map[string]IEvaluator),
+ }
+
+ if arguments.Count() == 0 {
+ return nil, arguments.Error("Tag 'with' requires at least one argument.", nil)
+ }
+
+ wrapper, endargs, err := doc.WrapUntilTag("endwith")
+ if err != nil {
+ return nil, err
+ }
+ withNode.wrapper = wrapper
+
+ if endargs.Count() > 0 {
+ return nil, endargs.Error("Arguments not allowed here.", nil)
+ }
+
+ // Scan through all arguments to see which style the user uses (old or new style).
+ // If we find any "as" keyword we will enforce old style; otherwise we will use new style.
+ oldStyle := false // by default we're using the new_style
+ for i := 0; i < arguments.Count(); i++ {
+ if arguments.PeekN(i, TokenKeyword, "as") != nil {
+ oldStyle = true
+ break
+ }
+ }
+
+ for arguments.Remaining() > 0 {
+ if oldStyle {
+ valueExpr, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ if arguments.Match(TokenKeyword, "as") == nil {
+ return nil, arguments.Error("Expected 'as' keyword.", nil)
+ }
+ keyToken := arguments.MatchType(TokenIdentifier)
+ if keyToken == nil {
+ return nil, arguments.Error("Expected an identifier", nil)
+ }
+ withNode.withPairs[keyToken.Val] = valueExpr
+ } else {
+ keyToken := arguments.MatchType(TokenIdentifier)
+ if keyToken == nil {
+ return nil, arguments.Error("Expected an identifier", nil)
+ }
+ if arguments.Match(TokenSymbol, "=") == nil {
+ return nil, arguments.Error("Expected '='.", nil)
+ }
+ valueExpr, err := arguments.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ withNode.withPairs[keyToken.Val] = valueExpr
+ }
+ }
+
+ return withNode, nil
+}
+
+func init() {
+ RegisterTag("with", tagWithParser)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template.go
new file mode 100644
index 000000000000..47666c940c91
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template.go
@@ -0,0 +1,276 @@
+package pongo2
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+)
+
+type TemplateWriter interface {
+ io.Writer
+ WriteString(string) (int, error)
+}
+
+type templateWriter struct {
+ w io.Writer
+}
+
+func (tw *templateWriter) WriteString(s string) (int, error) {
+ return tw.w.Write([]byte(s))
+}
+
+func (tw *templateWriter) Write(b []byte) (int, error) {
+ return tw.w.Write(b)
+}
+
+type Template struct {
+ set *TemplateSet
+
+ // Input
+ isTplString bool
+ name string
+ tpl string
+ size int
+
+ // Calculation
+ tokens []*Token
+ parser *Parser
+
+ // first come, first serve (it's important to not override existing entries in here)
+ level int
+ parent *Template
+ child *Template
+ blocks map[string]*NodeWrapper
+ exportedMacros map[string]*tagMacroNode
+
+ // Output
+ root *nodeDocument
+
+ // Options allow you to change the behavior of template-engine.
+ // You can change the options before calling the Execute method.
+ Options *Options
+}
+
+func newTemplateString(set *TemplateSet, tpl []byte) (*Template, error) {
+ return newTemplate(set, "", true, tpl)
+}
+
+func newTemplate(set *TemplateSet, name string, isTplString bool, tpl []byte) (*Template, error) {
+ strTpl := string(tpl)
+
+ // Create the template
+ t := &Template{
+ set: set,
+ isTplString: isTplString,
+ name: name,
+ tpl: strTpl,
+ size: len(strTpl),
+ blocks: make(map[string]*NodeWrapper),
+ exportedMacros: make(map[string]*tagMacroNode),
+ Options: newOptions(),
+ }
+ // Copy all settings from another Options.
+ t.Options.Update(set.Options)
+
+ // Tokenize it
+ tokens, err := lex(name, strTpl)
+ if err != nil {
+ return nil, err
+ }
+ t.tokens = tokens
+
+ // For debugging purposes, show all tokens:
+ /*for i, t := range tokens {
+ fmt.Printf("%3d. %s\n", i, t)
+ }*/
+
+ // Parse it
+ err = t.parse()
+ if err != nil {
+ return nil, err
+ }
+
+ return t, nil
+}
+
+func (tpl *Template) newContextForExecution(context Context) (*Template, *ExecutionContext, error) {
+ if tpl.Options.TrimBlocks || tpl.Options.LStripBlocks {
+ // Issue #94 https://github.com/flosch/pongo2/issues/94
+ // If an application configures pongo2 template to trim_blocks,
+ // the first newline after a template tag is removed automatically (like in PHP).
+ prev := &Token{
+ Typ: TokenHTML,
+ Val: "\n",
+ }
+
+ for _, t := range tpl.tokens {
+ if tpl.Options.LStripBlocks {
+ if prev.Typ == TokenHTML && t.Typ != TokenHTML && t.Val == "{%" {
+ prev.Val = strings.TrimRight(prev.Val, "\t ")
+ }
+ }
+
+ if tpl.Options.TrimBlocks {
+ if prev.Typ != TokenHTML && t.Typ == TokenHTML && prev.Val == "%}" {
+ if len(t.Val) > 0 && t.Val[0] == '\n' {
+ t.Val = t.Val[1:len(t.Val)]
+ }
+ }
+ }
+
+ prev = t
+ }
+ }
+
+ // Determine the parent to be executed (for template inheritance)
+ parent := tpl
+ for parent.parent != nil {
+ parent = parent.parent
+ }
+
+ // Create context if none is given
+ newContext := make(Context)
+ newContext.Update(tpl.set.Globals)
+
+ if context != nil {
+ newContext.Update(context)
+
+ if len(newContext) > 0 {
+ // Check for context name syntax
+ err := newContext.checkForValidIdentifiers()
+ if err != nil {
+ return parent, nil, err
+ }
+
+ // Check for clashes with macro names
+ for k := range newContext {
+ _, has := tpl.exportedMacros[k]
+ if has {
+ return parent, nil, &Error{
+ Filename: tpl.name,
+ Sender: "execution",
+ OrigError: fmt.Errorf("context key name '%s' clashes with macro '%s'", k, k),
+ }
+ }
+ }
+ }
+ }
+
+ // Create operational context
+ ctx := newExecutionContext(parent, newContext)
+
+ return parent, ctx, nil
+}
+
+func (tpl *Template) execute(context Context, writer TemplateWriter) error {
+ parent, ctx, err := tpl.newContextForExecution(context)
+ if err != nil {
+ return err
+ }
+
+ // Run the selected document
+ if err := parent.root.Execute(ctx, writer); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (tpl *Template) newTemplateWriterAndExecute(context Context, writer io.Writer) error {
+ return tpl.execute(context, &templateWriter{w: writer})
+}
+
+func (tpl *Template) newBufferAndExecute(context Context) (*bytes.Buffer, error) {
+ // Create output buffer
+ // We assume that the rendered template will be 30% larger
+ buffer := bytes.NewBuffer(make([]byte, 0, int(float64(tpl.size)*1.3)))
+ if err := tpl.execute(context, buffer); err != nil {
+ return nil, err
+ }
+ return buffer, nil
+}
+
+// Executes the template with the given context and writes to writer (io.Writer)
+// on success. Context can be nil. Nothing is written on error; instead the error
+// is being returned.
+func (tpl *Template) ExecuteWriter(context Context, writer io.Writer) error {
+ buf, err := tpl.newBufferAndExecute(context)
+ if err != nil {
+ return err
+ }
+ _, err = buf.WriteTo(writer)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// Same as ExecuteWriter. The only difference between both functions is that
+// this function might already have written parts of the generated template in the
+// case of an execution error because there's no intermediate buffer involved for
+// performance reasons. This is handy if you need high performance template
+// generation or if you want to manage your own pool of buffers.
+func (tpl *Template) ExecuteWriterUnbuffered(context Context, writer io.Writer) error {
+ return tpl.newTemplateWriterAndExecute(context, writer)
+}
+
+// Executes the template and returns the rendered template as a []byte
+func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
+ // Execute template
+ buffer, err := tpl.newBufferAndExecute(context)
+ if err != nil {
+ return nil, err
+ }
+ return buffer.Bytes(), nil
+}
+
+// Executes the template and returns the rendered template as a string
+func (tpl *Template) Execute(context Context) (string, error) {
+ // Execute template
+ buffer, err := tpl.newBufferAndExecute(context)
+ if err != nil {
+ return "", err
+ }
+
+ return buffer.String(), nil
+
+}
+
+func (tpl *Template) ExecuteBlocks(context Context, blocks []string) (map[string]string, error) {
+ var parents []*Template
+ result := make(map[string]string)
+
+ parent := tpl
+ for parent != nil {
+ parents = append(parents, parent)
+ parent = parent.parent
+ }
+
+ for _, t := range parents {
+ buffer := bytes.NewBuffer(make([]byte, 0, int(float64(t.size)*1.3)))
+ _, ctx, err := t.newContextForExecution(context)
+ if err != nil {
+ return nil, err
+ }
+ for _, blockName := range blocks {
+ if _, ok := result[blockName]; ok {
+ continue
+ }
+ if blockWrapper, ok := t.blocks[blockName]; ok {
+ bErr := blockWrapper.Execute(ctx, buffer)
+ if bErr != nil {
+ return nil, bErr
+ }
+ result[blockName] = buffer.String()
+ buffer.Reset()
+ }
+ }
+ // We have found all blocks
+ if len(blocks) == len(result) {
+ break
+ }
+ }
+
+ return result, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template_loader.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template_loader.go
new file mode 100644
index 000000000000..303d55e685eb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template_loader.go
@@ -0,0 +1,213 @@
+package pongo2
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+)
+
+// LocalFilesystemLoader represents a local filesystem loader with basic
+// BaseDirectory capabilities. The access to the local filesystem is unrestricted.
+type LocalFilesystemLoader struct {
+ baseDir string
+}
+
+// MustNewLocalFileSystemLoader creates a new LocalFilesystemLoader instance
+// and panics if there's any error during instantiation. The parameters
+// are the same like NewLocalFileSystemLoader.
+func MustNewLocalFileSystemLoader(baseDir string) *LocalFilesystemLoader {
+ fs, err := NewLocalFileSystemLoader(baseDir)
+ if err != nil {
+ log.Panic(err)
+ }
+ return fs
+}
+
+// NewLocalFileSystemLoader creates a new LocalFilesystemLoader and allows
+// templatesto be loaded from disk (unrestricted). If any base directory
+// is given (or being set using SetBaseDir), this base directory is being used
+// for path calculation in template inclusions/imports. Otherwise the path
+// is calculated based relatively to the including template's path.
+func NewLocalFileSystemLoader(baseDir string) (*LocalFilesystemLoader, error) {
+ fs := &LocalFilesystemLoader{}
+ if baseDir != "" {
+ if err := fs.SetBaseDir(baseDir); err != nil {
+ return nil, err
+ }
+ }
+ return fs, nil
+}
+
+// SetBaseDir sets the template's base directory. This directory will
+// be used for any relative path in filters, tags and From*-functions to determine
+// your template. See the comment for NewLocalFileSystemLoader as well.
+func (fs *LocalFilesystemLoader) SetBaseDir(path string) error {
+ // Make the path absolute
+ if !filepath.IsAbs(path) {
+ abs, err := filepath.Abs(path)
+ if err != nil {
+ return err
+ }
+ path = abs
+ }
+
+ // Check for existence
+ fi, err := os.Stat(path)
+ if err != nil {
+ return err
+ }
+ if !fi.IsDir() {
+ return fmt.Errorf("The given path '%s' is not a directory.", path)
+ }
+
+ fs.baseDir = path
+ return nil
+}
+
+// Get reads the path's content from your local filesystem.
+func (fs *LocalFilesystemLoader) Get(path string) (io.Reader, error) {
+ buf, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+ return bytes.NewReader(buf), nil
+}
+
+// Abs resolves a filename relative to the base directory. Absolute paths are allowed.
+// When there's no base dir set, the absolute path to the filename
+// will be calculated based on either the provided base directory (which
+// might be a path of a template which includes another template) or
+// the current working directory.
+func (fs *LocalFilesystemLoader) Abs(base, name string) string {
+ if filepath.IsAbs(name) {
+ return name
+ }
+
+ // Our own base dir has always priority; if there's none
+ // we use the path provided in base.
+ var err error
+ if fs.baseDir == "" {
+ if base == "" {
+ base, err = os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+ return filepath.Join(base, name)
+ }
+
+ return filepath.Join(filepath.Dir(base), name)
+ }
+
+ return filepath.Join(fs.baseDir, name)
+}
+
+// SandboxedFilesystemLoader is still WIP.
+type SandboxedFilesystemLoader struct {
+ *LocalFilesystemLoader
+}
+
+// NewSandboxedFilesystemLoader creates a new sandboxed local file system instance.
+func NewSandboxedFilesystemLoader(baseDir string) (*SandboxedFilesystemLoader, error) {
+ fs, err := NewLocalFileSystemLoader(baseDir)
+ if err != nil {
+ return nil, err
+ }
+ return &SandboxedFilesystemLoader{
+ LocalFilesystemLoader: fs,
+ }, nil
+}
+
+// Move sandbox to a virtual fs
+
+/*
+if len(set.SandboxDirectories) > 0 {
+ defer func() {
+ // Remove any ".." or other crap
+ resolvedPath = filepath.Clean(resolvedPath)
+
+ // Make the path absolute
+ absPath, err := filepath.Abs(resolvedPath)
+ if err != nil {
+ panic(err)
+ }
+ resolvedPath = absPath
+
+ // Check against the sandbox directories (once one pattern matches, we're done and can allow it)
+ for _, pattern := range set.SandboxDirectories {
+ matched, err := filepath.Match(pattern, resolvedPath)
+ if err != nil {
+ panic("Wrong sandbox directory match pattern (see http://golang.org/pkg/path/filepath/#Match).")
+ }
+ if matched {
+ // OK!
+ return
+ }
+ }
+
+ // No pattern matched, we have to log+deny the request
+ set.logf("Access attempt outside of the sandbox directories (blocked): '%s'", resolvedPath)
+ resolvedPath = ""
+ }()
+}
+*/
+
+// HttpFilesystemLoader supports loading templates
+// from an http.FileSystem - useful for using one of several
+// file-to-code generators that packs static files into
+// a go binary (ex: https://github.com/jteeuwen/go-bindata)
+type HttpFilesystemLoader struct {
+ fs http.FileSystem
+ baseDir string
+}
+
+// MustNewHttpFileSystemLoader creates a new HttpFilesystemLoader instance
+// and panics if there's any error during instantiation. The parameters
+// are the same like NewHttpFilesystemLoader.
+func MustNewHttpFileSystemLoader(httpfs http.FileSystem, baseDir string) *HttpFilesystemLoader {
+ fs, err := NewHttpFileSystemLoader(httpfs, baseDir)
+ if err != nil {
+ log.Panic(err)
+ }
+ return fs
+}
+
+// NewHttpFileSystemLoader creates a new HttpFileSystemLoader and allows
+// templates to be loaded from the virtual filesystem. The path
+// is calculated based relatively from the root of the http.Filesystem.
+func NewHttpFileSystemLoader(httpfs http.FileSystem, baseDir string) (*HttpFilesystemLoader, error) {
+ hfs := &HttpFilesystemLoader{
+ fs: httpfs,
+ baseDir: baseDir,
+ }
+ if httpfs == nil {
+ err := errors.New("httpfs cannot be nil")
+ return nil, err
+ }
+ return hfs, nil
+}
+
+// Abs in this instance simply returns the filename, since
+// there's no potential for an unexpanded path in an http.FileSystem
+func (h *HttpFilesystemLoader) Abs(base, name string) string {
+ return name
+}
+
+// Get returns an io.Reader where the template's content can be read from.
+func (h *HttpFilesystemLoader) Get(path string) (io.Reader, error) {
+ fullPath := path
+ if h.baseDir != "" {
+ fullPath = fmt.Sprintf(
+ "%s/%s",
+ h.baseDir,
+ fullPath,
+ )
+ }
+
+ return h.fs.Open(fullPath)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template_sets.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template_sets.go
new file mode 100644
index 000000000000..4b1e43da1930
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/template_sets.go
@@ -0,0 +1,305 @@
+package pongo2
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "sync"
+
+ "errors"
+)
+
+// TemplateLoader allows to implement a virtual file system.
+type TemplateLoader interface {
+ // Abs calculates the path to a given template. Whenever a path must be resolved
+ // due to an import from another template, the base equals the parent template's path.
+ Abs(base, name string) string
+
+ // Get returns an io.Reader where the template's content can be read from.
+ Get(path string) (io.Reader, error)
+}
+
+// TemplateSet allows you to create your own group of templates with their own
+// global context (which is shared among all members of the set) and their own
+// configuration.
+// It's useful for a separation of different kind of templates
+// (e. g. web templates vs. mail templates).
+type TemplateSet struct {
+ name string
+ loaders []TemplateLoader
+
+ // Globals will be provided to all templates created within this template set
+ Globals Context
+
+ // If debug is true (default false), ExecutionContext.Logf() will work and output
+ // to STDOUT. Furthermore, FromCache() won't cache the templates.
+ // Make sure to synchronize the access to it in case you're changing this
+ // variable during program execution (and template compilation/execution).
+ Debug bool
+
+ // Options allow you to change the behavior of template-engine.
+ // You can change the options before calling the Execute method.
+ Options *Options
+
+ // Sandbox features
+ // - Disallow access to specific tags and/or filters (using BanTag() and BanFilter())
+ //
+ // For efficiency reasons you can ban tags/filters only *before* you have
+ // added your first template to the set (restrictions are statically checked).
+ // After you added one, it's not possible anymore (for your personal security).
+ firstTemplateCreated bool
+ bannedTags map[string]bool
+ bannedFilters map[string]bool
+
+ // Template cache (for FromCache())
+ templateCache map[string]*Template
+ templateCacheMutex sync.Mutex
+}
+
+// NewSet can be used to create sets with different kind of templates
+// (e. g. web from mail templates), with different globals or
+// other configurations.
+func NewSet(name string, loaders ...TemplateLoader) *TemplateSet {
+ if len(loaders) == 0 {
+ panic(fmt.Errorf("at least one template loader must be specified"))
+ }
+
+ return &TemplateSet{
+ name: name,
+ loaders: loaders,
+ Globals: make(Context),
+ bannedTags: make(map[string]bool),
+ bannedFilters: make(map[string]bool),
+ templateCache: make(map[string]*Template),
+ Options: newOptions(),
+ }
+}
+
+func (set *TemplateSet) AddLoader(loaders ...TemplateLoader) {
+ set.loaders = append(set.loaders, loaders...)
+}
+
+func (set *TemplateSet) resolveFilename(tpl *Template, path string) string {
+ return set.resolveFilenameForLoader(set.loaders[0], tpl, path)
+}
+
+func (set *TemplateSet) resolveFilenameForLoader(loader TemplateLoader, tpl *Template, path string) string {
+ name := ""
+ if tpl != nil && tpl.isTplString {
+ return path
+ }
+ if tpl != nil {
+ name = tpl.name
+ }
+
+ return loader.Abs(name, path)
+}
+
+// BanTag bans a specific tag for this template set. See more in the documentation for TemplateSet.
+func (set *TemplateSet) BanTag(name string) error {
+ _, has := tags[name]
+ if !has {
+ return fmt.Errorf("tag '%s' not found", name)
+ }
+ if set.firstTemplateCreated {
+ return errors.New("you cannot ban any tags after you've added your first template to your template set")
+ }
+ _, has = set.bannedTags[name]
+ if has {
+ return fmt.Errorf("tag '%s' is already banned", name)
+ }
+ set.bannedTags[name] = true
+
+ return nil
+}
+
+// BanFilter bans a specific filter for this template set. See more in the documentation for TemplateSet.
+func (set *TemplateSet) BanFilter(name string) error {
+ _, has := filters[name]
+ if !has {
+ return fmt.Errorf("filter '%s' not found", name)
+ }
+ if set.firstTemplateCreated {
+ return errors.New("you cannot ban any filters after you've added your first template to your template set")
+ }
+ _, has = set.bannedFilters[name]
+ if has {
+ return fmt.Errorf("filter '%s' is already banned", name)
+ }
+ set.bannedFilters[name] = true
+
+ return nil
+}
+
+func (set *TemplateSet) resolveTemplate(tpl *Template, path string) (name string, loader TemplateLoader, fd io.Reader, err error) {
+ // iterate over loaders until we appear to have a valid template
+ for _, loader = range set.loaders {
+ name = set.resolveFilenameForLoader(loader, tpl, path)
+ fd, err = loader.Get(name)
+ if err == nil {
+ return
+ }
+ }
+
+ return path, nil, nil, fmt.Errorf("unable to resolve template")
+}
+
+// CleanCache cleans the template cache. If filenames is not empty,
+// it will remove the template caches of those filenames.
+// Or it will empty the whole template cache. It is thread-safe.
+func (set *TemplateSet) CleanCache(filenames ...string) {
+ set.templateCacheMutex.Lock()
+ defer set.templateCacheMutex.Unlock()
+
+ if len(filenames) == 0 {
+ set.templateCache = make(map[string]*Template, len(set.templateCache))
+ }
+
+ for _, filename := range filenames {
+ delete(set.templateCache, set.resolveFilename(nil, filename))
+ }
+}
+
+// FromCache is a convenient method to cache templates. It is thread-safe
+// and will only compile the template associated with a filename once.
+// If TemplateSet.Debug is true (for example during development phase),
+// FromCache() will not cache the template and instead recompile it on any
+// call (to make changes to a template live instantaneously).
+func (set *TemplateSet) FromCache(filename string) (*Template, error) {
+ if set.Debug {
+ // Recompile on any request
+ return set.FromFile(filename)
+ }
+ // Cache the template
+ cleanedFilename := set.resolveFilename(nil, filename)
+
+ set.templateCacheMutex.Lock()
+ defer set.templateCacheMutex.Unlock()
+
+ tpl, has := set.templateCache[cleanedFilename]
+
+ // Cache miss
+ if !has {
+ tpl, err := set.FromFile(cleanedFilename)
+ if err != nil {
+ return nil, err
+ }
+ set.templateCache[cleanedFilename] = tpl
+ return tpl, nil
+ }
+
+ // Cache hit
+ return tpl, nil
+}
+
+// FromString loads a template from string and returns a Template instance.
+func (set *TemplateSet) FromString(tpl string) (*Template, error) {
+ set.firstTemplateCreated = true
+
+ return newTemplateString(set, []byte(tpl))
+}
+
+// FromBytes loads a template from bytes and returns a Template instance.
+func (set *TemplateSet) FromBytes(tpl []byte) (*Template, error) {
+ set.firstTemplateCreated = true
+
+ return newTemplateString(set, tpl)
+}
+
+// FromFile loads a template from a filename and returns a Template instance.
+func (set *TemplateSet) FromFile(filename string) (*Template, error) {
+ set.firstTemplateCreated = true
+
+ _, _, fd, err := set.resolveTemplate(nil, filename)
+ if err != nil {
+ return nil, &Error{
+ Filename: filename,
+ Sender: "fromfile",
+ OrigError: err,
+ }
+ }
+ buf, err := ioutil.ReadAll(fd)
+ if err != nil {
+ return nil, &Error{
+ Filename: filename,
+ Sender: "fromfile",
+ OrigError: err,
+ }
+ }
+
+ return newTemplate(set, filename, false, buf)
+}
+
+// RenderTemplateString is a shortcut and renders a template string directly.
+func (set *TemplateSet) RenderTemplateString(s string, ctx Context) (string, error) {
+ set.firstTemplateCreated = true
+
+ tpl := Must(set.FromString(s))
+ result, err := tpl.Execute(ctx)
+ if err != nil {
+ return "", err
+ }
+ return result, nil
+}
+
+// RenderTemplateBytes is a shortcut and renders template bytes directly.
+func (set *TemplateSet) RenderTemplateBytes(b []byte, ctx Context) (string, error) {
+ set.firstTemplateCreated = true
+
+ tpl := Must(set.FromBytes(b))
+ result, err := tpl.Execute(ctx)
+ if err != nil {
+ return "", err
+ }
+ return result, nil
+}
+
+// RenderTemplateFile is a shortcut and renders a template file directly.
+func (set *TemplateSet) RenderTemplateFile(fn string, ctx Context) (string, error) {
+ set.firstTemplateCreated = true
+
+ tpl := Must(set.FromFile(fn))
+ result, err := tpl.Execute(ctx)
+ if err != nil {
+ return "", err
+ }
+ return result, nil
+}
+
+func (set *TemplateSet) logf(format string, args ...interface{}) {
+ if set.Debug {
+ logger.Printf(fmt.Sprintf("[template set: %s] %s", set.name, format), args...)
+ }
+}
+
+// Logging function (internally used)
+func logf(format string, items ...interface{}) {
+ if debug {
+ logger.Printf(format, items...)
+ }
+}
+
+var (
+ debug bool // internal debugging
+ logger = log.New(os.Stdout, "[pongo2] ", log.LstdFlags|log.Lshortfile)
+
+ // DefaultLoader allows the default un-sandboxed access to the local file
+ // system and is being used by the DefaultSet.
+ DefaultLoader = MustNewLocalFileSystemLoader("")
+
+ // DefaultSet is a set created for you for convinience reasons.
+ DefaultSet = NewSet("default", DefaultLoader)
+
+ // Methods on the default set
+ FromString = DefaultSet.FromString
+ FromBytes = DefaultSet.FromBytes
+ FromFile = DefaultSet.FromFile
+ FromCache = DefaultSet.FromCache
+ RenderTemplateString = DefaultSet.RenderTemplateString
+ RenderTemplateFile = DefaultSet.RenderTemplateFile
+
+ // Globals for the default set
+ Globals = DefaultSet.Globals
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/value.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/value.go
new file mode 100644
index 000000000000..d51d81450436
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/value.go
@@ -0,0 +1,540 @@
+package pongo2
+
+import (
+ "fmt"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type Value struct {
+ val reflect.Value
+ safe bool // used to indicate whether a Value needs explicit escaping in the template
+}
+
+// AsValue converts any given value to a pongo2.Value
+// Usually being used within own functions passed to a template
+// through a Context or within filter functions.
+//
+// Example:
+// AsValue("my string")
+func AsValue(i interface{}) *Value {
+ return &Value{
+ val: reflect.ValueOf(i),
+ }
+}
+
+// AsSafeValue works like AsValue, but does not apply the 'escape' filter.
+func AsSafeValue(i interface{}) *Value {
+ return &Value{
+ val: reflect.ValueOf(i),
+ safe: true,
+ }
+}
+
+func (v *Value) getResolvedValue() reflect.Value {
+ if v.val.IsValid() && v.val.Kind() == reflect.Ptr {
+ return v.val.Elem()
+ }
+ return v.val
+}
+
+// IsString checks whether the underlying value is a string
+func (v *Value) IsString() bool {
+ return v.getResolvedValue().Kind() == reflect.String
+}
+
+// IsBool checks whether the underlying value is a bool
+func (v *Value) IsBool() bool {
+ return v.getResolvedValue().Kind() == reflect.Bool
+}
+
+// IsFloat checks whether the underlying value is a float
+func (v *Value) IsFloat() bool {
+ return v.getResolvedValue().Kind() == reflect.Float32 ||
+ v.getResolvedValue().Kind() == reflect.Float64
+}
+
+// IsInteger checks whether the underlying value is an integer
+func (v *Value) IsInteger() bool {
+ return v.getResolvedValue().Kind() == reflect.Int ||
+ v.getResolvedValue().Kind() == reflect.Int8 ||
+ v.getResolvedValue().Kind() == reflect.Int16 ||
+ v.getResolvedValue().Kind() == reflect.Int32 ||
+ v.getResolvedValue().Kind() == reflect.Int64 ||
+ v.getResolvedValue().Kind() == reflect.Uint ||
+ v.getResolvedValue().Kind() == reflect.Uint8 ||
+ v.getResolvedValue().Kind() == reflect.Uint16 ||
+ v.getResolvedValue().Kind() == reflect.Uint32 ||
+ v.getResolvedValue().Kind() == reflect.Uint64
+}
+
+// IsNumber checks whether the underlying value is either an integer
+// or a float.
+func (v *Value) IsNumber() bool {
+ return v.IsInteger() || v.IsFloat()
+}
+
+// IsTime checks whether the underlying value is a time.Time.
+func (v *Value) IsTime() bool {
+ _, ok := v.Interface().(time.Time)
+ return ok
+}
+
+// IsNil checks whether the underlying value is NIL
+func (v *Value) IsNil() bool {
+ //fmt.Printf("%+v\n", v.getResolvedValue().Type().String())
+ return !v.getResolvedValue().IsValid()
+}
+
+// String returns a string for the underlying value. If this value is not
+// of type string, pongo2 tries to convert it. Currently the following
+// types for underlying values are supported:
+//
+// 1. string
+// 2. int/uint (any size)
+// 3. float (any precision)
+// 4. bool
+// 5. time.Time
+// 6. String() will be called on the underlying value if provided
+//
+// NIL values will lead to an empty string. Unsupported types are leading
+// to their respective type name.
+func (v *Value) String() string {
+ if v.IsNil() {
+ return ""
+ }
+
+ switch v.getResolvedValue().Kind() {
+ case reflect.String:
+ return v.getResolvedValue().String()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(v.getResolvedValue().Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.FormatUint(v.getResolvedValue().Uint(), 10)
+ case reflect.Float32, reflect.Float64:
+ return fmt.Sprintf("%f", v.getResolvedValue().Float())
+ case reflect.Bool:
+ if v.Bool() {
+ return "True"
+ }
+ return "False"
+ case reflect.Struct:
+ if t, ok := v.Interface().(fmt.Stringer); ok {
+ return t.String()
+ }
+ }
+
+ logf("Value.String() not implemented for type: %s\n", v.getResolvedValue().Kind().String())
+ return v.getResolvedValue().String()
+}
+
+// Integer returns the underlying value as an integer (converts the underlying
+// value, if necessary). If it's not possible to convert the underlying value,
+// it will return 0.
+func (v *Value) Integer() int {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return int(v.getResolvedValue().Int())
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return int(v.getResolvedValue().Uint())
+ case reflect.Float32, reflect.Float64:
+ return int(v.getResolvedValue().Float())
+ case reflect.String:
+ // Try to convert from string to int (base 10)
+ f, err := strconv.ParseFloat(v.getResolvedValue().String(), 64)
+ if err != nil {
+ return 0
+ }
+ return int(f)
+ default:
+ logf("Value.Integer() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return 0
+ }
+}
+
+// Float returns the underlying value as a float (converts the underlying
+// value, if necessary). If it's not possible to convert the underlying value,
+// it will return 0.0.
+func (v *Value) Float() float64 {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return float64(v.getResolvedValue().Int())
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return float64(v.getResolvedValue().Uint())
+ case reflect.Float32, reflect.Float64:
+ return v.getResolvedValue().Float()
+ case reflect.String:
+ // Try to convert from string to float64 (base 10)
+ f, err := strconv.ParseFloat(v.getResolvedValue().String(), 64)
+ if err != nil {
+ return 0.0
+ }
+ return f
+ default:
+ logf("Value.Float() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return 0.0
+ }
+}
+
+// Bool returns the underlying value as bool. If the value is not bool, false
+// will always be returned. If you're looking for true/false-evaluation of the
+// underlying value, have a look on the IsTrue()-function.
+func (v *Value) Bool() bool {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Bool:
+ return v.getResolvedValue().Bool()
+ default:
+ logf("Value.Bool() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return false
+ }
+}
+
+// Time returns the underlying value as time.Time.
+// If the underlying value is not a time.Time, it returns the zero value of time.Time.
+func (v *Value) Time() time.Time {
+ tm, ok := v.Interface().(time.Time)
+ if ok {
+ return tm
+ }
+ return time.Time{}
+}
+
+// IsTrue tries to evaluate the underlying value the Pythonic-way:
+//
+// Returns TRUE in one the following cases:
+//
+// * int != 0
+// * uint != 0
+// * float != 0.0
+// * len(array/chan/map/slice/string) > 0
+// * bool == true
+// * underlying value is a struct
+//
+// Otherwise returns always FALSE.
+func (v *Value) IsTrue() bool {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.getResolvedValue().Int() != 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return v.getResolvedValue().Uint() != 0
+ case reflect.Float32, reflect.Float64:
+ return v.getResolvedValue().Float() != 0
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
+ return v.getResolvedValue().Len() > 0
+ case reflect.Bool:
+ return v.getResolvedValue().Bool()
+ case reflect.Struct:
+ return true // struct instance is always true
+ default:
+ logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return false
+ }
+}
+
+// Negate tries to negate the underlying value. It's mainly used for
+// the NOT-operator and in conjunction with a call to
+// return_value.IsTrue() afterwards.
+//
+// Example:
+// AsValue(1).Negate().IsTrue() == false
+func (v *Value) Negate() *Value {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if v.Integer() != 0 {
+ return AsValue(0)
+ }
+ return AsValue(1)
+ case reflect.Float32, reflect.Float64:
+ if v.Float() != 0.0 {
+ return AsValue(float64(0.0))
+ }
+ return AsValue(float64(1.1))
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
+ return AsValue(v.getResolvedValue().Len() == 0)
+ case reflect.Bool:
+ return AsValue(!v.getResolvedValue().Bool())
+ case reflect.Struct:
+ return AsValue(false)
+ default:
+ logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return AsValue(true)
+ }
+}
+
+// Len returns the length for an array, chan, map, slice or string.
+// Otherwise it will return 0.
+func (v *Value) Len() int {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+ return v.getResolvedValue().Len()
+ case reflect.String:
+ runes := []rune(v.getResolvedValue().String())
+ return len(runes)
+ default:
+ logf("Value.Len() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return 0
+ }
+}
+
+// Slice slices an array, slice or string. Otherwise it will
+// return an empty []int.
+func (v *Value) Slice(i, j int) *Value {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Array, reflect.Slice:
+ return AsValue(v.getResolvedValue().Slice(i, j).Interface())
+ case reflect.String:
+ runes := []rune(v.getResolvedValue().String())
+ return AsValue(string(runes[i:j]))
+ default:
+ logf("Value.Slice() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return AsValue([]int{})
+ }
+}
+
+// Index gets the i-th item of an array, slice or string. Otherwise
+// it will return NIL.
+func (v *Value) Index(i int) *Value {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Array, reflect.Slice:
+ if i >= v.Len() {
+ return AsValue(nil)
+ }
+ return AsValue(v.getResolvedValue().Index(i).Interface())
+ case reflect.String:
+ //return AsValue(v.getResolvedValue().Slice(i, i+1).Interface())
+ s := v.getResolvedValue().String()
+ runes := []rune(s)
+ if i < len(runes) {
+ return AsValue(string(runes[i]))
+ }
+ return AsValue("")
+ default:
+ logf("Value.Slice() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return AsValue([]int{})
+ }
+}
+
+// Contains checks whether the underlying value (which must be of type struct, map,
+// string, array or slice) contains of another Value (e. g. used to check
+// whether a struct contains of a specific field or a map contains a specific key).
+//
+// Example:
+// AsValue("Hello, World!").Contains(AsValue("World")) == true
+func (v *Value) Contains(other *Value) bool {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Struct:
+ fieldValue := v.getResolvedValue().FieldByName(other.String())
+ return fieldValue.IsValid()
+ case reflect.Map:
+ var mapValue reflect.Value
+ switch other.Interface().(type) {
+ case int:
+ mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
+ case string:
+ mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
+ default:
+ logf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
+ return false
+ }
+
+ return mapValue.IsValid()
+ case reflect.String:
+ return strings.Contains(v.getResolvedValue().String(), other.String())
+
+ case reflect.Slice, reflect.Array:
+ for i := 0; i < v.getResolvedValue().Len(); i++ {
+ item := v.getResolvedValue().Index(i)
+ if other.EqualValueTo(AsValue(item.Interface())) {
+ return true
+ }
+ }
+ return false
+
+ default:
+ logf("Value.Contains() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ return false
+ }
+}
+
+// CanSlice checks whether the underlying value is of type array, slice or string.
+// You normally would use CanSlice() before using the Slice() operation.
+func (v *Value) CanSlice() bool {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Array, reflect.Slice, reflect.String:
+ return true
+ }
+ return false
+}
+
+// Iterate iterates over a map, array, slice or a string. It calls the
+// function's first argument for every value with the following arguments:
+//
+// idx current 0-index
+// count total amount of items
+// key *Value for the key or item
+// value *Value (only for maps, the respective value for a specific key)
+//
+// If the underlying value has no items or is not one of the types above,
+// the empty function (function's second argument) will be called.
+func (v *Value) Iterate(fn func(idx, count int, key, value *Value) bool, empty func()) {
+ v.IterateOrder(fn, empty, false, false)
+}
+
+// IterateOrder behaves like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
+// not affect the iteration through a map because maps don't have any particular order.
+// However, you can force an order using the `sorted` keyword (and even use `reversed sorted`).
+func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool, sorted bool) {
+ switch v.getResolvedValue().Kind() {
+ case reflect.Map:
+ keys := sortedKeys(v.getResolvedValue().MapKeys())
+ if sorted {
+ if reverse {
+ sort.Sort(sort.Reverse(keys))
+ } else {
+ sort.Sort(keys)
+ }
+ }
+ keyLen := len(keys)
+ for idx, key := range keys {
+ value := v.getResolvedValue().MapIndex(key)
+ if !fn(idx, keyLen, &Value{val: key}, &Value{val: value}) {
+ return
+ }
+ }
+ if keyLen == 0 {
+ empty()
+ }
+ return // done
+ case reflect.Array, reflect.Slice:
+ var items valuesList
+
+ itemCount := v.getResolvedValue().Len()
+ for i := 0; i < itemCount; i++ {
+ items = append(items, &Value{val: v.getResolvedValue().Index(i)})
+ }
+
+ if sorted {
+ if reverse {
+ sort.Sort(sort.Reverse(items))
+ } else {
+ sort.Sort(items)
+ }
+ } else {
+ if reverse {
+ for i := 0; i < itemCount/2; i++ {
+ items[i], items[itemCount-1-i] = items[itemCount-1-i], items[i]
+ }
+ }
+ }
+
+ if len(items) > 0 {
+ for idx, item := range items {
+ if !fn(idx, itemCount, item, nil) {
+ return
+ }
+ }
+ } else {
+ empty()
+ }
+ return // done
+ case reflect.String:
+ if sorted {
+ // TODO(flosch): Handle sorted
+ panic("TODO: handle sort for type string")
+ }
+
+ // TODO(flosch): Not utf8-compatible (utf8-decoding necessary)
+ charCount := v.getResolvedValue().Len()
+ if charCount > 0 {
+ if reverse {
+ for i := charCount - 1; i >= 0; i-- {
+ if !fn(i, charCount, &Value{val: v.getResolvedValue().Slice(i, i+1)}, nil) {
+ return
+ }
+ }
+ } else {
+ for i := 0; i < charCount; i++ {
+ if !fn(i, charCount, &Value{val: v.getResolvedValue().Slice(i, i+1)}, nil) {
+ return
+ }
+ }
+ }
+ } else {
+ empty()
+ }
+ return // done
+ default:
+ logf("Value.Iterate() not available for type: %s\n", v.getResolvedValue().Kind().String())
+ }
+ empty()
+}
+
+// Interface gives you access to the underlying value.
+func (v *Value) Interface() interface{} {
+ if v.val.IsValid() {
+ return v.val.Interface()
+ }
+ return nil
+}
+
+// EqualValueTo checks whether two values are containing the same value or object.
+func (v *Value) EqualValueTo(other *Value) bool {
+ // comparison of uint with int fails using .Interface()-comparison (see issue #64)
+ if v.IsInteger() && other.IsInteger() {
+ return v.Integer() == other.Integer()
+ }
+ if v.IsTime() && other.IsTime() {
+ return v.Time().Equal(other.Time())
+ }
+ return v.Interface() == other.Interface()
+}
+
+type sortedKeys []reflect.Value
+
+func (sk sortedKeys) Len() int {
+ return len(sk)
+}
+
+func (sk sortedKeys) Less(i, j int) bool {
+ vi := &Value{val: sk[i]}
+ vj := &Value{val: sk[j]}
+ switch {
+ case vi.IsInteger() && vj.IsInteger():
+ return vi.Integer() < vj.Integer()
+ case vi.IsFloat() && vj.IsFloat():
+ return vi.Float() < vj.Float()
+ default:
+ return vi.String() < vj.String()
+ }
+}
+
+func (sk sortedKeys) Swap(i, j int) {
+ sk[i], sk[j] = sk[j], sk[i]
+}
+
+type valuesList []*Value
+
+func (vl valuesList) Len() int {
+ return len(vl)
+}
+
+func (vl valuesList) Less(i, j int) bool {
+ vi := vl[i]
+ vj := vl[j]
+ switch {
+ case vi.IsInteger() && vj.IsInteger():
+ return vi.Integer() < vj.Integer()
+ case vi.IsFloat() && vj.IsFloat():
+ return vi.Float() < vj.Float()
+ default:
+ return vi.String() < vj.String()
+ }
+}
+
+func (vl valuesList) Swap(i, j int) {
+ vl[i], vl[j] = vl[j], vl[i]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/variable.go b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/variable.go
new file mode 100644
index 000000000000..25e2af40b3fb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/flosch/pongo2/v4/variable.go
@@ -0,0 +1,693 @@
+package pongo2
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+const (
+ varTypeInt = iota
+ varTypeIdent
+)
+
+var (
+ typeOfValuePtr = reflect.TypeOf(new(Value))
+ typeOfExecCtxPtr = reflect.TypeOf(new(ExecutionContext))
+)
+
+type variablePart struct {
+ typ int
+ s string
+ i int
+
+ isFunctionCall bool
+ callingArgs []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
+}
+
+type functionCallArgument interface {
+ Evaluate(*ExecutionContext) (*Value, *Error)
+}
+
+// TODO: Add location tokens
+type stringResolver struct {
+ locationToken *Token
+ val string
+}
+
+type intResolver struct {
+ locationToken *Token
+ val int
+}
+
+type floatResolver struct {
+ locationToken *Token
+ val float64
+}
+
+type boolResolver struct {
+ locationToken *Token
+ val bool
+}
+
+type variableResolver struct {
+ locationToken *Token
+
+ parts []*variablePart
+}
+
+type nodeFilteredVariable struct {
+ locationToken *Token
+
+ resolver IEvaluator
+ filterChain []*filterCall
+}
+
+type nodeVariable struct {
+ locationToken *Token
+ expr IEvaluator
+}
+
+type executionCtxEval struct{}
+
+func (v *nodeFilteredVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := v.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (vr *variableResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := vr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (s *stringResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := s.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (i *intResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := i.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (f *floatResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := f.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (b *boolResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := b.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (v *nodeFilteredVariable) GetPositionToken() *Token {
+ return v.locationToken
+}
+
+func (vr *variableResolver) GetPositionToken() *Token {
+ return vr.locationToken
+}
+
+func (s *stringResolver) GetPositionToken() *Token {
+ return s.locationToken
+}
+
+func (i *intResolver) GetPositionToken() *Token {
+ return i.locationToken
+}
+
+func (f *floatResolver) GetPositionToken() *Token {
+ return f.locationToken
+}
+
+func (b *boolResolver) GetPositionToken() *Token {
+ return b.locationToken
+}
+
+func (s *stringResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ return AsValue(s.val), nil
+}
+
+func (i *intResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ return AsValue(i.val), nil
+}
+
+func (f *floatResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ return AsValue(f.val), nil
+}
+
+func (b *boolResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ return AsValue(b.val), nil
+}
+
+func (s *stringResolver) FilterApplied(name string) bool {
+ return false
+}
+
+func (i *intResolver) FilterApplied(name string) bool {
+ return false
+}
+
+func (f *floatResolver) FilterApplied(name string) bool {
+ return false
+}
+
+func (b *boolResolver) FilterApplied(name string) bool {
+ return false
+}
+
+func (nv *nodeVariable) FilterApplied(name string) bool {
+ return nv.expr.FilterApplied(name)
+}
+
+func (nv *nodeVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
+ value, err := nv.expr.Evaluate(ctx)
+ if err != nil {
+ return err
+ }
+
+ if !nv.expr.FilterApplied("safe") && !value.safe && value.IsString() && ctx.Autoescape {
+ // apply escape filter
+ value, err = filters["escape"](value, nil)
+ if err != nil {
+ return err
+ }
+ }
+
+ writer.WriteString(value.String())
+ return nil
+}
+
+func (executionCtxEval) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ return AsValue(ctx), nil
+}
+
+func (vr *variableResolver) FilterApplied(name string) bool {
+ return false
+}
+
+func (vr *variableResolver) String() string {
+ parts := make([]string, 0, len(vr.parts))
+ for _, p := range vr.parts {
+ switch p.typ {
+ case varTypeInt:
+ parts = append(parts, strconv.Itoa(p.i))
+ case varTypeIdent:
+ parts = append(parts, p.s)
+ default:
+ panic("unimplemented")
+ }
+ }
+ return strings.Join(parts, ".")
+}
+
+func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
+ var current reflect.Value
+ var isSafe bool
+
+ for idx, part := range vr.parts {
+ if idx == 0 {
+ // We're looking up the first part of the variable.
+ // First we're having a look in our private
+ // context (e. g. information provided by tags, like the forloop)
+ val, inPrivate := ctx.Private[vr.parts[0].s]
+ if !inPrivate {
+ // Nothing found? Then have a final lookup in the public context
+ val = ctx.Public[vr.parts[0].s]
+ }
+ current = reflect.ValueOf(val) // Get the initial value
+ } else {
+ // Next parts, resolve it from current
+
+ // Before resolving the pointer, let's see if we have a method to call
+ // Problem with resolving the pointer is we're changing the receiver
+ isFunc := false
+ if part.typ == varTypeIdent {
+ funcValue := current.MethodByName(part.s)
+ if funcValue.IsValid() {
+ current = funcValue
+ isFunc = true
+ }
+ }
+
+ if !isFunc {
+ // If current a pointer, resolve it
+ if current.Kind() == reflect.Ptr {
+ current = current.Elem()
+ if !current.IsValid() {
+ // Value is not valid (anymore)
+ return AsValue(nil), nil
+ }
+ }
+
+ // Look up which part must be called now
+ switch part.typ {
+ case varTypeInt:
+ // Calling an index is only possible for:
+ // * slices/arrays/strings
+ switch current.Kind() {
+ case reflect.String, reflect.Array, reflect.Slice:
+ if part.i >= 0 && current.Len() > part.i {
+ current = current.Index(part.i)
+ } else {
+ // In Django, exceeding the length of a list is just empty.
+ return AsValue(nil), nil
+ }
+ default:
+ return nil, fmt.Errorf("Can't access an index on type %s (variable %s)",
+ current.Kind().String(), vr.String())
+ }
+ case varTypeIdent:
+ // debugging:
+ // fmt.Printf("now = %s (kind: %s)\n", part.s, current.Kind().String())
+
+ // Calling a field or key
+ switch current.Kind() {
+ case reflect.Struct:
+ current = current.FieldByName(part.s)
+ case reflect.Map:
+ current = current.MapIndex(reflect.ValueOf(part.s))
+ default:
+ return nil, fmt.Errorf("Can't access a field by name on type %s (variable %s)",
+ current.Kind().String(), vr.String())
+ }
+ default:
+ panic("unimplemented")
+ }
+ }
+ }
+
+ if !current.IsValid() {
+ // Value is not valid (anymore)
+ return AsValue(nil), nil
+ }
+
+ // If current is a reflect.ValueOf(pongo2.Value), then unpack it
+ // Happens in function calls (as a return value) or by injecting
+ // into the execution context (e.g. in a for-loop)
+ if current.Type() == typeOfValuePtr {
+ tmpValue := current.Interface().(*Value)
+ current = tmpValue.val
+ isSafe = tmpValue.safe
+ }
+
+ // Check whether this is an interface and resolve it where required
+ if current.Kind() == reflect.Interface {
+ current = reflect.ValueOf(current.Interface())
+ }
+
+ // Check if the part is a function call
+ if part.isFunctionCall || current.Kind() == reflect.Func {
+ // Check for callable
+ if current.Kind() != reflect.Func {
+ return nil, fmt.Errorf("'%s' is not a function (it is %s)", vr.String(), current.Kind().String())
+ }
+
+ // Check for correct function syntax and types
+ // func(*Value, ...) *Value
+ t := current.Type()
+ currArgs := part.callingArgs
+
+ // If an implicit ExecCtx is needed
+ if t.NumIn() > 0 && t.In(0) == typeOfExecCtxPtr {
+ currArgs = append([]functionCallArgument{executionCtxEval{}}, currArgs...)
+ }
+
+ // Input arguments
+ if len(currArgs) != t.NumIn() && !(len(currArgs) >= t.NumIn()-1 && t.IsVariadic()) {
+ return nil,
+ fmt.Errorf("Function input argument count (%d) of '%s' must be equal to the calling argument count (%d).",
+ t.NumIn(), vr.String(), len(currArgs))
+ }
+
+ // Output arguments
+ if t.NumOut() != 1 && t.NumOut() != 2 {
+ return nil, fmt.Errorf("'%s' must have exactly 1 or 2 output arguments, the second argument must be of type error", vr.String())
+ }
+
+ // Evaluate all parameters
+ var parameters []reflect.Value
+
+ numArgs := t.NumIn()
+ isVariadic := t.IsVariadic()
+ var fnArg reflect.Type
+
+ for idx, arg := range currArgs {
+ pv, err := arg.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ if isVariadic {
+ if idx >= t.NumIn()-1 {
+ fnArg = t.In(numArgs - 1).Elem()
+ } else {
+ fnArg = t.In(idx)
+ }
+ } else {
+ fnArg = t.In(idx)
+ }
+
+ if fnArg != typeOfValuePtr {
+ // Function's argument is not a *pongo2.Value, then we have to check whether input argument is of the same type as the function's argument
+ if !isVariadic {
+ if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
+ return nil, fmt.Errorf("Function input argument %d of '%s' must be of type %s or *pongo2.Value (not %T).",
+ idx, vr.String(), fnArg.String(), pv.Interface())
+ }
+ // Function's argument has another type, using the interface-value
+ parameters = append(parameters, reflect.ValueOf(pv.Interface()))
+ } else {
+ if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
+ return nil, fmt.Errorf("Function variadic input argument of '%s' must be of type %s or *pongo2.Value (not %T).",
+ vr.String(), fnArg.String(), pv.Interface())
+ }
+ // Function's argument has another type, using the interface-value
+ parameters = append(parameters, reflect.ValueOf(pv.Interface()))
+ }
+ } else {
+ // Function's argument is a *pongo2.Value
+ parameters = append(parameters, reflect.ValueOf(pv))
+ }
+ }
+
+ // Check if any of the values are invalid
+ for _, p := range parameters {
+ if p.Kind() == reflect.Invalid {
+ return nil, fmt.Errorf("Calling a function using an invalid parameter")
+ }
+ }
+
+ // Call it and get first return parameter back
+ values := current.Call(parameters)
+ rv := values[0]
+ if t.NumOut() == 2 {
+ e := values[1].Interface()
+ if e != nil {
+ err, ok := e.(error)
+ if !ok {
+ return nil, fmt.Errorf("The second return value is not an error")
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if rv.Type() != typeOfValuePtr {
+ current = reflect.ValueOf(rv.Interface())
+ } else {
+ // Return the function call value
+ current = rv.Interface().(*Value).val
+ isSafe = rv.Interface().(*Value).safe
+ }
+ }
+
+ if !current.IsValid() {
+ // Value is not valid (e. g. NIL value)
+ return AsValue(nil), nil
+ }
+ }
+
+ return &Value{val: current, safe: isSafe}, nil
+}
+
+func (vr *variableResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ value, err := vr.resolve(ctx)
+ if err != nil {
+ return AsValue(nil), ctx.Error(err.Error(), vr.locationToken)
+ }
+ return value, nil
+}
+
+func (v *nodeFilteredVariable) FilterApplied(name string) bool {
+ for _, filter := range v.filterChain {
+ if filter.name == name {
+ return true
+ }
+ }
+ return false
+}
+
+func (v *nodeFilteredVariable) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
+ value, err := v.resolver.Evaluate(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, filter := range v.filterChain {
+ value, err = filter.Execute(value, ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return value, nil
+}
+
+// IDENT | IDENT.(IDENT|NUMBER)...
+func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
+ t := p.Current()
+
+ if t == nil {
+ return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.lastToken)
+ }
+
+ // Is first part a number or a string, there's nothing to resolve (because there's only to return the value then)
+ switch t.Typ {
+ case TokenNumber:
+ p.Consume()
+
+ // One exception to the rule that we don't have float64 literals is at the beginning
+ // of an expression (or a variable name). Since we know we started with an integer
+ // which can't obviously be a variable name, we can check whether the first number
+ // is followed by dot (and then a number again). If so we're converting it to a float64.
+
+ if p.Match(TokenSymbol, ".") != nil {
+ // float64
+ t2 := p.MatchType(TokenNumber)
+ if t2 == nil {
+ return nil, p.Error("Expected a number after the '.'.", nil)
+ }
+ f, err := strconv.ParseFloat(fmt.Sprintf("%s.%s", t.Val, t2.Val), 64)
+ if err != nil {
+ return nil, p.Error(err.Error(), t)
+ }
+ fr := &floatResolver{
+ locationToken: t,
+ val: f,
+ }
+ return fr, nil
+ }
+ i, err := strconv.Atoi(t.Val)
+ if err != nil {
+ return nil, p.Error(err.Error(), t)
+ }
+ nr := &intResolver{
+ locationToken: t,
+ val: i,
+ }
+ return nr, nil
+
+ case TokenString:
+ p.Consume()
+ sr := &stringResolver{
+ locationToken: t,
+ val: t.Val,
+ }
+ return sr, nil
+ case TokenKeyword:
+ p.Consume()
+ switch t.Val {
+ case "true":
+ br := &boolResolver{
+ locationToken: t,
+ val: true,
+ }
+ return br, nil
+ case "false":
+ br := &boolResolver{
+ locationToken: t,
+ val: false,
+ }
+ return br, nil
+ default:
+ return nil, p.Error("This keyword is not allowed here.", nil)
+ }
+ }
+
+ resolver := &variableResolver{
+ locationToken: t,
+ }
+
+ // First part of a variable MUST be an identifier
+ if t.Typ != TokenIdentifier {
+ return nil, p.Error("Expected either a number, string, keyword or identifier.", t)
+ }
+
+ resolver.parts = append(resolver.parts, &variablePart{
+ typ: varTypeIdent,
+ s: t.Val,
+ })
+
+ p.Consume() // we consumed the first identifier of the variable name
+
+variableLoop:
+ for p.Remaining() > 0 {
+ t = p.Current()
+
+ if p.Match(TokenSymbol, ".") != nil {
+ // Next variable part (can be either NUMBER or IDENT)
+ t2 := p.Current()
+ if t2 != nil {
+ switch t2.Typ {
+ case TokenIdentifier:
+ resolver.parts = append(resolver.parts, &variablePart{
+ typ: varTypeIdent,
+ s: t2.Val,
+ })
+ p.Consume() // consume: IDENT
+ continue variableLoop
+ case TokenNumber:
+ i, err := strconv.Atoi(t2.Val)
+ if err != nil {
+ return nil, p.Error(err.Error(), t2)
+ }
+ resolver.parts = append(resolver.parts, &variablePart{
+ typ: varTypeInt,
+ i: i,
+ })
+ p.Consume() // consume: NUMBER
+ continue variableLoop
+ default:
+ return nil, p.Error("This token is not allowed within a variable name.", t2)
+ }
+ } else {
+ // EOF
+ return nil, p.Error("Unexpected EOF, expected either IDENTIFIER or NUMBER after DOT.",
+ p.lastToken)
+ }
+ } else if p.Match(TokenSymbol, "(") != nil {
+ // Function call
+ // FunctionName '(' Comma-separated list of expressions ')'
+ part := resolver.parts[len(resolver.parts)-1]
+ part.isFunctionCall = true
+ argumentLoop:
+ for {
+ if p.Remaining() == 0 {
+ return nil, p.Error("Unexpected EOF, expected function call argument list.", p.lastToken)
+ }
+
+ if p.Peek(TokenSymbol, ")") == nil {
+ // No closing bracket, so we're parsing an expression
+ exprArg, err := p.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ part.callingArgs = append(part.callingArgs, exprArg)
+
+ if p.Match(TokenSymbol, ")") != nil {
+ // If there's a closing bracket after an expression, we will stop parsing the arguments
+ break argumentLoop
+ } else {
+ // If there's NO closing bracket, there MUST be an comma
+ if p.Match(TokenSymbol, ",") == nil {
+ return nil, p.Error("Missing comma or closing bracket after argument.", nil)
+ }
+ }
+ } else {
+ // We got a closing bracket, so stop parsing arguments
+ p.Consume()
+ break argumentLoop
+ }
+
+ }
+ // We're done parsing the function call, next variable part
+ continue variableLoop
+ }
+
+ // No dot or function call? Then we're done with the variable parsing
+ break
+ }
+
+ return resolver, nil
+}
+
+func (p *Parser) parseVariableOrLiteralWithFilter() (*nodeFilteredVariable, *Error) {
+ v := &nodeFilteredVariable{
+ locationToken: p.Current(),
+ }
+
+ // Parse the variable name
+ resolver, err := p.parseVariableOrLiteral()
+ if err != nil {
+ return nil, err
+ }
+ v.resolver = resolver
+
+ // Parse all the filters
+filterLoop:
+ for p.Match(TokenSymbol, "|") != nil {
+ // Parse one single filter
+ filter, err := p.parseFilter()
+ if err != nil {
+ return nil, err
+ }
+
+ // Check sandbox filter restriction
+ if _, isBanned := p.template.set.bannedFilters[filter.name]; isBanned {
+ return nil, p.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", filter.name), nil)
+ }
+
+ v.filterChain = append(v.filterChain, filter)
+
+ continue filterLoop
+ }
+
+ return v, nil
+}
+
+func (p *Parser) parseVariableElement() (INode, *Error) {
+ node := &nodeVariable{
+ locationToken: p.Current(),
+ }
+
+ p.Consume() // consume '{{'
+
+ expr, err := p.ParseExpression()
+ if err != nil {
+ return nil, err
+ }
+ node.expr = expr
+
+ if p.Match(TokenSymbol, "}}") == nil {
+ return nil, p.Error("'}}' expected", nil)
+ }
+
+ return node, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.editorconfig b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.editorconfig
new file mode 100644
index 000000000000..fad895851e56
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.editorconfig
@@ -0,0 +1,12 @@
+root = true
+
+[*.go]
+indent_style = tab
+indent_size = 4
+insert_final_newline = true
+
+[*.{yml,yaml}]
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.gitattributes b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.gitattributes
new file mode 100644
index 000000000000..32f1001be0a5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.gitattributes
@@ -0,0 +1 @@
+go.sum linguist-generated
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.gitignore
new file mode 100644
index 000000000000..4cd0cbaf432c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.gitignore
@@ -0,0 +1,6 @@
+# Setup a Global .gitignore for OS and editor generated files:
+# https://help.github.com/articles/ignoring-files
+# git config --global core.excludesfile ~/.gitignore_global
+
+.vagrant
+*.sublime-project
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.mailmap b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.mailmap
new file mode 100644
index 000000000000..a04f2907fed3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/.mailmap
@@ -0,0 +1,2 @@
+Chris Howey
+Nathan Youngman <4566+nathany@users.noreply.github.com>
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/AUTHORS b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/AUTHORS
new file mode 100644
index 000000000000..6cbabe5ef50b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/AUTHORS
@@ -0,0 +1,62 @@
+# Names should be added to this file as
+# Name or Organization
+# The email address is not required for organizations.
+
+# You can update this list using the following command:
+#
+# $ (head -n10 AUTHORS && git shortlog -se | sed -E 's/^\s+[0-9]+\t//') | tee AUTHORS
+
+# Please keep the list sorted.
+
+Aaron L
+Adrien Bustany
+Alexey Kazakov
+Amit Krishnan
+Anmol Sethi
+Bjørn Erik Pedersen
+Brian Goff
+Bruno Bigras
+Caleb Spare
+Case Nelson
+Chris Howey
+Christoffer Buchholz
+Daniel Wagner-Hall
+Dave Cheney
+Eric Lin
+Evan Phoenix
+Francisco Souza
+Gautam Dey
+Hari haran
+Ichinose Shogo
+Johannes Ebke
+John C Barstow
+Kelvin Fo
+Ken-ichirou MATSUZAWA
+Matt Layher
+Matthias Stone
+Nathan Youngman
+Nickolai Zeldovich
+Oliver Bristow
+Patrick
+Paul Hammond
+Pawel Knap
+Pieter Droogendijk
+Pratik Shinde
+Pursuit92
+Riku Voipio
+Rob Figueiredo
+Rodrigo Chiossi
+Slawek Ligus
+Soge Zhang
+Tiffany Jernigan
+Tilak Sharma
+Tobias Klauser
+Tom Payne
+Travis Cline
+Tudor Golubenco
+Vahe Khachikyan
+Yukang
+bronze1man
+debrando
+henrikedwards
+铁哥
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
new file mode 100644
index 000000000000..cc01c08f56d5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
@@ -0,0 +1,357 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [1.5.4] - 2022-04-25
+
+* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
+* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
+* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
+
+## [1.5.3] - 2022-04-22
+
+* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
+
+## [1.5.2] - 2022-04-21
+
+* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
+* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
+* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
+* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
+* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
+
+## [1.5.1] - 2021-08-24
+
+* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
+
+## [1.5.0] - 2021-08-20
+
+* Go: Increase minimum required version to Go 1.12 [#381](https://github.com/fsnotify/fsnotify/pull/381)
+* Feature: Add AddRaw method which does not follow symlinks when adding a watch [#289](https://github.com/fsnotify/fsnotify/pull/298)
+* Windows: Follow symlinks by default like on all other systems [#289](https://github.com/fsnotify/fsnotify/pull/289)
+* CI: Use GitHub Actions for CI and cover go 1.12-1.17
+ [#378](https://github.com/fsnotify/fsnotify/pull/378)
+ [#381](https://github.com/fsnotify/fsnotify/pull/381)
+ [#385](https://github.com/fsnotify/fsnotify/pull/385)
+* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325)
+
+## [1.4.7] - 2018-01-09
+
+* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
+* Tests: Fix missing verb on format string (thanks @rchiossi)
+* Linux: Fix deadlock in Remove (thanks @aarondl)
+* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
+* Docs: Moved FAQ into the README (thanks @vahe)
+* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
+* Docs: replace references to OS X with macOS
+
+## [1.4.2] - 2016-10-10
+
+* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
+
+## [1.4.1] - 2016-10-04
+
+* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
+
+## [1.4.0] - 2016-10-01
+
+* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
+
+## [1.3.1] - 2016-06-28
+
+* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
+
+## [1.3.0] - 2016-04-19
+
+* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
+
+## [1.2.10] - 2016-03-02
+
+* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
+
+## [1.2.9] - 2016-01-13
+
+kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
+
+## [1.2.8] - 2015-12-17
+
+* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
+* inotify: fix race in test
+* enable race detection for continuous integration (Linux, Mac, Windows)
+
+## [1.2.5] - 2015-10-17
+
+* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
+* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
+* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
+* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
+
+## [1.2.1] - 2015-10-14
+
+* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
+
+## [1.2.0] - 2015-02-08
+
+* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
+* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
+* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
+
+## [1.1.1] - 2015-02-05
+
+* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
+
+## [1.1.0] - 2014-12-12
+
+* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
+ * add low-level functions
+ * only need to store flags on directories
+ * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
+ * done can be an unbuffered channel
+ * remove calls to os.NewSyscallError
+* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
+* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
+* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
+
+## [1.0.4] - 2014-09-07
+
+* kqueue: add dragonfly to the build tags.
+* Rename source code files, rearrange code so exported APIs are at the top.
+* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
+
+## [1.0.3] - 2014-08-19
+
+* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
+
+## [1.0.2] - 2014-08-17
+
+* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
+* [Fix] Make ./path and path equivalent. (thanks @zhsso)
+
+## [1.0.0] - 2014-08-15
+
+* [API] Remove AddWatch on Windows, use Add.
+* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
+* Minor updates based on feedback from golint.
+
+## dev / 2014-07-09
+
+* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
+* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
+
+## dev / 2014-07-04
+
+* kqueue: fix incorrect mutex used in Close()
+* Update example to demonstrate usage of Op.
+
+## dev / 2014-06-28
+
+* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
+* Fix for String() method on Event (thanks Alex Brainman)
+* Don't build on Plan 9 or Solaris (thanks @4ad)
+
+## dev / 2014-06-21
+
+* Events channel of type Event rather than *Event.
+* [internal] use syscall constants directly for inotify and kqueue.
+* [internal] kqueue: rename events to kevents and fileEvent to event.
+
+## dev / 2014-06-19
+
+* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
+* [internal] remove cookie from Event struct (unused).
+* [internal] Event struct has the same definition across every OS.
+* [internal] remove internal watch and removeWatch methods.
+
+## dev / 2014-06-12
+
+* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
+* [API] Pluralized channel names: Events and Errors.
+* [API] Renamed FileEvent struct to Event.
+* [API] Op constants replace methods like IsCreate().
+
+## dev / 2014-06-12
+
+* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
+
+## dev / 2014-05-23
+
+* [API] Remove current implementation of WatchFlags.
+ * current implementation doesn't take advantage of OS for efficiency
+ * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
+ * no tests for the current implementation
+ * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
+
+## [0.9.3] - 2014-12-31
+
+* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
+
+## [0.9.2] - 2014-08-17
+
+* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
+
+## [0.9.1] - 2014-06-12
+
+* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
+
+## [0.9.0] - 2014-01-17
+
+* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
+* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
+* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
+
+## [0.8.12] - 2013-11-13
+
+* [API] Remove FD_SET and friends from Linux adapter
+
+## [0.8.11] - 2013-11-02
+
+* [Doc] Add Changelog [#72][] (thanks @nathany)
+* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
+
+## [0.8.10] - 2013-10-19
+
+* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
+* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
+* [Doc] specify OS-specific limits in README (thanks @debrando)
+
+## [0.8.9] - 2013-09-08
+
+* [Doc] Contributing (thanks @nathany)
+* [Doc] update package path in example code [#63][] (thanks @paulhammond)
+* [Doc] GoCI badge in README (Linux only) [#60][]
+* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
+
+## [0.8.8] - 2013-06-17
+
+* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
+
+## [0.8.7] - 2013-06-03
+
+* [API] Make syscall flags internal
+* [Fix] inotify: ignore event changes
+* [Fix] race in symlink test [#45][] (reported by @srid)
+* [Fix] tests on Windows
+* lower case error messages
+
+## [0.8.6] - 2013-05-23
+
+* kqueue: Use EVT_ONLY flag on Darwin
+* [Doc] Update README with full example
+
+## [0.8.5] - 2013-05-09
+
+* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
+
+## [0.8.4] - 2013-04-07
+
+* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
+
+## [0.8.3] - 2013-03-13
+
+* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
+* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
+
+## [0.8.2] - 2013-02-07
+
+* [Doc] add Authors
+* [Fix] fix data races for map access [#29][] (thanks @fsouza)
+
+## [0.8.1] - 2013-01-09
+
+* [Fix] Windows path separators
+* [Doc] BSD License
+
+## [0.8.0] - 2012-11-09
+
+* kqueue: directory watching improvements (thanks @vmirage)
+* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
+* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
+
+## [0.7.4] - 2012-10-09
+
+* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
+* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
+* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
+* [Fix] kqueue: modify after recreation of file
+
+## [0.7.3] - 2012-09-27
+
+* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
+* [Fix] kqueue: no longer get duplicate CREATE events
+
+## [0.7.2] - 2012-09-01
+
+* kqueue: events for created directories
+
+## [0.7.1] - 2012-07-14
+
+* [Fix] for renaming files
+
+## [0.7.0] - 2012-07-02
+
+* [Feature] FSNotify flags
+* [Fix] inotify: Added file name back to event path
+
+## [0.6.0] - 2012-06-06
+
+* kqueue: watch files after directory created (thanks @tmc)
+
+## [0.5.1] - 2012-05-22
+
+* [Fix] inotify: remove all watches before Close()
+
+## [0.5.0] - 2012-05-03
+
+* [API] kqueue: return errors during watch instead of sending over channel
+* kqueue: match symlink behavior on Linux
+* inotify: add `DELETE_SELF` (requested by @taralx)
+* [Fix] kqueue: handle EINTR (reported by @robfig)
+* [Doc] Godoc example [#1][] (thanks @davecheney)
+
+## [0.4.0] - 2012-03-30
+
+* Go 1 released: build with go tool
+* [Feature] Windows support using winfsnotify
+* Windows does not have attribute change notifications
+* Roll attribute notifications into IsModify
+
+## [0.3.0] - 2012-02-19
+
+* kqueue: add files when watch directory
+
+## [0.2.0] - 2011-12-30
+
+* update to latest Go weekly code
+
+## [0.1.0] - 2011-10-19
+
+* kqueue: add watch on file creation to match inotify
+* kqueue: create file event
+* inotify: ignore `IN_IGNORED` events
+* event String()
+* linux: common FileEvent functions
+* initial commit
+
+[#79]: https://github.com/howeyc/fsnotify/pull/79
+[#77]: https://github.com/howeyc/fsnotify/pull/77
+[#72]: https://github.com/howeyc/fsnotify/issues/72
+[#71]: https://github.com/howeyc/fsnotify/issues/71
+[#70]: https://github.com/howeyc/fsnotify/issues/70
+[#63]: https://github.com/howeyc/fsnotify/issues/63
+[#62]: https://github.com/howeyc/fsnotify/issues/62
+[#60]: https://github.com/howeyc/fsnotify/issues/60
+[#59]: https://github.com/howeyc/fsnotify/issues/59
+[#49]: https://github.com/howeyc/fsnotify/issues/49
+[#45]: https://github.com/howeyc/fsnotify/issues/45
+[#40]: https://github.com/howeyc/fsnotify/issues/40
+[#36]: https://github.com/howeyc/fsnotify/issues/36
+[#33]: https://github.com/howeyc/fsnotify/issues/33
+[#29]: https://github.com/howeyc/fsnotify/issues/29
+[#25]: https://github.com/howeyc/fsnotify/issues/25
+[#24]: https://github.com/howeyc/fsnotify/issues/24
+[#21]: https://github.com/howeyc/fsnotify/issues/21
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
new file mode 100644
index 000000000000..8a642563d718
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
@@ -0,0 +1,60 @@
+# Contributing
+
+## Issues
+
+* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
+* Please indicate the platform you are using fsnotify on.
+* A code example to reproduce the problem is appreciated.
+
+## Pull Requests
+
+### Contributor License Agreement
+
+fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
+
+Please indicate that you have signed the CLA in your pull request.
+
+### How fsnotify is Developed
+
+* Development is done on feature branches.
+* Tests are run on BSD, Linux, macOS and Windows.
+* Pull requests are reviewed and [applied to master][am] using [hub][].
+ * Maintainers may modify or squash commits rather than asking contributors to.
+* To issue a new release, the maintainers will:
+ * Update the CHANGELOG
+ * Tag a version, which will become available through gopkg.in.
+
+### How to Fork
+
+For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
+
+1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Ensure everything works and the tests pass (see below)
+4. Commit your changes (`git commit -am 'Add some feature'`)
+
+Contribute upstream:
+
+1. Fork fsnotify on GitHub
+2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
+3. Push to the branch (`git push fork my-new-feature`)
+4. Create a new Pull Request on GitHub
+
+This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
+
+### Testing
+
+fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
+
+Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
+
+### Maintainers
+
+Help maintaining fsnotify is welcome. To be a maintainer:
+
+* Submit a pull request and sign the CLA as above.
+* You must be able to run the test suite on Mac, Windows, Linux and BSD.
+
+All code changes should be internal pull requests.
+
+Releases are tagged using [Semantic Versioning](http://semver.org/).
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/LICENSE
new file mode 100644
index 000000000000..e180c8fb0599
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+Copyright (c) 2012-2019 fsnotify Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/README.md
new file mode 100644
index 000000000000..0731c5ef8adc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/README.md
@@ -0,0 +1,120 @@
+# File system notifications for Go
+
+[![Go Reference](https://pkg.go.dev/badge/github.com/fsnotify/fsnotify.svg)](https://pkg.go.dev/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/fsnotify/fsnotify/issues/413)
+
+fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library.
+
+Cross platform: Windows, Linux, BSD and macOS.
+
+| Adapter | OS | Status |
+| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| inotify | Linux 2.6.27 or later, Android\* | Supported |
+| kqueue | BSD, macOS, iOS\* | Supported |
+| ReadDirectoryChangesW | Windows | Supported |
+| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
+| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
+| fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
+| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
+| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
+
+\* Android and iOS are untested.
+
+Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
+
+## API stability
+
+fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
+
+All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/).
+
+## Usage
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/fsnotify/fsnotify"
+)
+
+func main() {
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer watcher.Close()
+
+ done := make(chan bool)
+ go func() {
+ for {
+ select {
+ case event, ok := <-watcher.Events:
+ if !ok {
+ return
+ }
+ log.Println("event:", event)
+ if event.Op&fsnotify.Write == fsnotify.Write {
+ log.Println("modified file:", event.Name)
+ }
+ case err, ok := <-watcher.Errors:
+ if !ok {
+ return
+ }
+ log.Println("error:", err)
+ }
+ }
+ }()
+
+ err = watcher.Add("/tmp/foo")
+ if err != nil {
+ log.Fatal(err)
+ }
+ <-done
+}
+```
+
+## Contributing
+
+Please refer to [CONTRIBUTING][] before opening an issue or pull request.
+
+## FAQ
+
+**When a file is moved to another directory is it still being watched?**
+
+No (it shouldn't be, unless you are watching where it was moved to).
+
+**When I watch a directory, are all subdirectories watched as well?**
+
+No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
+
+**Do I have to watch the Error and Event channels in a separate goroutine?**
+
+As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
+
+**Why am I receiving multiple events for the same file on OS X?**
+
+Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
+
+**How many files can be watched at once?**
+
+There are OS-specific limits as to how many watches can be created:
+* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
+* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
+
+**Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?**
+
+fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications.
+
+[#62]: https://github.com/howeyc/fsnotify/issues/62
+[#18]: https://github.com/fsnotify/fsnotify/issues/18
+[#11]: https://github.com/fsnotify/fsnotify/issues/11
+[#7]: https://github.com/howeyc/fsnotify/issues/7
+
+[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
+
+## Related Projects
+
+* [notify](https://github.com/rjeczalik/notify)
+* [fsevents](https://github.com/fsnotify/fsevents)
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fen.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fen.go
new file mode 100644
index 000000000000..b3ac3d8f55fa
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fen.go
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build solaris
+// +build solaris
+
+package fsnotify
+
+import (
+ "errors"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+ Events chan Event
+ Errors chan error
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
+func NewWatcher() (*Watcher, error) {
+ return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+ return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+ return nil
+}
+
+// Remove stops watching the the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fsnotify.go
new file mode 100644
index 000000000000..0f4ee52e8aa2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fsnotify.go
@@ -0,0 +1,69 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !plan9
+// +build !plan9
+
+// Package fsnotify provides a platform-independent interface for file system notifications.
+package fsnotify
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+)
+
+// Event represents a single file system notification.
+type Event struct {
+ Name string // Relative path to the file or directory.
+ Op Op // File operation that triggered the event.
+}
+
+// Op describes a set of file operations.
+type Op uint32
+
+// These are the generalized file operations that can trigger a notification.
+const (
+ Create Op = 1 << iota
+ Write
+ Remove
+ Rename
+ Chmod
+)
+
+func (op Op) String() string {
+ // Use a buffer for efficient string concatenation
+ var buffer bytes.Buffer
+
+ if op&Create == Create {
+ buffer.WriteString("|CREATE")
+ }
+ if op&Remove == Remove {
+ buffer.WriteString("|REMOVE")
+ }
+ if op&Write == Write {
+ buffer.WriteString("|WRITE")
+ }
+ if op&Rename == Rename {
+ buffer.WriteString("|RENAME")
+ }
+ if op&Chmod == Chmod {
+ buffer.WriteString("|CHMOD")
+ }
+ if buffer.Len() == 0 {
+ return ""
+ }
+ return buffer.String()[1:] // Strip leading pipe
+}
+
+// String returns a string representation of the event in the form
+// "file: REMOVE|WRITE|..."
+func (e Event) String() string {
+ return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
+}
+
+// Common errors that can be reported by a watcher
+var (
+ ErrEventOverflow = errors.New("fsnotify queue overflow")
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go
new file mode 100644
index 000000000000..59688559836f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go
@@ -0,0 +1,36 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows
+// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
+
+package fsnotify
+
+import (
+ "fmt"
+ "runtime"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct{}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
+func NewWatcher() (*Watcher, error) {
+ return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+ return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+ return nil
+}
+
+// Remove stops watching the the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/inotify.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/inotify.go
new file mode 100644
index 000000000000..a6d0e0ec8c10
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/inotify.go
@@ -0,0 +1,351 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+// +build linux
+
+package fsnotify
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+ Events chan Event
+ Errors chan error
+ mu sync.Mutex // Map access
+ fd int
+ poller *fdPoller
+ watches map[string]*watch // Map of inotify watches (key: path)
+ paths map[int]string // Map of watched paths (key: watch descriptor)
+ done chan struct{} // Channel for sending a "quit message" to the reader goroutine
+ doneResp chan struct{} // Channel to respond to Close
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
+func NewWatcher() (*Watcher, error) {
+ // Create inotify fd
+ fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
+ if fd == -1 {
+ return nil, errno
+ }
+ // Create epoll
+ poller, err := newFdPoller(fd)
+ if err != nil {
+ unix.Close(fd)
+ return nil, err
+ }
+ w := &Watcher{
+ fd: fd,
+ poller: poller,
+ watches: make(map[string]*watch),
+ paths: make(map[int]string),
+ Events: make(chan Event),
+ Errors: make(chan error),
+ done: make(chan struct{}),
+ doneResp: make(chan struct{}),
+ }
+
+ go w.readEvents()
+ return w, nil
+}
+
+func (w *Watcher) isClosed() bool {
+ select {
+ case <-w.done:
+ return true
+ default:
+ return false
+ }
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+ if w.isClosed() {
+ return nil
+ }
+
+ // Send 'close' signal to goroutine, and set the Watcher to closed.
+ close(w.done)
+
+ // Wake up goroutine
+ w.poller.wake()
+
+ // Wait for goroutine to close
+ <-w.doneResp
+
+ return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+ name = filepath.Clean(name)
+ if w.isClosed() {
+ return errors.New("inotify instance already closed")
+ }
+
+ const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
+ unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
+ unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
+
+ var flags uint32 = agnosticEvents
+
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ watchEntry := w.watches[name]
+ if watchEntry != nil {
+ flags |= watchEntry.flags | unix.IN_MASK_ADD
+ }
+ wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
+ if wd == -1 {
+ return errno
+ }
+
+ if watchEntry == nil {
+ w.watches[name] = &watch{wd: uint32(wd), flags: flags}
+ w.paths[wd] = name
+ } else {
+ watchEntry.wd = uint32(wd)
+ watchEntry.flags = flags
+ }
+
+ return nil
+}
+
+// Remove stops watching the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+ name = filepath.Clean(name)
+
+ // Fetch the watch.
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ watch, ok := w.watches[name]
+
+ // Remove it from inotify.
+ if !ok {
+ return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
+ }
+
+ // We successfully removed the watch if InotifyRmWatch doesn't return an
+ // error, we need to clean up our internal state to ensure it matches
+ // inotify's kernel state.
+ delete(w.paths, int(watch.wd))
+ delete(w.watches, name)
+
+ // inotify_rm_watch will return EINVAL if the file has been deleted;
+ // the inotify will already have been removed.
+ // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
+ // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
+ // so that EINVAL means that the wd is being rm_watch()ed or its file removed
+ // by another thread and we have not received IN_IGNORE event.
+ success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
+ if success == -1 {
+ // TODO: Perhaps it's not helpful to return an error here in every case.
+ // the only two possible errors are:
+ // EBADF, which happens when w.fd is not a valid file descriptor of any kind.
+ // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
+ // Watch descriptors are invalidated when they are removed explicitly or implicitly;
+ // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
+ return errno
+ }
+
+ return nil
+}
+
+// WatchList returns the directories and files that are being monitered.
+func (w *Watcher) WatchList() []string {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ entries := make([]string, 0, len(w.watches))
+ for pathname := range w.watches {
+ entries = append(entries, pathname)
+ }
+
+ return entries
+}
+
+type watch struct {
+ wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
+ flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
+}
+
+// readEvents reads from the inotify file descriptor, converts the
+// received events into Event objects and sends them via the Events channel
+func (w *Watcher) readEvents() {
+ var (
+ buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
+ n int // Number of bytes read with read()
+ errno error // Syscall errno
+ ok bool // For poller.wait
+ )
+
+ defer close(w.doneResp)
+ defer close(w.Errors)
+ defer close(w.Events)
+ defer unix.Close(w.fd)
+ defer w.poller.close()
+
+ for {
+ // See if we have been closed.
+ if w.isClosed() {
+ return
+ }
+
+ ok, errno = w.poller.wait()
+ if errno != nil {
+ select {
+ case w.Errors <- errno:
+ case <-w.done:
+ return
+ }
+ continue
+ }
+
+ if !ok {
+ continue
+ }
+
+ n, errno = unix.Read(w.fd, buf[:])
+ // If a signal interrupted execution, see if we've been asked to close, and try again.
+ // http://man7.org/linux/man-pages/man7/signal.7.html :
+ // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
+ if errno == unix.EINTR {
+ continue
+ }
+
+ // unix.Read might have been woken up by Close. If so, we're done.
+ if w.isClosed() {
+ return
+ }
+
+ if n < unix.SizeofInotifyEvent {
+ var err error
+ if n == 0 {
+ // If EOF is received. This should really never happen.
+ err = io.EOF
+ } else if n < 0 {
+ // If an error occurred while reading.
+ err = errno
+ } else {
+ // Read was too short.
+ err = errors.New("notify: short read in readEvents()")
+ }
+ select {
+ case w.Errors <- err:
+ case <-w.done:
+ return
+ }
+ continue
+ }
+
+ var offset uint32
+ // We don't know how many events we just read into the buffer
+ // While the offset points to at least one whole event...
+ for offset <= uint32(n-unix.SizeofInotifyEvent) {
+ // Point "raw" to the event in the buffer
+ raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
+
+ mask := uint32(raw.Mask)
+ nameLen := uint32(raw.Len)
+
+ if mask&unix.IN_Q_OVERFLOW != 0 {
+ select {
+ case w.Errors <- ErrEventOverflow:
+ case <-w.done:
+ return
+ }
+ }
+
+ // If the event happened to the watched directory or the watched file, the kernel
+ // doesn't append the filename to the event, but we would like to always fill the
+ // the "Name" field with a valid filename. We retrieve the path of the watch from
+ // the "paths" map.
+ w.mu.Lock()
+ name, ok := w.paths[int(raw.Wd)]
+ // IN_DELETE_SELF occurs when the file/directory being watched is removed.
+ // This is a sign to clean up the maps, otherwise we are no longer in sync
+ // with the inotify kernel state which has already deleted the watch
+ // automatically.
+ if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
+ delete(w.paths, int(raw.Wd))
+ delete(w.watches, name)
+ }
+ w.mu.Unlock()
+
+ if nameLen > 0 {
+ // Point "bytes" at the first byte of the filename
+ bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
+ // The filename is padded with NULL bytes. TrimRight() gets rid of those.
+ name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
+ }
+
+ event := newEvent(name, mask)
+
+ // Send the events that are not ignored on the events channel
+ if !event.ignoreLinux(mask) {
+ select {
+ case w.Events <- event:
+ case <-w.done:
+ return
+ }
+ }
+
+ // Move to the next event in the buffer
+ offset += unix.SizeofInotifyEvent + nameLen
+ }
+ }
+}
+
+// Certain types of events can be "ignored" and not sent over the Events
+// channel. Such as events marked ignore by the kernel, or MODIFY events
+// against files that do not exist.
+func (e *Event) ignoreLinux(mask uint32) bool {
+ // Ignore anything the inotify API says to ignore
+ if mask&unix.IN_IGNORED == unix.IN_IGNORED {
+ return true
+ }
+
+ // If the event is not a DELETE or RENAME, the file must exist.
+ // Otherwise the event is ignored.
+ // *Note*: this was put in place because it was seen that a MODIFY
+ // event was sent after the DELETE. This ignores that MODIFY and
+ // assumes a DELETE will come or has come if the file doesn't exist.
+ if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
+ _, statErr := os.Lstat(e.Name)
+ return os.IsNotExist(statErr)
+ }
+ return false
+}
+
+// newEvent returns an platform-independent Event based on an inotify mask.
+func newEvent(name string, mask uint32) Event {
+ e := Event{Name: name}
+ if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
+ e.Op |= Create
+ }
+ if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
+ e.Op |= Remove
+ }
+ if mask&unix.IN_MODIFY == unix.IN_MODIFY {
+ e.Op |= Write
+ }
+ if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
+ e.Op |= Rename
+ }
+ if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
+ e.Op |= Chmod
+ }
+ return e
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/inotify_poller.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/inotify_poller.go
new file mode 100644
index 000000000000..b572a37c3f1a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/inotify_poller.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+// +build linux
+
+package fsnotify
+
+import (
+ "errors"
+
+ "golang.org/x/sys/unix"
+)
+
+type fdPoller struct {
+ fd int // File descriptor (as returned by the inotify_init() syscall)
+ epfd int // Epoll file descriptor
+ pipe [2]int // Pipe for waking up
+}
+
+func emptyPoller(fd int) *fdPoller {
+ poller := new(fdPoller)
+ poller.fd = fd
+ poller.epfd = -1
+ poller.pipe[0] = -1
+ poller.pipe[1] = -1
+ return poller
+}
+
+// Create a new inotify poller.
+// This creates an inotify handler, and an epoll handler.
+func newFdPoller(fd int) (*fdPoller, error) {
+ var errno error
+ poller := emptyPoller(fd)
+ defer func() {
+ if errno != nil {
+ poller.close()
+ }
+ }()
+
+ // Create epoll fd
+ poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
+ if poller.epfd == -1 {
+ return nil, errno
+ }
+ // Create pipe; pipe[0] is the read end, pipe[1] the write end.
+ errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC)
+ if errno != nil {
+ return nil, errno
+ }
+
+ // Register inotify fd with epoll
+ event := unix.EpollEvent{
+ Fd: int32(poller.fd),
+ Events: unix.EPOLLIN,
+ }
+ errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
+ if errno != nil {
+ return nil, errno
+ }
+
+ // Register pipe fd with epoll
+ event = unix.EpollEvent{
+ Fd: int32(poller.pipe[0]),
+ Events: unix.EPOLLIN,
+ }
+ errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
+ if errno != nil {
+ return nil, errno
+ }
+
+ return poller, nil
+}
+
+// Wait using epoll.
+// Returns true if something is ready to be read,
+// false if there is not.
+func (poller *fdPoller) wait() (bool, error) {
+ // 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
+ // I don't know whether epoll_wait returns the number of events returned,
+ // or the total number of events ready.
+ // I decided to catch both by making the buffer one larger than the maximum.
+ events := make([]unix.EpollEvent, 7)
+ for {
+ n, errno := unix.EpollWait(poller.epfd, events, -1)
+ if n == -1 {
+ if errno == unix.EINTR {
+ continue
+ }
+ return false, errno
+ }
+ if n == 0 {
+ // If there are no events, try again.
+ continue
+ }
+ if n > 6 {
+ // This should never happen. More events were returned than should be possible.
+ return false, errors.New("epoll_wait returned more events than I know what to do with")
+ }
+ ready := events[:n]
+ epollhup := false
+ epollerr := false
+ epollin := false
+ for _, event := range ready {
+ if event.Fd == int32(poller.fd) {
+ if event.Events&unix.EPOLLHUP != 0 {
+ // This should not happen, but if it does, treat it as a wakeup.
+ epollhup = true
+ }
+ if event.Events&unix.EPOLLERR != 0 {
+ // If an error is waiting on the file descriptor, we should pretend
+ // something is ready to read, and let unix.Read pick up the error.
+ epollerr = true
+ }
+ if event.Events&unix.EPOLLIN != 0 {
+ // There is data to read.
+ epollin = true
+ }
+ }
+ if event.Fd == int32(poller.pipe[0]) {
+ if event.Events&unix.EPOLLHUP != 0 {
+ // Write pipe descriptor was closed, by us. This means we're closing down the
+ // watcher, and we should wake up.
+ }
+ if event.Events&unix.EPOLLERR != 0 {
+ // If an error is waiting on the pipe file descriptor.
+ // This is an absolute mystery, and should never ever happen.
+ return false, errors.New("Error on the pipe descriptor.")
+ }
+ if event.Events&unix.EPOLLIN != 0 {
+ // This is a regular wakeup, so we have to clear the buffer.
+ err := poller.clearWake()
+ if err != nil {
+ return false, err
+ }
+ }
+ }
+ }
+
+ if epollhup || epollerr || epollin {
+ return true, nil
+ }
+ return false, nil
+ }
+}
+
+// Close the write end of the poller.
+func (poller *fdPoller) wake() error {
+ buf := make([]byte, 1)
+ n, errno := unix.Write(poller.pipe[1], buf)
+ if n == -1 {
+ if errno == unix.EAGAIN {
+ // Buffer is full, poller will wake.
+ return nil
+ }
+ return errno
+ }
+ return nil
+}
+
+func (poller *fdPoller) clearWake() error {
+ // You have to be woken up a LOT in order to get to 100!
+ buf := make([]byte, 100)
+ n, errno := unix.Read(poller.pipe[0], buf)
+ if n == -1 {
+ if errno == unix.EAGAIN {
+ // Buffer is empty, someone else cleared our wake.
+ return nil
+ }
+ return errno
+ }
+ return nil
+}
+
+// Close all poller file descriptors, but not the one passed to it.
+func (poller *fdPoller) close() {
+ if poller.pipe[1] != -1 {
+ unix.Close(poller.pipe[1])
+ }
+ if poller.pipe[0] != -1 {
+ unix.Close(poller.pipe[0])
+ }
+ if poller.epfd != -1 {
+ unix.Close(poller.epfd)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/kqueue.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/kqueue.go
new file mode 100644
index 000000000000..6fb8d8532e7f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/kqueue.go
@@ -0,0 +1,535 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd || openbsd || netbsd || dragonfly || darwin
+// +build freebsd openbsd netbsd dragonfly darwin
+
+package fsnotify
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sync"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+ Events chan Event
+ Errors chan error
+ done chan struct{} // Channel for sending a "quit message" to the reader goroutine
+
+ kq int // File descriptor (as returned by the kqueue() syscall).
+
+ mu sync.Mutex // Protects access to watcher data
+ watches map[string]int // Map of watched file descriptors (key: path).
+ externalWatches map[string]bool // Map of watches added by user of the library.
+ dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue.
+ paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events.
+ fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
+ isClosed bool // Set to true when Close() is first called
+}
+
+type pathInfo struct {
+ name string
+ isDir bool
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
+func NewWatcher() (*Watcher, error) {
+ kq, err := kqueue()
+ if err != nil {
+ return nil, err
+ }
+
+ w := &Watcher{
+ kq: kq,
+ watches: make(map[string]int),
+ dirFlags: make(map[string]uint32),
+ paths: make(map[int]pathInfo),
+ fileExists: make(map[string]bool),
+ externalWatches: make(map[string]bool),
+ Events: make(chan Event),
+ Errors: make(chan error),
+ done: make(chan struct{}),
+ }
+
+ go w.readEvents()
+ return w, nil
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+ w.mu.Lock()
+ if w.isClosed {
+ w.mu.Unlock()
+ return nil
+ }
+ w.isClosed = true
+
+ // copy paths to remove while locked
+ var pathsToRemove = make([]string, 0, len(w.watches))
+ for name := range w.watches {
+ pathsToRemove = append(pathsToRemove, name)
+ }
+ w.mu.Unlock()
+ // unlock before calling Remove, which also locks
+
+ for _, name := range pathsToRemove {
+ w.Remove(name)
+ }
+
+ // send a "quit" message to the reader goroutine
+ close(w.done)
+
+ return nil
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+ w.mu.Lock()
+ w.externalWatches[name] = true
+ w.mu.Unlock()
+ _, err := w.addWatch(name, noteAllEvents)
+ return err
+}
+
+// Remove stops watching the the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+ name = filepath.Clean(name)
+ w.mu.Lock()
+ watchfd, ok := w.watches[name]
+ w.mu.Unlock()
+ if !ok {
+ return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
+ }
+
+ const registerRemove = unix.EV_DELETE
+ if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
+ return err
+ }
+
+ unix.Close(watchfd)
+
+ w.mu.Lock()
+ isDir := w.paths[watchfd].isDir
+ delete(w.watches, name)
+ delete(w.paths, watchfd)
+ delete(w.dirFlags, name)
+ w.mu.Unlock()
+
+ // Find all watched paths that are in this directory that are not external.
+ if isDir {
+ var pathsToRemove []string
+ w.mu.Lock()
+ for _, path := range w.paths {
+ wdir, _ := filepath.Split(path.name)
+ if filepath.Clean(wdir) == name {
+ if !w.externalWatches[path.name] {
+ pathsToRemove = append(pathsToRemove, path.name)
+ }
+ }
+ }
+ w.mu.Unlock()
+ for _, name := range pathsToRemove {
+ // Since these are internal, not much sense in propagating error
+ // to the user, as that will just confuse them with an error about
+ // a path they did not explicitly watch themselves.
+ w.Remove(name)
+ }
+ }
+
+ return nil
+}
+
+// WatchList returns the directories and files that are being monitered.
+func (w *Watcher) WatchList() []string {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ entries := make([]string, 0, len(w.watches))
+ for pathname := range w.watches {
+ entries = append(entries, pathname)
+ }
+
+ return entries
+}
+
+// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
+const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
+
+// keventWaitTime to block on each read from kevent
+var keventWaitTime = durationToTimespec(100 * time.Millisecond)
+
+// addWatch adds name to the watched file set.
+// The flags are interpreted as described in kevent(2).
+// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
+func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
+ var isDir bool
+ // Make ./name and name equivalent
+ name = filepath.Clean(name)
+
+ w.mu.Lock()
+ if w.isClosed {
+ w.mu.Unlock()
+ return "", errors.New("kevent instance already closed")
+ }
+ watchfd, alreadyWatching := w.watches[name]
+ // We already have a watch, but we can still override flags.
+ if alreadyWatching {
+ isDir = w.paths[watchfd].isDir
+ }
+ w.mu.Unlock()
+
+ if !alreadyWatching {
+ fi, err := os.Lstat(name)
+ if err != nil {
+ return "", err
+ }
+
+ // Don't watch sockets.
+ if fi.Mode()&os.ModeSocket == os.ModeSocket {
+ return "", nil
+ }
+
+ // Don't watch named pipes.
+ if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
+ return "", nil
+ }
+
+ // Follow Symlinks
+ // Unfortunately, Linux can add bogus symlinks to watch list without
+ // issue, and Windows can't do symlinks period (AFAIK). To maintain
+ // consistency, we will act like everything is fine. There will simply
+ // be no file events for broken symlinks.
+ // Hence the returns of nil on errors.
+ if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
+ name, err = filepath.EvalSymlinks(name)
+ if err != nil {
+ return "", nil
+ }
+
+ w.mu.Lock()
+ _, alreadyWatching = w.watches[name]
+ w.mu.Unlock()
+
+ if alreadyWatching {
+ return name, nil
+ }
+
+ fi, err = os.Lstat(name)
+ if err != nil {
+ return "", nil
+ }
+ }
+
+ watchfd, err = unix.Open(name, openMode, 0700)
+ if watchfd == -1 {
+ return "", err
+ }
+
+ isDir = fi.IsDir()
+ }
+
+ const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
+ if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
+ unix.Close(watchfd)
+ return "", err
+ }
+
+ if !alreadyWatching {
+ w.mu.Lock()
+ w.watches[name] = watchfd
+ w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
+ w.mu.Unlock()
+ }
+
+ if isDir {
+ // Watch the directory if it has not been watched before,
+ // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
+ w.mu.Lock()
+
+ watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
+ (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
+ // Store flags so this watch can be updated later
+ w.dirFlags[name] = flags
+ w.mu.Unlock()
+
+ if watchDir {
+ if err := w.watchDirectoryFiles(name); err != nil {
+ return "", err
+ }
+ }
+ }
+ return name, nil
+}
+
+// readEvents reads from kqueue and converts the received kevents into
+// Event values that it sends down the Events channel.
+func (w *Watcher) readEvents() {
+ eventBuffer := make([]unix.Kevent_t, 10)
+
+loop:
+ for {
+ // See if there is a message on the "done" channel
+ select {
+ case <-w.done:
+ break loop
+ default:
+ }
+
+ // Get new events
+ kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
+ // EINTR is okay, the syscall was interrupted before timeout expired.
+ if err != nil && err != unix.EINTR {
+ select {
+ case w.Errors <- err:
+ case <-w.done:
+ break loop
+ }
+ continue
+ }
+
+ // Flush the events we received to the Events channel
+ for len(kevents) > 0 {
+ kevent := &kevents[0]
+ watchfd := int(kevent.Ident)
+ mask := uint32(kevent.Fflags)
+ w.mu.Lock()
+ path := w.paths[watchfd]
+ w.mu.Unlock()
+ event := newEvent(path.name, mask)
+
+ if path.isDir && !(event.Op&Remove == Remove) {
+ // Double check to make sure the directory exists. This can happen when
+ // we do a rm -fr on a recursively watched folders and we receive a
+ // modification event first but the folder has been deleted and later
+ // receive the delete event
+ if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
+ // mark is as delete event
+ event.Op |= Remove
+ }
+ }
+
+ if event.Op&Rename == Rename || event.Op&Remove == Remove {
+ w.Remove(event.Name)
+ w.mu.Lock()
+ delete(w.fileExists, event.Name)
+ w.mu.Unlock()
+ }
+
+ if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
+ w.sendDirectoryChangeEvents(event.Name)
+ } else {
+ // Send the event on the Events channel.
+ select {
+ case w.Events <- event:
+ case <-w.done:
+ break loop
+ }
+ }
+
+ if event.Op&Remove == Remove {
+ // Look for a file that may have overwritten this.
+ // For example, mv f1 f2 will delete f2, then create f2.
+ if path.isDir {
+ fileDir := filepath.Clean(event.Name)
+ w.mu.Lock()
+ _, found := w.watches[fileDir]
+ w.mu.Unlock()
+ if found {
+ // make sure the directory exists before we watch for changes. When we
+ // do a recursive watch and perform rm -fr, the parent directory might
+ // have gone missing, ignore the missing directory and let the
+ // upcoming delete event remove the watch from the parent directory.
+ if _, err := os.Lstat(fileDir); err == nil {
+ w.sendDirectoryChangeEvents(fileDir)
+ }
+ }
+ } else {
+ filePath := filepath.Clean(event.Name)
+ if fileInfo, err := os.Lstat(filePath); err == nil {
+ w.sendFileCreatedEventIfNew(filePath, fileInfo)
+ }
+ }
+ }
+
+ // Move to next event
+ kevents = kevents[1:]
+ }
+ }
+
+ // cleanup
+ err := unix.Close(w.kq)
+ if err != nil {
+ // only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
+ select {
+ case w.Errors <- err:
+ default:
+ }
+ }
+ close(w.Events)
+ close(w.Errors)
+}
+
+// newEvent returns an platform-independent Event based on kqueue Fflags.
+func newEvent(name string, mask uint32) Event {
+ e := Event{Name: name}
+ if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
+ e.Op |= Remove
+ }
+ if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
+ e.Op |= Write
+ }
+ if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
+ e.Op |= Rename
+ }
+ if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
+ e.Op |= Chmod
+ }
+ return e
+}
+
+func newCreateEvent(name string) Event {
+ return Event{Name: name, Op: Create}
+}
+
+// watchDirectoryFiles to mimic inotify when adding a watch on a directory
+func (w *Watcher) watchDirectoryFiles(dirPath string) error {
+ // Get all files
+ files, err := ioutil.ReadDir(dirPath)
+ if err != nil {
+ return err
+ }
+
+ for _, fileInfo := range files {
+ filePath := filepath.Join(dirPath, fileInfo.Name())
+ filePath, err = w.internalWatch(filePath, fileInfo)
+ if err != nil {
+ return err
+ }
+
+ w.mu.Lock()
+ w.fileExists[filePath] = true
+ w.mu.Unlock()
+ }
+
+ return nil
+}
+
+// sendDirectoryEvents searches the directory for newly created files
+// and sends them over the event channel. This functionality is to have
+// the BSD version of fsnotify match Linux inotify which provides a
+// create event for files created in a watched directory.
+func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
+ // Get all files
+ files, err := ioutil.ReadDir(dirPath)
+ if err != nil {
+ select {
+ case w.Errors <- err:
+ case <-w.done:
+ return
+ }
+ }
+
+ // Search for new files
+ for _, fileInfo := range files {
+ filePath := filepath.Join(dirPath, fileInfo.Name())
+ err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
+
+ if err != nil {
+ return
+ }
+ }
+}
+
+// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
+func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
+ w.mu.Lock()
+ _, doesExist := w.fileExists[filePath]
+ w.mu.Unlock()
+ if !doesExist {
+ // Send create event
+ select {
+ case w.Events <- newCreateEvent(filePath):
+ case <-w.done:
+ return
+ }
+ }
+
+ // like watchDirectoryFiles (but without doing another ReadDir)
+ filePath, err = w.internalWatch(filePath, fileInfo)
+ if err != nil {
+ return err
+ }
+
+ w.mu.Lock()
+ w.fileExists[filePath] = true
+ w.mu.Unlock()
+
+ return nil
+}
+
+func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
+ if fileInfo.IsDir() {
+ // mimic Linux providing delete events for subdirectories
+ // but preserve the flags used if currently watching subdirectory
+ w.mu.Lock()
+ flags := w.dirFlags[name]
+ w.mu.Unlock()
+
+ flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
+ return w.addWatch(name, flags)
+ }
+
+ // watch file to mimic Linux inotify
+ return w.addWatch(name, noteAllEvents)
+}
+
+// kqueue creates a new kernel event queue and returns a descriptor.
+func kqueue() (kq int, err error) {
+ kq, err = unix.Kqueue()
+ if kq == -1 {
+ return kq, err
+ }
+ return kq, nil
+}
+
+// register events with the queue
+func register(kq int, fds []int, flags int, fflags uint32) error {
+ changes := make([]unix.Kevent_t, len(fds))
+
+ for i, fd := range fds {
+ // SetKevent converts int to the platform-specific types:
+ unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
+ changes[i].Fflags = fflags
+ }
+
+ // register the events
+ success, err := unix.Kevent(kq, changes, nil, nil)
+ if success == -1 {
+ return err
+ }
+ return nil
+}
+
+// read retrieves pending events, or waits until an event occurs.
+// A timeout of nil blocks indefinitely, while 0 polls the queue.
+func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) {
+ n, err := unix.Kevent(kq, nil, events, timeout)
+ if err != nil {
+ return nil, err
+ }
+ return events[0:n], nil
+}
+
+// durationToTimespec prepares a timeout value
+func durationToTimespec(d time.Duration) unix.Timespec {
+ return unix.NsecToTimespec(d.Nanoseconds())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
new file mode 100644
index 000000000000..36cc3845b6e7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
@@ -0,0 +1,12 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd || openbsd || netbsd || dragonfly
+// +build freebsd openbsd netbsd dragonfly
+
+package fsnotify
+
+import "golang.org/x/sys/unix"
+
+const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
new file mode 100644
index 000000000000..98cd8476ffb8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
@@ -0,0 +1,13 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+// +build darwin
+
+package fsnotify
+
+import "golang.org/x/sys/unix"
+
+// note: this constant is not defined on BSD
+const openMode = unix.O_EVTONLY | unix.O_CLOEXEC
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/windows.go b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/windows.go
new file mode 100644
index 000000000000..02ce7deb0bbf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/fsnotify/fsnotify/windows.go
@@ -0,0 +1,586 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build windows
+// +build windows
+
+package fsnotify
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "sync"
+ "syscall"
+ "unsafe"
+)
+
+// Watcher watches a set of files, delivering events to a channel.
+type Watcher struct {
+ Events chan Event
+ Errors chan error
+ isClosed bool // Set to true when Close() is first called
+ mu sync.Mutex // Map access
+ port syscall.Handle // Handle to completion port
+ watches watchMap // Map of watches (key: i-number)
+ input chan *input // Inputs to the reader are sent on this channel
+ quit chan chan<- error
+}
+
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
+func NewWatcher() (*Watcher, error) {
+ port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
+ if e != nil {
+ return nil, os.NewSyscallError("CreateIoCompletionPort", e)
+ }
+ w := &Watcher{
+ port: port,
+ watches: make(watchMap),
+ input: make(chan *input, 1),
+ Events: make(chan Event, 50),
+ Errors: make(chan error),
+ quit: make(chan chan<- error, 1),
+ }
+ go w.readEvents()
+ return w, nil
+}
+
+// Close removes all watches and closes the events channel.
+func (w *Watcher) Close() error {
+ if w.isClosed {
+ return nil
+ }
+ w.isClosed = true
+
+ // Send "quit" message to the reader goroutine
+ ch := make(chan error)
+ w.quit <- ch
+ if err := w.wakeupReader(); err != nil {
+ return err
+ }
+ return <-ch
+}
+
+// Add starts watching the named file or directory (non-recursively).
+func (w *Watcher) Add(name string) error {
+ if w.isClosed {
+ return errors.New("watcher already closed")
+ }
+ in := &input{
+ op: opAddWatch,
+ path: filepath.Clean(name),
+ flags: sysFSALLEVENTS,
+ reply: make(chan error),
+ }
+ w.input <- in
+ if err := w.wakeupReader(); err != nil {
+ return err
+ }
+ return <-in.reply
+}
+
+// Remove stops watching the the named file or directory (non-recursively).
+func (w *Watcher) Remove(name string) error {
+ in := &input{
+ op: opRemoveWatch,
+ path: filepath.Clean(name),
+ reply: make(chan error),
+ }
+ w.input <- in
+ if err := w.wakeupReader(); err != nil {
+ return err
+ }
+ return <-in.reply
+}
+
+// WatchList returns the directories and files that are being monitered.
+func (w *Watcher) WatchList() []string {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ entries := make([]string, 0, len(w.watches))
+ for _, entry := range w.watches {
+ for _, watchEntry := range entry {
+ entries = append(entries, watchEntry.path)
+ }
+ }
+
+ return entries
+}
+
+const (
+ // Options for AddWatch
+ sysFSONESHOT = 0x80000000
+ sysFSONLYDIR = 0x1000000
+
+ // Events
+ sysFSACCESS = 0x1
+ sysFSALLEVENTS = 0xfff
+ sysFSATTRIB = 0x4
+ sysFSCLOSE = 0x18
+ sysFSCREATE = 0x100
+ sysFSDELETE = 0x200
+ sysFSDELETESELF = 0x400
+ sysFSMODIFY = 0x2
+ sysFSMOVE = 0xc0
+ sysFSMOVEDFROM = 0x40
+ sysFSMOVEDTO = 0x80
+ sysFSMOVESELF = 0x800
+
+ // Special events
+ sysFSIGNORED = 0x8000
+ sysFSQOVERFLOW = 0x4000
+)
+
+func newEvent(name string, mask uint32) Event {
+ e := Event{Name: name}
+ if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
+ e.Op |= Create
+ }
+ if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
+ e.Op |= Remove
+ }
+ if mask&sysFSMODIFY == sysFSMODIFY {
+ e.Op |= Write
+ }
+ if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
+ e.Op |= Rename
+ }
+ if mask&sysFSATTRIB == sysFSATTRIB {
+ e.Op |= Chmod
+ }
+ return e
+}
+
+const (
+ opAddWatch = iota
+ opRemoveWatch
+)
+
+const (
+ provisional uint64 = 1 << (32 + iota)
+)
+
+type input struct {
+ op int
+ path string
+ flags uint32
+ reply chan error
+}
+
+type inode struct {
+ handle syscall.Handle
+ volume uint32
+ index uint64
+}
+
+type watch struct {
+ ov syscall.Overlapped
+ ino *inode // i-number
+ path string // Directory path
+ mask uint64 // Directory itself is being watched with these notify flags
+ names map[string]uint64 // Map of names being watched and their notify flags
+ rename string // Remembers the old name while renaming a file
+ buf [4096]byte
+}
+
+type indexMap map[uint64]*watch
+type watchMap map[uint32]indexMap
+
+func (w *Watcher) wakeupReader() error {
+ e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
+ if e != nil {
+ return os.NewSyscallError("PostQueuedCompletionStatus", e)
+ }
+ return nil
+}
+
+func getDir(pathname string) (dir string, err error) {
+ attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
+ if e != nil {
+ return "", os.NewSyscallError("GetFileAttributes", e)
+ }
+ if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
+ dir = pathname
+ } else {
+ dir, _ = filepath.Split(pathname)
+ dir = filepath.Clean(dir)
+ }
+ return
+}
+
+func getIno(path string) (ino *inode, err error) {
+ h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
+ syscall.FILE_LIST_DIRECTORY,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ nil, syscall.OPEN_EXISTING,
+ syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
+ if e != nil {
+ return nil, os.NewSyscallError("CreateFile", e)
+ }
+ var fi syscall.ByHandleFileInformation
+ if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
+ syscall.CloseHandle(h)
+ return nil, os.NewSyscallError("GetFileInformationByHandle", e)
+ }
+ ino = &inode{
+ handle: h,
+ volume: fi.VolumeSerialNumber,
+ index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
+ }
+ return ino, nil
+}
+
+// Must run within the I/O thread.
+func (m watchMap) get(ino *inode) *watch {
+ if i := m[ino.volume]; i != nil {
+ return i[ino.index]
+ }
+ return nil
+}
+
+// Must run within the I/O thread.
+func (m watchMap) set(ino *inode, watch *watch) {
+ i := m[ino.volume]
+ if i == nil {
+ i = make(indexMap)
+ m[ino.volume] = i
+ }
+ i[ino.index] = watch
+}
+
+// Must run within the I/O thread.
+func (w *Watcher) addWatch(pathname string, flags uint64) error {
+ dir, err := getDir(pathname)
+ if err != nil {
+ return err
+ }
+ if flags&sysFSONLYDIR != 0 && pathname != dir {
+ return nil
+ }
+ ino, err := getIno(dir)
+ if err != nil {
+ return err
+ }
+ w.mu.Lock()
+ watchEntry := w.watches.get(ino)
+ w.mu.Unlock()
+ if watchEntry == nil {
+ if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
+ syscall.CloseHandle(ino.handle)
+ return os.NewSyscallError("CreateIoCompletionPort", e)
+ }
+ watchEntry = &watch{
+ ino: ino,
+ path: dir,
+ names: make(map[string]uint64),
+ }
+ w.mu.Lock()
+ w.watches.set(ino, watchEntry)
+ w.mu.Unlock()
+ flags |= provisional
+ } else {
+ syscall.CloseHandle(ino.handle)
+ }
+ if pathname == dir {
+ watchEntry.mask |= flags
+ } else {
+ watchEntry.names[filepath.Base(pathname)] |= flags
+ }
+ if err = w.startRead(watchEntry); err != nil {
+ return err
+ }
+ if pathname == dir {
+ watchEntry.mask &= ^provisional
+ } else {
+ watchEntry.names[filepath.Base(pathname)] &= ^provisional
+ }
+ return nil
+}
+
+// Must run within the I/O thread.
+func (w *Watcher) remWatch(pathname string) error {
+ dir, err := getDir(pathname)
+ if err != nil {
+ return err
+ }
+ ino, err := getIno(dir)
+ if err != nil {
+ return err
+ }
+ w.mu.Lock()
+ watch := w.watches.get(ino)
+ w.mu.Unlock()
+ if watch == nil {
+ return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
+ }
+ if pathname == dir {
+ w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
+ watch.mask = 0
+ } else {
+ name := filepath.Base(pathname)
+ w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
+ delete(watch.names, name)
+ }
+ return w.startRead(watch)
+}
+
+// Must run within the I/O thread.
+func (w *Watcher) deleteWatch(watch *watch) {
+ for name, mask := range watch.names {
+ if mask&provisional == 0 {
+ w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
+ }
+ delete(watch.names, name)
+ }
+ if watch.mask != 0 {
+ if watch.mask&provisional == 0 {
+ w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
+ }
+ watch.mask = 0
+ }
+}
+
+// Must run within the I/O thread.
+func (w *Watcher) startRead(watch *watch) error {
+ if e := syscall.CancelIo(watch.ino.handle); e != nil {
+ w.Errors <- os.NewSyscallError("CancelIo", e)
+ w.deleteWatch(watch)
+ }
+ mask := toWindowsFlags(watch.mask)
+ for _, m := range watch.names {
+ mask |= toWindowsFlags(m)
+ }
+ if mask == 0 {
+ if e := syscall.CloseHandle(watch.ino.handle); e != nil {
+ w.Errors <- os.NewSyscallError("CloseHandle", e)
+ }
+ w.mu.Lock()
+ delete(w.watches[watch.ino.volume], watch.ino.index)
+ w.mu.Unlock()
+ return nil
+ }
+ e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
+ uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
+ if e != nil {
+ err := os.NewSyscallError("ReadDirectoryChanges", e)
+ if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
+ // Watched directory was probably removed
+ if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
+ if watch.mask&sysFSONESHOT != 0 {
+ watch.mask = 0
+ }
+ }
+ err = nil
+ }
+ w.deleteWatch(watch)
+ w.startRead(watch)
+ return err
+ }
+ return nil
+}
+
+// readEvents reads from the I/O completion port, converts the
+// received events into Event objects and sends them via the Events channel.
+// Entry point to the I/O thread.
+func (w *Watcher) readEvents() {
+ var (
+ n, key uint32
+ ov *syscall.Overlapped
+ )
+ runtime.LockOSThread()
+
+ for {
+ e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
+ watch := (*watch)(unsafe.Pointer(ov))
+
+ if watch == nil {
+ select {
+ case ch := <-w.quit:
+ w.mu.Lock()
+ var indexes []indexMap
+ for _, index := range w.watches {
+ indexes = append(indexes, index)
+ }
+ w.mu.Unlock()
+ for _, index := range indexes {
+ for _, watch := range index {
+ w.deleteWatch(watch)
+ w.startRead(watch)
+ }
+ }
+ var err error
+ if e := syscall.CloseHandle(w.port); e != nil {
+ err = os.NewSyscallError("CloseHandle", e)
+ }
+ close(w.Events)
+ close(w.Errors)
+ ch <- err
+ return
+ case in := <-w.input:
+ switch in.op {
+ case opAddWatch:
+ in.reply <- w.addWatch(in.path, uint64(in.flags))
+ case opRemoveWatch:
+ in.reply <- w.remWatch(in.path)
+ }
+ default:
+ }
+ continue
+ }
+
+ switch e {
+ case syscall.ERROR_MORE_DATA:
+ if watch == nil {
+ w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
+ } else {
+ // The i/o succeeded but the buffer is full.
+ // In theory we should be building up a full packet.
+ // In practice we can get away with just carrying on.
+ n = uint32(unsafe.Sizeof(watch.buf))
+ }
+ case syscall.ERROR_ACCESS_DENIED:
+ // Watched directory was probably removed
+ w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
+ w.deleteWatch(watch)
+ w.startRead(watch)
+ continue
+ case syscall.ERROR_OPERATION_ABORTED:
+ // CancelIo was called on this handle
+ continue
+ default:
+ w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
+ continue
+ case nil:
+ }
+
+ var offset uint32
+ for {
+ if n == 0 {
+ w.Events <- newEvent("", sysFSQOVERFLOW)
+ w.Errors <- errors.New("short read in readEvents()")
+ break
+ }
+
+ // Point "raw" to the event in the buffer
+ raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
+ // TODO: Consider using unsafe.Slice that is available from go1.17
+ // https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang
+ // instead of using a fixed syscall.MAX_PATH buf, we create a buf that is the size of the path name
+ size := int(raw.FileNameLength / 2)
+ var buf []uint16
+ sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ sh.Data = uintptr(unsafe.Pointer(&raw.FileName))
+ sh.Len = size
+ sh.Cap = size
+ name := syscall.UTF16ToString(buf)
+ fullname := filepath.Join(watch.path, name)
+
+ var mask uint64
+ switch raw.Action {
+ case syscall.FILE_ACTION_REMOVED:
+ mask = sysFSDELETESELF
+ case syscall.FILE_ACTION_MODIFIED:
+ mask = sysFSMODIFY
+ case syscall.FILE_ACTION_RENAMED_OLD_NAME:
+ watch.rename = name
+ case syscall.FILE_ACTION_RENAMED_NEW_NAME:
+ if watch.names[watch.rename] != 0 {
+ watch.names[name] |= watch.names[watch.rename]
+ delete(watch.names, watch.rename)
+ mask = sysFSMOVESELF
+ }
+ }
+
+ sendNameEvent := func() {
+ if w.sendEvent(fullname, watch.names[name]&mask) {
+ if watch.names[name]&sysFSONESHOT != 0 {
+ delete(watch.names, name)
+ }
+ }
+ }
+ if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
+ sendNameEvent()
+ }
+ if raw.Action == syscall.FILE_ACTION_REMOVED {
+ w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
+ delete(watch.names, name)
+ }
+ if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
+ if watch.mask&sysFSONESHOT != 0 {
+ watch.mask = 0
+ }
+ }
+ if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
+ fullname = filepath.Join(watch.path, watch.rename)
+ sendNameEvent()
+ }
+
+ // Move to the next event in the buffer
+ if raw.NextEntryOffset == 0 {
+ break
+ }
+ offset += raw.NextEntryOffset
+
+ // Error!
+ if offset >= n {
+ w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
+ break
+ }
+ }
+
+ if err := w.startRead(watch); err != nil {
+ w.Errors <- err
+ }
+ }
+}
+
+func (w *Watcher) sendEvent(name string, mask uint64) bool {
+ if mask == 0 {
+ return false
+ }
+ event := newEvent(name, uint32(mask))
+ select {
+ case ch := <-w.quit:
+ w.quit <- ch
+ case w.Events <- event:
+ }
+ return true
+}
+
+func toWindowsFlags(mask uint64) uint32 {
+ var m uint32
+ if mask&sysFSACCESS != 0 {
+ m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
+ }
+ if mask&sysFSMODIFY != 0 {
+ m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
+ }
+ if mask&sysFSATTRIB != 0 {
+ m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
+ }
+ if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
+ m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
+ }
+ return m
+}
+
+func toFSnotifyFlags(action uint32) uint64 {
+ switch action {
+ case syscall.FILE_ACTION_ADDED:
+ return sysFSCREATE
+ case syscall.FILE_ACTION_REMOVED:
+ return sysFSDELETE
+ case syscall.FILE_ACTION_MODIFIED:
+ return sysFSMODIFY
+ case syscall.FILE_ACTION_RENAMED_OLD_NAME:
+ return sysFSMOVEDFROM
+ case syscall.FILE_ACTION_RENAMED_NEW_NAME:
+ return sysFSMOVEDTO
+ }
+ return 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/.travis.yml
new file mode 100644
index 000000000000..d0e8fcf99437
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/.travis.yml
@@ -0,0 +1,26 @@
+language: go
+sudo: false
+go:
+ - 1.8.x
+ - 1.9.x
+ - 1.10.x
+ - 1.11.x
+ - 1.12.x
+ - master
+
+git:
+ depth: 10
+
+matrix:
+ fast_finish: true
+ include:
+ - go: 1.11.x
+ env: GO111MODULE=on
+ - go: 1.12.x
+ env: GO111MODULE=on
+
+script:
+ - go test -v -covermode=count -coverprofile=coverage.out
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/LICENSE
new file mode 100644
index 000000000000..1ff7f3706055
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Manuel Martínez-Almeida
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/README.md
new file mode 100644
index 000000000000..c9c49cf94959
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/README.md
@@ -0,0 +1,58 @@
+# Server-Sent Events
+
+[![GoDoc](https://godoc.org/github.com/gin-contrib/sse?status.svg)](https://godoc.org/github.com/gin-contrib/sse)
+[![Build Status](https://travis-ci.org/gin-contrib/sse.svg)](https://travis-ci.org/gin-contrib/sse)
+[![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse)
+[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse)
+
+Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/).
+
+- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/)
+- [Browser support](http://caniuse.com/#feat=eventsource)
+
+## Sample code
+
+```go
+import "github.com/gin-contrib/sse"
+
+func httpHandler(w http.ResponseWriter, req *http.Request) {
+ // data can be a primitive like a string, an integer or a float
+ sse.Encode(w, sse.Event{
+ Event: "message",
+ Data: "some data\nmore data",
+ })
+
+ // also a complex type, like a map, a struct or a slice
+ sse.Encode(w, sse.Event{
+ Id: "124",
+ Event: "message",
+ Data: map[string]interface{}{
+ "user": "manu",
+ "date": time.Now().Unix(),
+ "content": "hi!",
+ },
+ })
+}
+```
+```
+event: message
+data: some data\\nmore data
+
+id: 124
+event: message
+data: {"content":"hi!","date":1431540810,"user":"manu"}
+
+```
+
+## Content-Type
+
+```go
+fmt.Println(sse.ContentType)
+```
+```
+text/event-stream
+```
+
+## Decoding support
+
+There is a client-side implementation of SSE coming soon.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/sse-decoder.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/sse-decoder.go
new file mode 100644
index 000000000000..fd49b9c37a45
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/sse-decoder.go
@@ -0,0 +1,116 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package sse
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+)
+
+type decoder struct {
+ events []Event
+}
+
+func Decode(r io.Reader) ([]Event, error) {
+ var dec decoder
+ return dec.decode(r)
+}
+
+func (d *decoder) dispatchEvent(event Event, data string) {
+ dataLength := len(data)
+ if dataLength > 0 {
+ //If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer.
+ data = data[:dataLength-1]
+ dataLength--
+ }
+ if dataLength == 0 && event.Event == "" {
+ return
+ }
+ if event.Event == "" {
+ event.Event = "message"
+ }
+ event.Data = data
+ d.events = append(d.events, event)
+}
+
+func (d *decoder) decode(r io.Reader) ([]Event, error) {
+ buf, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, err
+ }
+
+ var currentEvent Event
+ var dataBuffer *bytes.Buffer = new(bytes.Buffer)
+ // TODO (and unit tests)
+ // Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair,
+ // a single U+000A LINE FEED (LF) character,
+ // or a single U+000D CARRIAGE RETURN (CR) character.
+ lines := bytes.Split(buf, []byte{'\n'})
+ for _, line := range lines {
+ if len(line) == 0 {
+ // If the line is empty (a blank line). Dispatch the event.
+ d.dispatchEvent(currentEvent, dataBuffer.String())
+
+ // reset current event and data buffer
+ currentEvent = Event{}
+ dataBuffer.Reset()
+ continue
+ }
+ if line[0] == byte(':') {
+ // If the line starts with a U+003A COLON character (:), ignore the line.
+ continue
+ }
+
+ var field, value []byte
+ colonIndex := bytes.IndexRune(line, ':')
+ if colonIndex != -1 {
+ // If the line contains a U+003A COLON character character (:)
+ // Collect the characters on the line before the first U+003A COLON character (:),
+ // and let field be that string.
+ field = line[:colonIndex]
+ // Collect the characters on the line after the first U+003A COLON character (:),
+ // and let value be that string.
+ value = line[colonIndex+1:]
+ // If value starts with a single U+0020 SPACE character, remove it from value.
+ if len(value) > 0 && value[0] == ' ' {
+ value = value[1:]
+ }
+ } else {
+ // Otherwise, the string is not empty but does not contain a U+003A COLON character character (:)
+ // Use the whole line as the field name, and the empty string as the field value.
+ field = line
+ value = []byte{}
+ }
+ // The steps to process the field given a field name and a field value depend on the field name,
+ // as given in the following list. Field names must be compared literally,
+ // with no case folding performed.
+ switch string(field) {
+ case "event":
+ // Set the event name buffer to field value.
+ currentEvent.Event = string(value)
+ case "id":
+ // Set the event stream's last event ID to the field value.
+ currentEvent.Id = string(value)
+ case "retry":
+ // If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
+ // then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer.
+ // Otherwise, ignore the field.
+ currentEvent.Id = string(value)
+ case "data":
+ // Append the field value to the data buffer,
+ dataBuffer.Write(value)
+ // then append a single U+000A LINE FEED (LF) character to the data buffer.
+ dataBuffer.WriteString("\n")
+ default:
+ //Otherwise. The field is ignored.
+ continue
+ }
+ }
+ // Once the end of the file is reached, the user agent must dispatch the event one final time.
+ d.dispatchEvent(currentEvent, dataBuffer.String())
+
+ return d.events, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/sse-encoder.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/sse-encoder.go
new file mode 100644
index 000000000000..f9c8087504d4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/sse-encoder.go
@@ -0,0 +1,110 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package sse
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// Server-Sent Events
+// W3C Working Draft 29 October 2009
+// http://www.w3.org/TR/2009/WD-eventsource-20091029/
+
+const ContentType = "text/event-stream"
+
+var contentType = []string{ContentType}
+var noCache = []string{"no-cache"}
+
+var fieldReplacer = strings.NewReplacer(
+ "\n", "\\n",
+ "\r", "\\r")
+
+var dataReplacer = strings.NewReplacer(
+ "\n", "\ndata:",
+ "\r", "\\r")
+
+type Event struct {
+ Event string
+ Id string
+ Retry uint
+ Data interface{}
+}
+
+func Encode(writer io.Writer, event Event) error {
+ w := checkWriter(writer)
+ writeId(w, event.Id)
+ writeEvent(w, event.Event)
+ writeRetry(w, event.Retry)
+ return writeData(w, event.Data)
+}
+
+func writeId(w stringWriter, id string) {
+ if len(id) > 0 {
+ w.WriteString("id:")
+ fieldReplacer.WriteString(w, id)
+ w.WriteString("\n")
+ }
+}
+
+func writeEvent(w stringWriter, event string) {
+ if len(event) > 0 {
+ w.WriteString("event:")
+ fieldReplacer.WriteString(w, event)
+ w.WriteString("\n")
+ }
+}
+
+func writeRetry(w stringWriter, retry uint) {
+ if retry > 0 {
+ w.WriteString("retry:")
+ w.WriteString(strconv.FormatUint(uint64(retry), 10))
+ w.WriteString("\n")
+ }
+}
+
+func writeData(w stringWriter, data interface{}) error {
+ w.WriteString("data:")
+ switch kindOfData(data) {
+ case reflect.Struct, reflect.Slice, reflect.Map:
+ err := json.NewEncoder(w).Encode(data)
+ if err != nil {
+ return err
+ }
+ w.WriteString("\n")
+ default:
+ dataReplacer.WriteString(w, fmt.Sprint(data))
+ w.WriteString("\n\n")
+ }
+ return nil
+}
+
+func (r Event) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+ return Encode(w, r)
+}
+
+func (r Event) WriteContentType(w http.ResponseWriter) {
+ header := w.Header()
+ header["Content-Type"] = contentType
+
+ if _, exist := header["Cache-Control"]; !exist {
+ header["Cache-Control"] = noCache
+ }
+}
+
+func kindOfData(data interface{}) reflect.Kind {
+ value := reflect.ValueOf(data)
+ valueType := value.Kind()
+ if valueType == reflect.Ptr {
+ valueType = value.Elem().Kind()
+ }
+ return valueType
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/writer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/writer.go
new file mode 100644
index 000000000000..6f9806c55a3e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-contrib/sse/writer.go
@@ -0,0 +1,24 @@
+package sse
+
+import "io"
+
+type stringWriter interface {
+ io.Writer
+ WriteString(string) (int, error)
+}
+
+type stringWrapper struct {
+ io.Writer
+}
+
+func (w stringWrapper) WriteString(str string) (int, error) {
+ return w.Writer.Write([]byte(str))
+}
+
+func checkWriter(writer io.Writer) stringWriter {
+ if w, ok := writer.(stringWriter); ok {
+ return w
+ } else {
+ return stringWrapper{writer}
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/.gitignore
new file mode 100644
index 000000000000..bdd50c95cf9d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/.gitignore
@@ -0,0 +1,7 @@
+vendor/*
+!vendor/vendor.json
+coverage.out
+count.out
+test
+profile.out
+tmp.out
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/.travis.yml
new file mode 100644
index 000000000000..bcc21414d1b8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/.travis.yml
@@ -0,0 +1,48 @@
+language: go
+
+matrix:
+ fast_finish: true
+ include:
+ - go: 1.13.x
+ - go: 1.13.x
+ env:
+ - TESTTAGS=nomsgpack
+ - go: 1.14.x
+ - go: 1.14.x
+ env:
+ - TESTTAGS=nomsgpack
+ - go: 1.15.x
+ - go: 1.15.x
+ env:
+ - TESTTAGS=nomsgpack
+ - go: master
+
+git:
+ depth: 10
+
+before_install:
+ - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi
+
+install:
+ - if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
+ - if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
+ - if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
+
+go_import_path: github.com/gin-gonic/gin
+
+script:
+ - make vet
+ - make fmt-check
+ - make misspell-check
+ - make test
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
+
+notifications:
+ webhooks:
+ urls:
+ - https://webhooks.gitter.im/e/7f95bf605c4d356372f4
+ on_success: change # options: [always|never|change] default: always
+ on_failure: always # options: [always|never|change] default: always
+ on_start: false # default: false
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/AUTHORS.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/AUTHORS.md
new file mode 100644
index 000000000000..c634e6be05ae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/AUTHORS.md
@@ -0,0 +1,233 @@
+List of all the awesome people working to make Gin the best Web Framework in Go.
+
+## gin 1.x series authors
+
+**Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho)
+
+## gin 0.x series authors
+
+**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
+
+People and companies, who have contributed, in alphabetical order.
+
+**@858806258 (杰哥)**
+- Fix typo in example
+
+
+**@achedeuzot (Klemen Sever)**
+- Fix newline debug printing
+
+
+**@adammck (Adam Mckaig)**
+- Add MIT license
+
+
+**@AlexanderChen1989 (Alexander)**
+- Typos in README
+
+
+**@alexanderdidenko (Aleksandr Didenko)**
+- Add support multipart/form-data
+
+
+**@alexandernyquist (Alexander Nyquist)**
+- Using template.Must to fix multiple return issue
+- ★ Added support for OPTIONS verb
+- ★ Setting response headers before calling WriteHeader
+- Improved documentation for model binding
+- ★ Added Content.Redirect()
+- ★ Added tons of Unit tests
+
+
+**@austinheap (Austin Heap)**
+- Added travis CI integration
+
+
+**@andredublin (Andre Dublin)**
+- Fix typo in comment
+
+
+**@bredov (Ludwig Valda Vasquez)**
+- Fix html templating in debug mode
+
+
+**@bluele (Jun Kimura)**
+- Fixes code examples in README
+
+
+**@chad-russell**
+- ★ Support for serializing gin.H into XML
+
+
+**@dickeyxxx (Jeff Dickey)**
+- Typos in README
+- Add example about serving static files
+
+
+**@donileo (Adonis)**
+- Add NoMethod handler
+
+
+**@dutchcoders (DutchCoders)**
+- ★ Fix security bug that allows client to spoof ip
+- Fix typo. r.HTMLTemplates -> SetHTMLTemplate
+
+
+**@el3ctro- (Joshua Loper)**
+- Fix typo in example
+
+
+**@ethankan (Ethan Kan)**
+- Unsigned integers in binding
+
+
+**(Evgeny Persienko)**
+- Validate sub structures
+
+
+**@frankbille (Frank Bille)**
+- Add support for HTTP Realm Auth
+
+
+**@fmd (Fareed Dudhia)**
+- Fix typo. SetHTTPTemplate -> SetHTMLTemplate
+
+
+**@ironiridis (Christopher Harrington)**
+- Remove old reference
+
+
+**@jammie-stackhouse (Jamie Stackhouse)**
+- Add more shortcuts for router methods
+
+
+**@jasonrhansen**
+- Fix spelling and grammar errors in documentation
+
+
+**@JasonSoft (Jason Lee)**
+- Fix typo in comment
+
+
+**@joiggama (Ignacio Galindo)**
+- Add utf-8 charset header on renders
+
+
+**@julienschmidt (Julien Schmidt)**
+- gofmt the code examples
+
+
+**@kelcecil (Kel Cecil)**
+- Fix readme typo
+
+
+**@kyledinh (Kyle Dinh)**
+- Adds RunTLS()
+
+
+**@LinusU (Linus Unnebäck)**
+- Small fixes in README
+
+
+**@loongmxbt (Saint Asky)**
+- Fix typo in example
+
+
+**@lucas-clemente (Lucas Clemente)**
+- ★ work around path.Join removing trailing slashes from routes
+
+
+**@mattn (Yasuhiro Matsumoto)**
+- Improve color logger
+
+
+**@mdigger (Dmitry Sedykh)**
+- Fixes Form binding when content-type is x-www-form-urlencoded
+- No repeat call c.Writer.Status() in gin.Logger
+- Fixes Content-Type for json render
+
+
+**@mirzac (Mirza Ceric)**
+- Fix debug printing
+
+
+**@mopemope (Yutaka Matsubara)**
+- ★ Adds Godep support (Dependencies Manager)
+- Fix variadic parameter in the flexible render API
+- Fix Corrupted plain render
+- Add Pluggable View Renderer Example
+
+
+**@msemenistyi (Mykyta Semenistyi)**
+- update Readme.md. Add code to String method
+
+
+**@msoedov (Sasha Myasoedov)**
+- ★ Adds tons of unit tests.
+
+
+**@ngerakines (Nick Gerakines)**
+- ★ Improves API, c.GET() doesn't panic
+- Adds MustGet() method
+
+
+**@r8k (Rajiv Kilaparti)**
+- Fix Port usage in README.
+
+
+**@rayrod2030 (Ray Rodriguez)**
+- Fix typo in example
+
+
+**@rns**
+- Fix typo in example
+
+
+**@RobAWilkinson (Robert Wilkinson)**
+- Add example of forms and params
+
+
+**@rogierlommers (Rogier Lommers)**
+- Add updated static serve example
+
+**@rw-access (Ross Wolf)**
+- Added support to mix exact and param routes
+
+**@se77en (Damon Zhao)**
+- Improve color logging
+
+
+**@silasb (Silas Baronda)**
+- Fixing quotes in README
+
+
+**@SkuliOskarsson (Skuli Oskarsson)**
+- Fixes some texts in README II
+
+
+**@slimmy (Jimmy Pettersson)**
+- Added messages for required bindings
+
+
+**@smira (Andrey Smirnov)**
+- Add support for ignored/unexported fields in binding
+
+
+**@superalsrk (SRK.Lyu)**
+- Update httprouter godeps
+
+
+**@tebeka (Miki Tebeka)**
+- Use net/http constants instead of numeric values
+
+
+**@techjanitor**
+- Update context.go reserved IPs
+
+
+**@yosssi (Keiji Yoshida)**
+- Fix link in README
+
+
+**@yuyabee**
+- Fixed README
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/BENCHMARKS.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/BENCHMARKS.md
new file mode 100644
index 000000000000..c11ee99ae7f4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/BENCHMARKS.md
@@ -0,0 +1,666 @@
+
+# Benchmark System
+
+**VM HOST:** Travis
+**Machine:** Ubuntu 16.04.6 LTS x64
+**Date:** May 04th, 2020
+**Version:** Gin v1.6.3
+**Go Version:** 1.14.2 linux/amd64
+**Source:** [Go HTTP Router Benchmark](https://github.com/gin-gonic/go-http-routing-benchmark)
+**Result:** [See the gist](https://gist.github.com/appleboy/b5f2ecfaf50824ae9c64dcfb9165ae5e) or [Travis result](https://travis-ci.org/github/gin-gonic/go-http-routing-benchmark/jobs/682947061)
+
+## Static Routes: 157
+
+```sh
+Gin: 34936 Bytes
+
+HttpServeMux: 14512 Bytes
+Ace: 30680 Bytes
+Aero: 34536 Bytes
+Bear: 30456 Bytes
+Beego: 98456 Bytes
+Bone: 40224 Bytes
+Chi: 83608 Bytes
+Denco: 10216 Bytes
+Echo: 80328 Bytes
+GocraftWeb: 55288 Bytes
+Goji: 29744 Bytes
+Gojiv2: 105840 Bytes
+GoJsonRest: 137496 Bytes
+GoRestful: 816936 Bytes
+GorillaMux: 585632 Bytes
+GowwwRouter: 24968 Bytes
+HttpRouter: 21712 Bytes
+HttpTreeMux: 73448 Bytes
+Kocha: 115472 Bytes
+LARS: 30640 Bytes
+Macaron: 38592 Bytes
+Martini: 310864 Bytes
+Pat: 19696 Bytes
+Possum: 89920 Bytes
+R2router: 23712 Bytes
+Rivet: 24608 Bytes
+Tango: 28264 Bytes
+TigerTonic: 78768 Bytes
+Traffic: 538976 Bytes
+Vulcan: 369960 Bytes
+```
+
+## GithubAPI Routes: 203
+
+```sh
+Gin: 58512 Bytes
+
+Ace: 48688 Bytes
+Aero: 318568 Bytes
+Bear: 84248 Bytes
+Beego: 150936 Bytes
+Bone: 100976 Bytes
+Chi: 95112 Bytes
+Denco: 36736 Bytes
+Echo: 100296 Bytes
+GocraftWeb: 95432 Bytes
+Goji: 49680 Bytes
+Gojiv2: 104704 Bytes
+GoJsonRest: 141976 Bytes
+GoRestful: 1241656 Bytes
+GorillaMux: 1322784 Bytes
+GowwwRouter: 80008 Bytes
+HttpRouter: 37144 Bytes
+HttpTreeMux: 78800 Bytes
+Kocha: 785120 Bytes
+LARS: 48600 Bytes
+Macaron: 92784 Bytes
+Martini: 485264 Bytes
+Pat: 21200 Bytes
+Possum: 85312 Bytes
+R2router: 47104 Bytes
+Rivet: 42840 Bytes
+Tango: 54840 Bytes
+TigerTonic: 95264 Bytes
+Traffic: 921744 Bytes
+Vulcan: 425992 Bytes
+```
+
+## GPlusAPI Routes: 13
+
+```sh
+Gin: 4384 Bytes
+
+Ace: 3712 Bytes
+Aero: 26056 Bytes
+Bear: 7112 Bytes
+Beego: 10272 Bytes
+Bone: 6688 Bytes
+Chi: 8024 Bytes
+Denco: 3264 Bytes
+Echo: 9688 Bytes
+GocraftWeb: 7496 Bytes
+Goji: 3152 Bytes
+Gojiv2: 7376 Bytes
+GoJsonRest: 11400 Bytes
+GoRestful: 74328 Bytes
+GorillaMux: 66208 Bytes
+GowwwRouter: 5744 Bytes
+HttpRouter: 2808 Bytes
+HttpTreeMux: 7440 Bytes
+Kocha: 128880 Bytes
+LARS: 3656 Bytes
+Macaron: 8656 Bytes
+Martini: 23920 Bytes
+Pat: 1856 Bytes
+Possum: 7248 Bytes
+R2router: 3928 Bytes
+Rivet: 3064 Bytes
+Tango: 5168 Bytes
+TigerTonic: 9408 Bytes
+Traffic: 46400 Bytes
+Vulcan: 25544 Bytes
+```
+
+## ParseAPI Routes: 26
+
+```sh
+Gin: 7776 Bytes
+
+Ace: 6704 Bytes
+Aero: 28488 Bytes
+Bear: 12320 Bytes
+Beego: 19280 Bytes
+Bone: 11440 Bytes
+Chi: 9744 Bytes
+Denco: 4192 Bytes
+Echo: 11664 Bytes
+GocraftWeb: 12800 Bytes
+Goji: 5680 Bytes
+Gojiv2: 14464 Bytes
+GoJsonRest: 14072 Bytes
+GoRestful: 116264 Bytes
+GorillaMux: 105880 Bytes
+GowwwRouter: 9344 Bytes
+HttpRouter: 5072 Bytes
+HttpTreeMux: 7848 Bytes
+Kocha: 181712 Bytes
+LARS: 6632 Bytes
+Macaron: 13648 Bytes
+Martini: 45888 Bytes
+Pat: 2560 Bytes
+Possum: 9200 Bytes
+R2router: 7056 Bytes
+Rivet: 5680 Bytes
+Tango: 8920 Bytes
+TigerTonic: 9840 Bytes
+Traffic: 79096 Bytes
+Vulcan: 44504 Bytes
+```
+
+## Static Routes
+
+```sh
+BenchmarkGin_StaticAll 62169 19319 ns/op 0 B/op 0 allocs/op
+
+BenchmarkAce_StaticAll 65428 18313 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_StaticAll 121132 9632 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpServeMux_StaticAll 52626 22758 ns/op 0 B/op 0 allocs/op
+BenchmarkBeego_StaticAll 9962 179058 ns/op 55264 B/op 471 allocs/op
+BenchmarkBear_StaticAll 14894 80966 ns/op 20272 B/op 469 allocs/op
+BenchmarkBone_StaticAll 18718 64065 ns/op 0 B/op 0 allocs/op
+BenchmarkChi_StaticAll 10000 149827 ns/op 67824 B/op 471 allocs/op
+BenchmarkDenco_StaticAll 211393 5680 ns/op 0 B/op 0 allocs/op
+BenchmarkEcho_StaticAll 49341 24343 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_StaticAll 10000 126209 ns/op 46312 B/op 785 allocs/op
+BenchmarkGoji_StaticAll 27956 43174 ns/op 0 B/op 0 allocs/op
+BenchmarkGojiv2_StaticAll 3430 370718 ns/op 205984 B/op 1570 allocs/op
+BenchmarkGoJsonRest_StaticAll 9134 188888 ns/op 51653 B/op 1727 allocs/op
+BenchmarkGoRestful_StaticAll 706 1703330 ns/op 613280 B/op 2053 allocs/op
+BenchmarkGorillaMux_StaticAll 1268 924083 ns/op 153233 B/op 1413 allocs/op
+BenchmarkGowwwRouter_StaticAll 63374 18935 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpRouter_StaticAll 109938 10902 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_StaticAll 109166 10861 ns/op 0 B/op 0 allocs/op
+BenchmarkKocha_StaticAll 92258 12992 ns/op 0 B/op 0 allocs/op
+BenchmarkLARS_StaticAll 65200 18387 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_StaticAll 5671 291501 ns/op 115553 B/op 1256 allocs/op
+BenchmarkMartini_StaticAll 807 1460498 ns/op 125444 B/op 1717 allocs/op
+BenchmarkPat_StaticAll 513 2342396 ns/op 602832 B/op 12559 allocs/op
+BenchmarkPossum_StaticAll 10000 128270 ns/op 65312 B/op 471 allocs/op
+BenchmarkR2router_StaticAll 16726 71760 ns/op 22608 B/op 628 allocs/op
+BenchmarkRivet_StaticAll 41722 28723 ns/op 0 B/op 0 allocs/op
+BenchmarkTango_StaticAll 7606 205082 ns/op 39209 B/op 1256 allocs/op
+BenchmarkTigerTonic_StaticAll 26247 45806 ns/op 7376 B/op 157 allocs/op
+BenchmarkTraffic_StaticAll 550 2284518 ns/op 754864 B/op 14601 allocs/op
+BenchmarkVulcan_StaticAll 10000 131343 ns/op 15386 B/op 471 allocs/op
+```
+
+## Micro Benchmarks
+
+```sh
+BenchmarkGin_Param 18785022 63.9 ns/op 0 B/op 0 allocs/op
+
+BenchmarkAce_Param 14689765 81.5 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_Param 23094770 51.2 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_Param 1417045 845 ns/op 456 B/op 5 allocs/op
+BenchmarkBeego_Param 1000000 1080 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_Param 1000000 1463 ns/op 816 B/op 6 allocs/op
+BenchmarkChi_Param 1378756 885 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_Param 8557899 143 ns/op 32 B/op 1 allocs/op
+BenchmarkEcho_Param 16433347 75.5 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_Param 1000000 1218 ns/op 648 B/op 8 allocs/op
+BenchmarkGoji_Param 1921248 617 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_Param 561848 2156 ns/op 1328 B/op 11 allocs/op
+BenchmarkGoJsonRest_Param 1000000 1358 ns/op 649 B/op 13 allocs/op
+BenchmarkGoRestful_Param 224857 5307 ns/op 4192 B/op 14 allocs/op
+BenchmarkGorillaMux_Param 498313 2459 ns/op 1280 B/op 10 allocs/op
+BenchmarkGowwwRouter_Param 1864354 654 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_Param 26269074 47.7 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_Param 2109829 557 ns/op 352 B/op 3 allocs/op
+BenchmarkKocha_Param 5050216 243 ns/op 56 B/op 3 allocs/op
+BenchmarkLARS_Param 19811712 59.9 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_Param 662746 2329 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_Param 279902 4260 ns/op 1072 B/op 10 allocs/op
+BenchmarkPat_Param 1000000 1382 ns/op 536 B/op 11 allocs/op
+BenchmarkPossum_Param 1000000 1014 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_Param 1712559 707 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_Param 6648086 182 ns/op 48 B/op 1 allocs/op
+BenchmarkTango_Param 1221504 994 ns/op 248 B/op 8 allocs/op
+BenchmarkTigerTonic_Param 891661 2261 ns/op 776 B/op 16 allocs/op
+BenchmarkTraffic_Param 350059 3598 ns/op 1856 B/op 21 allocs/op
+BenchmarkVulcan_Param 2517823 472 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_Param5 9214365 130 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_Param5 15369013 77.9 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_Param5 1000000 1113 ns/op 501 B/op 5 allocs/op
+BenchmarkBeego_Param5 1000000 1269 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_Param5 986820 1873 ns/op 864 B/op 6 allocs/op
+BenchmarkChi_Param5 1000000 1156 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_Param5 3036331 400 ns/op 160 B/op 1 allocs/op
+BenchmarkEcho_Param5 6447133 186 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_Param5 10786068 110 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_Param5 844820 1944 ns/op 920 B/op 11 allocs/op
+BenchmarkGoji_Param5 1474965 827 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_Param5 442820 2516 ns/op 1392 B/op 11 allocs/op
+BenchmarkGoJsonRest_Param5 507555 2711 ns/op 1097 B/op 16 allocs/op
+BenchmarkGoRestful_Param5 216481 6093 ns/op 4288 B/op 14 allocs/op
+BenchmarkGorillaMux_Param5 314402 3628 ns/op 1344 B/op 10 allocs/op
+BenchmarkGowwwRouter_Param5 1624660 733 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_Param5 13167324 92.0 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_Param5 1000000 1295 ns/op 576 B/op 6 allocs/op
+BenchmarkKocha_Param5 1000000 1138 ns/op 440 B/op 10 allocs/op
+BenchmarkLARS_Param5 11580613 105 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_Param5 473596 2755 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_Param5 230756 5111 ns/op 1232 B/op 11 allocs/op
+BenchmarkPat_Param5 469190 3370 ns/op 888 B/op 29 allocs/op
+BenchmarkPossum_Param5 1000000 1002 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_Param5 1422129 844 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_Param5 2263789 539 ns/op 240 B/op 1 allocs/op
+BenchmarkTango_Param5 1000000 1256 ns/op 360 B/op 8 allocs/op
+BenchmarkTigerTonic_Param5 175500 7492 ns/op 2279 B/op 39 allocs/op
+BenchmarkTraffic_Param5 233631 5816 ns/op 2208 B/op 27 allocs/op
+BenchmarkVulcan_Param5 1923416 629 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_Param20 4321266 281 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_Param20 31501641 35.2 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_Param20 335204 3489 ns/op 1665 B/op 5 allocs/op
+BenchmarkBeego_Param20 503674 2860 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_Param20 298922 4741 ns/op 2031 B/op 6 allocs/op
+BenchmarkChi_Param20 878181 1957 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_Param20 1000000 1360 ns/op 640 B/op 1 allocs/op
+BenchmarkEcho_Param20 2104946 580 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_Param20 4167204 290 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_Param20 173064 7514 ns/op 3796 B/op 15 allocs/op
+BenchmarkGoji_Param20 458778 2651 ns/op 1247 B/op 2 allocs/op
+BenchmarkGojiv2_Param20 364862 3178 ns/op 1632 B/op 11 allocs/op
+BenchmarkGoJsonRest_Param20 125514 9760 ns/op 4485 B/op 20 allocs/op
+BenchmarkGoRestful_Param20 101217 11964 ns/op 6715 B/op 18 allocs/op
+BenchmarkGorillaMux_Param20 147654 8132 ns/op 3452 B/op 12 allocs/op
+BenchmarkGowwwRouter_Param20 1000000 1225 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_Param20 4920895 247 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_Param20 173202 6605 ns/op 3196 B/op 10 allocs/op
+BenchmarkKocha_Param20 345988 3620 ns/op 1808 B/op 27 allocs/op
+BenchmarkLARS_Param20 4592326 262 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_Param20 166492 7286 ns/op 2924 B/op 12 allocs/op
+BenchmarkMartini_Param20 122162 10653 ns/op 3595 B/op 13 allocs/op
+BenchmarkPat_Param20 78630 15239 ns/op 4424 B/op 93 allocs/op
+BenchmarkPossum_Param20 1000000 1008 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_Param20 294981 4587 ns/op 2284 B/op 7 allocs/op
+BenchmarkRivet_Param20 691798 2090 ns/op 1024 B/op 1 allocs/op
+BenchmarkTango_Param20 842440 2505 ns/op 856 B/op 8 allocs/op
+BenchmarkTigerTonic_Param20 38614 31509 ns/op 9870 B/op 119 allocs/op
+BenchmarkTraffic_Param20 57633 21107 ns/op 7853 B/op 47 allocs/op
+BenchmarkVulcan_Param20 1000000 1178 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_ParamWrite 7330743 180 ns/op 8 B/op 1 allocs/op
+BenchmarkAero_ParamWrite 13833598 86.7 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_ParamWrite 1363321 867 ns/op 456 B/op 5 allocs/op
+BenchmarkBeego_ParamWrite 1000000 1104 ns/op 360 B/op 4 allocs/op
+BenchmarkBone_ParamWrite 1000000 1475 ns/op 816 B/op 6 allocs/op
+BenchmarkChi_ParamWrite 1320590 892 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_ParamWrite 7093605 172 ns/op 32 B/op 1 allocs/op
+BenchmarkEcho_ParamWrite 8434424 161 ns/op 8 B/op 1 allocs/op
+BenchmarkGin_ParamWrite 10377034 118 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_ParamWrite 1000000 1266 ns/op 656 B/op 9 allocs/op
+BenchmarkGoji_ParamWrite 1874168 654 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_ParamWrite 459032 2352 ns/op 1360 B/op 13 allocs/op
+BenchmarkGoJsonRest_ParamWrite 499434 2145 ns/op 1128 B/op 18 allocs/op
+BenchmarkGoRestful_ParamWrite 241087 5470 ns/op 4200 B/op 15 allocs/op
+BenchmarkGorillaMux_ParamWrite 425686 2522 ns/op 1280 B/op 10 allocs/op
+BenchmarkGowwwRouter_ParamWrite 922172 1778 ns/op 976 B/op 8 allocs/op
+BenchmarkHttpRouter_ParamWrite 15392049 77.7 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_ParamWrite 1973385 597 ns/op 352 B/op 3 allocs/op
+BenchmarkKocha_ParamWrite 4262500 281 ns/op 56 B/op 3 allocs/op
+BenchmarkLARS_ParamWrite 10764410 113 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_ParamWrite 486769 2726 ns/op 1176 B/op 14 allocs/op
+BenchmarkMartini_ParamWrite 264804 4842 ns/op 1176 B/op 14 allocs/op
+BenchmarkPat_ParamWrite 735116 2047 ns/op 960 B/op 15 allocs/op
+BenchmarkPossum_ParamWrite 1000000 1004 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_ParamWrite 1592136 768 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_ParamWrite 3582051 339 ns/op 112 B/op 2 allocs/op
+BenchmarkTango_ParamWrite 2237337 534 ns/op 136 B/op 4 allocs/op
+BenchmarkTigerTonic_ParamWrite 439608 3136 ns/op 1216 B/op 21 allocs/op
+BenchmarkTraffic_ParamWrite 306979 4328 ns/op 2280 B/op 25 allocs/op
+BenchmarkVulcan_ParamWrite 2529973 472 ns/op 98 B/op 3 allocs/op
+```
+
+## GitHub
+
+```sh
+BenchmarkGin_GithubStatic 15629472 76.7 ns/op 0 B/op 0 allocs/op
+
+BenchmarkAce_GithubStatic 15542612 75.9 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GithubStatic 24777151 48.5 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GithubStatic 2788894 435 ns/op 120 B/op 3 allocs/op
+BenchmarkBeego_GithubStatic 1000000 1064 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_GithubStatic 93507 12838 ns/op 2880 B/op 60 allocs/op
+BenchmarkChi_GithubStatic 1387743 860 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_GithubStatic 39384996 30.4 ns/op 0 B/op 0 allocs/op
+BenchmarkEcho_GithubStatic 12076382 99.1 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GithubStatic 1596495 756 ns/op 296 B/op 5 allocs/op
+BenchmarkGoji_GithubStatic 6364876 189 ns/op 0 B/op 0 allocs/op
+BenchmarkGojiv2_GithubStatic 550202 2098 ns/op 1312 B/op 10 allocs/op
+BenchmarkGoRestful_GithubStatic 102183 12552 ns/op 4256 B/op 13 allocs/op
+BenchmarkGoJsonRest_GithubStatic 1000000 1029 ns/op 329 B/op 11 allocs/op
+BenchmarkGorillaMux_GithubStatic 255552 5190 ns/op 976 B/op 9 allocs/op
+BenchmarkGowwwRouter_GithubStatic 15531916 77.1 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpRouter_GithubStatic 27920724 43.1 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GithubStatic 21448953 55.8 ns/op 0 B/op 0 allocs/op
+BenchmarkKocha_GithubStatic 21405310 56.0 ns/op 0 B/op 0 allocs/op
+BenchmarkLARS_GithubStatic 13625156 89.0 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GithubStatic 1000000 1747 ns/op 736 B/op 8 allocs/op
+BenchmarkMartini_GithubStatic 187186 7326 ns/op 768 B/op 9 allocs/op
+BenchmarkPat_GithubStatic 109143 11563 ns/op 3648 B/op 76 allocs/op
+BenchmarkPossum_GithubStatic 1575898 770 ns/op 416 B/op 3 allocs/op
+BenchmarkR2router_GithubStatic 3046231 404 ns/op 144 B/op 4 allocs/op
+BenchmarkRivet_GithubStatic 11484826 105 ns/op 0 B/op 0 allocs/op
+BenchmarkTango_GithubStatic 1000000 1153 ns/op 248 B/op 8 allocs/op
+BenchmarkTigerTonic_GithubStatic 4929780 249 ns/op 48 B/op 1 allocs/op
+BenchmarkTraffic_GithubStatic 106351 11819 ns/op 4664 B/op 90 allocs/op
+BenchmarkVulcan_GithubStatic 1613271 722 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_GithubParam 8386032 143 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GithubParam 11816200 102 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GithubParam 1000000 1012 ns/op 496 B/op 5 allocs/op
+BenchmarkBeego_GithubParam 1000000 1157 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_GithubParam 184653 6912 ns/op 1888 B/op 19 allocs/op
+BenchmarkChi_GithubParam 1000000 1102 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_GithubParam 3484798 352 ns/op 128 B/op 1 allocs/op
+BenchmarkEcho_GithubParam 6337380 189 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_GithubParam 9132032 131 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GithubParam 1000000 1446 ns/op 712 B/op 9 allocs/op
+BenchmarkGoji_GithubParam 1248640 977 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_GithubParam 383233 2784 ns/op 1408 B/op 13 allocs/op
+BenchmarkGoJsonRest_GithubParam 1000000 1991 ns/op 713 B/op 14 allocs/op
+BenchmarkGoRestful_GithubParam 76414 16015 ns/op 4352 B/op 16 allocs/op
+BenchmarkGorillaMux_GithubParam 150026 7663 ns/op 1296 B/op 10 allocs/op
+BenchmarkGowwwRouter_GithubParam 1592044 751 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_GithubParam 10420628 115 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GithubParam 1403755 835 ns/op 384 B/op 4 allocs/op
+BenchmarkKocha_GithubParam 2286170 533 ns/op 128 B/op 5 allocs/op
+BenchmarkLARS_GithubParam 9540374 129 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GithubParam 533154 2742 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_GithubParam 119397 9638 ns/op 1152 B/op 11 allocs/op
+BenchmarkPat_GithubParam 150675 8858 ns/op 2408 B/op 48 allocs/op
+BenchmarkPossum_GithubParam 1000000 1001 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_GithubParam 1602886 761 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_GithubParam 2986579 409 ns/op 96 B/op 1 allocs/op
+BenchmarkTango_GithubParam 1000000 1356 ns/op 344 B/op 8 allocs/op
+BenchmarkTigerTonic_GithubParam 388899 3429 ns/op 1176 B/op 22 allocs/op
+BenchmarkTraffic_GithubParam 123160 9734 ns/op 2816 B/op 40 allocs/op
+BenchmarkVulcan_GithubParam 1000000 1138 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_GithubAll 40543 29670 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GithubAll 57632 20648 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GithubAll 9234 216179 ns/op 86448 B/op 943 allocs/op
+BenchmarkBeego_GithubAll 7407 243496 ns/op 71456 B/op 609 allocs/op
+BenchmarkBone_GithubAll 420 2922835 ns/op 720160 B/op 8620 allocs/op
+BenchmarkChi_GithubAll 7620 238331 ns/op 87696 B/op 609 allocs/op
+BenchmarkDenco_GithubAll 18355 64494 ns/op 20224 B/op 167 allocs/op
+BenchmarkEcho_GithubAll 31251 38479 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_GithubAll 43550 27364 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GithubAll 4117 300062 ns/op 131656 B/op 1686 allocs/op
+BenchmarkGoji_GithubAll 3274 416158 ns/op 56112 B/op 334 allocs/op
+BenchmarkGojiv2_GithubAll 1402 870518 ns/op 352720 B/op 4321 allocs/op
+BenchmarkGoJsonRest_GithubAll 2976 401507 ns/op 134371 B/op 2737 allocs/op
+BenchmarkGoRestful_GithubAll 410 2913158 ns/op 910144 B/op 2938 allocs/op
+BenchmarkGorillaMux_GithubAll 346 3384987 ns/op 251650 B/op 1994 allocs/op
+BenchmarkGowwwRouter_GithubAll 10000 143025 ns/op 72144 B/op 501 allocs/op
+BenchmarkHttpRouter_GithubAll 55938 21360 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GithubAll 10000 153944 ns/op 65856 B/op 671 allocs/op
+BenchmarkKocha_GithubAll 10000 106315 ns/op 23304 B/op 843 allocs/op
+BenchmarkLARS_GithubAll 47779 25084 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GithubAll 3266 371907 ns/op 149409 B/op 1624 allocs/op
+BenchmarkMartini_GithubAll 331 3444706 ns/op 226551 B/op 2325 allocs/op
+BenchmarkPat_GithubAll 273 4381818 ns/op 1483152 B/op 26963 allocs/op
+BenchmarkPossum_GithubAll 10000 164367 ns/op 84448 B/op 609 allocs/op
+BenchmarkR2router_GithubAll 10000 160220 ns/op 77328 B/op 979 allocs/op
+BenchmarkRivet_GithubAll 14625 82453 ns/op 16272 B/op 167 allocs/op
+BenchmarkTango_GithubAll 6255 279611 ns/op 63826 B/op 1618 allocs/op
+BenchmarkTigerTonic_GithubAll 2008 687874 ns/op 193856 B/op 4474 allocs/op
+BenchmarkTraffic_GithubAll 355 3478508 ns/op 820744 B/op 14114 allocs/op
+BenchmarkVulcan_GithubAll 6885 193333 ns/op 19894 B/op 609 allocs/op
+```
+
+## Google+
+
+```sh
+BenchmarkGin_GPlusStatic 19247326 62.2 ns/op 0 B/op 0 allocs/op
+
+BenchmarkAce_GPlusStatic 20235060 59.2 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GPlusStatic 31978935 37.6 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GPlusStatic 3516523 341 ns/op 104 B/op 3 allocs/op
+BenchmarkBeego_GPlusStatic 1212036 991 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_GPlusStatic 6736242 183 ns/op 32 B/op 1 allocs/op
+BenchmarkChi_GPlusStatic 1490640 814 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_GPlusStatic 55006856 21.8 ns/op 0 B/op 0 allocs/op
+BenchmarkEcho_GPlusStatic 17688258 67.9 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GPlusStatic 1829181 666 ns/op 280 B/op 5 allocs/op
+BenchmarkGoji_GPlusStatic 9147451 130 ns/op 0 B/op 0 allocs/op
+BenchmarkGojiv2_GPlusStatic 594015 2063 ns/op 1312 B/op 10 allocs/op
+BenchmarkGoJsonRest_GPlusStatic 1264906 950 ns/op 329 B/op 11 allocs/op
+BenchmarkGoRestful_GPlusStatic 231558 5341 ns/op 3872 B/op 13 allocs/op
+BenchmarkGorillaMux_GPlusStatic 908418 1809 ns/op 976 B/op 9 allocs/op
+BenchmarkGowwwRouter_GPlusStatic 40684604 29.5 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpRouter_GPlusStatic 46742804 25.7 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GPlusStatic 32567161 36.9 ns/op 0 B/op 0 allocs/op
+BenchmarkKocha_GPlusStatic 33800060 35.3 ns/op 0 B/op 0 allocs/op
+BenchmarkLARS_GPlusStatic 20431858 60.0 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GPlusStatic 1000000 1745 ns/op 736 B/op 8 allocs/op
+BenchmarkMartini_GPlusStatic 442248 3619 ns/op 768 B/op 9 allocs/op
+BenchmarkPat_GPlusStatic 4328004 292 ns/op 96 B/op 2 allocs/op
+BenchmarkPossum_GPlusStatic 1570753 763 ns/op 416 B/op 3 allocs/op
+BenchmarkR2router_GPlusStatic 3339474 355 ns/op 144 B/op 4 allocs/op
+BenchmarkRivet_GPlusStatic 18570961 64.7 ns/op 0 B/op 0 allocs/op
+BenchmarkTango_GPlusStatic 1388702 860 ns/op 200 B/op 8 allocs/op
+BenchmarkTigerTonic_GPlusStatic 7803543 159 ns/op 32 B/op 1 allocs/op
+BenchmarkTraffic_GPlusStatic 878605 2171 ns/op 1112 B/op 16 allocs/op
+BenchmarkVulcan_GPlusStatic 2742446 437 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_GPlusParam 11626975 105 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GPlusParam 16914322 71.6 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GPlusParam 1405173 832 ns/op 480 B/op 5 allocs/op
+BenchmarkBeego_GPlusParam 1000000 1075 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_GPlusParam 1000000 1557 ns/op 816 B/op 6 allocs/op
+BenchmarkChi_GPlusParam 1347926 894 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_GPlusParam 5513000 212 ns/op 64 B/op 1 allocs/op
+BenchmarkEcho_GPlusParam 11884383 101 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_GPlusParam 12898952 93.1 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GPlusParam 1000000 1194 ns/op 648 B/op 8 allocs/op
+BenchmarkGoji_GPlusParam 1857229 645 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_GPlusParam 520939 2322 ns/op 1328 B/op 11 allocs/op
+BenchmarkGoJsonRest_GPlusParam 1000000 1536 ns/op 649 B/op 13 allocs/op
+BenchmarkGoRestful_GPlusParam 205449 5800 ns/op 4192 B/op 14 allocs/op
+BenchmarkGorillaMux_GPlusParam 395310 3188 ns/op 1280 B/op 10 allocs/op
+BenchmarkGowwwRouter_GPlusParam 1851798 667 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_GPlusParam 18420789 65.2 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GPlusParam 1878463 629 ns/op 352 B/op 3 allocs/op
+BenchmarkKocha_GPlusParam 4495610 273 ns/op 56 B/op 3 allocs/op
+BenchmarkLARS_GPlusParam 14615976 83.2 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GPlusParam 584145 2549 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_GPlusParam 250501 4583 ns/op 1072 B/op 10 allocs/op
+BenchmarkPat_GPlusParam 1000000 1645 ns/op 576 B/op 11 allocs/op
+BenchmarkPossum_GPlusParam 1000000 1008 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_GPlusParam 1708191 688 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_GPlusParam 5795014 211 ns/op 48 B/op 1 allocs/op
+BenchmarkTango_GPlusParam 1000000 1091 ns/op 264 B/op 8 allocs/op
+BenchmarkTigerTonic_GPlusParam 760221 2489 ns/op 856 B/op 16 allocs/op
+BenchmarkTraffic_GPlusParam 309774 4039 ns/op 1872 B/op 21 allocs/op
+BenchmarkVulcan_GPlusParam 1935730 623 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_GPlus2Params 9158314 134 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GPlus2Params 11300517 107 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GPlus2Params 1239238 961 ns/op 496 B/op 5 allocs/op
+BenchmarkBeego_GPlus2Params 1000000 1202 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_GPlus2Params 335576 3725 ns/op 1168 B/op 10 allocs/op
+BenchmarkChi_GPlus2Params 1000000 1014 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_GPlus2Params 4394598 280 ns/op 64 B/op 1 allocs/op
+BenchmarkEcho_GPlus2Params 7851861 154 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_GPlus2Params 9958588 120 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GPlus2Params 1000000 1433 ns/op 712 B/op 9 allocs/op
+BenchmarkGoji_GPlus2Params 1325134 909 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_GPlus2Params 405955 2870 ns/op 1408 B/op 14 allocs/op
+BenchmarkGoJsonRest_GPlus2Params 977038 1987 ns/op 713 B/op 14 allocs/op
+BenchmarkGoRestful_GPlus2Params 205018 6142 ns/op 4384 B/op 16 allocs/op
+BenchmarkGorillaMux_GPlus2Params 205641 6015 ns/op 1296 B/op 10 allocs/op
+BenchmarkGowwwRouter_GPlus2Params 1748542 684 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_GPlus2Params 14047102 87.7 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GPlus2Params 1418673 828 ns/op 384 B/op 4 allocs/op
+BenchmarkKocha_GPlus2Params 2334562 520 ns/op 128 B/op 5 allocs/op
+BenchmarkLARS_GPlus2Params 11954094 101 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GPlus2Params 491552 2890 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_GPlus2Params 120532 9545 ns/op 1200 B/op 13 allocs/op
+BenchmarkPat_GPlus2Params 194739 6766 ns/op 2168 B/op 33 allocs/op
+BenchmarkPossum_GPlus2Params 1201224 1009 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_GPlus2Params 1575535 756 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_GPlus2Params 3698930 325 ns/op 96 B/op 1 allocs/op
+BenchmarkTango_GPlus2Params 1000000 1212 ns/op 344 B/op 8 allocs/op
+BenchmarkTigerTonic_GPlus2Params 349350 3660 ns/op 1200 B/op 22 allocs/op
+BenchmarkTraffic_GPlus2Params 169714 7862 ns/op 2248 B/op 28 allocs/op
+BenchmarkVulcan_GPlus2Params 1222288 974 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_GPlusAll 845606 1398 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_GPlusAll 1000000 1009 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_GPlusAll 103830 11386 ns/op 5488 B/op 61 allocs/op
+BenchmarkBeego_GPlusAll 82653 14784 ns/op 4576 B/op 39 allocs/op
+BenchmarkBone_GPlusAll 36601 33123 ns/op 11744 B/op 109 allocs/op
+BenchmarkChi_GPlusAll 95264 12831 ns/op 5616 B/op 39 allocs/op
+BenchmarkDenco_GPlusAll 567681 2950 ns/op 672 B/op 11 allocs/op
+BenchmarkEcho_GPlusAll 720366 1665 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_GPlusAll 1000000 1185 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_GPlusAll 71575 16365 ns/op 8040 B/op 103 allocs/op
+BenchmarkGoji_GPlusAll 136352 9191 ns/op 3696 B/op 22 allocs/op
+BenchmarkGojiv2_GPlusAll 38006 31802 ns/op 17616 B/op 154 allocs/op
+BenchmarkGoJsonRest_GPlusAll 57238 21561 ns/op 8117 B/op 170 allocs/op
+BenchmarkGoRestful_GPlusAll 15147 79276 ns/op 55520 B/op 192 allocs/op
+BenchmarkGorillaMux_GPlusAll 24446 48410 ns/op 16112 B/op 128 allocs/op
+BenchmarkGowwwRouter_GPlusAll 150112 7770 ns/op 4752 B/op 33 allocs/op
+BenchmarkHttpRouter_GPlusAll 1367820 878 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_GPlusAll 166628 8004 ns/op 4032 B/op 38 allocs/op
+BenchmarkKocha_GPlusAll 265694 4570 ns/op 976 B/op 43 allocs/op
+BenchmarkLARS_GPlusAll 1000000 1068 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_GPlusAll 54564 23305 ns/op 9568 B/op 104 allocs/op
+BenchmarkMartini_GPlusAll 16274 73845 ns/op 14016 B/op 145 allocs/op
+BenchmarkPat_GPlusAll 27181 44478 ns/op 15264 B/op 271 allocs/op
+BenchmarkPossum_GPlusAll 122587 10277 ns/op 5408 B/op 39 allocs/op
+BenchmarkR2router_GPlusAll 130137 9297 ns/op 5040 B/op 63 allocs/op
+BenchmarkRivet_GPlusAll 532438 3323 ns/op 768 B/op 11 allocs/op
+BenchmarkTango_GPlusAll 86054 14531 ns/op 3656 B/op 104 allocs/op
+BenchmarkTigerTonic_GPlusAll 33936 35356 ns/op 11600 B/op 242 allocs/op
+BenchmarkTraffic_GPlusAll 17833 68181 ns/op 26248 B/op 341 allocs/op
+BenchmarkVulcan_GPlusAll 120109 9861 ns/op 1274 B/op 39 allocs/op
+```
+
+## Parse.com
+
+```sh
+BenchmarkGin_ParseStatic 18877833 63.5 ns/op 0 B/op 0 allocs/op
+
+BenchmarkAce_ParseStatic 19663731 60.8 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_ParseStatic 28967341 41.5 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_ParseStatic 3006984 402 ns/op 120 B/op 3 allocs/op
+BenchmarkBeego_ParseStatic 1000000 1031 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_ParseStatic 1782482 675 ns/op 144 B/op 3 allocs/op
+BenchmarkChi_ParseStatic 1453261 819 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_ParseStatic 45023595 26.5 ns/op 0 B/op 0 allocs/op
+BenchmarkEcho_ParseStatic 17330470 69.3 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_ParseStatic 1644006 731 ns/op 296 B/op 5 allocs/op
+BenchmarkGoji_ParseStatic 7026930 170 ns/op 0 B/op 0 allocs/op
+BenchmarkGojiv2_ParseStatic 517618 2037 ns/op 1312 B/op 10 allocs/op
+BenchmarkGoJsonRest_ParseStatic 1227080 975 ns/op 329 B/op 11 allocs/op
+BenchmarkGoRestful_ParseStatic 192458 6659 ns/op 4256 B/op 13 allocs/op
+BenchmarkGorillaMux_ParseStatic 744062 2109 ns/op 976 B/op 9 allocs/op
+BenchmarkGowwwRouter_ParseStatic 37781062 31.8 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpRouter_ParseStatic 45311223 26.5 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_ParseStatic 21383475 56.1 ns/op 0 B/op 0 allocs/op
+BenchmarkKocha_ParseStatic 29953290 40.1 ns/op 0 B/op 0 allocs/op
+BenchmarkLARS_ParseStatic 20036196 62.7 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_ParseStatic 1000000 1740 ns/op 736 B/op 8 allocs/op
+BenchmarkMartini_ParseStatic 404156 3801 ns/op 768 B/op 9 allocs/op
+BenchmarkPat_ParseStatic 1547180 772 ns/op 240 B/op 5 allocs/op
+BenchmarkPossum_ParseStatic 1608991 757 ns/op 416 B/op 3 allocs/op
+BenchmarkR2router_ParseStatic 3177936 385 ns/op 144 B/op 4 allocs/op
+BenchmarkRivet_ParseStatic 17783205 67.4 ns/op 0 B/op 0 allocs/op
+BenchmarkTango_ParseStatic 1210777 990 ns/op 248 B/op 8 allocs/op
+BenchmarkTigerTonic_ParseStatic 5316440 231 ns/op 48 B/op 1 allocs/op
+BenchmarkTraffic_ParseStatic 496050 2539 ns/op 1256 B/op 19 allocs/op
+BenchmarkVulcan_ParseStatic 2462798 488 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_ParseParam 13393669 89.6 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_ParseParam 19836619 60.4 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_ParseParam 1405954 864 ns/op 467 B/op 5 allocs/op
+BenchmarkBeego_ParseParam 1000000 1065 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_ParseParam 1000000 1698 ns/op 896 B/op 7 allocs/op
+BenchmarkChi_ParseParam 1356037 873 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_ParseParam 6241392 204 ns/op 64 B/op 1 allocs/op
+BenchmarkEcho_ParseParam 14088100 85.1 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_ParseParam 17426064 68.9 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_ParseParam 1000000 1254 ns/op 664 B/op 8 allocs/op
+BenchmarkGoji_ParseParam 1682574 713 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_ParseParam 502224 2333 ns/op 1360 B/op 12 allocs/op
+BenchmarkGoJsonRest_ParseParam 1000000 1401 ns/op 649 B/op 13 allocs/op
+BenchmarkGoRestful_ParseParam 182623 7097 ns/op 4576 B/op 14 allocs/op
+BenchmarkGorillaMux_ParseParam 482332 2477 ns/op 1280 B/op 10 allocs/op
+BenchmarkGowwwRouter_ParseParam 1834873 657 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_ParseParam 23593393 51.0 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_ParseParam 2100160 574 ns/op 352 B/op 3 allocs/op
+BenchmarkKocha_ParseParam 4837220 252 ns/op 56 B/op 3 allocs/op
+BenchmarkLARS_ParseParam 18411192 66.2 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_ParseParam 571870 2398 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_ParseParam 286262 4268 ns/op 1072 B/op 10 allocs/op
+BenchmarkPat_ParseParam 692906 2157 ns/op 992 B/op 15 allocs/op
+BenchmarkPossum_ParseParam 1000000 1011 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_ParseParam 1722735 697 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_ParseParam 6058054 203 ns/op 48 B/op 1 allocs/op
+BenchmarkTango_ParseParam 1000000 1061 ns/op 280 B/op 8 allocs/op
+BenchmarkTigerTonic_ParseParam 890275 2277 ns/op 784 B/op 15 allocs/op
+BenchmarkTraffic_ParseParam 351322 3543 ns/op 1896 B/op 21 allocs/op
+BenchmarkVulcan_ParseParam 2076544 572 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_Parse2Params 11718074 101 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_Parse2Params 16264988 73.4 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_Parse2Params 1238322 973 ns/op 496 B/op 5 allocs/op
+BenchmarkBeego_Parse2Params 1000000 1120 ns/op 352 B/op 3 allocs/op
+BenchmarkBone_Parse2Params 1000000 1632 ns/op 848 B/op 6 allocs/op
+BenchmarkChi_Parse2Params 1239477 955 ns/op 432 B/op 3 allocs/op
+BenchmarkDenco_Parse2Params 4944133 245 ns/op 64 B/op 1 allocs/op
+BenchmarkEcho_Parse2Params 10518286 114 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_Parse2Params 14505195 82.7 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_Parse2Params 1000000 1437 ns/op 712 B/op 9 allocs/op
+BenchmarkGoji_Parse2Params 1689883 707 ns/op 336 B/op 2 allocs/op
+BenchmarkGojiv2_Parse2Params 502334 2308 ns/op 1344 B/op 11 allocs/op
+BenchmarkGoJsonRest_Parse2Params 1000000 1771 ns/op 713 B/op 14 allocs/op
+BenchmarkGoRestful_Parse2Params 159092 7583 ns/op 4928 B/op 14 allocs/op
+BenchmarkGorillaMux_Parse2Params 417548 2980 ns/op 1296 B/op 10 allocs/op
+BenchmarkGowwwRouter_Parse2Params 1751737 686 ns/op 432 B/op 3 allocs/op
+BenchmarkHttpRouter_Parse2Params 18089204 66.3 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_Parse2Params 1556986 777 ns/op 384 B/op 4 allocs/op
+BenchmarkKocha_Parse2Params 2493082 485 ns/op 128 B/op 5 allocs/op
+BenchmarkLARS_Parse2Params 15350108 78.5 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_Parse2Params 530974 2605 ns/op 1072 B/op 10 allocs/op
+BenchmarkMartini_Parse2Params 247069 4673 ns/op 1152 B/op 11 allocs/op
+BenchmarkPat_Parse2Params 816295 2126 ns/op 752 B/op 16 allocs/op
+BenchmarkPossum_Parse2Params 1000000 1002 ns/op 496 B/op 5 allocs/op
+BenchmarkR2router_Parse2Params 1569771 733 ns/op 432 B/op 5 allocs/op
+BenchmarkRivet_Parse2Params 4080546 295 ns/op 96 B/op 1 allocs/op
+BenchmarkTango_Parse2Params 1000000 1121 ns/op 312 B/op 8 allocs/op
+BenchmarkTigerTonic_Parse2Params 399556 3470 ns/op 1168 B/op 22 allocs/op
+BenchmarkTraffic_Parse2Params 314194 4159 ns/op 1944 B/op 22 allocs/op
+BenchmarkVulcan_Parse2Params 1827559 664 ns/op 98 B/op 3 allocs/op
+BenchmarkAce_ParseAll 478395 2503 ns/op 0 B/op 0 allocs/op
+BenchmarkAero_ParseAll 715392 1658 ns/op 0 B/op 0 allocs/op
+BenchmarkBear_ParseAll 59191 20124 ns/op 8928 B/op 110 allocs/op
+BenchmarkBeego_ParseAll 45507 27266 ns/op 9152 B/op 78 allocs/op
+BenchmarkBone_ParseAll 29328 41459 ns/op 16208 B/op 147 allocs/op
+BenchmarkChi_ParseAll 48531 25053 ns/op 11232 B/op 78 allocs/op
+BenchmarkDenco_ParseAll 325532 4284 ns/op 928 B/op 16 allocs/op
+BenchmarkEcho_ParseAll 433771 2759 ns/op 0 B/op 0 allocs/op
+BenchmarkGin_ParseAll 576316 2082 ns/op 0 B/op 0 allocs/op
+BenchmarkGocraftWeb_ParseAll 41500 29692 ns/op 13728 B/op 181 allocs/op
+BenchmarkGoji_ParseAll 80833 15563 ns/op 5376 B/op 32 allocs/op
+BenchmarkGojiv2_ParseAll 19836 60335 ns/op 34448 B/op 277 allocs/op
+BenchmarkGoJsonRest_ParseAll 32210 38027 ns/op 13866 B/op 321 allocs/op
+BenchmarkGoRestful_ParseAll 6644 190842 ns/op 117600 B/op 354 allocs/op
+BenchmarkGorillaMux_ParseAll 12634 95894 ns/op 30288 B/op 250 allocs/op
+BenchmarkGowwwRouter_ParseAll 98152 12159 ns/op 6912 B/op 48 allocs/op
+BenchmarkHttpRouter_ParseAll 933208 1273 ns/op 0 B/op 0 allocs/op
+BenchmarkHttpTreeMux_ParseAll 107191 11554 ns/op 5728 B/op 51 allocs/op
+BenchmarkKocha_ParseAll 184862 6225 ns/op 1112 B/op 54 allocs/op
+BenchmarkLARS_ParseAll 644546 1858 ns/op 0 B/op 0 allocs/op
+BenchmarkMacaron_ParseAll 26145 46484 ns/op 19136 B/op 208 allocs/op
+BenchmarkMartini_ParseAll 10000 121838 ns/op 25072 B/op 253 allocs/op
+BenchmarkPat_ParseAll 25417 47196 ns/op 15216 B/op 308 allocs/op
+BenchmarkPossum_ParseAll 58550 20735 ns/op 10816 B/op 78 allocs/op
+BenchmarkR2router_ParseAll 72732 16584 ns/op 8352 B/op 120 allocs/op
+BenchmarkRivet_ParseAll 281365 4968 ns/op 912 B/op 16 allocs/op
+BenchmarkTango_ParseAll 42831 28668 ns/op 7168 B/op 208 allocs/op
+BenchmarkTigerTonic_ParseAll 23774 49972 ns/op 16048 B/op 332 allocs/op
+BenchmarkTraffic_ParseAll 10000 104679 ns/op 45520 B/op 605 allocs/op
+BenchmarkVulcan_ParseAll 64810 18108 ns/op 2548 B/op 78 allocs/op
+```
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CHANGELOG.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CHANGELOG.md
new file mode 100644
index 000000000000..4c806a5a7de9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CHANGELOG.md
@@ -0,0 +1,454 @@
+# Gin ChangeLog
+
+## Gin v1.7.7
+
+### BUGFIXES
+
+* Fixed X-Forwarded-For unsafe handling of CVE-2020-28483 [#2844](https://github.com/gin-gonic/gin/pull/2844), closed issue [#2862](https://github.com/gin-gonic/gin/issues/2862).
+* Tree: updated the code logic for `latestNode` [#2897](https://github.com/gin-gonic/gin/pull/2897), closed issue [#2894](https://github.com/gin-gonic/gin/issues/2894) [#2878](https://github.com/gin-gonic/gin/issues/2878).
+* Tree: fixed the misplacement of adding slashes [#2847](https://github.com/gin-gonic/gin/pull/2847), closed issue [#2843](https://github.com/gin-gonic/gin/issues/2843).
+* Tree: fixed tsr with mixed static and wildcard paths [#2924](https://github.com/gin-gonic/gin/pull/2924), closed issue [#2918](https://github.com/gin-gonic/gin/issues/2918).
+
+### ENHANCEMENTS
+
+* TrustedProxies: make it backward-compatible [#2887](https://github.com/gin-gonic/gin/pull/2887), closed issue [#2819](https://github.com/gin-gonic/gin/issues/2819).
+* TrustedPlatform: provide custom options for another CDN services [#2906](https://github.com/gin-gonic/gin/pull/2906).
+
+### DOCS
+
+* NoMethod: added usage annotation ([#2832](https://github.com/gin-gonic/gin/pull/2832#issuecomment-929954463)).
+
+## Gin v1.7.6
+
+### BUGFIXES
+
+* bump new release to fix v1.7.5 release error by using v1.7.4 codes.
+
+## Gin v1.7.4
+
+### BUGFIXES
+
+* bump new release to fix checksum mismatch
+
+## Gin v1.7.3
+
+### BUGFIXES
+
+* fix level 1 router match [#2767](https://github.com/gin-gonic/gin/issues/2767), [#2796](https://github.com/gin-gonic/gin/issues/2796)
+
+## Gin v1.7.2
+
+### BUGFIXES
+
+* Fix conflict between param and exact path [#2706](https://github.com/gin-gonic/gin/issues/2706). Close issue [#2682](https://github.com/gin-gonic/gin/issues/2682) [#2696](https://github.com/gin-gonic/gin/issues/2696).
+
+## Gin v1.7.1
+
+### BUGFIXES
+
+* fix: data race with trustedCIDRs from [#2674](https://github.com/gin-gonic/gin/issues/2674)([#2675](https://github.com/gin-gonic/gin/pull/2675))
+
+## Gin v1.7.0
+
+### BUGFIXES
+
+* fix compile error from [#2572](https://github.com/gin-gonic/gin/pull/2572) ([#2600](https://github.com/gin-gonic/gin/pull/2600))
+* fix: print headers without Authorization header on broken pipe ([#2528](https://github.com/gin-gonic/gin/pull/2528))
+* fix(tree): reassign fullpath when register new node ([#2366](https://github.com/gin-gonic/gin/pull/2366))
+
+### ENHANCEMENTS
+
+* Support params and exact routes without creating conflicts ([#2663](https://github.com/gin-gonic/gin/pull/2663))
+* chore: improve render string performance ([#2365](https://github.com/gin-gonic/gin/pull/2365))
+* Sync route tree to httprouter latest code ([#2368](https://github.com/gin-gonic/gin/pull/2368))
+* chore: rename getQueryCache/getFormCache to initQueryCache/initFormCa ([#2375](https://github.com/gin-gonic/gin/pull/2375))
+* chore(performance): improve countParams ([#2378](https://github.com/gin-gonic/gin/pull/2378))
+* Remove some functions that have the same effect as the bytes package ([#2387](https://github.com/gin-gonic/gin/pull/2387))
+* update:SetMode function ([#2321](https://github.com/gin-gonic/gin/pull/2321))
+* remove a unused type SecureJSONPrefix ([#2391](https://github.com/gin-gonic/gin/pull/2391))
+* Add a redirect sample for POST method ([#2389](https://github.com/gin-gonic/gin/pull/2389))
+* Add CustomRecovery builtin middleware ([#2322](https://github.com/gin-gonic/gin/pull/2322))
+* binding: avoid 2038 problem on 32-bit architectures ([#2450](https://github.com/gin-gonic/gin/pull/2450))
+* Prevent panic in Context.GetQuery() when there is no Request ([#2412](https://github.com/gin-gonic/gin/pull/2412))
+* Add GetUint and GetUint64 method on gin.context ([#2487](https://github.com/gin-gonic/gin/pull/2487))
+* update content-disposition header to MIME-style ([#2512](https://github.com/gin-gonic/gin/pull/2512))
+* reduce allocs and improve the render `WriteString` ([#2508](https://github.com/gin-gonic/gin/pull/2508))
+* implement ".Unwrap() error" on Error type ([#2525](https://github.com/gin-gonic/gin/pull/2525)) ([#2526](https://github.com/gin-gonic/gin/pull/2526))
+* Allow bind with a map[string]string ([#2484](https://github.com/gin-gonic/gin/pull/2484))
+* chore: update tree ([#2371](https://github.com/gin-gonic/gin/pull/2371))
+* Support binding for slice/array obj [Rewrite] ([#2302](https://github.com/gin-gonic/gin/pull/2302))
+* basic auth: fix timing oracle ([#2609](https://github.com/gin-gonic/gin/pull/2609))
+* Add mixed param and non-param paths (port of httprouter[#329](https://github.com/gin-gonic/gin/pull/329)) ([#2663](https://github.com/gin-gonic/gin/pull/2663))
+* feat(engine): add trustedproxies and remoteIP ([#2632](https://github.com/gin-gonic/gin/pull/2632))
+
+## Gin v1.6.3
+
+### ENHANCEMENTS
+
+ * Improve performance: Change `*sync.RWMutex` to `sync.RWMutex` in context. [#2351](https://github.com/gin-gonic/gin/pull/2351)
+
+## Gin v1.6.2
+
+### BUGFIXES
+ * fix missing initial sync.RWMutex [#2305](https://github.com/gin-gonic/gin/pull/2305)
+### ENHANCEMENTS
+ * Add set samesite in cookie. [#2306](https://github.com/gin-gonic/gin/pull/2306)
+
+## Gin v1.6.1
+
+### BUGFIXES
+ * Revert "fix accept incoming network connections" [#2294](https://github.com/gin-gonic/gin/pull/2294)
+
+## Gin v1.6.0
+
+### BREAKING
+ * chore(performance): Improve performance for adding RemoveExtraSlash flag [#2159](https://github.com/gin-gonic/gin/pull/2159)
+ * drop support govendor [#2148](https://github.com/gin-gonic/gin/pull/2148)
+ * Added support for SameSite cookie flag [#1615](https://github.com/gin-gonic/gin/pull/1615)
+### FEATURES
+ * add yaml negotiation [#2220](https://github.com/gin-gonic/gin/pull/2220)
+ * FileFromFS [#2112](https://github.com/gin-gonic/gin/pull/2112)
+### BUGFIXES
+ * Unix Socket Handling [#2280](https://github.com/gin-gonic/gin/pull/2280)
+ * Use json marshall in context json to fix breaking new line issue. Fixes #2209 [#2228](https://github.com/gin-gonic/gin/pull/2228)
+ * fix accept incoming network connections [#2216](https://github.com/gin-gonic/gin/pull/2216)
+ * Fixed a bug in the calculation of the maximum number of parameters [#2166](https://github.com/gin-gonic/gin/pull/2166)
+ * [FIX] allow empty headers on DataFromReader [#2121](https://github.com/gin-gonic/gin/pull/2121)
+ * Add mutex for protect Context.Keys map [#1391](https://github.com/gin-gonic/gin/pull/1391)
+### ENHANCEMENTS
+ * Add mitigation for log injection [#2277](https://github.com/gin-gonic/gin/pull/2277)
+ * tree: range over nodes values [#2229](https://github.com/gin-gonic/gin/pull/2229)
+ * tree: remove duplicate assignment [#2222](https://github.com/gin-gonic/gin/pull/2222)
+ * chore: upgrade go-isatty and json-iterator/go [#2215](https://github.com/gin-gonic/gin/pull/2215)
+ * path: sync code with httprouter [#2212](https://github.com/gin-gonic/gin/pull/2212)
+ * Use zero-copy approach to convert types between string and byte slice [#2206](https://github.com/gin-gonic/gin/pull/2206)
+ * Reuse bytes when cleaning the URL paths [#2179](https://github.com/gin-gonic/gin/pull/2179)
+ * tree: remove one else statement [#2177](https://github.com/gin-gonic/gin/pull/2177)
+ * tree: sync httprouter update (#2173) (#2172) [#2171](https://github.com/gin-gonic/gin/pull/2171)
+ * tree: sync part httprouter codes and reduce if/else [#2163](https://github.com/gin-gonic/gin/pull/2163)
+ * use http method constant [#2155](https://github.com/gin-gonic/gin/pull/2155)
+ * upgrade go-validator to v10 [#2149](https://github.com/gin-gonic/gin/pull/2149)
+ * Refactor redirect request in gin.go [#1970](https://github.com/gin-gonic/gin/pull/1970)
+ * Add build tag nomsgpack [#1852](https://github.com/gin-gonic/gin/pull/1852)
+### DOCS
+ * docs(path): improve comments [#2223](https://github.com/gin-gonic/gin/pull/2223)
+ * Renew README to fit the modification of SetCookie method [#2217](https://github.com/gin-gonic/gin/pull/2217)
+ * Fix spelling [#2202](https://github.com/gin-gonic/gin/pull/2202)
+ * Remove broken link from README. [#2198](https://github.com/gin-gonic/gin/pull/2198)
+ * Update docs on Context.Done(), Context.Deadline() and Context.Err() [#2196](https://github.com/gin-gonic/gin/pull/2196)
+ * Update validator to v10 [#2190](https://github.com/gin-gonic/gin/pull/2190)
+ * upgrade go-validator to v10 for README [#2189](https://github.com/gin-gonic/gin/pull/2189)
+ * Update to currently output [#2188](https://github.com/gin-gonic/gin/pull/2188)
+ * Fix "Custom Validators" example [#2186](https://github.com/gin-gonic/gin/pull/2186)
+ * Add project to README [#2165](https://github.com/gin-gonic/gin/pull/2165)
+ * docs(benchmarks): for gin v1.5 [#2153](https://github.com/gin-gonic/gin/pull/2153)
+ * Changed wording for clarity in README.md [#2122](https://github.com/gin-gonic/gin/pull/2122)
+### MISC
+ * ci support go1.14 [#2262](https://github.com/gin-gonic/gin/pull/2262)
+ * chore: upgrade depend version [#2231](https://github.com/gin-gonic/gin/pull/2231)
+ * Drop support go1.10 [#2147](https://github.com/gin-gonic/gin/pull/2147)
+ * fix comment in `mode.go` [#2129](https://github.com/gin-gonic/gin/pull/2129)
+
+## Gin v1.5.0
+
+- [FIX] Use DefaultWriter and DefaultErrorWriter for debug messages [#1891](https://github.com/gin-gonic/gin/pull/1891)
+- [NEW] Now you can parse the inline lowercase start structure [#1893](https://github.com/gin-gonic/gin/pull/1893)
+- [FIX] Some code improvements [#1909](https://github.com/gin-gonic/gin/pull/1909)
+- [FIX] Use encode replace json marshal increase json encoder speed [#1546](https://github.com/gin-gonic/gin/pull/1546)
+- [NEW] Hold matched route full path in the Context [#1826](https://github.com/gin-gonic/gin/pull/1826)
+- [FIX] Fix context.Params race condition on Copy() [#1841](https://github.com/gin-gonic/gin/pull/1841)
+- [NEW] Add context param query cache [#1450](https://github.com/gin-gonic/gin/pull/1450)
+- [FIX] Improve GetQueryMap performance [#1918](https://github.com/gin-gonic/gin/pull/1918)
+- [FIX] Improve get post data [#1920](https://github.com/gin-gonic/gin/pull/1920)
+- [FIX] Use context instead of x/net/context [#1922](https://github.com/gin-gonic/gin/pull/1922)
+- [FIX] Attempt to fix PostForm cache bug [#1931](https://github.com/gin-gonic/gin/pull/1931)
+- [NEW] Add support of multipart multi files [#1949](https://github.com/gin-gonic/gin/pull/1949)
+- [NEW] Support bind http header param [#1957](https://github.com/gin-gonic/gin/pull/1957)
+- [FIX] Drop support for go1.8 and go1.9 [#1933](https://github.com/gin-gonic/gin/pull/1933)
+- [FIX] Bugfix for the FullPath feature [#1919](https://github.com/gin-gonic/gin/pull/1919)
+- [FIX] Gin1.5 bytes.Buffer to strings.Builder [#1939](https://github.com/gin-gonic/gin/pull/1939)
+- [FIX] Upgrade github.com/ugorji/go/codec [#1969](https://github.com/gin-gonic/gin/pull/1969)
+- [NEW] Support bind unix time [#1980](https://github.com/gin-gonic/gin/pull/1980)
+- [FIX] Simplify code [#2004](https://github.com/gin-gonic/gin/pull/2004)
+- [NEW] Support negative Content-Length in DataFromReader [#1981](https://github.com/gin-gonic/gin/pull/1981)
+- [FIX] Identify terminal on a RISC-V architecture for auto-colored logs [#2019](https://github.com/gin-gonic/gin/pull/2019)
+- [BREAKING] `Context.JSONP()` now expects a semicolon (`;`) at the end [#2007](https://github.com/gin-gonic/gin/pull/2007)
+- [BREAKING] Upgrade default `binding.Validator` to v9 (see [its changelog](https://github.com/go-playground/validator/releases/tag/v9.0.0)) [#1015](https://github.com/gin-gonic/gin/pull/1015)
+- [NEW] Add `DisallowUnknownFields()` in `Context.BindJSON()` [#2028](https://github.com/gin-gonic/gin/pull/2028)
+- [NEW] Use specific `net.Listener` with `Engine.RunListener()` [#2023](https://github.com/gin-gonic/gin/pull/2023)
+- [FIX] Fix some typo [#2079](https://github.com/gin-gonic/gin/pull/2079) [#2080](https://github.com/gin-gonic/gin/pull/2080)
+- [FIX] Relocate binding body tests [#2086](https://github.com/gin-gonic/gin/pull/2086)
+- [FIX] Use Writer in Context.Status [#1606](https://github.com/gin-gonic/gin/pull/1606)
+- [FIX] `Engine.RunUnix()` now returns the error if it can't change the file mode [#2093](https://github.com/gin-gonic/gin/pull/2093)
+- [FIX] `RouterGroup.StaticFS()` leaked files. Now it closes them. [#2118](https://github.com/gin-gonic/gin/pull/2118)
+- [FIX] `Context.Request.FormFile` leaked file. Now it closes it. [#2114](https://github.com/gin-gonic/gin/pull/2114)
+- [FIX] Ignore walking on `form:"-"` mapping [#1943](https://github.com/gin-gonic/gin/pull/1943)
+
+### Gin v1.4.0
+
+- [NEW] Support for [Go Modules](https://github.com/golang/go/wiki/Modules) [#1569](https://github.com/gin-gonic/gin/pull/1569)
+- [NEW] Refactor of form mapping multipart request [#1829](https://github.com/gin-gonic/gin/pull/1829)
+- [FIX] Truncate Latency precision in long running request [#1830](https://github.com/gin-gonic/gin/pull/1830)
+- [FIX] IsTerm flag should not be affected by DisableConsoleColor method. [#1802](https://github.com/gin-gonic/gin/pull/1802)
+- [NEW] Supporting file binding [#1264](https://github.com/gin-gonic/gin/pull/1264)
+- [NEW] Add support for mapping arrays [#1797](https://github.com/gin-gonic/gin/pull/1797)
+- [FIX] Readme updates [#1793](https://github.com/gin-gonic/gin/pull/1793) [#1788](https://github.com/gin-gonic/gin/pull/1788) [1789](https://github.com/gin-gonic/gin/pull/1789)
+- [FIX] StaticFS: Fixed Logging two log lines on 404. [#1805](https://github.com/gin-gonic/gin/pull/1805), [#1804](https://github.com/gin-gonic/gin/pull/1804)
+- [NEW] Make context.Keys available as LogFormatterParams [#1779](https://github.com/gin-gonic/gin/pull/1779)
+- [NEW] Use internal/json for Marshal/Unmarshal [#1791](https://github.com/gin-gonic/gin/pull/1791)
+- [NEW] Support mapping time.Duration [#1794](https://github.com/gin-gonic/gin/pull/1794)
+- [NEW] Refactor form mappings [#1749](https://github.com/gin-gonic/gin/pull/1749)
+- [NEW] Added flag to context.Stream indicates if client disconnected in middle of stream [#1252](https://github.com/gin-gonic/gin/pull/1252)
+- [FIX] Moved [examples](https://github.com/gin-gonic/examples) to stand alone Repo [#1775](https://github.com/gin-gonic/gin/pull/1775)
+- [NEW] Extend context.File to allow for the content-disposition attachments via a new method context.Attachment [#1260](https://github.com/gin-gonic/gin/pull/1260)
+- [FIX] Support HTTP content negotiation wildcards [#1112](https://github.com/gin-gonic/gin/pull/1112)
+- [NEW] Add prefix from X-Forwarded-Prefix in redirectTrailingSlash [#1238](https://github.com/gin-gonic/gin/pull/1238)
+- [FIX] context.Copy() race condition [#1020](https://github.com/gin-gonic/gin/pull/1020)
+- [NEW] Add context.HandlerNames() [#1729](https://github.com/gin-gonic/gin/pull/1729)
+- [FIX] Change color methods to public in the defaultLogger. [#1771](https://github.com/gin-gonic/gin/pull/1771)
+- [FIX] Update writeHeaders method to use http.Header.Set [#1722](https://github.com/gin-gonic/gin/pull/1722)
+- [NEW] Add response size to LogFormatterParams [#1752](https://github.com/gin-gonic/gin/pull/1752)
+- [NEW] Allow ignoring field on form mapping [#1733](https://github.com/gin-gonic/gin/pull/1733)
+- [NEW] Add a function to force color in console output. [#1724](https://github.com/gin-gonic/gin/pull/1724)
+- [FIX] Context.Next() - recheck len of handlers on every iteration. [#1745](https://github.com/gin-gonic/gin/pull/1745)
+- [FIX] Fix all errcheck warnings [#1739](https://github.com/gin-gonic/gin/pull/1739) [#1653](https://github.com/gin-gonic/gin/pull/1653)
+- [NEW] context: inherits context cancellation and deadline from http.Request context for Go>=1.7 [#1690](https://github.com/gin-gonic/gin/pull/1690)
+- [NEW] Binding for URL Params [#1694](https://github.com/gin-gonic/gin/pull/1694)
+- [NEW] Add LoggerWithFormatter method [#1677](https://github.com/gin-gonic/gin/pull/1677)
+- [FIX] CI testing updates [#1671](https://github.com/gin-gonic/gin/pull/1671) [#1670](https://github.com/gin-gonic/gin/pull/1670) [#1682](https://github.com/gin-gonic/gin/pull/1682) [#1669](https://github.com/gin-gonic/gin/pull/1669)
+- [FIX] StaticFS(): Send 404 when path does not exist [#1663](https://github.com/gin-gonic/gin/pull/1663)
+- [FIX] Handle nil body for JSON binding [#1638](https://github.com/gin-gonic/gin/pull/1638)
+- [FIX] Support bind uri param [#1612](https://github.com/gin-gonic/gin/pull/1612)
+- [FIX] recovery: fix issue with syscall import on google app engine [#1640](https://github.com/gin-gonic/gin/pull/1640)
+- [FIX] Make sure the debug log contains line breaks [#1650](https://github.com/gin-gonic/gin/pull/1650)
+- [FIX] Panic stack trace being printed during recovery of broken pipe [#1089](https://github.com/gin-gonic/gin/pull/1089) [#1259](https://github.com/gin-gonic/gin/pull/1259)
+- [NEW] RunFd method to run http.Server through a file descriptor [#1609](https://github.com/gin-gonic/gin/pull/1609)
+- [NEW] Yaml binding support [#1618](https://github.com/gin-gonic/gin/pull/1618)
+- [FIX] Pass MaxMultipartMemory when FormFile is called [#1600](https://github.com/gin-gonic/gin/pull/1600)
+- [FIX] LoadHTML* tests [#1559](https://github.com/gin-gonic/gin/pull/1559)
+- [FIX] Removed use of sync.pool from HandleContext [#1565](https://github.com/gin-gonic/gin/pull/1565)
+- [FIX] Format output log to os.Stderr [#1571](https://github.com/gin-gonic/gin/pull/1571)
+- [FIX] Make logger use a yellow background and a darkgray text for legibility [#1570](https://github.com/gin-gonic/gin/pull/1570)
+- [FIX] Remove sensitive request information from panic log. [#1370](https://github.com/gin-gonic/gin/pull/1370)
+- [FIX] log.Println() does not print timestamp [#829](https://github.com/gin-gonic/gin/pull/829) [#1560](https://github.com/gin-gonic/gin/pull/1560)
+- [NEW] Add PureJSON renderer [#694](https://github.com/gin-gonic/gin/pull/694)
+- [FIX] Add missing copyright and update if/else [#1497](https://github.com/gin-gonic/gin/pull/1497)
+- [FIX] Update msgpack usage [#1498](https://github.com/gin-gonic/gin/pull/1498)
+- [FIX] Use protobuf on render [#1496](https://github.com/gin-gonic/gin/pull/1496)
+- [FIX] Add support for Protobuf format response [#1479](https://github.com/gin-gonic/gin/pull/1479)
+- [NEW] Set default time format in form binding [#1487](https://github.com/gin-gonic/gin/pull/1487)
+- [FIX] Add BindXML and ShouldBindXML [#1485](https://github.com/gin-gonic/gin/pull/1485)
+- [NEW] Upgrade dependency libraries [#1491](https://github.com/gin-gonic/gin/pull/1491)
+
+
+## Gin v1.3.0
+
+- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383)
+- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358)
+- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273)
+- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304)
+- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341)
+- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336)
+- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333)
+- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138)
+- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277)
+- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047)
+- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117)
+- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029)
+- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026)
+- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999)
+- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993)
+- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie)
+- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072)
+- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250)
+- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460)
+
+## Gin 1.2.0
+
+- [NEW] Switch from godeps to govendor
+- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
+- [NEW] Improve README examples and add extra at examples folder
+- [NEW] Improved support with App Engine
+- [NEW] Add custom template delimiters, see #860
+- [NEW] Add Template Func Maps, see #962
+- [NEW] Add \*context.Handler(), see #928
+- [NEW] Add \*context.GetRawData()
+- [NEW] Add \*context.GetHeader() (request)
+- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
+- [NEW] Add \*context.Keys type cast helpers
+- [NEW] Add \*context.ShouldBindWith()
+- [NEW] Add \*context.MustBindWith()
+- [NEW] Add \*engine.SetFuncMap()
+- [DEPRECATE] On next release: \*context.BindWith(), see #855
+- [FIX] Refactor render
+- [FIX] Reworked tests
+- [FIX] logger now supports cygwin
+- [FIX] Use X-Forwarded-For before X-Real-Ip
+- [FIX] time.Time binding (#904)
+
+## Gin 1.1.4
+
+- [NEW] Support google appengine for IsTerminal func
+
+## Gin 1.1.3
+
+- [FIX] Reverted Logger: skip ANSI color commands
+
+## Gin 1.1
+
+- [NEW] Implement QueryArray and PostArray methods
+- [NEW] Refactor GetQuery and GetPostForm
+- [NEW] Add contribution guide
+- [FIX] Corrected typos in README
+- [FIX] Removed additional Iota
+- [FIX] Changed imports to gopkg instead of github in README (#733)
+- [FIX] Logger: skip ANSI color commands if output is not a tty
+
+## Gin 1.0rc2 (...)
+
+- [PERFORMANCE] Fast path for writing Content-Type.
+- [PERFORMANCE] Much faster 404 routing
+- [PERFORMANCE] Allocation optimizations
+- [PERFORMANCE] Faster root tree lookup
+- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
+- [PERFORMANCE] Faster ClientIP parsing
+- [PERFORMANCE] Much faster SSE implementation
+- [NEW] Benchmarks suite
+- [NEW] Bind validation can be disabled and replaced with custom validators.
+- [NEW] More flexible HTML render
+- [NEW] Multipart and PostForm bindings
+- [NEW] Adds method to return all the registered routes
+- [NEW] Context.HandlerName() returns the main handler's name
+- [NEW] Adds Error.IsType() helper
+- [FIX] Binding multipart form
+- [FIX] Integration tests
+- [FIX] Crash when binding non struct object in Context.
+- [FIX] RunTLS() implementation
+- [FIX] Logger() unit tests
+- [FIX] Adds SetHTMLTemplate() warning
+- [FIX] Context.IsAborted()
+- [FIX] More unit tests
+- [FIX] JSON, XML, HTML renders accept custom content-types
+- [FIX] gin.AbortIndex is unexported
+- [FIX] Better approach to avoid directory listing in StaticFS()
+- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
+- [FIX] Better warning when running in debug mode.
+- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
+- [FIX] Fixes integer overflow in error type
+- [FIX] Error implements the json.Marshaller interface
+- [FIX] MIT license in every file
+
+
+## Gin 1.0rc1 (May 22, 2015)
+
+- [PERFORMANCE] Zero allocation router
+- [PERFORMANCE] Faster JSON, XML and text rendering
+- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
+- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
+- [NEW] Built-in support for golang.org/x/net/context
+- [NEW] Any(path, handler). Create a route that matches any path
+- [NEW] Refactored rendering pipeline (faster and static typed)
+- [NEW] Refactored errors API
+- [NEW] IndentedJSON() prints pretty JSON
+- [NEW] Added gin.DefaultWriter
+- [NEW] UNIX socket support
+- [NEW] RouterGroup.BasePath is exposed
+- [NEW] JSON validation using go-validate-yourself (very powerful options)
+- [NEW] Completed suite of unit tests
+- [NEW] HTTP streaming with c.Stream()
+- [NEW] StaticFile() creates a router for serving just one file.
+- [NEW] StaticFS() has an option to disable directory listing.
+- [NEW] StaticFS() for serving static files through virtual filesystems
+- [NEW] Server-Sent Events native support
+- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
+- [NEW] Added LoggerWithWriter() middleware
+- [NEW] Added RecoveryWithWriter() middleware
+- [NEW] Added DefaultPostFormValue()
+- [NEW] Added DefaultFormValue()
+- [NEW] Added DefaultParamValue()
+- [FIX] BasicAuth() when using custom realm
+- [FIX] Bug when serving static files in nested routing group
+- [FIX] Redirect using built-in http.Redirect()
+- [FIX] Logger when printing the requested path
+- [FIX] Documentation typos
+- [FIX] Context.Engine renamed to Context.engine
+- [FIX] Better debugging messages
+- [FIX] ErrorLogger
+- [FIX] Debug HTTP render
+- [FIX] Refactored binding and render modules
+- [FIX] Refactored Context initialization
+- [FIX] Refactored BasicAuth()
+- [FIX] NoMethod/NoRoute handlers
+- [FIX] Hijacking http
+- [FIX] Better support for Google App Engine (using log instead of fmt)
+
+
+## Gin 0.6 (Mar 9, 2015)
+
+- [NEW] Support multipart/form-data
+- [NEW] NoMethod handler
+- [NEW] Validate sub structures
+- [NEW] Support for HTTP Realm Auth
+- [FIX] Unsigned integers in binding
+- [FIX] Improve color logger
+
+
+## Gin 0.5 (Feb 7, 2015)
+
+- [NEW] Content Negotiation
+- [FIX] Solved security bug that allow a client to spoof ip
+- [FIX] Fix unexported/ignored fields in binding
+
+
+## Gin 0.4 (Aug 21, 2014)
+
+- [NEW] Development mode
+- [NEW] Unit tests
+- [NEW] Add Content.Redirect()
+- [FIX] Deferring WriteHeader()
+- [FIX] Improved documentation for model binding
+
+
+## Gin 0.3 (Jul 18, 2014)
+
+- [PERFORMANCE] Normal log and error log are printed in the same call.
+- [PERFORMANCE] Improve performance of NoRouter()
+- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults.
+- [NEW] Flexible rendering API
+- [NEW] Add Context.File()
+- [NEW] Add shortcut RunTLS() for http.ListenAndServeTLS
+- [FIX] Rename NotFound404() to NoRoute()
+- [FIX] Errors in context are purged
+- [FIX] Adds HEAD method in Static file serving
+- [FIX] Refactors Static() file serving
+- [FIX] Using keyed initialization to fix app-engine integration
+- [FIX] Can't unmarshal JSON array, #63
+- [FIX] Renaming Context.Req to Context.Request
+- [FIX] Check application/x-www-form-urlencoded when parsing form
+
+
+## Gin 0.2b (Jul 08, 2014)
+- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
+- [NEW] Travis CI integration
+- [NEW] Completely new logger
+- [NEW] New API for serving static files. gin.Static()
+- [NEW] gin.H() can be serialized into XML
+- [NEW] Typed errors. Errors can be typed. Internet/external/custom.
+- [NEW] Support for Godeps
+- [NEW] Travis/Godocs badges in README
+- [NEW] New Bind() and BindWith() methods for parsing request body.
+- [NEW] Add Content.Copy()
+- [NEW] Add context.LastError()
+- [NEW] Add shortcut for OPTIONS HTTP method
+- [FIX] Tons of README fixes
+- [FIX] Header is written before body
+- [FIX] BasicAuth() and changes API a little bit
+- [FIX] Recovery() middleware only prints panics
+- [FIX] Context.Get() does not panic anymore. Use MustGet() instead.
+- [FIX] Multiple http.WriteHeader() in NotFound handlers
+- [FIX] Engine.Run() panics if http server can't be set up
+- [FIX] Crash when route path doesn't start with '/'
+- [FIX] Do not update header when status code is negative
+- [FIX] Setting response headers before calling WriteHeader in context.String()
+- [FIX] Add MIT license
+- [FIX] Changes behaviour of ErrorLogger() and Logger()
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000000..4ea14f3955ce
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md
new file mode 100644
index 000000000000..97daa808f0f4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md
@@ -0,0 +1,13 @@
+## Contributing
+
+- With issues:
+ - Use the search tool before opening a new issue.
+ - Please provide source code and commit sha if you found a bug.
+ - Review existing issues and provide feedback or react to them.
+
+- With pull requests:
+ - Open your pull request against `master`
+ - Your pull request should have no more than two commits, if not you should squash them.
+ - It should pass all tests in the available continuous integration systems such as TravisCI.
+ - You should add/modify tests to cover your proposed code changes.
+ - If your pull request contains a new feature, please document it on the README.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/LICENSE
new file mode 100644
index 000000000000..1ff7f3706055
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Manuel Martínez-Almeida
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/Makefile b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/Makefile
new file mode 100644
index 000000000000..1a99193959ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/Makefile
@@ -0,0 +1,71 @@
+GO ?= go
+GOFMT ?= gofmt "-s"
+PACKAGES ?= $(shell $(GO) list ./...)
+VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /examples/)
+GOFILES := $(shell find . -name "*.go")
+TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples)
+TESTTAGS ?= ""
+
+.PHONY: test
+test:
+ echo "mode: count" > coverage.out
+ for d in $(TESTFOLDER); do \
+ $(GO) test -tags $(TESTTAGS) -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \
+ cat tmp.out; \
+ if grep -q "^--- FAIL" tmp.out; then \
+ rm tmp.out; \
+ exit 1; \
+ elif grep -q "build failed" tmp.out; then \
+ rm tmp.out; \
+ exit 1; \
+ elif grep -q "setup failed" tmp.out; then \
+ rm tmp.out; \
+ exit 1; \
+ fi; \
+ if [ -f profile.out ]; then \
+ cat profile.out | grep -v "mode:" >> coverage.out; \
+ rm profile.out; \
+ fi; \
+ done
+
+.PHONY: fmt
+fmt:
+ $(GOFMT) -w $(GOFILES)
+
+.PHONY: fmt-check
+fmt-check:
+ @diff=$$($(GOFMT) -d $(GOFILES)); \
+ if [ -n "$$diff" ]; then \
+ echo "Please run 'make fmt' and commit the result:"; \
+ echo "$${diff}"; \
+ exit 1; \
+ fi;
+
+vet:
+ $(GO) vet $(VETPACKAGES)
+
+.PHONY: lint
+lint:
+ @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
+ $(GO) get -u golang.org/x/lint/golint; \
+ fi
+ for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
+
+.PHONY: misspell-check
+misspell-check:
+ @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
+ $(GO) get -u github.com/client9/misspell/cmd/misspell; \
+ fi
+ misspell -error $(GOFILES)
+
+.PHONY: misspell
+misspell:
+ @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
+ $(GO) get -u github.com/client9/misspell/cmd/misspell; \
+ fi
+ misspell -w $(GOFILES)
+
+.PHONY: tools
+tools:
+ go install golang.org/x/lint/golint; \
+ go install github.com/client9/misspell/cmd/misspell;
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/README.md
new file mode 100644
index 000000000000..9bf459b09ffd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/README.md
@@ -0,0 +1,2252 @@
+# Gin Web Framework
+
+
+
+[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
+[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
+[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
+[![GoDoc](https://pkg.go.dev/badge/github.com/gin-gonic/gin?status.svg)](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc)
+[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge)
+[![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin)
+[![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases)
+[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/gin-gonic/gin)](https://www.tickgit.com/browse?repo=github.com/gin-gonic/gin)
+
+Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.
+
+
+## Contents
+
+- [Gin Web Framework](#gin-web-framework)
+ - [Contents](#contents)
+ - [Installation](#installation)
+ - [Quick start](#quick-start)
+ - [Benchmarks](#benchmarks)
+ - [Gin v1. stable](#gin-v1-stable)
+ - [Build with jsoniter](#build-with-jsoniter)
+ - [API Examples](#api-examples)
+ - [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options)
+ - [Parameters in path](#parameters-in-path)
+ - [Querystring parameters](#querystring-parameters)
+ - [Multipart/Urlencoded Form](#multiparturlencoded-form)
+ - [Another example: query + post form](#another-example-query--post-form)
+ - [Map as querystring or postform parameters](#map-as-querystring-or-postform-parameters)
+ - [Upload files](#upload-files)
+ - [Single file](#single-file)
+ - [Multiple files](#multiple-files)
+ - [Grouping routes](#grouping-routes)
+ - [Blank Gin without middleware by default](#blank-gin-without-middleware-by-default)
+ - [Using middleware](#using-middleware)
+ - [How to write log file](#how-to-write-log-file)
+ - [Custom Log Format](#custom-log-format)
+ - [Controlling Log output coloring](#controlling-log-output-coloring)
+ - [Model binding and validation](#model-binding-and-validation)
+ - [Custom Validators](#custom-validators)
+ - [Only Bind Query String](#only-bind-query-string)
+ - [Bind Query String or Post Data](#bind-query-string-or-post-data)
+ - [Bind Uri](#bind-uri)
+ - [Bind Header](#bind-header)
+ - [Bind HTML checkboxes](#bind-html-checkboxes)
+ - [Multipart/Urlencoded binding](#multiparturlencoded-binding)
+ - [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering)
+ - [SecureJSON](#securejson)
+ - [JSONP](#jsonp)
+ - [AsciiJSON](#asciijson)
+ - [PureJSON](#purejson)
+ - [Serving static files](#serving-static-files)
+ - [Serving data from file](#serving-data-from-file)
+ - [Serving data from reader](#serving-data-from-reader)
+ - [HTML rendering](#html-rendering)
+ - [Custom Template renderer](#custom-template-renderer)
+ - [Custom Delimiters](#custom-delimiters)
+ - [Custom Template Funcs](#custom-template-funcs)
+ - [Multitemplate](#multitemplate)
+ - [Redirects](#redirects)
+ - [Custom Middleware](#custom-middleware)
+ - [Using BasicAuth() middleware](#using-basicauth-middleware)
+ - [Goroutines inside a middleware](#goroutines-inside-a-middleware)
+ - [Custom HTTP configuration](#custom-http-configuration)
+ - [Support Let's Encrypt](#support-lets-encrypt)
+ - [Run multiple service using Gin](#run-multiple-service-using-gin)
+ - [Graceful shutdown or restart](#graceful-shutdown-or-restart)
+ - [Third-party packages](#third-party-packages)
+ - [Manually](#manually)
+ - [Build a single binary with templates](#build-a-single-binary-with-templates)
+ - [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct)
+ - [Try to bind body into different structs](#try-to-bind-body-into-different-structs)
+ - [http2 server push](#http2-server-push)
+ - [Define format for the log of routes](#define-format-for-the-log-of-routes)
+ - [Set and get a cookie](#set-and-get-a-cookie)
+ - [Don't trust all proxies](#don't-trust-all-proxies)
+ - [Testing](#testing)
+ - [Users](#users)
+
+## Installation
+
+To install Gin package, you need to install Go and set your Go workspace first.
+
+1. The first need [Go](https://golang.org/) installed (**version 1.13+ is required**), then you can use the below Go command to install Gin.
+
+```sh
+$ go get -u github.com/gin-gonic/gin
+```
+
+2. Import it in your code:
+
+```go
+import "github.com/gin-gonic/gin"
+```
+
+3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`.
+
+```go
+import "net/http"
+```
+
+## Quick start
+
+```sh
+# assume the following codes in example.go file
+$ cat example.go
+```
+
+```go
+package main
+
+import "github.com/gin-gonic/gin"
+
+func main() {
+ r := gin.Default()
+ r.GET("/ping", func(c *gin.Context) {
+ c.JSON(200, gin.H{
+ "message": "pong",
+ })
+ })
+ r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
+}
+```
+
+```
+# run example.go and visit 0.0.0.0:8080/ping (for windows "localhost:8080/ping") on browser
+$ go run example.go
+```
+
+## Benchmarks
+
+Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter)
+
+[See all benchmarks](/BENCHMARKS.md)
+
+| Benchmark name | (1) | (2) | (3) | (4) |
+| ------------------------------ | ---------:| ---------------:| ------------:| ---------------:|
+| BenchmarkGin_GithubAll | **43550** | **27364 ns/op** | **0 B/op** | **0 allocs/op** |
+| BenchmarkAce_GithubAll | 40543 | 29670 ns/op | 0 B/op | 0 allocs/op |
+| BenchmarkAero_GithubAll | 57632 | 20648 ns/op | 0 B/op | 0 allocs/op |
+| BenchmarkBear_GithubAll | 9234 | 216179 ns/op | 86448 B/op | 943 allocs/op |
+| BenchmarkBeego_GithubAll | 7407 | 243496 ns/op | 71456 B/op | 609 allocs/op |
+| BenchmarkBone_GithubAll | 420 | 2922835 ns/op | 720160 B/op | 8620 allocs/op |
+| BenchmarkChi_GithubAll | 7620 | 238331 ns/op | 87696 B/op | 609 allocs/op |
+| BenchmarkDenco_GithubAll | 18355 | 64494 ns/op | 20224 B/op | 167 allocs/op |
+| BenchmarkEcho_GithubAll | 31251 | 38479 ns/op | 0 B/op | 0 allocs/op |
+| BenchmarkGocraftWeb_GithubAll | 4117 | 300062 ns/op | 131656 B/op | 1686 allocs/op |
+| BenchmarkGoji_GithubAll | 3274 | 416158 ns/op | 56112 B/op | 334 allocs/op |
+| BenchmarkGojiv2_GithubAll | 1402 | 870518 ns/op | 352720 B/op | 4321 allocs/op |
+| BenchmarkGoJsonRest_GithubAll | 2976 | 401507 ns/op | 134371 B/op | 2737 allocs/op |
+| BenchmarkGoRestful_GithubAll | 410 | 2913158 ns/op | 910144 B/op | 2938 allocs/op |
+| BenchmarkGorillaMux_GithubAll | 346 | 3384987 ns/op | 251650 B/op | 1994 allocs/op |
+| BenchmarkGowwwRouter_GithubAll | 10000 | 143025 ns/op | 72144 B/op | 501 allocs/op |
+| BenchmarkHttpRouter_GithubAll | 55938 | 21360 ns/op | 0 B/op | 0 allocs/op |
+| BenchmarkHttpTreeMux_GithubAll | 10000 | 153944 ns/op | 65856 B/op | 671 allocs/op |
+| BenchmarkKocha_GithubAll | 10000 | 106315 ns/op | 23304 B/op | 843 allocs/op |
+| BenchmarkLARS_GithubAll | 47779 | 25084 ns/op | 0 B/op | 0 allocs/op |
+| BenchmarkMacaron_GithubAll | 3266 | 371907 ns/op | 149409 B/op | 1624 allocs/op |
+| BenchmarkMartini_GithubAll | 331 | 3444706 ns/op | 226551 B/op | 2325 allocs/op |
+| BenchmarkPat_GithubAll | 273 | 4381818 ns/op | 1483152 B/op | 26963 allocs/op |
+| BenchmarkPossum_GithubAll | 10000 | 164367 ns/op | 84448 B/op | 609 allocs/op |
+| BenchmarkR2router_GithubAll | 10000 | 160220 ns/op | 77328 B/op | 979 allocs/op |
+| BenchmarkRivet_GithubAll | 14625 | 82453 ns/op | 16272 B/op | 167 allocs/op |
+| BenchmarkTango_GithubAll | 6255 | 279611 ns/op | 63826 B/op | 1618 allocs/op |
+| BenchmarkTigerTonic_GithubAll | 2008 | 687874 ns/op | 193856 B/op | 4474 allocs/op |
+| BenchmarkTraffic_GithubAll | 355 | 3478508 ns/op | 820744 B/op | 14114 allocs/op |
+| BenchmarkVulcan_GithubAll | 6885 | 193333 ns/op | 19894 B/op | 609 allocs/op |
+
+- (1): Total Repetitions achieved in constant time, higher means more confident result
+- (2): Single Repetition Duration (ns/op), lower is better
+- (3): Heap Memory (B/op), lower is better
+- (4): Average Allocations per Repetition (allocs/op), lower is better
+
+## Gin v1. stable
+
+- [x] Zero allocation router.
+- [x] Still the fastest http router and framework. From routing to writing.
+- [x] Complete suite of unit tests.
+- [x] Battle tested.
+- [x] API frozen, new releases will not break your code.
+
+## Build with [jsoniter](https://github.com/json-iterator/go)
+
+Gin uses `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags.
+
+```sh
+$ go build -tags=jsoniter .
+```
+
+## API Examples
+
+You can find a number of ready-to-run examples at [Gin examples repository](https://github.com/gin-gonic/examples).
+
+### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
+
+```go
+func main() {
+ // Creates a gin router with default middleware:
+ // logger and recovery (crash-free) middleware
+ router := gin.Default()
+
+ router.GET("/someGet", getting)
+ router.POST("/somePost", posting)
+ router.PUT("/somePut", putting)
+ router.DELETE("/someDelete", deleting)
+ router.PATCH("/somePatch", patching)
+ router.HEAD("/someHead", head)
+ router.OPTIONS("/someOptions", options)
+
+ // By default it serves on :8080 unless a
+ // PORT environment variable was defined.
+ router.Run()
+ // router.Run(":3000") for a hard coded port
+}
+```
+
+### Parameters in path
+
+```go
+func main() {
+ router := gin.Default()
+
+ // This handler will match /user/john but will not match /user/ or /user
+ router.GET("/user/:name", func(c *gin.Context) {
+ name := c.Param("name")
+ c.String(http.StatusOK, "Hello %s", name)
+ })
+
+ // However, this one will match /user/john/ and also /user/john/send
+ // If no other routers match /user/john, it will redirect to /user/john/
+ router.GET("/user/:name/*action", func(c *gin.Context) {
+ name := c.Param("name")
+ action := c.Param("action")
+ message := name + " is " + action
+ c.String(http.StatusOK, message)
+ })
+
+ // For each matched request Context will hold the route definition
+ router.POST("/user/:name/*action", func(c *gin.Context) {
+ c.FullPath() == "/user/:name/*action" // true
+ })
+
+ // This handler will add a new router for /user/groups.
+ // Exact routes are resolved before param routes, regardless of the order they were defined.
+ // Routes starting with /user/groups are never interpreted as /user/:name/... routes
+ router.GET("/user/groups", func(c *gin.Context) {
+ c.String(http.StatusOK, "The available groups are [...]", name)
+ })
+
+ router.Run(":8080")
+}
+```
+
+### Querystring parameters
+
+```go
+func main() {
+ router := gin.Default()
+
+ // Query string parameters are parsed using the existing underlying request object.
+ // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe
+ router.GET("/welcome", func(c *gin.Context) {
+ firstname := c.DefaultQuery("firstname", "Guest")
+ lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")
+
+ c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
+ })
+ router.Run(":8080")
+}
+```
+
+### Multipart/Urlencoded Form
+
+```go
+func main() {
+ router := gin.Default()
+
+ router.POST("/form_post", func(c *gin.Context) {
+ message := c.PostForm("message")
+ nick := c.DefaultPostForm("nick", "anonymous")
+
+ c.JSON(200, gin.H{
+ "status": "posted",
+ "message": message,
+ "nick": nick,
+ })
+ })
+ router.Run(":8080")
+}
+```
+
+### Another example: query + post form
+
+```
+POST /post?id=1234&page=1 HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+
+name=manu&message=this_is_great
+```
+
+```go
+func main() {
+ router := gin.Default()
+
+ router.POST("/post", func(c *gin.Context) {
+
+ id := c.Query("id")
+ page := c.DefaultQuery("page", "0")
+ name := c.PostForm("name")
+ message := c.PostForm("message")
+
+ fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
+ })
+ router.Run(":8080")
+}
+```
+
+```
+id: 1234; page: 1; name: manu; message: this_is_great
+```
+
+### Map as querystring or postform parameters
+
+```
+POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+
+names[first]=thinkerou&names[second]=tianou
+```
+
+```go
+func main() {
+ router := gin.Default()
+
+ router.POST("/post", func(c *gin.Context) {
+
+ ids := c.QueryMap("ids")
+ names := c.PostFormMap("names")
+
+ fmt.Printf("ids: %v; names: %v", ids, names)
+ })
+ router.Run(":8080")
+}
+```
+
+```
+ids: map[b:hello a:1234]; names: map[second:tianou first:thinkerou]
+```
+
+### Upload files
+
+#### Single file
+
+References issue [#774](https://github.com/gin-gonic/gin/issues/774) and detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/single).
+
+`file.Filename` **SHOULD NOT** be trusted. See [`Content-Disposition` on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#Directives) and [#1693](https://github.com/gin-gonic/gin/issues/1693)
+
+> The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done.
+
+```go
+func main() {
+ router := gin.Default()
+ // Set a lower memory limit for multipart forms (default is 32 MiB)
+ router.MaxMultipartMemory = 8 << 20 // 8 MiB
+ router.POST("/upload", func(c *gin.Context) {
+ // single file
+ file, _ := c.FormFile("file")
+ log.Println(file.Filename)
+
+ // Upload the file to specific dst.
+ c.SaveUploadedFile(file, dst)
+
+ c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
+ })
+ router.Run(":8080")
+}
+```
+
+How to `curl`:
+
+```bash
+curl -X POST http://localhost:8080/upload \
+ -F "file=@/Users/appleboy/test.zip" \
+ -H "Content-Type: multipart/form-data"
+```
+
+#### Multiple files
+
+See the detail [example code](https://github.com/gin-gonic/examples/tree/master/upload-file/multiple).
+
+```go
+func main() {
+ router := gin.Default()
+ // Set a lower memory limit for multipart forms (default is 32 MiB)
+ router.MaxMultipartMemory = 8 << 20 // 8 MiB
+ router.POST("/upload", func(c *gin.Context) {
+ // Multipart form
+ form, _ := c.MultipartForm()
+ files := form.File["upload[]"]
+
+ for _, file := range files {
+ log.Println(file.Filename)
+
+ // Upload the file to specific dst.
+ c.SaveUploadedFile(file, dst)
+ }
+ c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
+ })
+ router.Run(":8080")
+}
+```
+
+How to `curl`:
+
+```bash
+curl -X POST http://localhost:8080/upload \
+ -F "upload[]=@/Users/appleboy/test1.zip" \
+ -F "upload[]=@/Users/appleboy/test2.zip" \
+ -H "Content-Type: multipart/form-data"
+```
+
+### Grouping routes
+
+```go
+func main() {
+ router := gin.Default()
+
+ // Simple group: v1
+ v1 := router.Group("/v1")
+ {
+ v1.POST("/login", loginEndpoint)
+ v1.POST("/submit", submitEndpoint)
+ v1.POST("/read", readEndpoint)
+ }
+
+ // Simple group: v2
+ v2 := router.Group("/v2")
+ {
+ v2.POST("/login", loginEndpoint)
+ v2.POST("/submit", submitEndpoint)
+ v2.POST("/read", readEndpoint)
+ }
+
+ router.Run(":8080")
+}
+```
+
+### Blank Gin without middleware by default
+
+Use
+
+```go
+r := gin.New()
+```
+
+instead of
+
+```go
+// Default With the Logger and Recovery middleware already attached
+r := gin.Default()
+```
+
+
+### Using middleware
+```go
+func main() {
+ // Creates a router without any middleware by default
+ r := gin.New()
+
+ // Global middleware
+ // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release.
+ // By default gin.DefaultWriter = os.Stdout
+ r.Use(gin.Logger())
+
+ // Recovery middleware recovers from any panics and writes a 500 if there was one.
+ r.Use(gin.Recovery())
+
+ // Per route middleware, you can add as many as you desire.
+ r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
+
+ // Authorization group
+ // authorized := r.Group("/", AuthRequired())
+ // exactly the same as:
+ authorized := r.Group("/")
+ // per group middleware! in this case we use the custom created
+ // AuthRequired() middleware just in the "authorized" group.
+ authorized.Use(AuthRequired())
+ {
+ authorized.POST("/login", loginEndpoint)
+ authorized.POST("/submit", submitEndpoint)
+ authorized.POST("/read", readEndpoint)
+
+ // nested group
+ testing := authorized.Group("testing")
+ testing.GET("/analytics", analyticsEndpoint)
+ }
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+### Custom Recovery behavior
+```go
+func main() {
+ // Creates a router without any middleware by default
+ r := gin.New()
+
+ // Global middleware
+ // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release.
+ // By default gin.DefaultWriter = os.Stdout
+ r.Use(gin.Logger())
+
+ // Recovery middleware recovers from any panics and writes a 500 if there was one.
+ r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
+ if err, ok := recovered.(string); ok {
+ c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
+ }
+ c.AbortWithStatus(http.StatusInternalServerError)
+ }))
+
+ r.GET("/panic", func(c *gin.Context) {
+ // panic with a string -- the custom middleware could save this to a database or report it to the user
+ panic("foo")
+ })
+
+ r.GET("/", func(c *gin.Context) {
+ c.String(http.StatusOK, "ohai")
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+### How to write log file
+```go
+func main() {
+ // Disable Console Color, you don't need console color when writing the logs to file.
+ gin.DisableConsoleColor()
+
+ // Logging to a file.
+ f, _ := os.Create("gin.log")
+ gin.DefaultWriter = io.MultiWriter(f)
+
+ // Use the following code if you need to write the logs to file and console at the same time.
+ // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
+
+ router := gin.Default()
+ router.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+
+ router.Run(":8080")
+}
+```
+
+### Custom Log Format
+```go
+func main() {
+ router := gin.New()
+
+ // LoggerWithFormatter middleware will write the logs to gin.DefaultWriter
+ // By default gin.DefaultWriter = os.Stdout
+ router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
+
+ // your custom format
+ return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
+ param.ClientIP,
+ param.TimeStamp.Format(time.RFC1123),
+ param.Method,
+ param.Path,
+ param.Request.Proto,
+ param.StatusCode,
+ param.Latency,
+ param.Request.UserAgent(),
+ param.ErrorMessage,
+ )
+ }))
+ router.Use(gin.Recovery())
+
+ router.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+
+ router.Run(":8080")
+}
+```
+
+**Sample Output**
+```
+::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
+```
+
+### Controlling Log output coloring
+
+By default, logs output on console should be colorized depending on the detected TTY.
+
+Never colorize logs:
+
+```go
+func main() {
+ // Disable log's color
+ gin.DisableConsoleColor()
+
+ // Creates a gin router with default middleware:
+ // logger and recovery (crash-free) middleware
+ router := gin.Default()
+
+ router.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+
+ router.Run(":8080")
+}
+```
+
+Always colorize logs:
+
+```go
+func main() {
+ // Force log's color
+ gin.ForceConsoleColor()
+
+ // Creates a gin router with default middleware:
+ // logger and recovery (crash-free) middleware
+ router := gin.Default()
+
+ router.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+
+ router.Run(":8080")
+}
+```
+
+### Model binding and validation
+
+To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz).
+
+Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags).
+
+Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.
+
+Also, Gin provides two sets of methods for binding:
+- **Type** - Must bind
+ - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`
+ - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method.
+- **Type** - Should bind
+ - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`
+ - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately.
+
+When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`.
+
+You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, an error will be returned.
+
+```go
+// Binding from JSON
+type Login struct {
+ User string `form:"user" json:"user" xml:"user" binding:"required"`
+ Password string `form:"password" json:"password" xml:"password" binding:"required"`
+}
+
+func main() {
+ router := gin.Default()
+
+ // Example for binding JSON ({"user": "manu", "password": "123"})
+ router.POST("/loginJSON", func(c *gin.Context) {
+ var json Login
+ if err := c.ShouldBindJSON(&json); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ if json.User != "manu" || json.Password != "123" {
+ c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
+ })
+
+ // Example for binding XML (
+ //
+ //
+ // user
+ // 123
+ // )
+ router.POST("/loginXML", func(c *gin.Context) {
+ var xml Login
+ if err := c.ShouldBindXML(&xml); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ if xml.User != "manu" || xml.Password != "123" {
+ c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
+ })
+
+ // Example for binding a HTML form (user=manu&password=123)
+ router.POST("/loginForm", func(c *gin.Context) {
+ var form Login
+ // This will infer what binder to use depending on the content-type header.
+ if err := c.ShouldBind(&form); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ if form.User != "manu" || form.Password != "123" {
+ c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ router.Run(":8080")
+}
+```
+
+**Sample request**
+```shell
+$ curl -v -X POST \
+ http://localhost:8080/loginJSON \
+ -H 'content-type: application/json' \
+ -d '{ "user": "manu" }'
+> POST /loginJSON HTTP/1.1
+> Host: localhost:8080
+> User-Agent: curl/7.51.0
+> Accept: */*
+> content-type: application/json
+> Content-Length: 18
+>
+* upload completely sent off: 18 out of 18 bytes
+< HTTP/1.1 400 Bad Request
+< Content-Type: application/json; charset=utf-8
+< Date: Fri, 04 Aug 2017 03:51:31 GMT
+< Content-Length: 100
+<
+{"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'required' tag"}
+```
+
+**Skip validate**
+
+When running the above example using the above the `curl` command, it returns error. Because the example use `binding:"required"` for `Password`. If use `binding:"-"` for `Password`, then it will not return error when running the above example again.
+
+### Custom Validators
+
+It is also possible to register custom validators. See the [example code](https://github.com/gin-gonic/examples/tree/master/custom-validation/server.go).
+
+```go
+package main
+
+import (
+ "net/http"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/go-playground/validator/v10"
+)
+
+// Booking contains binded and validated data.
+type Booking struct {
+ CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
+ CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
+}
+
+var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
+ date, ok := fl.Field().Interface().(time.Time)
+ if ok {
+ today := time.Now()
+ if today.After(date) {
+ return false
+ }
+ }
+ return true
+}
+
+func main() {
+ route := gin.Default()
+
+ if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
+ v.RegisterValidation("bookabledate", bookableDate)
+ }
+
+ route.GET("/bookable", getBookable)
+ route.Run(":8085")
+}
+
+func getBookable(c *gin.Context) {
+ var b Booking
+ if err := c.ShouldBindWith(&b, binding.Query); err == nil {
+ c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
+ } else {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ }
+}
+```
+
+```console
+$ curl "localhost:8085/bookable?check_in=2030-04-16&check_out=2030-04-17"
+{"message":"Booking dates are valid!"}
+
+$ curl "localhost:8085/bookable?check_in=2030-03-10&check_out=2030-03-09"
+{"error":"Key: 'Booking.CheckOut' Error:Field validation for 'CheckOut' failed on the 'gtfield' tag"}
+
+$ curl "localhost:8085/bookable?check_in=2000-03-09&check_out=2000-03-10"
+{"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}%
+```
+
+[Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way.
+See the [struct-lvl-validation example](https://github.com/gin-gonic/examples/tree/master/struct-lvl-validations) to learn more.
+
+### Only Bind Query String
+
+`ShouldBindQuery` function only binds the query params and not the post data. See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-315953017).
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/gin-gonic/gin"
+)
+
+type Person struct {
+ Name string `form:"name"`
+ Address string `form:"address"`
+}
+
+func main() {
+ route := gin.Default()
+ route.Any("/testing", startPage)
+ route.Run(":8085")
+}
+
+func startPage(c *gin.Context) {
+ var person Person
+ if c.ShouldBindQuery(&person) == nil {
+ log.Println("====== Only Bind By Query String ======")
+ log.Println(person.Name)
+ log.Println(person.Address)
+ }
+ c.String(200, "Success")
+}
+
+```
+
+### Bind Query String or Post Data
+
+See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
+
+```go
+package main
+
+import (
+ "log"
+ "time"
+
+ "github.com/gin-gonic/gin"
+)
+
+type Person struct {
+ Name string `form:"name"`
+ Address string `form:"address"`
+ Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
+ CreateTime time.Time `form:"createTime" time_format:"unixNano"`
+ UnixTime time.Time `form:"unixTime" time_format:"unix"`
+}
+
+func main() {
+ route := gin.Default()
+ route.GET("/testing", startPage)
+ route.Run(":8085")
+}
+
+func startPage(c *gin.Context) {
+ var person Person
+ // If `GET`, only `Form` binding engine (`query`) used.
+ // If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
+ // See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
+ if c.ShouldBind(&person) == nil {
+ log.Println(person.Name)
+ log.Println(person.Address)
+ log.Println(person.Birthday)
+ log.Println(person.CreateTime)
+ log.Println(person.UnixTime)
+ }
+
+ c.String(200, "Success")
+}
+```
+
+Test it with:
+```sh
+$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033"
+```
+
+### Bind Uri
+
+See the [detail information](https://github.com/gin-gonic/gin/issues/846).
+
+```go
+package main
+
+import "github.com/gin-gonic/gin"
+
+type Person struct {
+ ID string `uri:"id" binding:"required,uuid"`
+ Name string `uri:"name" binding:"required"`
+}
+
+func main() {
+ route := gin.Default()
+ route.GET("/:name/:id", func(c *gin.Context) {
+ var person Person
+ if err := c.ShouldBindUri(&person); err != nil {
+ c.JSON(400, gin.H{"msg": err})
+ return
+ }
+ c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
+ })
+ route.Run(":8088")
+}
+```
+
+Test it with:
+```sh
+$ curl -v localhost:8088/thinkerou/987fbc97-4bed-5078-9f07-9141ba07c9f3
+$ curl -v localhost:8088/thinkerou/not-uuid
+```
+
+### Bind Header
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/gin-gonic/gin"
+)
+
+type testHeader struct {
+ Rate int `header:"Rate"`
+ Domain string `header:"Domain"`
+}
+
+func main() {
+ r := gin.Default()
+ r.GET("/", func(c *gin.Context) {
+ h := testHeader{}
+
+ if err := c.ShouldBindHeader(&h); err != nil {
+ c.JSON(200, err)
+ }
+
+ fmt.Printf("%#v\n", h)
+ c.JSON(200, gin.H{"Rate": h.Rate, "Domain": h.Domain})
+ })
+
+ r.Run()
+
+// client
+// curl -H "rate:300" -H "domain:music" 127.0.0.1:8080/
+// output
+// {"Domain":"music","Rate":300}
+}
+```
+
+### Bind HTML checkboxes
+
+See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)
+
+main.go
+
+```go
+...
+
+type myForm struct {
+ Colors []string `form:"colors[]"`
+}
+
+...
+
+func formHandler(c *gin.Context) {
+ var fakeForm myForm
+ c.ShouldBind(&fakeForm)
+ c.JSON(200, gin.H{"color": fakeForm.Colors})
+}
+
+...
+
+```
+
+form.html
+
+```html
+
+```
+
+result:
+
+```
+{"color":["red","green","blue"]}
+```
+
+### Multipart/Urlencoded binding
+
+```go
+type ProfileForm struct {
+ Name string `form:"name" binding:"required"`
+ Avatar *multipart.FileHeader `form:"avatar" binding:"required"`
+
+ // or for multiple files
+ // Avatars []*multipart.FileHeader `form:"avatar" binding:"required"`
+}
+
+func main() {
+ router := gin.Default()
+ router.POST("/profile", func(c *gin.Context) {
+ // you can bind multipart form with explicit binding declaration:
+ // c.ShouldBindWith(&form, binding.Form)
+ // or you can simply use autobinding with ShouldBind method:
+ var form ProfileForm
+ // in this case proper binding will be automatically selected
+ if err := c.ShouldBind(&form); err != nil {
+ c.String(http.StatusBadRequest, "bad request")
+ return
+ }
+
+ err := c.SaveUploadedFile(form.Avatar, form.Avatar.Filename)
+ if err != nil {
+ c.String(http.StatusInternalServerError, "unknown error")
+ return
+ }
+
+ // db.Save(&form)
+
+ c.String(http.StatusOK, "ok")
+ })
+ router.Run(":8080")
+}
+```
+
+Test it with:
+```sh
+$ curl -X POST -v --form name=user --form "avatar=@./avatar.png" http://localhost:8080/profile
+```
+
+### XML, JSON, YAML and ProtoBuf rendering
+
+```go
+func main() {
+ r := gin.Default()
+
+ // gin.H is a shortcut for map[string]interface{}
+ r.GET("/someJSON", func(c *gin.Context) {
+ c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
+ })
+
+ r.GET("/moreJSON", func(c *gin.Context) {
+ // You also can use a struct
+ var msg struct {
+ Name string `json:"user"`
+ Message string
+ Number int
+ }
+ msg.Name = "Lena"
+ msg.Message = "hey"
+ msg.Number = 123
+ // Note that msg.Name becomes "user" in the JSON
+ // Will output : {"user": "Lena", "Message": "hey", "Number": 123}
+ c.JSON(http.StatusOK, msg)
+ })
+
+ r.GET("/someXML", func(c *gin.Context) {
+ c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
+ })
+
+ r.GET("/someYAML", func(c *gin.Context) {
+ c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
+ })
+
+ r.GET("/someProtoBuf", func(c *gin.Context) {
+ reps := []int64{int64(1), int64(2)}
+ label := "test"
+ // The specific definition of protobuf is written in the testdata/protoexample file.
+ data := &protoexample.Test{
+ Label: &label,
+ Reps: reps,
+ }
+ // Note that data becomes binary data in the response
+ // Will output protoexample.Test protobuf serialized data
+ c.ProtoBuf(http.StatusOK, data)
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+#### SecureJSON
+
+Using SecureJSON to prevent json hijacking. Default prepends `"while(1),"` to response body if the given struct is array values.
+
+```go
+func main() {
+ r := gin.Default()
+
+ // You can also use your own secure json prefix
+ // r.SecureJsonPrefix(")]}',\n")
+
+ r.GET("/someJSON", func(c *gin.Context) {
+ names := []string{"lena", "austin", "foo"}
+
+ // Will output : while(1);["lena","austin","foo"]
+ c.SecureJSON(http.StatusOK, names)
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+#### JSONP
+
+Using JSONP to request data from a server in a different domain. Add callback to response body if the query parameter callback exists.
+
+```go
+func main() {
+ r := gin.Default()
+
+ r.GET("/JSONP", func(c *gin.Context) {
+ data := gin.H{
+ "foo": "bar",
+ }
+
+ //callback is x
+ // Will output : x({\"foo\":\"bar\"})
+ c.JSONP(http.StatusOK, data)
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+
+ // client
+ // curl http://127.0.0.1:8080/JSONP?callback=x
+}
+```
+
+#### AsciiJSON
+
+Using AsciiJSON to Generates ASCII-only JSON with escaped non-ASCII characters.
+
+```go
+func main() {
+ r := gin.Default()
+
+ r.GET("/someJSON", func(c *gin.Context) {
+ data := gin.H{
+ "lang": "GO语言",
+ "tag": " ",
+ }
+
+ // will output : {"lang":"GO\u8bed\u8a00","tag":"\u003cbr\u003e"}
+ c.AsciiJSON(http.StatusOK, data)
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+#### PureJSON
+
+Normally, JSON replaces special HTML characters with their unicode entities, e.g. `<` becomes `\u003c`. If you want to encode such characters literally, you can use PureJSON instead.
+This feature is unavailable in Go 1.6 and lower.
+
+```go
+func main() {
+ r := gin.Default()
+
+ // Serves unicode entities
+ r.GET("/json", func(c *gin.Context) {
+ c.JSON(200, gin.H{
+ "html": "Hello, world! ",
+ })
+ })
+
+ // Serves literal characters
+ r.GET("/purejson", func(c *gin.Context) {
+ c.PureJSON(200, gin.H{
+ "html": "Hello, world! ",
+ })
+ })
+
+ // listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+### Serving static files
+
+```go
+func main() {
+ router := gin.Default()
+ router.Static("/assets", "./assets")
+ router.StaticFS("/more_static", http.Dir("my_file_system"))
+ router.StaticFile("/favicon.ico", "./resources/favicon.ico")
+
+ // Listen and serve on 0.0.0.0:8080
+ router.Run(":8080")
+}
+```
+
+### Serving data from file
+
+```go
+func main() {
+ router := gin.Default()
+
+ router.GET("/local/file", func(c *gin.Context) {
+ c.File("local/file.go")
+ })
+
+ var fs http.FileSystem = // ...
+ router.GET("/fs/file", func(c *gin.Context) {
+ c.FileFromFS("fs/file.go", fs)
+ })
+}
+
+```
+
+### Serving data from reader
+
+```go
+func main() {
+ router := gin.Default()
+ router.GET("/someDataFromReader", func(c *gin.Context) {
+ response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png")
+ if err != nil || response.StatusCode != http.StatusOK {
+ c.Status(http.StatusServiceUnavailable)
+ return
+ }
+
+ reader := response.Body
+ defer reader.Close()
+ contentLength := response.ContentLength
+ contentType := response.Header.Get("Content-Type")
+
+ extraHeaders := map[string]string{
+ "Content-Disposition": `attachment; filename="gopher.png"`,
+ }
+
+ c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
+ })
+ router.Run(":8080")
+}
+```
+
+### HTML rendering
+
+Using LoadHTMLGlob() or LoadHTMLFiles()
+
+```go
+func main() {
+ router := gin.Default()
+ router.LoadHTMLGlob("templates/*")
+ //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
+ router.GET("/index", func(c *gin.Context) {
+ c.HTML(http.StatusOK, "index.tmpl", gin.H{
+ "title": "Main website",
+ })
+ })
+ router.Run(":8080")
+}
+```
+
+templates/index.tmpl
+
+```html
+
+
+ {{ .title }}
+
+
+```
+
+Using templates with same name in different directories
+
+```go
+func main() {
+ router := gin.Default()
+ router.LoadHTMLGlob("templates/**/*")
+ router.GET("/posts/index", func(c *gin.Context) {
+ c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
+ "title": "Posts",
+ })
+ })
+ router.GET("/users/index", func(c *gin.Context) {
+ c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
+ "title": "Users",
+ })
+ })
+ router.Run(":8080")
+}
+```
+
+templates/posts/index.tmpl
+
+```html
+{{ define "posts/index.tmpl" }}
+
+ {{ .title }}
+
+Using posts/index.tmpl
+
+{{ end }}
+```
+
+templates/users/index.tmpl
+
+```html
+{{ define "users/index.tmpl" }}
+
+ {{ .title }}
+
+Using users/index.tmpl
+
+{{ end }}
+```
+
+#### Custom Template renderer
+
+You can also use your own html template render
+
+```go
+import "html/template"
+
+func main() {
+ router := gin.Default()
+ html := template.Must(template.ParseFiles("file1", "file2"))
+ router.SetHTMLTemplate(html)
+ router.Run(":8080")
+}
+```
+
+#### Custom Delimiters
+
+You may use custom delims
+
+```go
+ r := gin.Default()
+ r.Delims("{[{", "}]}")
+ r.LoadHTMLGlob("/path/to/templates")
+```
+
+#### Custom Template Funcs
+
+See the detail [example code](https://github.com/gin-gonic/examples/tree/master/template).
+
+main.go
+
+```go
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+ "time"
+
+ "github.com/gin-gonic/gin"
+)
+
+func formatAsDate(t time.Time) string {
+ year, month, day := t.Date()
+ return fmt.Sprintf("%d%02d/%02d", year, month, day)
+}
+
+func main() {
+ router := gin.Default()
+ router.Delims("{[{", "}]}")
+ router.SetFuncMap(template.FuncMap{
+ "formatAsDate": formatAsDate,
+ })
+ router.LoadHTMLFiles("./testdata/template/raw.tmpl")
+
+ router.GET("/raw", func(c *gin.Context) {
+ c.HTML(http.StatusOK, "raw.tmpl", gin.H{
+ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
+ })
+ })
+
+ router.Run(":8080")
+}
+
+```
+
+raw.tmpl
+
+```html
+Date: {[{.now | formatAsDate}]}
+```
+
+Result:
+```
+Date: 2017/07/01
+```
+
+### Multitemplate
+
+Gin allow by default use only one html.Template. Check [a multitemplate render](https://github.com/gin-contrib/multitemplate) for using features like go 1.6 `block template`.
+
+### Redirects
+
+Issuing a HTTP redirect is easy. Both internal and external locations are supported.
+
+```go
+r.GET("/test", func(c *gin.Context) {
+ c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
+})
+```
+
+Issuing a HTTP redirect from POST. Refer to issue: [#444](https://github.com/gin-gonic/gin/issues/444)
+```go
+r.POST("/test", func(c *gin.Context) {
+ c.Redirect(http.StatusFound, "/foo")
+})
+```
+
+Issuing a Router redirect, use `HandleContext` like below.
+
+``` go
+r.GET("/test", func(c *gin.Context) {
+ c.Request.URL.Path = "/test2"
+ r.HandleContext(c)
+})
+r.GET("/test2", func(c *gin.Context) {
+ c.JSON(200, gin.H{"hello": "world"})
+})
+```
+
+
+### Custom Middleware
+
+```go
+func Logger() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ t := time.Now()
+
+ // Set example variable
+ c.Set("example", "12345")
+
+ // before request
+
+ c.Next()
+
+ // after request
+ latency := time.Since(t)
+ log.Print(latency)
+
+ // access the status we are sending
+ status := c.Writer.Status()
+ log.Println(status)
+ }
+}
+
+func main() {
+ r := gin.New()
+ r.Use(Logger())
+
+ r.GET("/test", func(c *gin.Context) {
+ example := c.MustGet("example").(string)
+
+ // it would print: "12345"
+ log.Println(example)
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+### Using BasicAuth() middleware
+
+```go
+// simulate some private data
+var secrets = gin.H{
+ "foo": gin.H{"email": "foo@bar.com", "phone": "123433"},
+ "austin": gin.H{"email": "austin@example.com", "phone": "666"},
+ "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"},
+}
+
+func main() {
+ r := gin.Default()
+
+ // Group using gin.BasicAuth() middleware
+ // gin.Accounts is a shortcut for map[string]string
+ authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
+ "foo": "bar",
+ "austin": "1234",
+ "lena": "hello2",
+ "manu": "4321",
+ }))
+
+ // /admin/secrets endpoint
+ // hit "localhost:8080/admin/secrets
+ authorized.GET("/secrets", func(c *gin.Context) {
+ // get user, it was set by the BasicAuth middleware
+ user := c.MustGet(gin.AuthUserKey).(string)
+ if secret, ok := secrets[user]; ok {
+ c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
+ } else {
+ c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
+ }
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+### Goroutines inside a middleware
+
+When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy.
+
+```go
+func main() {
+ r := gin.Default()
+
+ r.GET("/long_async", func(c *gin.Context) {
+ // create copy to be used inside the goroutine
+ cCp := c.Copy()
+ go func() {
+ // simulate a long task with time.Sleep(). 5 seconds
+ time.Sleep(5 * time.Second)
+
+ // note that you are using the copied context "cCp", IMPORTANT
+ log.Println("Done! in path " + cCp.Request.URL.Path)
+ }()
+ })
+
+ r.GET("/long_sync", func(c *gin.Context) {
+ // simulate a long task with time.Sleep(). 5 seconds
+ time.Sleep(5 * time.Second)
+
+ // since we are NOT using a goroutine, we do not have to copy the context
+ log.Println("Done! in path " + c.Request.URL.Path)
+ })
+
+ // Listen and serve on 0.0.0.0:8080
+ r.Run(":8080")
+}
+```
+
+### Custom HTTP configuration
+
+Use `http.ListenAndServe()` directly, like this:
+
+```go
+func main() {
+ router := gin.Default()
+ http.ListenAndServe(":8080", router)
+}
+```
+or
+
+```go
+func main() {
+ router := gin.Default()
+
+ s := &http.Server{
+ Addr: ":8080",
+ Handler: router,
+ ReadTimeout: 10 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ MaxHeaderBytes: 1 << 20,
+ }
+ s.ListenAndServe()
+}
+```
+
+### Support Let's Encrypt
+
+example for 1-line LetsEncrypt HTTPS servers.
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/gin-gonic/autotls"
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+ r := gin.Default()
+
+ // Ping handler
+ r.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+
+ log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
+}
+```
+
+example for custom autocert manager.
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/gin-gonic/autotls"
+ "github.com/gin-gonic/gin"
+ "golang.org/x/crypto/acme/autocert"
+)
+
+func main() {
+ r := gin.Default()
+
+ // Ping handler
+ r.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+
+ m := autocert.Manager{
+ Prompt: autocert.AcceptTOS,
+ HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
+ Cache: autocert.DirCache("/var/www/.cache"),
+ }
+
+ log.Fatal(autotls.RunWithManager(r, &m))
+}
+```
+
+### Run multiple service using Gin
+
+See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example:
+
+```go
+package main
+
+import (
+ "log"
+ "net/http"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "golang.org/x/sync/errgroup"
+)
+
+var (
+ g errgroup.Group
+)
+
+func router01() http.Handler {
+ e := gin.New()
+ e.Use(gin.Recovery())
+ e.GET("/", func(c *gin.Context) {
+ c.JSON(
+ http.StatusOK,
+ gin.H{
+ "code": http.StatusOK,
+ "error": "Welcome server 01",
+ },
+ )
+ })
+
+ return e
+}
+
+func router02() http.Handler {
+ e := gin.New()
+ e.Use(gin.Recovery())
+ e.GET("/", func(c *gin.Context) {
+ c.JSON(
+ http.StatusOK,
+ gin.H{
+ "code": http.StatusOK,
+ "error": "Welcome server 02",
+ },
+ )
+ })
+
+ return e
+}
+
+func main() {
+ server01 := &http.Server{
+ Addr: ":8080",
+ Handler: router01(),
+ ReadTimeout: 5 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ }
+
+ server02 := &http.Server{
+ Addr: ":8081",
+ Handler: router02(),
+ ReadTimeout: 5 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ }
+
+ g.Go(func() error {
+ err := server01.ListenAndServe()
+ if err != nil && err != http.ErrServerClosed {
+ log.Fatal(err)
+ }
+ return err
+ })
+
+ g.Go(func() error {
+ err := server02.ListenAndServe()
+ if err != nil && err != http.ErrServerClosed {
+ log.Fatal(err)
+ }
+ return err
+ })
+
+ if err := g.Wait(); err != nil {
+ log.Fatal(err)
+ }
+}
+```
+
+### Graceful shutdown or restart
+
+There are a few approaches you can use to perform a graceful shutdown or restart. You can make use of third-party packages specifically built for that, or you can manually do the same with the functions and methods from the built-in packages.
+
+#### Third-party packages
+
+We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer to issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details.
+
+```go
+router := gin.Default()
+router.GET("/", handler)
+// [...]
+endless.ListenAndServe(":4242", router)
+```
+
+Alternatives:
+
+* [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully.
+* [graceful](https://github.com/tylerb/graceful): Graceful is a Go package enabling graceful shutdown of an http.Handler server.
+* [grace](https://github.com/facebookgo/grace): Graceful restart & zero downtime deploy for Go servers.
+
+#### Manually
+
+In case you are using Go 1.8 or a later version, you may not need to use those libraries. Consider using `http.Server`'s built-in [Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) method for graceful shutdowns. The example below describes its usage, and we've got more examples using gin [here](https://github.com/gin-gonic/examples/tree/master/graceful-shutdown).
+
+```go
+// +build go1.8
+
+package main
+
+import (
+ "context"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "syscall"
+ "time"
+
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+ router := gin.Default()
+ router.GET("/", func(c *gin.Context) {
+ time.Sleep(5 * time.Second)
+ c.String(http.StatusOK, "Welcome Gin Server")
+ })
+
+ srv := &http.Server{
+ Addr: ":8080",
+ Handler: router,
+ }
+
+ // Initializing the server in a goroutine so that
+ // it won't block the graceful shutdown handling below
+ go func() {
+ if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
+ log.Printf("listen: %s\n", err)
+ }
+ }()
+
+ // Wait for interrupt signal to gracefully shutdown the server with
+ // a timeout of 5 seconds.
+ quit := make(chan os.Signal)
+ // kill (no param) default send syscall.SIGTERM
+ // kill -2 is syscall.SIGINT
+ // kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+ <-quit
+ log.Println("Shutting down server...")
+
+ // The context is used to inform the server it has 5 seconds to finish
+ // the request it is currently handling
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ if err := srv.Shutdown(ctx); err != nil {
+ log.Fatal("Server forced to shutdown:", err)
+ }
+
+ log.Println("Server exiting")
+}
+```
+
+### Build a single binary with templates
+
+You can build a server into a single binary containing templates by using [go-assets][].
+
+[go-assets]: https://github.com/jessevdk/go-assets
+
+```go
+func main() {
+ r := gin.New()
+
+ t, err := loadTemplate()
+ if err != nil {
+ panic(err)
+ }
+ r.SetHTMLTemplate(t)
+
+ r.GET("/", func(c *gin.Context) {
+ c.HTML(http.StatusOK, "/html/index.tmpl",nil)
+ })
+ r.Run(":8080")
+}
+
+// loadTemplate loads templates embedded by go-assets-builder
+func loadTemplate() (*template.Template, error) {
+ t := template.New("")
+ for name, file := range Assets.Files {
+ defer file.Close()
+ if file.IsDir() || !strings.HasSuffix(name, ".tmpl") {
+ continue
+ }
+ h, err := ioutil.ReadAll(file)
+ if err != nil {
+ return nil, err
+ }
+ t, err = t.New(name).Parse(string(h))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return t, nil
+}
+```
+
+See a complete example in the `https://github.com/gin-gonic/examples/tree/master/assets-in-binary` directory.
+
+### Bind form-data request with custom struct
+
+The follow example using custom struct:
+
+```go
+type StructA struct {
+ FieldA string `form:"field_a"`
+}
+
+type StructB struct {
+ NestedStruct StructA
+ FieldB string `form:"field_b"`
+}
+
+type StructC struct {
+ NestedStructPointer *StructA
+ FieldC string `form:"field_c"`
+}
+
+type StructD struct {
+ NestedAnonyStruct struct {
+ FieldX string `form:"field_x"`
+ }
+ FieldD string `form:"field_d"`
+}
+
+func GetDataB(c *gin.Context) {
+ var b StructB
+ c.Bind(&b)
+ c.JSON(200, gin.H{
+ "a": b.NestedStruct,
+ "b": b.FieldB,
+ })
+}
+
+func GetDataC(c *gin.Context) {
+ var b StructC
+ c.Bind(&b)
+ c.JSON(200, gin.H{
+ "a": b.NestedStructPointer,
+ "c": b.FieldC,
+ })
+}
+
+func GetDataD(c *gin.Context) {
+ var b StructD
+ c.Bind(&b)
+ c.JSON(200, gin.H{
+ "x": b.NestedAnonyStruct,
+ "d": b.FieldD,
+ })
+}
+
+func main() {
+ r := gin.Default()
+ r.GET("/getb", GetDataB)
+ r.GET("/getc", GetDataC)
+ r.GET("/getd", GetDataD)
+
+ r.Run()
+}
+```
+
+Using the command `curl` command result:
+
+```
+$ curl "http://localhost:8080/getb?field_a=hello&field_b=world"
+{"a":{"FieldA":"hello"},"b":"world"}
+$ curl "http://localhost:8080/getc?field_a=hello&field_c=world"
+{"a":{"FieldA":"hello"},"c":"world"}
+$ curl "http://localhost:8080/getd?field_x=hello&field_d=world"
+{"d":"world","x":{"FieldX":"hello"}}
+```
+
+### Try to bind body into different structs
+
+The normal methods for binding request body consumes `c.Request.Body` and they
+cannot be called multiple times.
+
+```go
+type formA struct {
+ Foo string `json:"foo" xml:"foo" binding:"required"`
+}
+
+type formB struct {
+ Bar string `json:"bar" xml:"bar" binding:"required"`
+}
+
+func SomeHandler(c *gin.Context) {
+ objA := formA{}
+ objB := formB{}
+ // This c.ShouldBind consumes c.Request.Body and it cannot be reused.
+ if errA := c.ShouldBind(&objA); errA == nil {
+ c.String(http.StatusOK, `the body should be formA`)
+ // Always an error is occurred by this because c.Request.Body is EOF now.
+ } else if errB := c.ShouldBind(&objB); errB == nil {
+ c.String(http.StatusOK, `the body should be formB`)
+ } else {
+ ...
+ }
+}
+```
+
+For this, you can use `c.ShouldBindBodyWith`.
+
+```go
+func SomeHandler(c *gin.Context) {
+ objA := formA{}
+ objB := formB{}
+ // This reads c.Request.Body and stores the result into the context.
+ if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
+ c.String(http.StatusOK, `the body should be formA`)
+ // At this time, it reuses body stored in the context.
+ } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
+ c.String(http.StatusOK, `the body should be formB JSON`)
+ // And it can accepts other formats
+ } else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
+ c.String(http.StatusOK, `the body should be formB XML`)
+ } else {
+ ...
+ }
+}
+```
+
+* `c.ShouldBindBodyWith` stores body into the context before binding. This has
+a slight impact to performance, so you should not use this method if you are
+enough to call binding at once.
+* This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`,
+`ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`,
+can be called by `c.ShouldBind()` multiple times without any damage to
+performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)).
+
+### http2 server push
+
+http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information.
+
+```go
+package main
+
+import (
+ "html/template"
+ "log"
+
+ "github.com/gin-gonic/gin"
+)
+
+var html = template.Must(template.New("https").Parse(`
+
+
+ Https Test
+
+
+
+ Welcome, Ginner!
+
+
+`))
+
+func main() {
+ r := gin.Default()
+ r.Static("/assets", "./assets")
+ r.SetHTMLTemplate(html)
+
+ r.GET("/", func(c *gin.Context) {
+ if pusher := c.Writer.Pusher(); pusher != nil {
+ // use pusher.Push() to do server push
+ if err := pusher.Push("/assets/app.js", nil); err != nil {
+ log.Printf("Failed to push: %v", err)
+ }
+ }
+ c.HTML(200, "https", gin.H{
+ "status": "success",
+ })
+ })
+
+ // Listen and Server in https://127.0.0.1:8080
+ r.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
+}
+```
+
+### Define format for the log of routes
+
+The default log of routes is:
+```
+[GIN-debug] POST /foo --> main.main.func1 (3 handlers)
+[GIN-debug] GET /bar --> main.main.func2 (3 handlers)
+[GIN-debug] GET /status --> main.main.func3 (3 handlers)
+```
+
+If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`.
+In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs.
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+ r := gin.Default()
+ gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
+ log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers)
+ }
+
+ r.POST("/foo", func(c *gin.Context) {
+ c.JSON(http.StatusOK, "foo")
+ })
+
+ r.GET("/bar", func(c *gin.Context) {
+ c.JSON(http.StatusOK, "bar")
+ })
+
+ r.GET("/status", func(c *gin.Context) {
+ c.JSON(http.StatusOK, "ok")
+ })
+
+ // Listen and Server in http://0.0.0.0:8080
+ r.Run()
+}
+```
+
+### Set and get a cookie
+
+```go
+import (
+ "fmt"
+
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+
+ router := gin.Default()
+
+ router.GET("/cookie", func(c *gin.Context) {
+
+ cookie, err := c.Cookie("gin_cookie")
+
+ if err != nil {
+ cookie = "NotSet"
+ c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)
+ }
+
+ fmt.Printf("Cookie value: %s \n", cookie)
+ })
+
+ router.Run()
+}
+```
+
+## Don't trust all proxies
+
+Gin lets you specify which headers to hold the real client IP (if any),
+as well as specifying which proxies (or direct clients) you trust to
+specify one of these headers.
+
+Use function `SetTrustedProxies()` on your `gin.Engine` to specify network addresses
+or network CIDRs from where clients which their request headers related to client
+IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or
+IPv6 CIDRs.
+
+**Attention:** Gin trust all proxies by default if you don't specify a trusted
+proxy using the function above, **this is NOT safe**. At the same time, if you don't
+use any proxy, you can disable this feature by using `Engine.SetTrustedProxies(nil)`,
+then `Context.ClientIP()` will return the remote address directly to avoid some
+unnecessary computation.
+
+```go
+import (
+ "fmt"
+
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+
+ router := gin.Default()
+ router.SetTrustedProxies([]string{"192.168.1.2"})
+
+ router.GET("/", func(c *gin.Context) {
+ // If the client is 192.168.1.2, use the X-Forwarded-For
+ // header to deduce the original client IP from the trust-
+ // worthy parts of that header.
+ // Otherwise, simply return the direct client IP
+ fmt.Printf("ClientIP: %s\n", c.ClientIP())
+ })
+ router.Run()
+}
+```
+
+**Notice:** If you are using a CDN service, you can set the `Engine.TrustedPlatform`
+to skip TrustedProxies check, it has a higher priority than TrustedProxies.
+Look at the example below:
+```go
+import (
+ "fmt"
+
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+
+ router := gin.Default()
+ // Use predefined header gin.PlatformXXX
+ router.TrustedPlatform = gin.PlatformGoogleAppEngine
+ // Or set your own trusted request header for another trusted proxy service
+ // Don't set it to any suspect request header, it's unsafe
+ router.TrustedPlatform = "X-CDN-IP"
+
+ router.GET("/", func(c *gin.Context) {
+ // If you set TrustedPlatform, ClientIP() will resolve the
+ // corresponding header and return IP directly
+ fmt.Printf("ClientIP: %s\n", c.ClientIP())
+ })
+ router.Run()
+}
+```
+
+## Testing
+
+The `net/http/httptest` package is preferable way for HTTP testing.
+
+```go
+package main
+
+func setupRouter() *gin.Engine {
+ r := gin.Default()
+ r.GET("/ping", func(c *gin.Context) {
+ c.String(200, "pong")
+ })
+ return r
+}
+
+func main() {
+ r := setupRouter()
+ r.Run(":8080")
+}
+```
+
+Test for code example above:
+
+```go
+package main
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestPingRoute(t *testing.T) {
+ router := setupRouter()
+
+ w := httptest.NewRecorder()
+ req, _ := http.NewRequest("GET", "/ping", nil)
+ router.ServeHTTP(w, req)
+
+ assert.Equal(t, 200, w.Code)
+ assert.Equal(t, "pong", w.Body.String())
+}
+```
+
+## Users
+
+Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.
+
+* [gorush](https://github.com/appleboy/gorush): A push notification server written in Go.
+* [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform.
+* [photoprism](https://github.com/photoprism/photoprism): Personal photo management powered by Go and Google TensorFlow.
+* [krakend](https://github.com/devopsfaith/krakend): Ultra performant API Gateway with middlewares.
+* [picfit](https://github.com/thoas/picfit): An image resizing server written in Go.
+* [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes.
+* [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/auth.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/auth.go
new file mode 100644
index 000000000000..4d8a6ce484c4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/auth.go
@@ -0,0 +1,91 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "crypto/subtle"
+ "encoding/base64"
+ "net/http"
+ "strconv"
+
+ "github.com/gin-gonic/gin/internal/bytesconv"
+)
+
+// AuthUserKey is the cookie name for user credential in basic auth.
+const AuthUserKey = "user"
+
+// Accounts defines a key/value for user/pass list of authorized logins.
+type Accounts map[string]string
+
+type authPair struct {
+ value string
+ user string
+}
+
+type authPairs []authPair
+
+func (a authPairs) searchCredential(authValue string) (string, bool) {
+ if authValue == "" {
+ return "", false
+ }
+ for _, pair := range a {
+ if subtle.ConstantTimeCompare([]byte(pair.value), []byte(authValue)) == 1 {
+ return pair.user, true
+ }
+ }
+ return "", false
+}
+
+// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
+// the key is the user name and the value is the password, as well as the name of the Realm.
+// If the realm is empty, "Authorization Required" will be used by default.
+// (see http://tools.ietf.org/html/rfc2617#section-1.2)
+func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
+ if realm == "" {
+ realm = "Authorization Required"
+ }
+ realm = "Basic realm=" + strconv.Quote(realm)
+ pairs := processAccounts(accounts)
+ return func(c *Context) {
+ // Search user in the slice of allowed credentials
+ user, found := pairs.searchCredential(c.requestHeader("Authorization"))
+ if !found {
+ // Credentials doesn't match, we return 401 and abort handlers chain.
+ c.Header("WWW-Authenticate", realm)
+ c.AbortWithStatus(http.StatusUnauthorized)
+ return
+ }
+
+ // The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using
+ // c.MustGet(gin.AuthUserKey).
+ c.Set(AuthUserKey, user)
+ }
+}
+
+// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
+// the key is the user name and the value is the password.
+func BasicAuth(accounts Accounts) HandlerFunc {
+ return BasicAuthForRealm(accounts, "")
+}
+
+func processAccounts(accounts Accounts) authPairs {
+ length := len(accounts)
+ assert1(length > 0, "Empty list of authorized credentials")
+ pairs := make(authPairs, 0, length)
+ for user, password := range accounts {
+ assert1(user != "", "User can not be empty")
+ value := authorizationHeader(user, password)
+ pairs = append(pairs, authPair{
+ value: value,
+ user: user,
+ })
+ }
+ return pairs
+}
+
+func authorizationHeader(user, password string) string {
+ base := user + ":" + password
+ return "Basic " + base64.StdEncoding.EncodeToString(bytesconv.StringToBytes(base))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/binding.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/binding.go
new file mode 100644
index 000000000000..5caeb581afe7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/binding.go
@@ -0,0 +1,118 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build !nomsgpack
+// +build !nomsgpack
+
+package binding
+
+import "net/http"
+
+// Content-Type MIME of the most common data formats.
+const (
+ MIMEJSON = "application/json"
+ MIMEHTML = "text/html"
+ MIMEXML = "application/xml"
+ MIMEXML2 = "text/xml"
+ MIMEPlain = "text/plain"
+ MIMEPOSTForm = "application/x-www-form-urlencoded"
+ MIMEMultipartPOSTForm = "multipart/form-data"
+ MIMEPROTOBUF = "application/x-protobuf"
+ MIMEMSGPACK = "application/x-msgpack"
+ MIMEMSGPACK2 = "application/msgpack"
+ MIMEYAML = "application/x-yaml"
+)
+
+// Binding describes the interface which needs to be implemented for binding the
+// data present in the request such as JSON request body, query parameters or
+// the form POST.
+type Binding interface {
+ Name() string
+ Bind(*http.Request, interface{}) error
+}
+
+// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
+// but it reads the body from supplied bytes instead of req.Body.
+type BindingBody interface {
+ Binding
+ BindBody([]byte, interface{}) error
+}
+
+// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
+// but it read the Params.
+type BindingUri interface {
+ Name() string
+ BindUri(map[string][]string, interface{}) error
+}
+
+// StructValidator is the minimal interface which needs to be implemented in
+// order for it to be used as the validator engine for ensuring the correctness
+// of the request. Gin provides a default implementation for this using
+// https://github.com/go-playground/validator/tree/v8.18.2.
+type StructValidator interface {
+ // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
+ // If the received type is a slice|array, the validation should be performed travel on every element.
+ // If the received type is not a struct or slice|array, any validation should be skipped and nil must be returned.
+ // If the received type is a struct or pointer to a struct, the validation should be performed.
+ // If the struct is not valid or the validation itself fails, a descriptive error should be returned.
+ // Otherwise nil must be returned.
+ ValidateStruct(interface{}) error
+
+ // Engine returns the underlying validator engine which powers the
+ // StructValidator implementation.
+ Engine() interface{}
+}
+
+// Validator is the default validator which implements the StructValidator
+// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
+// under the hood.
+var Validator StructValidator = &defaultValidator{}
+
+// These implement the Binding interface and can be used to bind the data
+// present in the request to struct instances.
+var (
+ JSON = jsonBinding{}
+ XML = xmlBinding{}
+ Form = formBinding{}
+ Query = queryBinding{}
+ FormPost = formPostBinding{}
+ FormMultipart = formMultipartBinding{}
+ ProtoBuf = protobufBinding{}
+ MsgPack = msgpackBinding{}
+ YAML = yamlBinding{}
+ Uri = uriBinding{}
+ Header = headerBinding{}
+)
+
+// Default returns the appropriate Binding instance based on the HTTP method
+// and the content type.
+func Default(method, contentType string) Binding {
+ if method == http.MethodGet {
+ return Form
+ }
+
+ switch contentType {
+ case MIMEJSON:
+ return JSON
+ case MIMEXML, MIMEXML2:
+ return XML
+ case MIMEPROTOBUF:
+ return ProtoBuf
+ case MIMEMSGPACK, MIMEMSGPACK2:
+ return MsgPack
+ case MIMEYAML:
+ return YAML
+ case MIMEMultipartPOSTForm:
+ return FormMultipart
+ default: // case MIMEPOSTForm:
+ return Form
+ }
+}
+
+func validate(obj interface{}) error {
+ if Validator == nil {
+ return nil
+ }
+ return Validator.ValidateStruct(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go
new file mode 100644
index 000000000000..9afa3dcf6dad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go
@@ -0,0 +1,112 @@
+// Copyright 2020 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build nomsgpack
+// +build nomsgpack
+
+package binding
+
+import "net/http"
+
+// Content-Type MIME of the most common data formats.
+const (
+ MIMEJSON = "application/json"
+ MIMEHTML = "text/html"
+ MIMEXML = "application/xml"
+ MIMEXML2 = "text/xml"
+ MIMEPlain = "text/plain"
+ MIMEPOSTForm = "application/x-www-form-urlencoded"
+ MIMEMultipartPOSTForm = "multipart/form-data"
+ MIMEPROTOBUF = "application/x-protobuf"
+ MIMEYAML = "application/x-yaml"
+)
+
+// Binding describes the interface which needs to be implemented for binding the
+// data present in the request such as JSON request body, query parameters or
+// the form POST.
+type Binding interface {
+ Name() string
+ Bind(*http.Request, interface{}) error
+}
+
+// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
+// but it reads the body from supplied bytes instead of req.Body.
+type BindingBody interface {
+ Binding
+ BindBody([]byte, interface{}) error
+}
+
+// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
+// but it read the Params.
+type BindingUri interface {
+ Name() string
+ BindUri(map[string][]string, interface{}) error
+}
+
+// StructValidator is the minimal interface which needs to be implemented in
+// order for it to be used as the validator engine for ensuring the correctness
+// of the request. Gin provides a default implementation for this using
+// https://github.com/go-playground/validator/tree/v8.18.2.
+type StructValidator interface {
+ // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
+ // If the received type is not a struct, any validation should be skipped and nil must be returned.
+ // If the received type is a struct or pointer to a struct, the validation should be performed.
+ // If the struct is not valid or the validation itself fails, a descriptive error should be returned.
+ // Otherwise nil must be returned.
+ ValidateStruct(interface{}) error
+
+ // Engine returns the underlying validator engine which powers the
+ // StructValidator implementation.
+ Engine() interface{}
+}
+
+// Validator is the default validator which implements the StructValidator
+// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
+// under the hood.
+var Validator StructValidator = &defaultValidator{}
+
+// These implement the Binding interface and can be used to bind the data
+// present in the request to struct instances.
+var (
+ JSON = jsonBinding{}
+ XML = xmlBinding{}
+ Form = formBinding{}
+ Query = queryBinding{}
+ FormPost = formPostBinding{}
+ FormMultipart = formMultipartBinding{}
+ ProtoBuf = protobufBinding{}
+ YAML = yamlBinding{}
+ Uri = uriBinding{}
+ Header = headerBinding{}
+)
+
+// Default returns the appropriate Binding instance based on the HTTP method
+// and the content type.
+func Default(method, contentType string) Binding {
+ if method == "GET" {
+ return Form
+ }
+
+ switch contentType {
+ case MIMEJSON:
+ return JSON
+ case MIMEXML, MIMEXML2:
+ return XML
+ case MIMEPROTOBUF:
+ return ProtoBuf
+ case MIMEYAML:
+ return YAML
+ case MIMEMultipartPOSTForm:
+ return FormMultipart
+ default: // case MIMEPOSTForm:
+ return Form
+ }
+}
+
+func validate(obj interface{}) error {
+ if Validator == nil {
+ return nil
+ }
+ return Validator.ValidateStruct(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/default_validator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/default_validator.go
new file mode 100644
index 000000000000..c57a120fc2eb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/default_validator.go
@@ -0,0 +1,85 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+
+ "github.com/go-playground/validator/v10"
+)
+
+type defaultValidator struct {
+ once sync.Once
+ validate *validator.Validate
+}
+
+type sliceValidateError []error
+
+func (err sliceValidateError) Error() string {
+ var errMsgs []string
+ for i, e := range err {
+ if e == nil {
+ continue
+ }
+ errMsgs = append(errMsgs, fmt.Sprintf("[%d]: %s", i, e.Error()))
+ }
+ return strings.Join(errMsgs, "\n")
+}
+
+var _ StructValidator = &defaultValidator{}
+
+// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
+func (v *defaultValidator) ValidateStruct(obj interface{}) error {
+ if obj == nil {
+ return nil
+ }
+
+ value := reflect.ValueOf(obj)
+ switch value.Kind() {
+ case reflect.Ptr:
+ return v.ValidateStruct(value.Elem().Interface())
+ case reflect.Struct:
+ return v.validateStruct(obj)
+ case reflect.Slice, reflect.Array:
+ count := value.Len()
+ validateRet := make(sliceValidateError, 0)
+ for i := 0; i < count; i++ {
+ if err := v.ValidateStruct(value.Index(i).Interface()); err != nil {
+ validateRet = append(validateRet, err)
+ }
+ }
+ if len(validateRet) == 0 {
+ return nil
+ }
+ return validateRet
+ default:
+ return nil
+ }
+}
+
+// validateStruct receives struct type
+func (v *defaultValidator) validateStruct(obj interface{}) error {
+ v.lazyinit()
+ return v.validate.Struct(obj)
+}
+
+// Engine returns the underlying validator engine which powers the default
+// Validator instance. This is useful if you want to register custom validations
+// or struct level validations. See validator GoDoc for more info -
+// https://godoc.org/gopkg.in/go-playground/validator.v8
+func (v *defaultValidator) Engine() interface{} {
+ v.lazyinit()
+ return v.validate
+}
+
+func (v *defaultValidator) lazyinit() {
+ v.once.Do(func() {
+ v.validate = validator.New()
+ v.validate.SetTagName("binding")
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/form.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/form.go
new file mode 100644
index 000000000000..b93c34cf42d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/form.go
@@ -0,0 +1,63 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "net/http"
+)
+
+const defaultMemory = 32 << 20
+
+type formBinding struct{}
+type formPostBinding struct{}
+type formMultipartBinding struct{}
+
+func (formBinding) Name() string {
+ return "form"
+}
+
+func (formBinding) Bind(req *http.Request, obj interface{}) error {
+ if err := req.ParseForm(); err != nil {
+ return err
+ }
+ if err := req.ParseMultipartForm(defaultMemory); err != nil {
+ if err != http.ErrNotMultipart {
+ return err
+ }
+ }
+ if err := mapForm(obj, req.Form); err != nil {
+ return err
+ }
+ return validate(obj)
+}
+
+func (formPostBinding) Name() string {
+ return "form-urlencoded"
+}
+
+func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
+ if err := req.ParseForm(); err != nil {
+ return err
+ }
+ if err := mapForm(obj, req.PostForm); err != nil {
+ return err
+ }
+ return validate(obj)
+}
+
+func (formMultipartBinding) Name() string {
+ return "multipart/form-data"
+}
+
+func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
+ if err := req.ParseMultipartForm(defaultMemory); err != nil {
+ return err
+ }
+ if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil {
+ return err
+ }
+
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/form_mapping.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/form_mapping.go
new file mode 100644
index 000000000000..2f4e45b40fcb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/form_mapping.go
@@ -0,0 +1,392 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gin-gonic/gin/internal/bytesconv"
+ "github.com/gin-gonic/gin/internal/json"
+)
+
+var errUnknownType = errors.New("unknown type")
+
+func mapUri(ptr interface{}, m map[string][]string) error {
+ return mapFormByTag(ptr, m, "uri")
+}
+
+func mapForm(ptr interface{}, form map[string][]string) error {
+ return mapFormByTag(ptr, form, "form")
+}
+
+var emptyField = reflect.StructField{}
+
+func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
+ // Check if ptr is a map
+ ptrVal := reflect.ValueOf(ptr)
+ var pointed interface{}
+ if ptrVal.Kind() == reflect.Ptr {
+ ptrVal = ptrVal.Elem()
+ pointed = ptrVal.Interface()
+ }
+ if ptrVal.Kind() == reflect.Map &&
+ ptrVal.Type().Key().Kind() == reflect.String {
+ if pointed != nil {
+ ptr = pointed
+ }
+ return setFormMap(ptr, form)
+ }
+
+ return mappingByPtr(ptr, formSource(form), tag)
+}
+
+// setter tries to set value on a walking by fields of a struct
+type setter interface {
+ TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
+}
+
+type formSource map[string][]string
+
+var _ setter = formSource(nil)
+
+// TrySet tries to set a value by request's form source (like map[string][]string)
+func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
+ return setByForm(value, field, form, tagValue, opt)
+}
+
+func mappingByPtr(ptr interface{}, setter setter, tag string) error {
+ _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
+ return err
+}
+
+func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
+ if field.Tag.Get(tag) == "-" { // just ignoring this field
+ return false, nil
+ }
+
+ var vKind = value.Kind()
+
+ if vKind == reflect.Ptr {
+ var isNew bool
+ vPtr := value
+ if value.IsNil() {
+ isNew = true
+ vPtr = reflect.New(value.Type().Elem())
+ }
+ isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
+ if err != nil {
+ return false, err
+ }
+ if isNew && isSetted {
+ value.Set(vPtr)
+ }
+ return isSetted, nil
+ }
+
+ if vKind != reflect.Struct || !field.Anonymous {
+ ok, err := tryToSetValue(value, field, setter, tag)
+ if err != nil {
+ return false, err
+ }
+ if ok {
+ return true, nil
+ }
+ }
+
+ if vKind == reflect.Struct {
+ tValue := value.Type()
+
+ var isSetted bool
+ for i := 0; i < value.NumField(); i++ {
+ sf := tValue.Field(i)
+ if sf.PkgPath != "" && !sf.Anonymous { // unexported
+ continue
+ }
+ ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
+ if err != nil {
+ return false, err
+ }
+ isSetted = isSetted || ok
+ }
+ return isSetted, nil
+ }
+ return false, nil
+}
+
+type setOptions struct {
+ isDefaultExists bool
+ defaultValue string
+}
+
+func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
+ var tagValue string
+ var setOpt setOptions
+
+ tagValue = field.Tag.Get(tag)
+ tagValue, opts := head(tagValue, ",")
+
+ if tagValue == "" { // default value is FieldName
+ tagValue = field.Name
+ }
+ if tagValue == "" { // when field is "emptyField" variable
+ return false, nil
+ }
+
+ var opt string
+ for len(opts) > 0 {
+ opt, opts = head(opts, ",")
+
+ if k, v := head(opt, "="); k == "default" {
+ setOpt.isDefaultExists = true
+ setOpt.defaultValue = v
+ }
+ }
+
+ return setter.TrySet(value, field, tagValue, setOpt)
+}
+
+func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) {
+ vs, ok := form[tagValue]
+ if !ok && !opt.isDefaultExists {
+ return false, nil
+ }
+
+ switch value.Kind() {
+ case reflect.Slice:
+ if !ok {
+ vs = []string{opt.defaultValue}
+ }
+ return true, setSlice(vs, value, field)
+ case reflect.Array:
+ if !ok {
+ vs = []string{opt.defaultValue}
+ }
+ if len(vs) != value.Len() {
+ return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
+ }
+ return true, setArray(vs, value, field)
+ default:
+ var val string
+ if !ok {
+ val = opt.defaultValue
+ }
+
+ if len(vs) > 0 {
+ val = vs[0]
+ }
+ return true, setWithProperType(val, value, field)
+ }
+}
+
+func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
+ switch value.Kind() {
+ case reflect.Int:
+ return setIntField(val, 0, value)
+ case reflect.Int8:
+ return setIntField(val, 8, value)
+ case reflect.Int16:
+ return setIntField(val, 16, value)
+ case reflect.Int32:
+ return setIntField(val, 32, value)
+ case reflect.Int64:
+ switch value.Interface().(type) {
+ case time.Duration:
+ return setTimeDuration(val, value, field)
+ }
+ return setIntField(val, 64, value)
+ case reflect.Uint:
+ return setUintField(val, 0, value)
+ case reflect.Uint8:
+ return setUintField(val, 8, value)
+ case reflect.Uint16:
+ return setUintField(val, 16, value)
+ case reflect.Uint32:
+ return setUintField(val, 32, value)
+ case reflect.Uint64:
+ return setUintField(val, 64, value)
+ case reflect.Bool:
+ return setBoolField(val, value)
+ case reflect.Float32:
+ return setFloatField(val, 32, value)
+ case reflect.Float64:
+ return setFloatField(val, 64, value)
+ case reflect.String:
+ value.SetString(val)
+ case reflect.Struct:
+ switch value.Interface().(type) {
+ case time.Time:
+ return setTimeField(val, field, value)
+ }
+ return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
+ case reflect.Map:
+ return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
+ default:
+ return errUnknownType
+ }
+ return nil
+}
+
+func setIntField(val string, bitSize int, field reflect.Value) error {
+ if val == "" {
+ val = "0"
+ }
+ intVal, err := strconv.ParseInt(val, 10, bitSize)
+ if err == nil {
+ field.SetInt(intVal)
+ }
+ return err
+}
+
+func setUintField(val string, bitSize int, field reflect.Value) error {
+ if val == "" {
+ val = "0"
+ }
+ uintVal, err := strconv.ParseUint(val, 10, bitSize)
+ if err == nil {
+ field.SetUint(uintVal)
+ }
+ return err
+}
+
+func setBoolField(val string, field reflect.Value) error {
+ if val == "" {
+ val = "false"
+ }
+ boolVal, err := strconv.ParseBool(val)
+ if err == nil {
+ field.SetBool(boolVal)
+ }
+ return err
+}
+
+func setFloatField(val string, bitSize int, field reflect.Value) error {
+ if val == "" {
+ val = "0.0"
+ }
+ floatVal, err := strconv.ParseFloat(val, bitSize)
+ if err == nil {
+ field.SetFloat(floatVal)
+ }
+ return err
+}
+
+func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
+ timeFormat := structField.Tag.Get("time_format")
+ if timeFormat == "" {
+ timeFormat = time.RFC3339
+ }
+
+ switch tf := strings.ToLower(timeFormat); tf {
+ case "unix", "unixnano":
+ tv, err := strconv.ParseInt(val, 10, 64)
+ if err != nil {
+ return err
+ }
+
+ d := time.Duration(1)
+ if tf == "unixnano" {
+ d = time.Second
+ }
+
+ t := time.Unix(tv/int64(d), tv%int64(d))
+ value.Set(reflect.ValueOf(t))
+ return nil
+
+ }
+
+ if val == "" {
+ value.Set(reflect.ValueOf(time.Time{}))
+ return nil
+ }
+
+ l := time.Local
+ if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
+ l = time.UTC
+ }
+
+ if locTag := structField.Tag.Get("time_location"); locTag != "" {
+ loc, err := time.LoadLocation(locTag)
+ if err != nil {
+ return err
+ }
+ l = loc
+ }
+
+ t, err := time.ParseInLocation(timeFormat, val, l)
+ if err != nil {
+ return err
+ }
+
+ value.Set(reflect.ValueOf(t))
+ return nil
+}
+
+func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
+ for i, s := range vals {
+ err := setWithProperType(s, value.Index(i), field)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
+ slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
+ err := setArray(vals, slice, field)
+ if err != nil {
+ return err
+ }
+ value.Set(slice)
+ return nil
+}
+
+func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
+ d, err := time.ParseDuration(val)
+ if err != nil {
+ return err
+ }
+ value.Set(reflect.ValueOf(d))
+ return nil
+}
+
+func head(str, sep string) (head string, tail string) {
+ idx := strings.Index(str, sep)
+ if idx < 0 {
+ return str, ""
+ }
+ return str[:idx], str[idx+len(sep):]
+}
+
+func setFormMap(ptr interface{}, form map[string][]string) error {
+ el := reflect.TypeOf(ptr).Elem()
+
+ if el.Kind() == reflect.Slice {
+ ptrMap, ok := ptr.(map[string][]string)
+ if !ok {
+ return errors.New("cannot convert to map slices of strings")
+ }
+ for k, v := range form {
+ ptrMap[k] = v
+ }
+
+ return nil
+ }
+
+ ptrMap, ok := ptr.(map[string]string)
+ if !ok {
+ return errors.New("cannot convert to map of strings")
+ }
+ for k, v := range form {
+ ptrMap[k] = v[len(v)-1] // pick last
+ }
+
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/header.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/header.go
new file mode 100644
index 000000000000..179ce4ea2037
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/header.go
@@ -0,0 +1,34 @@
+package binding
+
+import (
+ "net/http"
+ "net/textproto"
+ "reflect"
+)
+
+type headerBinding struct{}
+
+func (headerBinding) Name() string {
+ return "header"
+}
+
+func (headerBinding) Bind(req *http.Request, obj interface{}) error {
+
+ if err := mapHeader(obj, req.Header); err != nil {
+ return err
+ }
+
+ return validate(obj)
+}
+
+func mapHeader(ptr interface{}, h map[string][]string) error {
+ return mappingByPtr(ptr, headerSource(h), "header")
+}
+
+type headerSource map[string][]string
+
+var _ setter = headerSource(nil)
+
+func (hs headerSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
+ return setByForm(value, field, hs, textproto.CanonicalMIMEHeaderKey(tagValue), opt)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/json.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/json.go
new file mode 100644
index 000000000000..d62e07059482
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/json.go
@@ -0,0 +1,56 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net/http"
+
+ "github.com/gin-gonic/gin/internal/json"
+)
+
+// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
+// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an
+// interface{} as a Number instead of as a float64.
+var EnableDecoderUseNumber = false
+
+// EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method
+// on the JSON Decoder instance. DisallowUnknownFields causes the Decoder to
+// return an error when the destination is a struct and the input contains object
+// keys which do not match any non-ignored, exported fields in the destination.
+var EnableDecoderDisallowUnknownFields = false
+
+type jsonBinding struct{}
+
+func (jsonBinding) Name() string {
+ return "json"
+}
+
+func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
+ if req == nil || req.Body == nil {
+ return fmt.Errorf("invalid request")
+ }
+ return decodeJSON(req.Body, obj)
+}
+
+func (jsonBinding) BindBody(body []byte, obj interface{}) error {
+ return decodeJSON(bytes.NewReader(body), obj)
+}
+
+func decodeJSON(r io.Reader, obj interface{}) error {
+ decoder := json.NewDecoder(r)
+ if EnableDecoderUseNumber {
+ decoder.UseNumber()
+ }
+ if EnableDecoderDisallowUnknownFields {
+ decoder.DisallowUnknownFields()
+ }
+ if err := decoder.Decode(obj); err != nil {
+ return err
+ }
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/msgpack.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/msgpack.go
new file mode 100644
index 000000000000..2a442996a63e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/msgpack.go
@@ -0,0 +1,38 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build !nomsgpack
+// +build !nomsgpack
+
+package binding
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+
+ "github.com/ugorji/go/codec"
+)
+
+type msgpackBinding struct{}
+
+func (msgpackBinding) Name() string {
+ return "msgpack"
+}
+
+func (msgpackBinding) Bind(req *http.Request, obj interface{}) error {
+ return decodeMsgPack(req.Body, obj)
+}
+
+func (msgpackBinding) BindBody(body []byte, obj interface{}) error {
+ return decodeMsgPack(bytes.NewReader(body), obj)
+}
+
+func decodeMsgPack(r io.Reader, obj interface{}) error {
+ cdc := new(codec.MsgpackHandle)
+ if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil {
+ return err
+ }
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go
new file mode 100644
index 000000000000..f85a1aa60455
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go
@@ -0,0 +1,66 @@
+// Copyright 2019 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "errors"
+ "mime/multipart"
+ "net/http"
+ "reflect"
+)
+
+type multipartRequest http.Request
+
+var _ setter = (*multipartRequest)(nil)
+
+// TrySet tries to set a value by the multipart request with the binding a form file
+func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) {
+ if files := r.MultipartForm.File[key]; len(files) != 0 {
+ return setByMultipartFormFile(value, field, files)
+ }
+
+ return setByForm(value, field, r.MultipartForm.Value, key, opt)
+}
+
+func setByMultipartFormFile(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) {
+ switch value.Kind() {
+ case reflect.Ptr:
+ switch value.Interface().(type) {
+ case *multipart.FileHeader:
+ value.Set(reflect.ValueOf(files[0]))
+ return true, nil
+ }
+ case reflect.Struct:
+ switch value.Interface().(type) {
+ case multipart.FileHeader:
+ value.Set(reflect.ValueOf(*files[0]))
+ return true, nil
+ }
+ case reflect.Slice:
+ slice := reflect.MakeSlice(value.Type(), len(files), len(files))
+ isSetted, err = setArrayOfMultipartFormFiles(slice, field, files)
+ if err != nil || !isSetted {
+ return isSetted, err
+ }
+ value.Set(slice)
+ return true, nil
+ case reflect.Array:
+ return setArrayOfMultipartFormFiles(value, field, files)
+ }
+ return false, errors.New("unsupported field type for multipart.FileHeader")
+}
+
+func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) {
+ if value.Len() != len(files) {
+ return false, errors.New("unsupported len of array for []*multipart.FileHeader")
+ }
+ for i := range files {
+ setted, err := setByMultipartFormFile(value.Index(i), field, files[i:i+1])
+ if err != nil || !setted {
+ return setted, err
+ }
+ }
+ return true, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/protobuf.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/protobuf.go
new file mode 100644
index 000000000000..f9ece928d489
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/protobuf.go
@@ -0,0 +1,36 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "io/ioutil"
+ "net/http"
+
+ "github.com/golang/protobuf/proto"
+)
+
+type protobufBinding struct{}
+
+func (protobufBinding) Name() string {
+ return "protobuf"
+}
+
+func (b protobufBinding) Bind(req *http.Request, obj interface{}) error {
+ buf, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ return err
+ }
+ return b.BindBody(buf, obj)
+}
+
+func (protobufBinding) BindBody(body []byte, obj interface{}) error {
+ if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil {
+ return err
+ }
+ // Here it's same to return validate(obj), but util now we can't add
+ // `binding:""` to the struct which automatically generate by gen-proto
+ return nil
+ // return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/query.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/query.go
new file mode 100644
index 000000000000..219743f2a950
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/query.go
@@ -0,0 +1,21 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import "net/http"
+
+type queryBinding struct{}
+
+func (queryBinding) Name() string {
+ return "query"
+}
+
+func (queryBinding) Bind(req *http.Request, obj interface{}) error {
+ values := req.URL.Query()
+ if err := mapForm(obj, values); err != nil {
+ return err
+ }
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/uri.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/uri.go
new file mode 100644
index 000000000000..f91ec3819942
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/uri.go
@@ -0,0 +1,18 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+type uriBinding struct{}
+
+func (uriBinding) Name() string {
+ return "uri"
+}
+
+func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
+ if err := mapUri(obj, m); err != nil {
+ return err
+ }
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/xml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/xml.go
new file mode 100644
index 000000000000..4e9011496260
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/xml.go
@@ -0,0 +1,33 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "bytes"
+ "encoding/xml"
+ "io"
+ "net/http"
+)
+
+type xmlBinding struct{}
+
+func (xmlBinding) Name() string {
+ return "xml"
+}
+
+func (xmlBinding) Bind(req *http.Request, obj interface{}) error {
+ return decodeXML(req.Body, obj)
+}
+
+func (xmlBinding) BindBody(body []byte, obj interface{}) error {
+ return decodeXML(bytes.NewReader(body), obj)
+}
+func decodeXML(r io.Reader, obj interface{}) error {
+ decoder := xml.NewDecoder(r)
+ if err := decoder.Decode(obj); err != nil {
+ return err
+ }
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/yaml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/yaml.go
new file mode 100644
index 000000000000..a2d36d6a549f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/binding/yaml.go
@@ -0,0 +1,35 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package binding
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+
+ "gopkg.in/yaml.v2"
+)
+
+type yamlBinding struct{}
+
+func (yamlBinding) Name() string {
+ return "yaml"
+}
+
+func (yamlBinding) Bind(req *http.Request, obj interface{}) error {
+ return decodeYAML(req.Body, obj)
+}
+
+func (yamlBinding) BindBody(body []byte, obj interface{}) error {
+ return decodeYAML(bytes.NewReader(body), obj)
+}
+
+func decodeYAML(r io.Reader, obj interface{}) error {
+ decoder := yaml.NewDecoder(r)
+ if err := decoder.Decode(obj); err != nil {
+ return err
+ }
+ return validate(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/codecov.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/codecov.yml
new file mode 100644
index 000000000000..c9c9a522da9f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/codecov.yml
@@ -0,0 +1,5 @@
+coverage:
+ notify:
+ gitter:
+ default:
+ url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/context.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/context.go
new file mode 100644
index 000000000000..220d1bc7b454
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/context.go
@@ -0,0 +1,1192 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "math"
+ "mime/multipart"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/gin-contrib/sse"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/gin-gonic/gin/render"
+)
+
+// Content-Type MIME of the most common data formats.
+const (
+ MIMEJSON = binding.MIMEJSON
+ MIMEHTML = binding.MIMEHTML
+ MIMEXML = binding.MIMEXML
+ MIMEXML2 = binding.MIMEXML2
+ MIMEPlain = binding.MIMEPlain
+ MIMEPOSTForm = binding.MIMEPOSTForm
+ MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
+ MIMEYAML = binding.MIMEYAML
+)
+
+// BodyBytesKey indicates a default body bytes key.
+const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
+
+const abortIndex int8 = math.MaxInt8 / 2
+
+// Context is the most important part of gin. It allows us to pass variables between middleware,
+// manage the flow, validate the JSON of a request and render a JSON response for example.
+type Context struct {
+ writermem responseWriter
+ Request *http.Request
+ Writer ResponseWriter
+
+ Params Params
+ handlers HandlersChain
+ index int8
+ fullPath string
+
+ engine *Engine
+ params *Params
+ skippedNodes *[]skippedNode
+
+ // This mutex protect Keys map
+ mu sync.RWMutex
+
+ // Keys is a key/value pair exclusively for the context of each request.
+ Keys map[string]interface{}
+
+ // Errors is a list of errors attached to all the handlers/middlewares who used this context.
+ Errors errorMsgs
+
+ // Accepted defines a list of manually accepted formats for content negotiation.
+ Accepted []string
+
+ // queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
+ queryCache url.Values
+
+ // formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
+ // or PUT body parameters.
+ formCache url.Values
+
+ // SameSite allows a server to define a cookie attribute making it impossible for
+ // the browser to send this cookie along with cross-site requests.
+ sameSite http.SameSite
+}
+
+/************************************/
+/********** CONTEXT CREATION ********/
+/************************************/
+
+func (c *Context) reset() {
+ c.Writer = &c.writermem
+ c.Params = c.Params[0:0]
+ c.handlers = nil
+ c.index = -1
+
+ c.fullPath = ""
+ c.Keys = nil
+ c.Errors = c.Errors[0:0]
+ c.Accepted = nil
+ c.queryCache = nil
+ c.formCache = nil
+ *c.params = (*c.params)[:0]
+ *c.skippedNodes = (*c.skippedNodes)[:0]
+}
+
+// Copy returns a copy of the current context that can be safely used outside the request's scope.
+// This has to be used when the context has to be passed to a goroutine.
+func (c *Context) Copy() *Context {
+ cp := Context{
+ writermem: c.writermem,
+ Request: c.Request,
+ Params: c.Params,
+ engine: c.engine,
+ }
+ cp.writermem.ResponseWriter = nil
+ cp.Writer = &cp.writermem
+ cp.index = abortIndex
+ cp.handlers = nil
+ cp.Keys = map[string]interface{}{}
+ for k, v := range c.Keys {
+ cp.Keys[k] = v
+ }
+ paramCopy := make([]Param, len(cp.Params))
+ copy(paramCopy, cp.Params)
+ cp.Params = paramCopy
+ return &cp
+}
+
+// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()",
+// this function will return "main.handleGetUsers".
+func (c *Context) HandlerName() string {
+ return nameOfFunction(c.handlers.Last())
+}
+
+// HandlerNames returns a list of all registered handlers for this context in descending order,
+// following the semantics of HandlerName()
+func (c *Context) HandlerNames() []string {
+ hn := make([]string, 0, len(c.handlers))
+ for _, val := range c.handlers {
+ hn = append(hn, nameOfFunction(val))
+ }
+ return hn
+}
+
+// Handler returns the main handler.
+func (c *Context) Handler() HandlerFunc {
+ return c.handlers.Last()
+}
+
+// FullPath returns a matched route full path. For not found routes
+// returns an empty string.
+// router.GET("/user/:id", func(c *gin.Context) {
+// c.FullPath() == "/user/:id" // true
+// })
+func (c *Context) FullPath() string {
+ return c.fullPath
+}
+
+/************************************/
+/*********** FLOW CONTROL ***********/
+/************************************/
+
+// Next should be used only inside middleware.
+// It executes the pending handlers in the chain inside the calling handler.
+// See example in GitHub.
+func (c *Context) Next() {
+ c.index++
+ for c.index < int8(len(c.handlers)) {
+ c.handlers[c.index](c)
+ c.index++
+ }
+}
+
+// IsAborted returns true if the current context was aborted.
+func (c *Context) IsAborted() bool {
+ return c.index >= abortIndex
+}
+
+// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
+// Let's say you have an authorization middleware that validates that the current request is authorized.
+// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
+// for this request are not called.
+func (c *Context) Abort() {
+ c.index = abortIndex
+}
+
+// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
+// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
+func (c *Context) AbortWithStatus(code int) {
+ c.Status(code)
+ c.Writer.WriteHeaderNow()
+ c.Abort()
+}
+
+// AbortWithStatusJSON calls `Abort()` and then `JSON` internally.
+// This method stops the chain, writes the status code and return a JSON body.
+// It also sets the Content-Type as "application/json".
+func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) {
+ c.Abort()
+ c.JSON(code, jsonObj)
+}
+
+// AbortWithError calls `AbortWithStatus()` and `Error()` internally.
+// This method stops the chain, writes the status code and pushes the specified error to `c.Errors`.
+// See Context.Error() for more details.
+func (c *Context) AbortWithError(code int, err error) *Error {
+ c.AbortWithStatus(code)
+ return c.Error(err)
+}
+
+/************************************/
+/********* ERROR MANAGEMENT *********/
+/************************************/
+
+// Error attaches an error to the current context. The error is pushed to a list of errors.
+// It's a good idea to call Error for each error that occurred during the resolution of a request.
+// A middleware can be used to collect all the errors and push them to a database together,
+// print a log, or append it in the HTTP response.
+// Error will panic if err is nil.
+func (c *Context) Error(err error) *Error {
+ if err == nil {
+ panic("err is nil")
+ }
+
+ parsedError, ok := err.(*Error)
+ if !ok {
+ parsedError = &Error{
+ Err: err,
+ Type: ErrorTypePrivate,
+ }
+ }
+
+ c.Errors = append(c.Errors, parsedError)
+ return parsedError
+}
+
+/************************************/
+/******** METADATA MANAGEMENT********/
+/************************************/
+
+// Set is used to store a new key/value pair exclusively for this context.
+// It also lazy initializes c.Keys if it was not used previously.
+func (c *Context) Set(key string, value interface{}) {
+ c.mu.Lock()
+ if c.Keys == nil {
+ c.Keys = make(map[string]interface{})
+ }
+
+ c.Keys[key] = value
+ c.mu.Unlock()
+}
+
+// Get returns the value for the given key, ie: (value, true).
+// If the value does not exists it returns (nil, false)
+func (c *Context) Get(key string) (value interface{}, exists bool) {
+ c.mu.RLock()
+ value, exists = c.Keys[key]
+ c.mu.RUnlock()
+ return
+}
+
+// MustGet returns the value for the given key if it exists, otherwise it panics.
+func (c *Context) MustGet(key string) interface{} {
+ if value, exists := c.Get(key); exists {
+ return value
+ }
+ panic("Key \"" + key + "\" does not exist")
+}
+
+// GetString returns the value associated with the key as a string.
+func (c *Context) GetString(key string) (s string) {
+ if val, ok := c.Get(key); ok && val != nil {
+ s, _ = val.(string)
+ }
+ return
+}
+
+// GetBool returns the value associated with the key as a boolean.
+func (c *Context) GetBool(key string) (b bool) {
+ if val, ok := c.Get(key); ok && val != nil {
+ b, _ = val.(bool)
+ }
+ return
+}
+
+// GetInt returns the value associated with the key as an integer.
+func (c *Context) GetInt(key string) (i int) {
+ if val, ok := c.Get(key); ok && val != nil {
+ i, _ = val.(int)
+ }
+ return
+}
+
+// GetInt64 returns the value associated with the key as an integer.
+func (c *Context) GetInt64(key string) (i64 int64) {
+ if val, ok := c.Get(key); ok && val != nil {
+ i64, _ = val.(int64)
+ }
+ return
+}
+
+// GetUint returns the value associated with the key as an unsigned integer.
+func (c *Context) GetUint(key string) (ui uint) {
+ if val, ok := c.Get(key); ok && val != nil {
+ ui, _ = val.(uint)
+ }
+ return
+}
+
+// GetUint64 returns the value associated with the key as an unsigned integer.
+func (c *Context) GetUint64(key string) (ui64 uint64) {
+ if val, ok := c.Get(key); ok && val != nil {
+ ui64, _ = val.(uint64)
+ }
+ return
+}
+
+// GetFloat64 returns the value associated with the key as a float64.
+func (c *Context) GetFloat64(key string) (f64 float64) {
+ if val, ok := c.Get(key); ok && val != nil {
+ f64, _ = val.(float64)
+ }
+ return
+}
+
+// GetTime returns the value associated with the key as time.
+func (c *Context) GetTime(key string) (t time.Time) {
+ if val, ok := c.Get(key); ok && val != nil {
+ t, _ = val.(time.Time)
+ }
+ return
+}
+
+// GetDuration returns the value associated with the key as a duration.
+func (c *Context) GetDuration(key string) (d time.Duration) {
+ if val, ok := c.Get(key); ok && val != nil {
+ d, _ = val.(time.Duration)
+ }
+ return
+}
+
+// GetStringSlice returns the value associated with the key as a slice of strings.
+func (c *Context) GetStringSlice(key string) (ss []string) {
+ if val, ok := c.Get(key); ok && val != nil {
+ ss, _ = val.([]string)
+ }
+ return
+}
+
+// GetStringMap returns the value associated with the key as a map of interfaces.
+func (c *Context) GetStringMap(key string) (sm map[string]interface{}) {
+ if val, ok := c.Get(key); ok && val != nil {
+ sm, _ = val.(map[string]interface{})
+ }
+ return
+}
+
+// GetStringMapString returns the value associated with the key as a map of strings.
+func (c *Context) GetStringMapString(key string) (sms map[string]string) {
+ if val, ok := c.Get(key); ok && val != nil {
+ sms, _ = val.(map[string]string)
+ }
+ return
+}
+
+// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
+func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) {
+ if val, ok := c.Get(key); ok && val != nil {
+ smss, _ = val.(map[string][]string)
+ }
+ return
+}
+
+/************************************/
+/************ INPUT DATA ************/
+/************************************/
+
+// Param returns the value of the URL param.
+// It is a shortcut for c.Params.ByName(key)
+// router.GET("/user/:id", func(c *gin.Context) {
+// // a GET request to /user/john
+// id := c.Param("id") // id == "john"
+// })
+func (c *Context) Param(key string) string {
+ return c.Params.ByName(key)
+}
+
+// Query returns the keyed url query value if it exists,
+// otherwise it returns an empty string `("")`.
+// It is shortcut for `c.Request.URL.Query().Get(key)`
+// GET /path?id=1234&name=Manu&value=
+// c.Query("id") == "1234"
+// c.Query("name") == "Manu"
+// c.Query("value") == ""
+// c.Query("wtf") == ""
+func (c *Context) Query(key string) string {
+ value, _ := c.GetQuery(key)
+ return value
+}
+
+// DefaultQuery returns the keyed url query value if it exists,
+// otherwise it returns the specified defaultValue string.
+// See: Query() and GetQuery() for further information.
+// GET /?name=Manu&lastname=
+// c.DefaultQuery("name", "unknown") == "Manu"
+// c.DefaultQuery("id", "none") == "none"
+// c.DefaultQuery("lastname", "none") == ""
+func (c *Context) DefaultQuery(key, defaultValue string) string {
+ if value, ok := c.GetQuery(key); ok {
+ return value
+ }
+ return defaultValue
+}
+
+// GetQuery is like Query(), it returns the keyed url query value
+// if it exists `(value, true)` (even when the value is an empty string),
+// otherwise it returns `("", false)`.
+// It is shortcut for `c.Request.URL.Query().Get(key)`
+// GET /?name=Manu&lastname=
+// ("Manu", true) == c.GetQuery("name")
+// ("", false) == c.GetQuery("id")
+// ("", true) == c.GetQuery("lastname")
+func (c *Context) GetQuery(key string) (string, bool) {
+ if values, ok := c.GetQueryArray(key); ok {
+ return values[0], ok
+ }
+ return "", false
+}
+
+// QueryArray returns a slice of strings for a given query key.
+// The length of the slice depends on the number of params with the given key.
+func (c *Context) QueryArray(key string) []string {
+ values, _ := c.GetQueryArray(key)
+ return values
+}
+
+func (c *Context) initQueryCache() {
+ if c.queryCache == nil {
+ if c.Request != nil {
+ c.queryCache = c.Request.URL.Query()
+ } else {
+ c.queryCache = url.Values{}
+ }
+ }
+}
+
+// GetQueryArray returns a slice of strings for a given query key, plus
+// a boolean value whether at least one value exists for the given key.
+func (c *Context) GetQueryArray(key string) ([]string, bool) {
+ c.initQueryCache()
+ if values, ok := c.queryCache[key]; ok && len(values) > 0 {
+ return values, true
+ }
+ return []string{}, false
+}
+
+// QueryMap returns a map for a given query key.
+func (c *Context) QueryMap(key string) map[string]string {
+ dicts, _ := c.GetQueryMap(key)
+ return dicts
+}
+
+// GetQueryMap returns a map for a given query key, plus a boolean value
+// whether at least one value exists for the given key.
+func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
+ c.initQueryCache()
+ return c.get(c.queryCache, key)
+}
+
+// PostForm returns the specified key from a POST urlencoded form or multipart form
+// when it exists, otherwise it returns an empty string `("")`.
+func (c *Context) PostForm(key string) string {
+ value, _ := c.GetPostForm(key)
+ return value
+}
+
+// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
+// when it exists, otherwise it returns the specified defaultValue string.
+// See: PostForm() and GetPostForm() for further information.
+func (c *Context) DefaultPostForm(key, defaultValue string) string {
+ if value, ok := c.GetPostForm(key); ok {
+ return value
+ }
+ return defaultValue
+}
+
+// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded
+// form or multipart form when it exists `(value, true)` (even when the value is an empty string),
+// otherwise it returns ("", false).
+// For example, during a PATCH request to update the user's email:
+// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com"
+// email= --> ("", true) := GetPostForm("email") // set email to ""
+// --> ("", false) := GetPostForm("email") // do nothing with email
+func (c *Context) GetPostForm(key string) (string, bool) {
+ if values, ok := c.GetPostFormArray(key); ok {
+ return values[0], ok
+ }
+ return "", false
+}
+
+// PostFormArray returns a slice of strings for a given form key.
+// The length of the slice depends on the number of params with the given key.
+func (c *Context) PostFormArray(key string) []string {
+ values, _ := c.GetPostFormArray(key)
+ return values
+}
+
+func (c *Context) initFormCache() {
+ if c.formCache == nil {
+ c.formCache = make(url.Values)
+ req := c.Request
+ if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
+ if err != http.ErrNotMultipart {
+ debugPrint("error on parse multipart form array: %v", err)
+ }
+ }
+ c.formCache = req.PostForm
+ }
+}
+
+// GetPostFormArray returns a slice of strings for a given form key, plus
+// a boolean value whether at least one value exists for the given key.
+func (c *Context) GetPostFormArray(key string) ([]string, bool) {
+ c.initFormCache()
+ if values := c.formCache[key]; len(values) > 0 {
+ return values, true
+ }
+ return []string{}, false
+}
+
+// PostFormMap returns a map for a given form key.
+func (c *Context) PostFormMap(key string) map[string]string {
+ dicts, _ := c.GetPostFormMap(key)
+ return dicts
+}
+
+// GetPostFormMap returns a map for a given form key, plus a boolean value
+// whether at least one value exists for the given key.
+func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
+ c.initFormCache()
+ return c.get(c.formCache, key)
+}
+
+// get is an internal method and returns a map which satisfy conditions.
+func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) {
+ dicts := make(map[string]string)
+ exist := false
+ for k, v := range m {
+ if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key {
+ if j := strings.IndexByte(k[i+1:], ']'); j >= 1 {
+ exist = true
+ dicts[k[i+1:][:j]] = v[0]
+ }
+ }
+ }
+ return dicts, exist
+}
+
+// FormFile returns the first file for the provided form key.
+func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
+ if c.Request.MultipartForm == nil {
+ if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
+ return nil, err
+ }
+ }
+ f, fh, err := c.Request.FormFile(name)
+ if err != nil {
+ return nil, err
+ }
+ f.Close()
+ return fh, err
+}
+
+// MultipartForm is the parsed multipart form, including file uploads.
+func (c *Context) MultipartForm() (*multipart.Form, error) {
+ err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory)
+ return c.Request.MultipartForm, err
+}
+
+// SaveUploadedFile uploads the form file to specific dst.
+func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error {
+ src, err := file.Open()
+ if err != nil {
+ return err
+ }
+ defer src.Close()
+
+ out, err := os.Create(dst)
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+
+ _, err = io.Copy(out, src)
+ return err
+}
+
+// Bind checks the Content-Type to select a binding engine automatically,
+// Depending the "Content-Type" header different bindings are used:
+// "application/json" --> JSON binding
+// "application/xml" --> XML binding
+// otherwise --> returns an error.
+// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
+// It decodes the json payload into the struct specified as a pointer.
+// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
+func (c *Context) Bind(obj interface{}) error {
+ b := binding.Default(c.Request.Method, c.ContentType())
+ return c.MustBindWith(obj, b)
+}
+
+// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
+func (c *Context) BindJSON(obj interface{}) error {
+ return c.MustBindWith(obj, binding.JSON)
+}
+
+// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
+func (c *Context) BindXML(obj interface{}) error {
+ return c.MustBindWith(obj, binding.XML)
+}
+
+// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
+func (c *Context) BindQuery(obj interface{}) error {
+ return c.MustBindWith(obj, binding.Query)
+}
+
+// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
+func (c *Context) BindYAML(obj interface{}) error {
+ return c.MustBindWith(obj, binding.YAML)
+}
+
+// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
+func (c *Context) BindHeader(obj interface{}) error {
+ return c.MustBindWith(obj, binding.Header)
+}
+
+// BindUri binds the passed struct pointer using binding.Uri.
+// It will abort the request with HTTP 400 if any error occurs.
+func (c *Context) BindUri(obj interface{}) error {
+ if err := c.ShouldBindUri(obj); err != nil {
+ c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
+ return err
+ }
+ return nil
+}
+
+// MustBindWith binds the passed struct pointer using the specified binding engine.
+// It will abort the request with HTTP 400 if any error occurs.
+// See the binding package.
+func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
+ if err := c.ShouldBindWith(obj, b); err != nil {
+ c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
+ return err
+ }
+ return nil
+}
+
+// ShouldBind checks the Content-Type to select a binding engine automatically,
+// Depending the "Content-Type" header different bindings are used:
+// "application/json" --> JSON binding
+// "application/xml" --> XML binding
+// otherwise --> returns an error
+// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
+// It decodes the json payload into the struct specified as a pointer.
+// Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid.
+func (c *Context) ShouldBind(obj interface{}) error {
+ b := binding.Default(c.Request.Method, c.ContentType())
+ return c.ShouldBindWith(obj, b)
+}
+
+// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
+func (c *Context) ShouldBindJSON(obj interface{}) error {
+ return c.ShouldBindWith(obj, binding.JSON)
+}
+
+// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
+func (c *Context) ShouldBindXML(obj interface{}) error {
+ return c.ShouldBindWith(obj, binding.XML)
+}
+
+// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
+func (c *Context) ShouldBindQuery(obj interface{}) error {
+ return c.ShouldBindWith(obj, binding.Query)
+}
+
+// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
+func (c *Context) ShouldBindYAML(obj interface{}) error {
+ return c.ShouldBindWith(obj, binding.YAML)
+}
+
+// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
+func (c *Context) ShouldBindHeader(obj interface{}) error {
+ return c.ShouldBindWith(obj, binding.Header)
+}
+
+// ShouldBindUri binds the passed struct pointer using the specified binding engine.
+func (c *Context) ShouldBindUri(obj interface{}) error {
+ m := make(map[string][]string)
+ for _, v := range c.Params {
+ m[v.Key] = []string{v.Value}
+ }
+ return binding.Uri.BindUri(m, obj)
+}
+
+// ShouldBindWith binds the passed struct pointer using the specified binding engine.
+// See the binding package.
+func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
+ return b.Bind(c.Request, obj)
+}
+
+// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
+// body into the context, and reuse when it is called again.
+//
+// NOTE: This method reads the body before binding. So you should use
+// ShouldBindWith for better performance if you need to call only once.
+func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error) {
+ var body []byte
+ if cb, ok := c.Get(BodyBytesKey); ok {
+ if cbb, ok := cb.([]byte); ok {
+ body = cbb
+ }
+ }
+ if body == nil {
+ body, err = ioutil.ReadAll(c.Request.Body)
+ if err != nil {
+ return err
+ }
+ c.Set(BodyBytesKey, body)
+ }
+ return bb.BindBody(body, obj)
+}
+
+// ClientIP implements one best effort algorithm to return the real client IP.
+// It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
+// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
+// If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy,
+// the remote IP (coming form Request.RemoteAddr) is returned.
+func (c *Context) ClientIP() string {
+ // Check if we're running on a trusted platform, continue running backwards if error
+ if c.engine.TrustedPlatform != "" {
+ // Developers can define their own header of Trusted Platform or use predefined constants
+ if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" {
+ return addr
+ }
+ }
+
+ // Legacy "AppEngine" flag
+ if c.engine.AppEngine {
+ log.Println(`The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`)
+ if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
+ return addr
+ }
+ }
+
+ remoteIP, trusted := c.RemoteIP()
+ if remoteIP == nil {
+ return ""
+ }
+
+ if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil {
+ for _, headerName := range c.engine.RemoteIPHeaders {
+ ip, valid := c.engine.validateHeader(c.requestHeader(headerName))
+ if valid {
+ return ip
+ }
+ }
+ }
+ return remoteIP.String()
+}
+
+func (e *Engine) isTrustedProxy(ip net.IP) bool {
+ if e.trustedCIDRs != nil {
+ for _, cidr := range e.trustedCIDRs {
+ if cidr.Contains(ip) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port).
+// It also checks if the remoteIP is a trusted proxy or not.
+// In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks
+// defined by Engine.SetTrustedProxies()
+func (c *Context) RemoteIP() (net.IP, bool) {
+ ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr))
+ if err != nil {
+ return nil, false
+ }
+ remoteIP := net.ParseIP(ip)
+ if remoteIP == nil {
+ return nil, false
+ }
+
+ return remoteIP, c.engine.isTrustedProxy(remoteIP)
+}
+
+func (e *Engine) validateHeader(header string) (clientIP string, valid bool) {
+ if header == "" {
+ return "", false
+ }
+ items := strings.Split(header, ",")
+ for i := len(items) - 1; i >= 0; i-- {
+ ipStr := strings.TrimSpace(items[i])
+ ip := net.ParseIP(ipStr)
+ if ip == nil {
+ return "", false
+ }
+
+ // X-Forwarded-For is appended by proxy
+ // Check IPs in reverse order and stop when find untrusted proxy
+ if (i == 0) || (!e.isTrustedProxy(ip)) {
+ return ipStr, true
+ }
+ }
+ return
+}
+
+// ContentType returns the Content-Type header of the request.
+func (c *Context) ContentType() string {
+ return filterFlags(c.requestHeader("Content-Type"))
+}
+
+// IsWebsocket returns true if the request headers indicate that a websocket
+// handshake is being initiated by the client.
+func (c *Context) IsWebsocket() bool {
+ if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") &&
+ strings.EqualFold(c.requestHeader("Upgrade"), "websocket") {
+ return true
+ }
+ return false
+}
+
+func (c *Context) requestHeader(key string) string {
+ return c.Request.Header.Get(key)
+}
+
+/************************************/
+/******** RESPONSE RENDERING ********/
+/************************************/
+
+// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function.
+func bodyAllowedForStatus(status int) bool {
+ switch {
+ case status >= 100 && status <= 199:
+ return false
+ case status == http.StatusNoContent:
+ return false
+ case status == http.StatusNotModified:
+ return false
+ }
+ return true
+}
+
+// Status sets the HTTP response code.
+func (c *Context) Status(code int) {
+ c.Writer.WriteHeader(code)
+}
+
+// Header is a intelligent shortcut for c.Writer.Header().Set(key, value).
+// It writes a header in the response.
+// If value == "", this method removes the header `c.Writer.Header().Del(key)`
+func (c *Context) Header(key, value string) {
+ if value == "" {
+ c.Writer.Header().Del(key)
+ return
+ }
+ c.Writer.Header().Set(key, value)
+}
+
+// GetHeader returns value from request headers.
+func (c *Context) GetHeader(key string) string {
+ return c.requestHeader(key)
+}
+
+// GetRawData return stream data.
+func (c *Context) GetRawData() ([]byte, error) {
+ return ioutil.ReadAll(c.Request.Body)
+}
+
+// SetSameSite with cookie
+func (c *Context) SetSameSite(samesite http.SameSite) {
+ c.sameSite = samesite
+}
+
+// SetCookie adds a Set-Cookie header to the ResponseWriter's headers.
+// The provided cookie must have a valid Name. Invalid cookies may be
+// silently dropped.
+func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
+ if path == "" {
+ path = "/"
+ }
+ http.SetCookie(c.Writer, &http.Cookie{
+ Name: name,
+ Value: url.QueryEscape(value),
+ MaxAge: maxAge,
+ Path: path,
+ Domain: domain,
+ SameSite: c.sameSite,
+ Secure: secure,
+ HttpOnly: httpOnly,
+ })
+}
+
+// Cookie returns the named cookie provided in the request or
+// ErrNoCookie if not found. And return the named cookie is unescaped.
+// If multiple cookies match the given name, only one cookie will
+// be returned.
+func (c *Context) Cookie(name string) (string, error) {
+ cookie, err := c.Request.Cookie(name)
+ if err != nil {
+ return "", err
+ }
+ val, _ := url.QueryUnescape(cookie.Value)
+ return val, nil
+}
+
+// Render writes the response headers and calls render.Render to render data.
+func (c *Context) Render(code int, r render.Render) {
+ c.Status(code)
+
+ if !bodyAllowedForStatus(code) {
+ r.WriteContentType(c.Writer)
+ c.Writer.WriteHeaderNow()
+ return
+ }
+
+ if err := r.Render(c.Writer); err != nil {
+ panic(err)
+ }
+}
+
+// HTML renders the HTTP template specified by its file name.
+// It also updates the HTTP code and sets the Content-Type as "text/html".
+// See http://golang.org/doc/articles/wiki/
+func (c *Context) HTML(code int, name string, obj interface{}) {
+ instance := c.engine.HTMLRender.Instance(name, obj)
+ c.Render(code, instance)
+}
+
+// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
+// It also sets the Content-Type as "application/json".
+// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
+// more CPU and bandwidth consuming. Use Context.JSON() instead.
+func (c *Context) IndentedJSON(code int, obj interface{}) {
+ c.Render(code, render.IndentedJSON{Data: obj})
+}
+
+// SecureJSON serializes the given struct as Secure JSON into the response body.
+// Default prepends "while(1)," to response body if the given struct is array values.
+// It also sets the Content-Type as "application/json".
+func (c *Context) SecureJSON(code int, obj interface{}) {
+ c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj})
+}
+
+// JSONP serializes the given struct as JSON into the response body.
+// It adds padding to response body to request data from a server residing in a different domain than the client.
+// It also sets the Content-Type as "application/javascript".
+func (c *Context) JSONP(code int, obj interface{}) {
+ callback := c.DefaultQuery("callback", "")
+ if callback == "" {
+ c.Render(code, render.JSON{Data: obj})
+ return
+ }
+ c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
+}
+
+// JSON serializes the given struct as JSON into the response body.
+// It also sets the Content-Type as "application/json".
+func (c *Context) JSON(code int, obj interface{}) {
+ c.Render(code, render.JSON{Data: obj})
+}
+
+// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
+// It also sets the Content-Type as "application/json".
+func (c *Context) AsciiJSON(code int, obj interface{}) {
+ c.Render(code, render.AsciiJSON{Data: obj})
+}
+
+// PureJSON serializes the given struct as JSON into the response body.
+// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
+func (c *Context) PureJSON(code int, obj interface{}) {
+ c.Render(code, render.PureJSON{Data: obj})
+}
+
+// XML serializes the given struct as XML into the response body.
+// It also sets the Content-Type as "application/xml".
+func (c *Context) XML(code int, obj interface{}) {
+ c.Render(code, render.XML{Data: obj})
+}
+
+// YAML serializes the given struct as YAML into the response body.
+func (c *Context) YAML(code int, obj interface{}) {
+ c.Render(code, render.YAML{Data: obj})
+}
+
+// ProtoBuf serializes the given struct as ProtoBuf into the response body.
+func (c *Context) ProtoBuf(code int, obj interface{}) {
+ c.Render(code, render.ProtoBuf{Data: obj})
+}
+
+// String writes the given string into the response body.
+func (c *Context) String(code int, format string, values ...interface{}) {
+ c.Render(code, render.String{Format: format, Data: values})
+}
+
+// Redirect returns a HTTP redirect to the specific location.
+func (c *Context) Redirect(code int, location string) {
+ c.Render(-1, render.Redirect{
+ Code: code,
+ Location: location,
+ Request: c.Request,
+ })
+}
+
+// Data writes some data into the body stream and updates the HTTP code.
+func (c *Context) Data(code int, contentType string, data []byte) {
+ c.Render(code, render.Data{
+ ContentType: contentType,
+ Data: data,
+ })
+}
+
+// DataFromReader writes the specified reader into the body stream and updates the HTTP code.
+func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) {
+ c.Render(code, render.Reader{
+ Headers: extraHeaders,
+ ContentType: contentType,
+ ContentLength: contentLength,
+ Reader: reader,
+ })
+}
+
+// File writes the specified file into the body stream in an efficient way.
+func (c *Context) File(filepath string) {
+ http.ServeFile(c.Writer, c.Request, filepath)
+}
+
+// FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way.
+func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
+ defer func(old string) {
+ c.Request.URL.Path = old
+ }(c.Request.URL.Path)
+
+ c.Request.URL.Path = filepath
+
+ http.FileServer(fs).ServeHTTP(c.Writer, c.Request)
+}
+
+// FileAttachment writes the specified file into the body stream in an efficient way
+// On the client side, the file will typically be downloaded with the given filename
+func (c *Context) FileAttachment(filepath, filename string) {
+ c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
+ http.ServeFile(c.Writer, c.Request, filepath)
+}
+
+// SSEvent writes a Server-Sent Event into the body stream.
+func (c *Context) SSEvent(name string, message interface{}) {
+ c.Render(-1, sse.Event{
+ Event: name,
+ Data: message,
+ })
+}
+
+// Stream sends a streaming response and returns a boolean
+// indicates "Is client disconnected in middle of stream"
+func (c *Context) Stream(step func(w io.Writer) bool) bool {
+ w := c.Writer
+ clientGone := w.CloseNotify()
+ for {
+ select {
+ case <-clientGone:
+ return true
+ default:
+ keepOpen := step(w)
+ w.Flush()
+ if !keepOpen {
+ return false
+ }
+ }
+ }
+}
+
+/************************************/
+/******** CONTENT NEGOTIATION *******/
+/************************************/
+
+// Negotiate contains all negotiations data.
+type Negotiate struct {
+ Offered []string
+ HTMLName string
+ HTMLData interface{}
+ JSONData interface{}
+ XMLData interface{}
+ YAMLData interface{}
+ Data interface{}
+}
+
+// Negotiate calls different Render according acceptable Accept format.
+func (c *Context) Negotiate(code int, config Negotiate) {
+ switch c.NegotiateFormat(config.Offered...) {
+ case binding.MIMEJSON:
+ data := chooseData(config.JSONData, config.Data)
+ c.JSON(code, data)
+
+ case binding.MIMEHTML:
+ data := chooseData(config.HTMLData, config.Data)
+ c.HTML(code, config.HTMLName, data)
+
+ case binding.MIMEXML:
+ data := chooseData(config.XMLData, config.Data)
+ c.XML(code, data)
+
+ case binding.MIMEYAML:
+ data := chooseData(config.YAMLData, config.Data)
+ c.YAML(code, data)
+
+ default:
+ c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck
+ }
+}
+
+// NegotiateFormat returns an acceptable Accept format.
+func (c *Context) NegotiateFormat(offered ...string) string {
+ assert1(len(offered) > 0, "you must provide at least one offer")
+
+ if c.Accepted == nil {
+ c.Accepted = parseAccept(c.requestHeader("Accept"))
+ }
+ if len(c.Accepted) == 0 {
+ return offered[0]
+ }
+ for _, accepted := range c.Accepted {
+ for _, offer := range offered {
+ // According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers,
+ // therefore we can just iterate over the string without casting it into []rune
+ i := 0
+ for ; i < len(accepted); i++ {
+ if accepted[i] == '*' || offer[i] == '*' {
+ return offer
+ }
+ if accepted[i] != offer[i] {
+ break
+ }
+ }
+ if i == len(accepted) {
+ return offer
+ }
+ }
+ }
+ return ""
+}
+
+// SetAccepted sets Accept header data.
+func (c *Context) SetAccepted(formats ...string) {
+ c.Accepted = formats
+}
+
+/************************************/
+/***** GOLANG.ORG/X/NET/CONTEXT *****/
+/************************************/
+
+// Deadline always returns that there is no deadline (ok==false),
+// maybe you want to use Request.Context().Deadline() instead.
+func (c *Context) Deadline() (deadline time.Time, ok bool) {
+ return
+}
+
+// Done always returns nil (chan which will wait forever),
+// if you want to abort your work when the connection was closed
+// you should use Request.Context().Done() instead.
+func (c *Context) Done() <-chan struct{} {
+ return nil
+}
+
+// Err always returns nil, maybe you want to use Request.Context().Err() instead.
+func (c *Context) Err() error {
+ return nil
+}
+
+// Value returns the value associated with this context for key, or nil
+// if no value is associated with key. Successive calls to Value with
+// the same key returns the same result.
+func (c *Context) Value(key interface{}) interface{} {
+ if key == 0 {
+ return c.Request
+ }
+ if keyAsString, ok := key.(string); ok {
+ val, _ := c.Get(keyAsString)
+ return val
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/context_appengine.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/context_appengine.go
new file mode 100644
index 000000000000..8bf938961d31
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/context_appengine.go
@@ -0,0 +1,12 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build appengine
+// +build appengine
+
+package gin
+
+func init() {
+ defaultPlatform = PlatformGoogleAppEngine
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/debug.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/debug.go
new file mode 100644
index 000000000000..9bacc68571c1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/debug.go
@@ -0,0 +1,103 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "fmt"
+ "html/template"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+const ginSupportMinGoVer = 13
+
+// IsDebugging returns true if the framework is running in debug mode.
+// Use SetMode(gin.ReleaseMode) to disable debug mode.
+func IsDebugging() bool {
+ return ginMode == debugCode
+}
+
+// DebugPrintRouteFunc indicates debug log output format.
+var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int)
+
+func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) {
+ if IsDebugging() {
+ nuHandlers := len(handlers)
+ handlerName := nameOfFunction(handlers.Last())
+ if DebugPrintRouteFunc == nil {
+ debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
+ } else {
+ DebugPrintRouteFunc(httpMethod, absolutePath, handlerName, nuHandlers)
+ }
+ }
+}
+
+func debugPrintLoadTemplate(tmpl *template.Template) {
+ if IsDebugging() {
+ var buf strings.Builder
+ for _, tmpl := range tmpl.Templates() {
+ buf.WriteString("\t- ")
+ buf.WriteString(tmpl.Name())
+ buf.WriteString("\n")
+ }
+ debugPrint("Loaded HTML Templates (%d): \n%s\n", len(tmpl.Templates()), buf.String())
+ }
+}
+
+func debugPrint(format string, values ...interface{}) {
+ if IsDebugging() {
+ if !strings.HasSuffix(format, "\n") {
+ format += "\n"
+ }
+ fmt.Fprintf(DefaultWriter, "[GIN-debug] "+format, values...)
+ }
+}
+
+func getMinVer(v string) (uint64, error) {
+ first := strings.IndexByte(v, '.')
+ last := strings.LastIndexByte(v, '.')
+ if first == last {
+ return strconv.ParseUint(v[first+1:], 10, 64)
+ }
+ return strconv.ParseUint(v[first+1:last], 10, 64)
+}
+
+func debugPrintWARNINGDefault() {
+ if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer {
+ debugPrint(`[WARNING] Now Gin requires Go 1.13+.
+
+`)
+ }
+ debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
+
+`)
+}
+
+func debugPrintWARNINGNew() {
+ debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production.
+ - using env: export GIN_MODE=release
+ - using code: gin.SetMode(gin.ReleaseMode)
+
+`)
+}
+
+func debugPrintWARNINGSetHTMLTemplate() {
+ debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called
+at initialization. ie. before any route is registered or the router is listening in a socket:
+
+ router := gin.Default()
+ router.SetHTMLTemplate(template) // << good place
+
+`)
+}
+
+func debugPrintError(err error) {
+ if err != nil {
+ if IsDebugging() {
+ fmt.Fprintf(DefaultErrorWriter, "[GIN-debug] [ERROR] %v\n", err)
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/deprecated.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/deprecated.go
new file mode 100644
index 000000000000..ab4474296e5b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/deprecated.go
@@ -0,0 +1,21 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "log"
+
+ "github.com/gin-gonic/gin/binding"
+)
+
+// BindWith binds the passed struct pointer using the specified binding engine.
+// See the binding package.
+func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
+ log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
+ be deprecated, please check issue #662 and either use MustBindWith() if you
+ want HTTP 400 to be automatically returned if any error occur, or use
+ ShouldBindWith() if you need to manage the error.`)
+ return c.MustBindWith(obj, b)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/doc.go
new file mode 100644
index 000000000000..1bd03864f17b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/doc.go
@@ -0,0 +1,6 @@
+/*
+Package gin implements a HTTP web framework called gin.
+
+See https://gin-gonic.com/ for more information about gin.
+*/
+package gin // import "github.com/gin-gonic/gin"
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/errors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/errors.go
new file mode 100644
index 000000000000..0f276c13d4c9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/errors.go
@@ -0,0 +1,174 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/gin-gonic/gin/internal/json"
+)
+
+// ErrorType is an unsigned 64-bit error code as defined in the gin spec.
+type ErrorType uint64
+
+const (
+ // ErrorTypeBind is used when Context.Bind() fails.
+ ErrorTypeBind ErrorType = 1 << 63
+ // ErrorTypeRender is used when Context.Render() fails.
+ ErrorTypeRender ErrorType = 1 << 62
+ // ErrorTypePrivate indicates a private error.
+ ErrorTypePrivate ErrorType = 1 << 0
+ // ErrorTypePublic indicates a public error.
+ ErrorTypePublic ErrorType = 1 << 1
+ // ErrorTypeAny indicates any other error.
+ ErrorTypeAny ErrorType = 1<<64 - 1
+ // ErrorTypeNu indicates any other error.
+ ErrorTypeNu = 2
+)
+
+// Error represents a error's specification.
+type Error struct {
+ Err error
+ Type ErrorType
+ Meta interface{}
+}
+
+type errorMsgs []*Error
+
+var _ error = &Error{}
+
+// SetType sets the error's type.
+func (msg *Error) SetType(flags ErrorType) *Error {
+ msg.Type = flags
+ return msg
+}
+
+// SetMeta sets the error's meta data.
+func (msg *Error) SetMeta(data interface{}) *Error {
+ msg.Meta = data
+ return msg
+}
+
+// JSON creates a properly formatted JSON
+func (msg *Error) JSON() interface{} {
+ jsonData := H{}
+ if msg.Meta != nil {
+ value := reflect.ValueOf(msg.Meta)
+ switch value.Kind() {
+ case reflect.Struct:
+ return msg.Meta
+ case reflect.Map:
+ for _, key := range value.MapKeys() {
+ jsonData[key.String()] = value.MapIndex(key).Interface()
+ }
+ default:
+ jsonData["meta"] = msg.Meta
+ }
+ }
+ if _, ok := jsonData["error"]; !ok {
+ jsonData["error"] = msg.Error()
+ }
+ return jsonData
+}
+
+// MarshalJSON implements the json.Marshaller interface.
+func (msg *Error) MarshalJSON() ([]byte, error) {
+ return json.Marshal(msg.JSON())
+}
+
+// Error implements the error interface.
+func (msg Error) Error() string {
+ return msg.Err.Error()
+}
+
+// IsType judges one error.
+func (msg *Error) IsType(flags ErrorType) bool {
+ return (msg.Type & flags) > 0
+}
+
+// Unwrap returns the wrapped error, to allow interoperability with errors.Is(), errors.As() and errors.Unwrap()
+func (msg *Error) Unwrap() error {
+ return msg.Err
+}
+
+// ByType returns a readonly copy filtered the byte.
+// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic.
+func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
+ if len(a) == 0 {
+ return nil
+ }
+ if typ == ErrorTypeAny {
+ return a
+ }
+ var result errorMsgs
+ for _, msg := range a {
+ if msg.IsType(typ) {
+ result = append(result, msg)
+ }
+ }
+ return result
+}
+
+// Last returns the last error in the slice. It returns nil if the array is empty.
+// Shortcut for errors[len(errors)-1].
+func (a errorMsgs) Last() *Error {
+ if length := len(a); length > 0 {
+ return a[length-1]
+ }
+ return nil
+}
+
+// Errors returns an array will all the error messages.
+// Example:
+// c.Error(errors.New("first"))
+// c.Error(errors.New("second"))
+// c.Error(errors.New("third"))
+// c.Errors.Errors() // == []string{"first", "second", "third"}
+func (a errorMsgs) Errors() []string {
+ if len(a) == 0 {
+ return nil
+ }
+ errorStrings := make([]string, len(a))
+ for i, err := range a {
+ errorStrings[i] = err.Error()
+ }
+ return errorStrings
+}
+
+func (a errorMsgs) JSON() interface{} {
+ switch length := len(a); length {
+ case 0:
+ return nil
+ case 1:
+ return a.Last().JSON()
+ default:
+ jsonData := make([]interface{}, length)
+ for i, err := range a {
+ jsonData[i] = err.JSON()
+ }
+ return jsonData
+ }
+}
+
+// MarshalJSON implements the json.Marshaller interface.
+func (a errorMsgs) MarshalJSON() ([]byte, error) {
+ return json.Marshal(a.JSON())
+}
+
+func (a errorMsgs) String() string {
+ if len(a) == 0 {
+ return ""
+ }
+ var buffer strings.Builder
+ for i, msg := range a {
+ fmt.Fprintf(&buffer, "Error #%02d: %s\n", i+1, msg.Err)
+ if msg.Meta != nil {
+ fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta)
+ }
+ }
+ return buffer.String()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/fs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/fs.go
new file mode 100644
index 000000000000..007d9b75514f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/fs.go
@@ -0,0 +1,45 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "net/http"
+ "os"
+)
+
+type onlyFilesFS struct {
+ fs http.FileSystem
+}
+
+type neuteredReaddirFile struct {
+ http.File
+}
+
+// Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally
+// in router.Static().
+// if listDirectory == true, then it works the same as http.Dir() otherwise it returns
+// a filesystem that prevents http.FileServer() to list the directory files.
+func Dir(root string, listDirectory bool) http.FileSystem {
+ fs := http.Dir(root)
+ if listDirectory {
+ return fs
+ }
+ return &onlyFilesFS{fs}
+}
+
+// Open conforms to http.Filesystem.
+func (fs onlyFilesFS) Open(name string) (http.File, error) {
+ f, err := fs.fs.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ return neuteredReaddirFile{f}, nil
+}
+
+// Readdir overrides the http.File default implementation.
+func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
+ // this disables directory listing
+ return nil, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/gin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/gin.go
new file mode 100644
index 000000000000..58e76f41fbe7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/gin.go
@@ -0,0 +1,643 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "fmt"
+ "html/template"
+ "net"
+ "net/http"
+ "os"
+ "path"
+ "reflect"
+ "strings"
+ "sync"
+
+ "github.com/gin-gonic/gin/internal/bytesconv"
+ "github.com/gin-gonic/gin/render"
+)
+
+const defaultMultipartMemory = 32 << 20 // 32 MB
+
+var (
+ default404Body = []byte("404 page not found")
+ default405Body = []byte("405 method not allowed")
+)
+
+var defaultPlatform string
+
+var defaultTrustedCIDRs = []*net.IPNet{{IP: net.IP{0x0, 0x0, 0x0, 0x0}, Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}}} // 0.0.0.0/0
+
+// HandlerFunc defines the handler used by gin middleware as return value.
+type HandlerFunc func(*Context)
+
+// HandlersChain defines a HandlerFunc array.
+type HandlersChain []HandlerFunc
+
+// Last returns the last handler in the chain. ie. the last handler is the main one.
+func (c HandlersChain) Last() HandlerFunc {
+ if length := len(c); length > 0 {
+ return c[length-1]
+ }
+ return nil
+}
+
+// RouteInfo represents a request route's specification which contains method and path and its handler.
+type RouteInfo struct {
+ Method string
+ Path string
+ Handler string
+ HandlerFunc HandlerFunc
+}
+
+// RoutesInfo defines a RouteInfo array.
+type RoutesInfo []RouteInfo
+
+// Trusted platforms
+const (
+ // When running on Google App Engine. Trust X-Appengine-Remote-Addr
+ // for determining the client's IP
+ PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
+ // When using Cloudflare's CDN. Trust CF-Connecting-IP for determining
+ // the client's IP
+ PlatformCloudflare = "CF-Connecting-IP"
+)
+
+// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
+// Create an instance of Engine, by using New() or Default()
+type Engine struct {
+ RouterGroup
+
+ // Enables automatic redirection if the current route can't be matched but a
+ // handler for the path with (without) the trailing slash exists.
+ // For example if /foo/ is requested but a route only exists for /foo, the
+ // client is redirected to /foo with http status code 301 for GET requests
+ // and 307 for all other request methods.
+ RedirectTrailingSlash bool
+
+ // If enabled, the router tries to fix the current request path, if no
+ // handle is registered for it.
+ // First superfluous path elements like ../ or // are removed.
+ // Afterwards the router does a case-insensitive lookup of the cleaned path.
+ // If a handle can be found for this route, the router makes a redirection
+ // to the corrected path with status code 301 for GET requests and 307 for
+ // all other request methods.
+ // For example /FOO and /..//Foo could be redirected to /foo.
+ // RedirectTrailingSlash is independent of this option.
+ RedirectFixedPath bool
+
+ // If enabled, the router checks if another method is allowed for the
+ // current route, if the current request can not be routed.
+ // If this is the case, the request is answered with 'Method Not Allowed'
+ // and HTTP status code 405.
+ // If no other Method is allowed, the request is delegated to the NotFound
+ // handler.
+ HandleMethodNotAllowed bool
+
+ // If enabled, client IP will be parsed from the request's headers that
+ // match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was
+ // fetched, it falls back to the IP obtained from
+ // `(*gin.Context).Request.RemoteAddr`.
+ ForwardedByClientIP bool
+
+ // DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INSTEAD
+ // #726 #755 If enabled, it will trust some headers starting with
+ // 'X-AppEngine...' for better integration with that PaaS.
+ AppEngine bool
+
+ // If enabled, the url.RawPath will be used to find parameters.
+ UseRawPath bool
+
+ // If true, the path value will be unescaped.
+ // If UseRawPath is false (by default), the UnescapePathValues effectively is true,
+ // as url.Path gonna be used, which is already unescaped.
+ UnescapePathValues bool
+
+ // RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.
+ // See the PR #1817 and issue #1644
+ RemoveExtraSlash bool
+
+ // List of headers used to obtain the client IP when
+ // `(*gin.Engine).ForwardedByClientIP` is `true` and
+ // `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
+ // network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.
+ RemoteIPHeaders []string
+
+ // If set to a constant of value gin.Platform*, trusts the headers set by
+ // that platform, for example to determine the client IP
+ TrustedPlatform string
+
+ // Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
+ // method call.
+ MaxMultipartMemory int64
+
+ delims render.Delims
+ secureJSONPrefix string
+ HTMLRender render.HTMLRender
+ FuncMap template.FuncMap
+ allNoRoute HandlersChain
+ allNoMethod HandlersChain
+ noRoute HandlersChain
+ noMethod HandlersChain
+ pool sync.Pool
+ trees methodTrees
+ maxParams uint16
+ maxSections uint16
+ trustedProxies []string
+ trustedCIDRs []*net.IPNet
+}
+
+var _ IRouter = &Engine{}
+
+// New returns a new blank Engine instance without any middleware attached.
+// By default the configuration is:
+// - RedirectTrailingSlash: true
+// - RedirectFixedPath: false
+// - HandleMethodNotAllowed: false
+// - ForwardedByClientIP: true
+// - UseRawPath: false
+// - UnescapePathValues: true
+func New() *Engine {
+ debugPrintWARNINGNew()
+ engine := &Engine{
+ RouterGroup: RouterGroup{
+ Handlers: nil,
+ basePath: "/",
+ root: true,
+ },
+ FuncMap: template.FuncMap{},
+ RedirectTrailingSlash: true,
+ RedirectFixedPath: false,
+ HandleMethodNotAllowed: false,
+ ForwardedByClientIP: true,
+ RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
+ TrustedPlatform: defaultPlatform,
+ UseRawPath: false,
+ RemoveExtraSlash: false,
+ UnescapePathValues: true,
+ MaxMultipartMemory: defaultMultipartMemory,
+ trees: make(methodTrees, 0, 9),
+ delims: render.Delims{Left: "{{", Right: "}}"},
+ secureJSONPrefix: "while(1);",
+ trustedProxies: []string{"0.0.0.0/0"},
+ trustedCIDRs: defaultTrustedCIDRs,
+ }
+ engine.RouterGroup.engine = engine
+ engine.pool.New = func() interface{} {
+ return engine.allocateContext()
+ }
+ return engine
+}
+
+// Default returns an Engine instance with the Logger and Recovery middleware already attached.
+func Default() *Engine {
+ debugPrintWARNINGDefault()
+ engine := New()
+ engine.Use(Logger(), Recovery())
+ return engine
+}
+
+func (engine *Engine) allocateContext() *Context {
+ v := make(Params, 0, engine.maxParams)
+ skippedNodes := make([]skippedNode, 0, engine.maxSections)
+ return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes}
+}
+
+// Delims sets template left and right delims and returns a Engine instance.
+func (engine *Engine) Delims(left, right string) *Engine {
+ engine.delims = render.Delims{Left: left, Right: right}
+ return engine
+}
+
+// SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON.
+func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
+ engine.secureJSONPrefix = prefix
+ return engine
+}
+
+// LoadHTMLGlob loads HTML files identified by glob pattern
+// and associates the result with HTML renderer.
+func (engine *Engine) LoadHTMLGlob(pattern string) {
+ left := engine.delims.Left
+ right := engine.delims.Right
+ templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern))
+
+ if IsDebugging() {
+ debugPrintLoadTemplate(templ)
+ engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims}
+ return
+ }
+
+ engine.SetHTMLTemplate(templ)
+}
+
+// LoadHTMLFiles loads a slice of HTML files
+// and associates the result with HTML renderer.
+func (engine *Engine) LoadHTMLFiles(files ...string) {
+ if IsDebugging() {
+ engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims}
+ return
+ }
+
+ templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...))
+ engine.SetHTMLTemplate(templ)
+}
+
+// SetHTMLTemplate associate a template with HTML renderer.
+func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
+ if len(engine.trees) > 0 {
+ debugPrintWARNINGSetHTMLTemplate()
+ }
+
+ engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)}
+}
+
+// SetFuncMap sets the FuncMap used for template.FuncMap.
+func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
+ engine.FuncMap = funcMap
+}
+
+// NoRoute adds handlers for NoRoute. It return a 404 code by default.
+func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
+ engine.noRoute = handlers
+ engine.rebuild404Handlers()
+}
+
+// NoMethod sets the handlers called when Engine.HandleMethodNotAllowed = true.
+func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
+ engine.noMethod = handlers
+ engine.rebuild405Handlers()
+}
+
+// Use attaches a global middleware to the router. ie. the middleware attached though Use() will be
+// included in the handlers chain for every single request. Even 404, 405, static files...
+// For example, this is the right place for a logger or error management middleware.
+func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
+ engine.RouterGroup.Use(middleware...)
+ engine.rebuild404Handlers()
+ engine.rebuild405Handlers()
+ return engine
+}
+
+func (engine *Engine) rebuild404Handlers() {
+ engine.allNoRoute = engine.combineHandlers(engine.noRoute)
+}
+
+func (engine *Engine) rebuild405Handlers() {
+ engine.allNoMethod = engine.combineHandlers(engine.noMethod)
+}
+
+func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
+ assert1(path[0] == '/', "path must begin with '/'")
+ assert1(method != "", "HTTP method can not be empty")
+ assert1(len(handlers) > 0, "there must be at least one handler")
+
+ debugPrintRoute(method, path, handlers)
+
+ root := engine.trees.get(method)
+ if root == nil {
+ root = new(node)
+ root.fullPath = "/"
+ engine.trees = append(engine.trees, methodTree{method: method, root: root})
+ }
+ root.addRoute(path, handlers)
+
+ // Update maxParams
+ if paramsCount := countParams(path); paramsCount > engine.maxParams {
+ engine.maxParams = paramsCount
+ }
+
+ if sectionsCount := countSections(path); sectionsCount > engine.maxSections {
+ engine.maxSections = sectionsCount
+ }
+}
+
+// Routes returns a slice of registered routes, including some useful information, such as:
+// the http method, path and the handler name.
+func (engine *Engine) Routes() (routes RoutesInfo) {
+ for _, tree := range engine.trees {
+ routes = iterate("", tree.method, routes, tree.root)
+ }
+ return routes
+}
+
+func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
+ path += root.path
+ if len(root.handlers) > 0 {
+ handlerFunc := root.handlers.Last()
+ routes = append(routes, RouteInfo{
+ Method: method,
+ Path: path,
+ Handler: nameOfFunction(handlerFunc),
+ HandlerFunc: handlerFunc,
+ })
+ }
+ for _, child := range root.children {
+ routes = iterate(path, method, routes, child)
+ }
+ return routes
+}
+
+// Run attaches the router to a http.Server and starts listening and serving HTTP requests.
+// It is a shortcut for http.ListenAndServe(addr, router)
+// Note: this method will block the calling goroutine indefinitely unless an error happens.
+func (engine *Engine) Run(addr ...string) (err error) {
+ defer func() { debugPrintError(err) }()
+
+ if engine.isUnsafeTrustedProxies() {
+ debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
+ "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
+ }
+
+ address := resolveAddress(addr)
+ debugPrint("Listening and serving HTTP on %s\n", address)
+ err = http.ListenAndServe(address, engine)
+ return
+}
+
+func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
+ if engine.trustedProxies == nil {
+ return nil, nil
+ }
+
+ cidr := make([]*net.IPNet, 0, len(engine.trustedProxies))
+ for _, trustedProxy := range engine.trustedProxies {
+ if !strings.Contains(trustedProxy, "/") {
+ ip := parseIP(trustedProxy)
+ if ip == nil {
+ return cidr, &net.ParseError{Type: "IP address", Text: trustedProxy}
+ }
+
+ switch len(ip) {
+ case net.IPv4len:
+ trustedProxy += "/32"
+ case net.IPv6len:
+ trustedProxy += "/128"
+ }
+ }
+ _, cidrNet, err := net.ParseCIDR(trustedProxy)
+ if err != nil {
+ return cidr, err
+ }
+ cidr = append(cidr, cidrNet)
+ }
+ return cidr, nil
+}
+
+// SetTrustedProxies set a list of network origins (IPv4 addresses,
+// IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust
+// request's headers that contain alternative client IP when
+// `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies`
+// feature is enabled by default, and it also trusts all proxies
+// by default. If you want to disable this feature, use
+// Engine.SetTrustedProxies(nil), then Context.ClientIP() will
+// return the remote address directly.
+func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
+ engine.trustedProxies = trustedProxies
+ return engine.parseTrustedProxies()
+}
+
+// isUnsafeTrustedProxies compares Engine.trustedCIDRs and defaultTrustedCIDRs, it's not safe if equal (returns true)
+func (engine *Engine) isUnsafeTrustedProxies() bool {
+ return reflect.DeepEqual(engine.trustedCIDRs, defaultTrustedCIDRs)
+}
+
+// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs
+func (engine *Engine) parseTrustedProxies() error {
+ trustedCIDRs, err := engine.prepareTrustedCIDRs()
+ engine.trustedCIDRs = trustedCIDRs
+ return err
+}
+
+// parseIP parse a string representation of an IP and returns a net.IP with the
+// minimum byte representation or nil if input is invalid.
+func parseIP(ip string) net.IP {
+ parsedIP := net.ParseIP(ip)
+
+ if ipv4 := parsedIP.To4(); ipv4 != nil {
+ // return ip in a 4-byte representation
+ return ipv4
+ }
+
+ // return ip in a 16-byte representation or nil
+ return parsedIP
+}
+
+// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
+// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
+// Note: this method will block the calling goroutine indefinitely unless an error happens.
+func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
+ debugPrint("Listening and serving HTTPS on %s\n", addr)
+ defer func() { debugPrintError(err) }()
+
+ if engine.isUnsafeTrustedProxies() {
+ debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
+ "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
+ }
+
+ err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
+ return
+}
+
+// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
+// through the specified unix socket (ie. a file).
+// Note: this method will block the calling goroutine indefinitely unless an error happens.
+func (engine *Engine) RunUnix(file string) (err error) {
+ debugPrint("Listening and serving HTTP on unix:/%s", file)
+ defer func() { debugPrintError(err) }()
+
+ if engine.isUnsafeTrustedProxies() {
+ debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
+ "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
+ }
+
+ listener, err := net.Listen("unix", file)
+ if err != nil {
+ return
+ }
+ defer listener.Close()
+ defer os.Remove(file)
+
+ err = http.Serve(listener, engine)
+ return
+}
+
+// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
+// through the specified file descriptor.
+// Note: this method will block the calling goroutine indefinitely unless an error happens.
+func (engine *Engine) RunFd(fd int) (err error) {
+ debugPrint("Listening and serving HTTP on fd@%d", fd)
+ defer func() { debugPrintError(err) }()
+
+ if engine.isUnsafeTrustedProxies() {
+ debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
+ "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
+ }
+
+ f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
+ listener, err := net.FileListener(f)
+ if err != nil {
+ return
+ }
+ defer listener.Close()
+ err = engine.RunListener(listener)
+ return
+}
+
+// RunListener attaches the router to a http.Server and starts listening and serving HTTP requests
+// through the specified net.Listener
+func (engine *Engine) RunListener(listener net.Listener) (err error) {
+ debugPrint("Listening and serving HTTP on listener what's bind with address@%s", listener.Addr())
+ defer func() { debugPrintError(err) }()
+
+ if engine.isUnsafeTrustedProxies() {
+ debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
+ "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
+ }
+
+ err = http.Serve(listener, engine)
+ return
+}
+
+// ServeHTTP conforms to the http.Handler interface.
+func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ c := engine.pool.Get().(*Context)
+ c.writermem.reset(w)
+ c.Request = req
+ c.reset()
+
+ engine.handleHTTPRequest(c)
+
+ engine.pool.Put(c)
+}
+
+// HandleContext re-enter a context that has been rewritten.
+// This can be done by setting c.Request.URL.Path to your new target.
+// Disclaimer: You can loop yourself to death with this, use wisely.
+func (engine *Engine) HandleContext(c *Context) {
+ oldIndexValue := c.index
+ c.reset()
+ engine.handleHTTPRequest(c)
+
+ c.index = oldIndexValue
+}
+
+func (engine *Engine) handleHTTPRequest(c *Context) {
+ httpMethod := c.Request.Method
+ rPath := c.Request.URL.Path
+ unescape := false
+ if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
+ rPath = c.Request.URL.RawPath
+ unescape = engine.UnescapePathValues
+ }
+
+ if engine.RemoveExtraSlash {
+ rPath = cleanPath(rPath)
+ }
+
+ // Find root of the tree for the given HTTP method
+ t := engine.trees
+ for i, tl := 0, len(t); i < tl; i++ {
+ if t[i].method != httpMethod {
+ continue
+ }
+ root := t[i].root
+ // Find route in tree
+ value := root.getValue(rPath, c.params, c.skippedNodes, unescape)
+ if value.params != nil {
+ c.Params = *value.params
+ }
+ if value.handlers != nil {
+ c.handlers = value.handlers
+ c.fullPath = value.fullPath
+ c.Next()
+ c.writermem.WriteHeaderNow()
+ return
+ }
+ if httpMethod != "CONNECT" && rPath != "/" {
+ if value.tsr && engine.RedirectTrailingSlash {
+ redirectTrailingSlash(c)
+ return
+ }
+ if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
+ return
+ }
+ }
+ break
+ }
+
+ if engine.HandleMethodNotAllowed {
+ for _, tree := range engine.trees {
+ if tree.method == httpMethod {
+ continue
+ }
+ if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
+ c.handlers = engine.allNoMethod
+ serveError(c, http.StatusMethodNotAllowed, default405Body)
+ return
+ }
+ }
+ }
+ c.handlers = engine.allNoRoute
+ serveError(c, http.StatusNotFound, default404Body)
+}
+
+var mimePlain = []string{MIMEPlain}
+
+func serveError(c *Context, code int, defaultMessage []byte) {
+ c.writermem.status = code
+ c.Next()
+ if c.writermem.Written() {
+ return
+ }
+ if c.writermem.Status() == code {
+ c.writermem.Header()["Content-Type"] = mimePlain
+ _, err := c.Writer.Write(defaultMessage)
+ if err != nil {
+ debugPrint("cannot write message to writer during serve error: %v", err)
+ }
+ return
+ }
+ c.writermem.WriteHeaderNow()
+}
+
+func redirectTrailingSlash(c *Context) {
+ req := c.Request
+ p := req.URL.Path
+ if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." {
+ p = prefix + "/" + req.URL.Path
+ }
+ req.URL.Path = p + "/"
+ if length := len(p); length > 1 && p[length-1] == '/' {
+ req.URL.Path = p[:length-1]
+ }
+ redirectRequest(c)
+}
+
+func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
+ req := c.Request
+ rPath := req.URL.Path
+
+ if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(rPath), trailingSlash); ok {
+ req.URL.Path = bytesconv.BytesToString(fixedPath)
+ redirectRequest(c)
+ return true
+ }
+ return false
+}
+
+func redirectRequest(c *Context) {
+ req := c.Request
+ rPath := req.URL.Path
+ rURL := req.URL.String()
+
+ code := http.StatusMovedPermanently // Permanent redirect, request with GET method
+ if req.Method != http.MethodGet {
+ code = http.StatusTemporaryRedirect
+ }
+ debugPrint("redirecting request %d: %s --> %s", code, rPath, rURL)
+ http.Redirect(c.Writer, req, rURL, code)
+ c.writermem.WriteHeaderNow()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go
new file mode 100644
index 000000000000..86e4c4d44cdf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/bytesconv/bytesconv.go
@@ -0,0 +1,24 @@
+// Copyright 2020 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package bytesconv
+
+import (
+ "unsafe"
+)
+
+// StringToBytes converts string to byte slice without a memory allocation.
+func StringToBytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(
+ &struct {
+ string
+ Cap int
+ }{s, len(s)},
+ ))
+}
+
+// BytesToString converts byte slice to string without a memory allocation.
+func BytesToString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/json/json.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/json/json.go
new file mode 100644
index 000000000000..172aeb2414c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/json/json.go
@@ -0,0 +1,23 @@
+// Copyright 2017 Bo-Yi Wu. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build !jsoniter
+// +build !jsoniter
+
+package json
+
+import "encoding/json"
+
+var (
+ // Marshal is exported by gin/json package.
+ Marshal = json.Marshal
+ // Unmarshal is exported by gin/json package.
+ Unmarshal = json.Unmarshal
+ // MarshalIndent is exported by gin/json package.
+ MarshalIndent = json.MarshalIndent
+ // NewDecoder is exported by gin/json package.
+ NewDecoder = json.NewDecoder
+ // NewEncoder is exported by gin/json package.
+ NewEncoder = json.NewEncoder
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go
new file mode 100644
index 000000000000..232f8dcada12
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/internal/json/jsoniter.go
@@ -0,0 +1,24 @@
+// Copyright 2017 Bo-Yi Wu. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build jsoniter
+// +build jsoniter
+
+package json
+
+import jsoniter "github.com/json-iterator/go"
+
+var (
+ json = jsoniter.ConfigCompatibleWithStandardLibrary
+ // Marshal is exported by gin/json package.
+ Marshal = json.Marshal
+ // Unmarshal is exported by gin/json package.
+ Unmarshal = json.Unmarshal
+ // MarshalIndent is exported by gin/json package.
+ MarshalIndent = json.MarshalIndent
+ // NewDecoder is exported by gin/json package.
+ NewDecoder = json.NewDecoder
+ // NewEncoder is exported by gin/json package.
+ NewEncoder = json.NewEncoder
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/logger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/logger.go
new file mode 100644
index 000000000000..d361b74d3239
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/logger.go
@@ -0,0 +1,271 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/mattn/go-isatty"
+)
+
+type consoleColorModeValue int
+
+const (
+ autoColor consoleColorModeValue = iota
+ disableColor
+ forceColor
+)
+
+const (
+ green = "\033[97;42m"
+ white = "\033[90;47m"
+ yellow = "\033[90;43m"
+ red = "\033[97;41m"
+ blue = "\033[97;44m"
+ magenta = "\033[97;45m"
+ cyan = "\033[97;46m"
+ reset = "\033[0m"
+)
+
+var consoleColorMode = autoColor
+
+// LoggerConfig defines the config for Logger middleware.
+type LoggerConfig struct {
+ // Optional. Default value is gin.defaultLogFormatter
+ Formatter LogFormatter
+
+ // Output is a writer where logs are written.
+ // Optional. Default value is gin.DefaultWriter.
+ Output io.Writer
+
+ // SkipPaths is a url path array which logs are not written.
+ // Optional.
+ SkipPaths []string
+}
+
+// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
+type LogFormatter func(params LogFormatterParams) string
+
+// LogFormatterParams is the structure any formatter will be handed when time to log comes
+type LogFormatterParams struct {
+ Request *http.Request
+
+ // TimeStamp shows the time after the server returns a response.
+ TimeStamp time.Time
+ // StatusCode is HTTP response code.
+ StatusCode int
+ // Latency is how much time the server cost to process a certain request.
+ Latency time.Duration
+ // ClientIP equals Context's ClientIP method.
+ ClientIP string
+ // Method is the HTTP method given to the request.
+ Method string
+ // Path is a path the client requests.
+ Path string
+ // ErrorMessage is set if error has occurred in processing the request.
+ ErrorMessage string
+ // isTerm shows whether does gin's output descriptor refers to a terminal.
+ isTerm bool
+ // BodySize is the size of the Response Body
+ BodySize int
+ // Keys are the keys set on the request's context.
+ Keys map[string]interface{}
+}
+
+// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal.
+func (p *LogFormatterParams) StatusCodeColor() string {
+ code := p.StatusCode
+
+ switch {
+ case code >= http.StatusOK && code < http.StatusMultipleChoices:
+ return green
+ case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
+ return white
+ case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
+ return yellow
+ default:
+ return red
+ }
+}
+
+// MethodColor is the ANSI color for appropriately logging http method to a terminal.
+func (p *LogFormatterParams) MethodColor() string {
+ method := p.Method
+
+ switch method {
+ case http.MethodGet:
+ return blue
+ case http.MethodPost:
+ return cyan
+ case http.MethodPut:
+ return yellow
+ case http.MethodDelete:
+ return red
+ case http.MethodPatch:
+ return green
+ case http.MethodHead:
+ return magenta
+ case http.MethodOptions:
+ return white
+ default:
+ return reset
+ }
+}
+
+// ResetColor resets all escape attributes.
+func (p *LogFormatterParams) ResetColor() string {
+ return reset
+}
+
+// IsOutputColor indicates whether can colors be outputted to the log.
+func (p *LogFormatterParams) IsOutputColor() bool {
+ return consoleColorMode == forceColor || (consoleColorMode == autoColor && p.isTerm)
+}
+
+// defaultLogFormatter is the default log format function Logger middleware uses.
+var defaultLogFormatter = func(param LogFormatterParams) string {
+ var statusColor, methodColor, resetColor string
+ if param.IsOutputColor() {
+ statusColor = param.StatusCodeColor()
+ methodColor = param.MethodColor()
+ resetColor = param.ResetColor()
+ }
+
+ if param.Latency > time.Minute {
+ // Truncate in a golang < 1.8 safe way
+ param.Latency = param.Latency - param.Latency%time.Second
+ }
+ return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
+ param.TimeStamp.Format("2006/01/02 - 15:04:05"),
+ statusColor, param.StatusCode, resetColor,
+ param.Latency,
+ param.ClientIP,
+ methodColor, param.Method, resetColor,
+ param.Path,
+ param.ErrorMessage,
+ )
+}
+
+// DisableConsoleColor disables color output in the console.
+func DisableConsoleColor() {
+ consoleColorMode = disableColor
+}
+
+// ForceConsoleColor force color output in the console.
+func ForceConsoleColor() {
+ consoleColorMode = forceColor
+}
+
+// ErrorLogger returns a handlerfunc for any error type.
+func ErrorLogger() HandlerFunc {
+ return ErrorLoggerT(ErrorTypeAny)
+}
+
+// ErrorLoggerT returns a handlerfunc for a given error type.
+func ErrorLoggerT(typ ErrorType) HandlerFunc {
+ return func(c *Context) {
+ c.Next()
+ errors := c.Errors.ByType(typ)
+ if len(errors) > 0 {
+ c.JSON(-1, errors)
+ }
+ }
+}
+
+// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter.
+// By default gin.DefaultWriter = os.Stdout.
+func Logger() HandlerFunc {
+ return LoggerWithConfig(LoggerConfig{})
+}
+
+// LoggerWithFormatter instance a Logger middleware with the specified log format function.
+func LoggerWithFormatter(f LogFormatter) HandlerFunc {
+ return LoggerWithConfig(LoggerConfig{
+ Formatter: f,
+ })
+}
+
+// LoggerWithWriter instance a Logger middleware with the specified writer buffer.
+// Example: os.Stdout, a file opened in write mode, a socket...
+func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
+ return LoggerWithConfig(LoggerConfig{
+ Output: out,
+ SkipPaths: notlogged,
+ })
+}
+
+// LoggerWithConfig instance a Logger middleware with config.
+func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
+ formatter := conf.Formatter
+ if formatter == nil {
+ formatter = defaultLogFormatter
+ }
+
+ out := conf.Output
+ if out == nil {
+ out = DefaultWriter
+ }
+
+ notlogged := conf.SkipPaths
+
+ isTerm := true
+
+ if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
+ (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
+ isTerm = false
+ }
+
+ var skip map[string]struct{}
+
+ if length := len(notlogged); length > 0 {
+ skip = make(map[string]struct{}, length)
+
+ for _, path := range notlogged {
+ skip[path] = struct{}{}
+ }
+ }
+
+ return func(c *Context) {
+ // Start timer
+ start := time.Now()
+ path := c.Request.URL.Path
+ raw := c.Request.URL.RawQuery
+
+ // Process request
+ c.Next()
+
+ // Log only when path is not being skipped
+ if _, ok := skip[path]; !ok {
+ param := LogFormatterParams{
+ Request: c.Request,
+ isTerm: isTerm,
+ Keys: c.Keys,
+ }
+
+ // Stop timer
+ param.TimeStamp = time.Now()
+ param.Latency = param.TimeStamp.Sub(start)
+
+ param.ClientIP = c.ClientIP()
+ param.Method = c.Request.Method
+ param.StatusCode = c.Writer.Status()
+ param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
+
+ param.BodySize = c.Writer.Size()
+
+ if raw != "" {
+ path = path + "?" + raw
+ }
+
+ param.Path = path
+
+ fmt.Fprint(out, formatter(param))
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/mode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/mode.go
new file mode 100644
index 000000000000..c8813aff26c5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/mode.go
@@ -0,0 +1,92 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "io"
+ "os"
+
+ "github.com/gin-gonic/gin/binding"
+)
+
+// EnvGinMode indicates environment name for gin mode.
+const EnvGinMode = "GIN_MODE"
+
+const (
+ // DebugMode indicates gin mode is debug.
+ DebugMode = "debug"
+ // ReleaseMode indicates gin mode is release.
+ ReleaseMode = "release"
+ // TestMode indicates gin mode is test.
+ TestMode = "test"
+)
+
+const (
+ debugCode = iota
+ releaseCode
+ testCode
+)
+
+// DefaultWriter is the default io.Writer used by Gin for debug output and
+// middleware output like Logger() or Recovery().
+// Note that both Logger and Recovery provides custom ways to configure their
+// output io.Writer.
+// To support coloring in Windows use:
+// import "github.com/mattn/go-colorable"
+// gin.DefaultWriter = colorable.NewColorableStdout()
+var DefaultWriter io.Writer = os.Stdout
+
+// DefaultErrorWriter is the default io.Writer used by Gin to debug errors
+var DefaultErrorWriter io.Writer = os.Stderr
+
+var ginMode = debugCode
+var modeName = DebugMode
+
+func init() {
+ mode := os.Getenv(EnvGinMode)
+ SetMode(mode)
+}
+
+// SetMode sets gin mode according to input string.
+func SetMode(value string) {
+ if value == "" {
+ value = DebugMode
+ }
+
+ switch value {
+ case DebugMode:
+ ginMode = debugCode
+ case ReleaseMode:
+ ginMode = releaseCode
+ case TestMode:
+ ginMode = testCode
+ default:
+ panic("gin mode unknown: " + value + " (available mode: debug release test)")
+ }
+
+ modeName = value
+}
+
+// DisableBindValidation closes the default validator.
+func DisableBindValidation() {
+ binding.Validator = nil
+}
+
+// EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumber to
+// call the UseNumber method on the JSON Decoder instance.
+func EnableJsonDecoderUseNumber() {
+ binding.EnableDecoderUseNumber = true
+}
+
+// EnableJsonDecoderDisallowUnknownFields sets true for binding.EnableDecoderDisallowUnknownFields to
+// call the DisallowUnknownFields method on the JSON Decoder instance.
+func EnableJsonDecoderDisallowUnknownFields() {
+ binding.EnableDecoderDisallowUnknownFields = true
+}
+
+// Mode returns currently gin mode.
+func Mode() string {
+ return modeName
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/path.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/path.go
new file mode 100644
index 000000000000..d42d6b9d05d6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/path.go
@@ -0,0 +1,150 @@
+// Copyright 2013 Julien Schmidt. All rights reserved.
+// Based on the path package, Copyright 2009 The Go Authors.
+// Use of this source code is governed by a BSD-style license that can be found
+// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE.
+
+package gin
+
+// cleanPath is the URL version of path.Clean, it returns a canonical URL path
+// for p, eliminating . and .. elements.
+//
+// The following rules are applied iteratively until no further processing can
+// be done:
+// 1. Replace multiple slashes with a single slash.
+// 2. Eliminate each . path name element (the current directory).
+// 3. Eliminate each inner .. path name element (the parent directory)
+// along with the non-.. element that precedes it.
+// 4. Eliminate .. elements that begin a rooted path:
+// that is, replace "/.." by "/" at the beginning of a path.
+//
+// If the result of this process is an empty string, "/" is returned.
+func cleanPath(p string) string {
+ const stackBufSize = 128
+ // Turn empty string into "/"
+ if p == "" {
+ return "/"
+ }
+
+ // Reasonably sized buffer on stack to avoid allocations in the common case.
+ // If a larger buffer is required, it gets allocated dynamically.
+ buf := make([]byte, 0, stackBufSize)
+
+ n := len(p)
+
+ // Invariants:
+ // reading from path; r is index of next byte to process.
+ // writing to buf; w is index of next byte to write.
+
+ // path must start with '/'
+ r := 1
+ w := 1
+
+ if p[0] != '/' {
+ r = 0
+
+ if n+1 > stackBufSize {
+ buf = make([]byte, n+1)
+ } else {
+ buf = buf[:n+1]
+ }
+ buf[0] = '/'
+ }
+
+ trailing := n > 1 && p[n-1] == '/'
+
+ // A bit more clunky without a 'lazybuf' like the path package, but the loop
+ // gets completely inlined (bufApp calls).
+ // loop has no expensive function calls (except 1x make) // So in contrast to the path package this loop has no expensive function
+ // calls (except make, if needed).
+
+ for r < n {
+ switch {
+ case p[r] == '/':
+ // empty path element, trailing slash is added after the end
+ r++
+
+ case p[r] == '.' && r+1 == n:
+ trailing = true
+ r++
+
+ case p[r] == '.' && p[r+1] == '/':
+ // . element
+ r += 2
+
+ case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
+ // .. element: remove to last /
+ r += 3
+
+ if w > 1 {
+ // can backtrack
+ w--
+
+ if len(buf) == 0 {
+ for w > 1 && p[w] != '/' {
+ w--
+ }
+ } else {
+ for w > 1 && buf[w] != '/' {
+ w--
+ }
+ }
+ }
+
+ default:
+ // Real path element.
+ // Add slash if needed
+ if w > 1 {
+ bufApp(&buf, p, w, '/')
+ w++
+ }
+
+ // Copy element
+ for r < n && p[r] != '/' {
+ bufApp(&buf, p, w, p[r])
+ w++
+ r++
+ }
+ }
+ }
+
+ // Re-append trailing slash
+ if trailing && w > 1 {
+ bufApp(&buf, p, w, '/')
+ w++
+ }
+
+ // If the original string was not modified (or only shortened at the end),
+ // return the respective substring of the original string.
+ // Otherwise return a new string from the buffer.
+ if len(buf) == 0 {
+ return p[:w]
+ }
+ return string(buf[:w])
+}
+
+// Internal helper to lazily create a buffer if necessary.
+// Calls to this function get inlined.
+func bufApp(buf *[]byte, s string, w int, c byte) {
+ b := *buf
+ if len(b) == 0 {
+ // No modification of the original string so far.
+ // If the next character is the same as in the original string, we do
+ // not yet have to allocate a buffer.
+ if s[w] == c {
+ return
+ }
+
+ // Otherwise use either the stack buffer, if it is large enough, or
+ // allocate a new buffer on the heap, and copy all previous characters.
+ length := len(s)
+ if length > cap(b) {
+ *buf = make([]byte, length)
+ } else {
+ *buf = (*buf)[:length]
+ }
+ b = *buf
+
+ copy(b, s[:w])
+ }
+ b[w] = c
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/recovery.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/recovery.go
new file mode 100644
index 000000000000..563f5aaa8e24
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/recovery.go
@@ -0,0 +1,171 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "net/http/httputil"
+ "os"
+ "runtime"
+ "strings"
+ "time"
+)
+
+var (
+ dunno = []byte("???")
+ centerDot = []byte("·")
+ dot = []byte(".")
+ slash = []byte("/")
+)
+
+// RecoveryFunc defines the function passable to CustomRecovery.
+type RecoveryFunc func(c *Context, err interface{})
+
+// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
+func Recovery() HandlerFunc {
+ return RecoveryWithWriter(DefaultErrorWriter)
+}
+
+//CustomRecovery returns a middleware that recovers from any panics and calls the provided handle func to handle it.
+func CustomRecovery(handle RecoveryFunc) HandlerFunc {
+ return RecoveryWithWriter(DefaultErrorWriter, handle)
+}
+
+// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.
+func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc {
+ if len(recovery) > 0 {
+ return CustomRecoveryWithWriter(out, recovery[0])
+ }
+ return CustomRecoveryWithWriter(out, defaultHandleRecovery)
+}
+
+// CustomRecoveryWithWriter returns a middleware for a given writer that recovers from any panics and calls the provided handle func to handle it.
+func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc {
+ var logger *log.Logger
+ if out != nil {
+ logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags)
+ }
+ return func(c *Context) {
+ defer func() {
+ if err := recover(); err != nil {
+ // Check for a broken connection, as it is not really a
+ // condition that warrants a panic stack trace.
+ var brokenPipe bool
+ if ne, ok := err.(*net.OpError); ok {
+ if se, ok := ne.Err.(*os.SyscallError); ok {
+ if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
+ brokenPipe = true
+ }
+ }
+ }
+ if logger != nil {
+ stack := stack(3)
+ httpRequest, _ := httputil.DumpRequest(c.Request, false)
+ headers := strings.Split(string(httpRequest), "\r\n")
+ for idx, header := range headers {
+ current := strings.Split(header, ":")
+ if current[0] == "Authorization" {
+ headers[idx] = current[0] + ": *"
+ }
+ }
+ headersToStr := strings.Join(headers, "\r\n")
+ if brokenPipe {
+ logger.Printf("%s\n%s%s", err, headersToStr, reset)
+ } else if IsDebugging() {
+ logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s",
+ timeFormat(time.Now()), headersToStr, err, stack, reset)
+ } else {
+ logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s",
+ timeFormat(time.Now()), err, stack, reset)
+ }
+ }
+ if brokenPipe {
+ // If the connection is dead, we can't write a status to it.
+ c.Error(err.(error)) // nolint: errcheck
+ c.Abort()
+ } else {
+ handle(c, err)
+ }
+ }
+ }()
+ c.Next()
+ }
+}
+
+func defaultHandleRecovery(c *Context, err interface{}) {
+ c.AbortWithStatus(http.StatusInternalServerError)
+}
+
+// stack returns a nicely formatted stack frame, skipping skip frames.
+func stack(skip int) []byte {
+ buf := new(bytes.Buffer) // the returned data
+ // As we loop, we open files and read them. These variables record the currently
+ // loaded file.
+ var lines [][]byte
+ var lastFile string
+ for i := skip; ; i++ { // Skip the expected number of frames
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ // Print this much at least. If we can't find the source, it won't show.
+ fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
+ if file != lastFile {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ continue
+ }
+ lines = bytes.Split(data, []byte{'\n'})
+ lastFile = file
+ }
+ fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
+ }
+ return buf.Bytes()
+}
+
+// source returns a space-trimmed slice of the n'th line.
+func source(lines [][]byte, n int) []byte {
+ n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
+ if n < 0 || n >= len(lines) {
+ return dunno
+ }
+ return bytes.TrimSpace(lines[n])
+}
+
+// function returns, if possible, the name of the function containing the PC.
+func function(pc uintptr) []byte {
+ fn := runtime.FuncForPC(pc)
+ if fn == nil {
+ return dunno
+ }
+ name := []byte(fn.Name())
+ // The name includes the path name to the package, which is unnecessary
+ // since the file name is already included. Plus, it has center dots.
+ // That is, we see
+ // runtime/debug.*T·ptrmethod
+ // and want
+ // *T.ptrmethod
+ // Also the package path might contains dot (e.g. code.google.com/...),
+ // so first eliminate the path prefix
+ if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 {
+ name = name[lastSlash+1:]
+ }
+ if period := bytes.Index(name, dot); period >= 0 {
+ name = name[period+1:]
+ }
+ name = bytes.Replace(name, centerDot, dot, -1)
+ return name
+}
+
+func timeFormat(t time.Time) string {
+ timeString := t.Format("2006/01/02 - 15:04:05")
+ return timeString
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/data.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/data.go
new file mode 100644
index 000000000000..6ba657ba0a5f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/data.go
@@ -0,0 +1,25 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import "net/http"
+
+// Data contains ContentType and bytes data.
+type Data struct {
+ ContentType string
+ Data []byte
+}
+
+// Render (Data) writes data with custom ContentType.
+func (r Data) Render(w http.ResponseWriter) (err error) {
+ r.WriteContentType(w)
+ _, err = w.Write(r.Data)
+ return
+}
+
+// WriteContentType (Data) writes custom ContentType.
+func (r Data) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, []string{r.ContentType})
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/html.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/html.go
new file mode 100644
index 000000000000..6696ece99716
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/html.go
@@ -0,0 +1,92 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "html/template"
+ "net/http"
+)
+
+// Delims represents a set of Left and Right delimiters for HTML template rendering.
+type Delims struct {
+ // Left delimiter, defaults to {{.
+ Left string
+ // Right delimiter, defaults to }}.
+ Right string
+}
+
+// HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug.
+type HTMLRender interface {
+ // Instance returns an HTML instance.
+ Instance(string, interface{}) Render
+}
+
+// HTMLProduction contains template reference and its delims.
+type HTMLProduction struct {
+ Template *template.Template
+ Delims Delims
+}
+
+// HTMLDebug contains template delims and pattern and function with file list.
+type HTMLDebug struct {
+ Files []string
+ Glob string
+ Delims Delims
+ FuncMap template.FuncMap
+}
+
+// HTML contains template reference and its name with given interface object.
+type HTML struct {
+ Template *template.Template
+ Name string
+ Data interface{}
+}
+
+var htmlContentType = []string{"text/html; charset=utf-8"}
+
+// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface.
+func (r HTMLProduction) Instance(name string, data interface{}) Render {
+ return HTML{
+ Template: r.Template,
+ Name: name,
+ Data: data,
+ }
+}
+
+// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.
+func (r HTMLDebug) Instance(name string, data interface{}) Render {
+ return HTML{
+ Template: r.loadTemplate(),
+ Name: name,
+ Data: data,
+ }
+}
+func (r HTMLDebug) loadTemplate() *template.Template {
+ if r.FuncMap == nil {
+ r.FuncMap = template.FuncMap{}
+ }
+ if len(r.Files) > 0 {
+ return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...))
+ }
+ if r.Glob != "" {
+ return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseGlob(r.Glob))
+ }
+ panic("the HTML debug render was created without files or glob pattern")
+}
+
+// Render (HTML) executes template and writes its result with custom ContentType for response.
+func (r HTML) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+
+ if r.Name == "" {
+ return r.Template.Execute(w, r.Data)
+ }
+ return r.Template.ExecuteTemplate(w, r.Name, r.Data)
+}
+
+// WriteContentType (HTML) writes HTML ContentType.
+func (r HTML) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, htmlContentType)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/json.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/json.go
new file mode 100644
index 000000000000..418630939808
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/json.go
@@ -0,0 +1,193 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "net/http"
+
+ "github.com/gin-gonic/gin/internal/bytesconv"
+ "github.com/gin-gonic/gin/internal/json"
+)
+
+// JSON contains the given interface object.
+type JSON struct {
+ Data interface{}
+}
+
+// IndentedJSON contains the given interface object.
+type IndentedJSON struct {
+ Data interface{}
+}
+
+// SecureJSON contains the given interface object and its prefix.
+type SecureJSON struct {
+ Prefix string
+ Data interface{}
+}
+
+// JsonpJSON contains the given interface object its callback.
+type JsonpJSON struct {
+ Callback string
+ Data interface{}
+}
+
+// AsciiJSON contains the given interface object.
+type AsciiJSON struct {
+ Data interface{}
+}
+
+// PureJSON contains the given interface object.
+type PureJSON struct {
+ Data interface{}
+}
+
+var jsonContentType = []string{"application/json; charset=utf-8"}
+var jsonpContentType = []string{"application/javascript; charset=utf-8"}
+var jsonAsciiContentType = []string{"application/json"}
+
+// Render (JSON) writes data with custom ContentType.
+func (r JSON) Render(w http.ResponseWriter) (err error) {
+ if err = WriteJSON(w, r.Data); err != nil {
+ panic(err)
+ }
+ return
+}
+
+// WriteContentType (JSON) writes JSON ContentType.
+func (r JSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonContentType)
+}
+
+// WriteJSON marshals the given interface object and writes it with custom ContentType.
+func WriteJSON(w http.ResponseWriter, obj interface{}) error {
+ writeContentType(w, jsonContentType)
+ jsonBytes, err := json.Marshal(obj)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(jsonBytes)
+ return err
+}
+
+// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType.
+func (r IndentedJSON) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+ jsonBytes, err := json.MarshalIndent(r.Data, "", " ")
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(jsonBytes)
+ return err
+}
+
+// WriteContentType (IndentedJSON) writes JSON ContentType.
+func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonContentType)
+}
+
+// Render (SecureJSON) marshals the given interface object and writes it with custom ContentType.
+func (r SecureJSON) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+ jsonBytes, err := json.Marshal(r.Data)
+ if err != nil {
+ return err
+ }
+ // if the jsonBytes is array values
+ if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes,
+ bytesconv.StringToBytes("]")) {
+ _, err = w.Write(bytesconv.StringToBytes(r.Prefix))
+ if err != nil {
+ return err
+ }
+ }
+ _, err = w.Write(jsonBytes)
+ return err
+}
+
+// WriteContentType (SecureJSON) writes JSON ContentType.
+func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonContentType)
+}
+
+// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
+func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
+ r.WriteContentType(w)
+ ret, err := json.Marshal(r.Data)
+ if err != nil {
+ return err
+ }
+
+ if r.Callback == "" {
+ _, err = w.Write(ret)
+ return err
+ }
+
+ callback := template.JSEscapeString(r.Callback)
+ _, err = w.Write(bytesconv.StringToBytes(callback))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(bytesconv.StringToBytes("("))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(ret)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(bytesconv.StringToBytes(");"))
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// WriteContentType (JsonpJSON) writes Javascript ContentType.
+func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonpContentType)
+}
+
+// Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType.
+func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
+ r.WriteContentType(w)
+ ret, err := json.Marshal(r.Data)
+ if err != nil {
+ return err
+ }
+
+ var buffer bytes.Buffer
+ for _, r := range bytesconv.BytesToString(ret) {
+ cvt := string(r)
+ if r >= 128 {
+ cvt = fmt.Sprintf("\\u%04x", int64(r))
+ }
+ buffer.WriteString(cvt)
+ }
+
+ _, err = w.Write(buffer.Bytes())
+ return err
+}
+
+// WriteContentType (AsciiJSON) writes JSON ContentType.
+func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonAsciiContentType)
+}
+
+// Render (PureJSON) writes custom ContentType and encodes the given interface object.
+func (r PureJSON) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+ encoder := json.NewEncoder(w)
+ encoder.SetEscapeHTML(false)
+ return encoder.Encode(r.Data)
+}
+
+// WriteContentType (PureJSON) writes custom ContentType.
+func (r PureJSON) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, jsonContentType)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/msgpack.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/msgpack.go
new file mode 100644
index 000000000000..6ef5b6e514c3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/msgpack.go
@@ -0,0 +1,42 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build !nomsgpack
+// +build !nomsgpack
+
+package render
+
+import (
+ "net/http"
+
+ "github.com/ugorji/go/codec"
+)
+
+var (
+ _ Render = MsgPack{}
+)
+
+// MsgPack contains the given interface object.
+type MsgPack struct {
+ Data interface{}
+}
+
+var msgpackContentType = []string{"application/msgpack; charset=utf-8"}
+
+// WriteContentType (MsgPack) writes MsgPack ContentType.
+func (r MsgPack) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, msgpackContentType)
+}
+
+// Render (MsgPack) encodes the given interface object and writes data with custom ContentType.
+func (r MsgPack) Render(w http.ResponseWriter) error {
+ return WriteMsgPack(w, r.Data)
+}
+
+// WriteMsgPack writes MsgPack ContentType and encodes the given interface object.
+func WriteMsgPack(w http.ResponseWriter, obj interface{}) error {
+ writeContentType(w, msgpackContentType)
+ var mh codec.MsgpackHandle
+ return codec.NewEncoder(w, &mh).Encode(obj)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/protobuf.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/protobuf.go
new file mode 100644
index 000000000000..15aca9959cd6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/protobuf.go
@@ -0,0 +1,36 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "net/http"
+
+ "github.com/golang/protobuf/proto"
+)
+
+// ProtoBuf contains the given interface object.
+type ProtoBuf struct {
+ Data interface{}
+}
+
+var protobufContentType = []string{"application/x-protobuf"}
+
+// Render (ProtoBuf) marshals the given interface object and writes data with custom ContentType.
+func (r ProtoBuf) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+
+ bytes, err := proto.Marshal(r.Data.(proto.Message))
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(bytes)
+ return err
+}
+
+// WriteContentType (ProtoBuf) writes ProtoBuf ContentType.
+func (r ProtoBuf) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, protobufContentType)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/reader.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/reader.go
new file mode 100644
index 000000000000..d5282e492724
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/reader.go
@@ -0,0 +1,48 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "io"
+ "net/http"
+ "strconv"
+)
+
+// Reader contains the IO reader and its length, and custom ContentType and other headers.
+type Reader struct {
+ ContentType string
+ ContentLength int64
+ Reader io.Reader
+ Headers map[string]string
+}
+
+// Render (Reader) writes data with custom ContentType and headers.
+func (r Reader) Render(w http.ResponseWriter) (err error) {
+ r.WriteContentType(w)
+ if r.ContentLength >= 0 {
+ if r.Headers == nil {
+ r.Headers = map[string]string{}
+ }
+ r.Headers["Content-Length"] = strconv.FormatInt(r.ContentLength, 10)
+ }
+ r.writeHeaders(w, r.Headers)
+ _, err = io.Copy(w, r.Reader)
+ return
+}
+
+// WriteContentType (Reader) writes custom ContentType.
+func (r Reader) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, []string{r.ContentType})
+}
+
+// writeHeaders writes custom Header.
+func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) {
+ header := w.Header()
+ for k, v := range headers {
+ if header.Get(k) == "" {
+ header.Set(k, v)
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/redirect.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/redirect.go
new file mode 100644
index 000000000000..c006691ca635
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/redirect.go
@@ -0,0 +1,29 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "fmt"
+ "net/http"
+)
+
+// Redirect contains the http request reference and redirects status code and location.
+type Redirect struct {
+ Code int
+ Request *http.Request
+ Location string
+}
+
+// Render (Redirect) redirects the http request to new location and writes redirect response.
+func (r Redirect) Render(w http.ResponseWriter) error {
+ if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated {
+ panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
+ }
+ http.Redirect(w, r.Request, r.Location, r.Code)
+ return nil
+}
+
+// WriteContentType (Redirect) don't write any ContentType.
+func (r Redirect) WriteContentType(http.ResponseWriter) {}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/render.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/render.go
new file mode 100644
index 000000000000..bcd568bfba7a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/render.go
@@ -0,0 +1,40 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import "net/http"
+
+// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
+type Render interface {
+ // Render writes data with custom ContentType.
+ Render(http.ResponseWriter) error
+ // WriteContentType writes custom ContentType.
+ WriteContentType(w http.ResponseWriter)
+}
+
+var (
+ _ Render = JSON{}
+ _ Render = IndentedJSON{}
+ _ Render = SecureJSON{}
+ _ Render = JsonpJSON{}
+ _ Render = XML{}
+ _ Render = String{}
+ _ Render = Redirect{}
+ _ Render = Data{}
+ _ Render = HTML{}
+ _ HTMLRender = HTMLDebug{}
+ _ HTMLRender = HTMLProduction{}
+ _ Render = YAML{}
+ _ Render = Reader{}
+ _ Render = AsciiJSON{}
+ _ Render = ProtoBuf{}
+)
+
+func writeContentType(w http.ResponseWriter, value []string) {
+ header := w.Header()
+ if val := header["Content-Type"]; len(val) == 0 {
+ header["Content-Type"] = value
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/text.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/text.go
new file mode 100644
index 000000000000..461b720af5ed
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/text.go
@@ -0,0 +1,41 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/gin-gonic/gin/internal/bytesconv"
+)
+
+// String contains the given interface object slice and its format.
+type String struct {
+ Format string
+ Data []interface{}
+}
+
+var plainContentType = []string{"text/plain; charset=utf-8"}
+
+// Render (String) writes data with custom ContentType.
+func (r String) Render(w http.ResponseWriter) error {
+ return WriteString(w, r.Format, r.Data)
+}
+
+// WriteContentType (String) writes Plain ContentType.
+func (r String) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, plainContentType)
+}
+
+// WriteString writes data according to its format and write custom ContentType.
+func WriteString(w http.ResponseWriter, format string, data []interface{}) (err error) {
+ writeContentType(w, plainContentType)
+ if len(data) > 0 {
+ _, err = fmt.Fprintf(w, format, data...)
+ return
+ }
+ _, err = w.Write(bytesconv.StringToBytes(format))
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/xml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/xml.go
new file mode 100644
index 000000000000..cc5390a2d05b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/xml.go
@@ -0,0 +1,28 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "encoding/xml"
+ "net/http"
+)
+
+// XML contains the given interface object.
+type XML struct {
+ Data interface{}
+}
+
+var xmlContentType = []string{"application/xml; charset=utf-8"}
+
+// Render (XML) encodes the given interface object and writes data with custom ContentType.
+func (r XML) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+ return xml.NewEncoder(w).Encode(r.Data)
+}
+
+// WriteContentType (XML) writes XML ContentType for response.
+func (r XML) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, xmlContentType)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/yaml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/yaml.go
new file mode 100644
index 000000000000..0df78360893c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/render/yaml.go
@@ -0,0 +1,36 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package render
+
+import (
+ "net/http"
+
+ "gopkg.in/yaml.v2"
+)
+
+// YAML contains the given interface object.
+type YAML struct {
+ Data interface{}
+}
+
+var yamlContentType = []string{"application/x-yaml; charset=utf-8"}
+
+// Render (YAML) marshals the given interface object and writes data with custom ContentType.
+func (r YAML) Render(w http.ResponseWriter) error {
+ r.WriteContentType(w)
+
+ bytes, err := yaml.Marshal(r.Data)
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(bytes)
+ return err
+}
+
+// WriteContentType (YAML) writes YAML ContentType for response.
+func (r YAML) WriteContentType(w http.ResponseWriter) {
+ writeContentType(w, yamlContentType)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/response_writer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/response_writer.go
new file mode 100644
index 000000000000..26826689a5cf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/response_writer.go
@@ -0,0 +1,126 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+)
+
+const (
+ noWritten = -1
+ defaultStatus = http.StatusOK
+)
+
+// ResponseWriter ...
+type ResponseWriter interface {
+ http.ResponseWriter
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+
+ // Returns the HTTP response status code of the current request.
+ Status() int
+
+ // Returns the number of bytes already written into the response http body.
+ // See Written()
+ Size() int
+
+ // Writes the string into the response body.
+ WriteString(string) (int, error)
+
+ // Returns true if the response body was already written.
+ Written() bool
+
+ // Forces to write the http header (status code + headers).
+ WriteHeaderNow()
+
+ // get the http.Pusher for server push
+ Pusher() http.Pusher
+}
+
+type responseWriter struct {
+ http.ResponseWriter
+ size int
+ status int
+}
+
+var _ ResponseWriter = &responseWriter{}
+
+func (w *responseWriter) reset(writer http.ResponseWriter) {
+ w.ResponseWriter = writer
+ w.size = noWritten
+ w.status = defaultStatus
+}
+
+func (w *responseWriter) WriteHeader(code int) {
+ if code > 0 && w.status != code {
+ if w.Written() {
+ debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code)
+ }
+ w.status = code
+ }
+}
+
+func (w *responseWriter) WriteHeaderNow() {
+ if !w.Written() {
+ w.size = 0
+ w.ResponseWriter.WriteHeader(w.status)
+ }
+}
+
+func (w *responseWriter) Write(data []byte) (n int, err error) {
+ w.WriteHeaderNow()
+ n, err = w.ResponseWriter.Write(data)
+ w.size += n
+ return
+}
+
+func (w *responseWriter) WriteString(s string) (n int, err error) {
+ w.WriteHeaderNow()
+ n, err = io.WriteString(w.ResponseWriter, s)
+ w.size += n
+ return
+}
+
+func (w *responseWriter) Status() int {
+ return w.status
+}
+
+func (w *responseWriter) Size() int {
+ return w.size
+}
+
+func (w *responseWriter) Written() bool {
+ return w.size != noWritten
+}
+
+// Hijack implements the http.Hijacker interface.
+func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ if w.size < 0 {
+ w.size = 0
+ }
+ return w.ResponseWriter.(http.Hijacker).Hijack()
+}
+
+// CloseNotify implements the http.CloseNotify interface.
+func (w *responseWriter) CloseNotify() <-chan bool {
+ return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
+
+// Flush implements the http.Flush interface.
+func (w *responseWriter) Flush() {
+ w.WriteHeaderNow()
+ w.ResponseWriter.(http.Flusher).Flush()
+}
+
+func (w *responseWriter) Pusher() (pusher http.Pusher) {
+ if pusher, ok := w.ResponseWriter.(http.Pusher); ok {
+ return pusher
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/routergroup.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/routergroup.go
new file mode 100644
index 000000000000..15d9930d3d14
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/routergroup.go
@@ -0,0 +1,230 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "net/http"
+ "path"
+ "regexp"
+ "strings"
+)
+
+// IRouter defines all router handle interface includes single and group router.
+type IRouter interface {
+ IRoutes
+ Group(string, ...HandlerFunc) *RouterGroup
+}
+
+// IRoutes defines all router handle interface.
+type IRoutes interface {
+ Use(...HandlerFunc) IRoutes
+
+ Handle(string, string, ...HandlerFunc) IRoutes
+ Any(string, ...HandlerFunc) IRoutes
+ GET(string, ...HandlerFunc) IRoutes
+ POST(string, ...HandlerFunc) IRoutes
+ DELETE(string, ...HandlerFunc) IRoutes
+ PATCH(string, ...HandlerFunc) IRoutes
+ PUT(string, ...HandlerFunc) IRoutes
+ OPTIONS(string, ...HandlerFunc) IRoutes
+ HEAD(string, ...HandlerFunc) IRoutes
+
+ StaticFile(string, string) IRoutes
+ Static(string, string) IRoutes
+ StaticFS(string, http.FileSystem) IRoutes
+}
+
+// RouterGroup is used internally to configure router, a RouterGroup is associated with
+// a prefix and an array of handlers (middleware).
+type RouterGroup struct {
+ Handlers HandlersChain
+ basePath string
+ engine *Engine
+ root bool
+}
+
+var _ IRouter = &RouterGroup{}
+
+// Use adds middleware to the group, see example code in GitHub.
+func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
+ group.Handlers = append(group.Handlers, middleware...)
+ return group.returnObj()
+}
+
+// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
+// For example, all the routes that use a common middleware for authorization could be grouped.
+func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
+ return &RouterGroup{
+ Handlers: group.combineHandlers(handlers),
+ basePath: group.calculateAbsolutePath(relativePath),
+ engine: group.engine,
+ }
+}
+
+// BasePath returns the base path of router group.
+// For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api".
+func (group *RouterGroup) BasePath() string {
+ return group.basePath
+}
+
+func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
+ absolutePath := group.calculateAbsolutePath(relativePath)
+ handlers = group.combineHandlers(handlers)
+ group.engine.addRoute(httpMethod, absolutePath, handlers)
+ return group.returnObj()
+}
+
+// Handle registers a new request handle and middleware with the given path and method.
+// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes.
+// See the example code in GitHub.
+//
+// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
+// functions can be used.
+//
+// This function is intended for bulk loading and to allow the usage of less
+// frequently used, non-standardized or custom methods (e.g. for internal
+// communication with a proxy).
+func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
+ if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil {
+ panic("http method " + httpMethod + " is not valid")
+ }
+ return group.handle(httpMethod, relativePath, handlers)
+}
+
+// POST is a shortcut for router.Handle("POST", path, handle).
+func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodPost, relativePath, handlers)
+}
+
+// GET is a shortcut for router.Handle("GET", path, handle).
+func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodGet, relativePath, handlers)
+}
+
+// DELETE is a shortcut for router.Handle("DELETE", path, handle).
+func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodDelete, relativePath, handlers)
+}
+
+// PATCH is a shortcut for router.Handle("PATCH", path, handle).
+func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodPatch, relativePath, handlers)
+}
+
+// PUT is a shortcut for router.Handle("PUT", path, handle).
+func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodPut, relativePath, handlers)
+}
+
+// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle).
+func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodOptions, relativePath, handlers)
+}
+
+// HEAD is a shortcut for router.Handle("HEAD", path, handle).
+func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
+ return group.handle(http.MethodHead, relativePath, handlers)
+}
+
+// Any registers a route that matches all the HTTP methods.
+// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
+func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes {
+ group.handle(http.MethodGet, relativePath, handlers)
+ group.handle(http.MethodPost, relativePath, handlers)
+ group.handle(http.MethodPut, relativePath, handlers)
+ group.handle(http.MethodPatch, relativePath, handlers)
+ group.handle(http.MethodHead, relativePath, handlers)
+ group.handle(http.MethodOptions, relativePath, handlers)
+ group.handle(http.MethodDelete, relativePath, handlers)
+ group.handle(http.MethodConnect, relativePath, handlers)
+ group.handle(http.MethodTrace, relativePath, handlers)
+ return group.returnObj()
+}
+
+// StaticFile registers a single route in order to serve a single file of the local filesystem.
+// router.StaticFile("favicon.ico", "./resources/favicon.ico")
+func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
+ if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
+ panic("URL parameters can not be used when serving a static file")
+ }
+ handler := func(c *Context) {
+ c.File(filepath)
+ }
+ group.GET(relativePath, handler)
+ group.HEAD(relativePath, handler)
+ return group.returnObj()
+}
+
+// Static serves files from the given file system root.
+// Internally a http.FileServer is used, therefore http.NotFound is used instead
+// of the Router's NotFound handler.
+// To use the operating system's file system implementation,
+// use :
+// router.Static("/static", "/var/www")
+func (group *RouterGroup) Static(relativePath, root string) IRoutes {
+ return group.StaticFS(relativePath, Dir(root, false))
+}
+
+// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead.
+// Gin by default user: gin.Dir()
+func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
+ if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
+ panic("URL parameters can not be used when serving a static folder")
+ }
+ handler := group.createStaticHandler(relativePath, fs)
+ urlPattern := path.Join(relativePath, "/*filepath")
+
+ // Register GET and HEAD handlers
+ group.GET(urlPattern, handler)
+ group.HEAD(urlPattern, handler)
+ return group.returnObj()
+}
+
+func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
+ absolutePath := group.calculateAbsolutePath(relativePath)
+ fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
+
+ return func(c *Context) {
+ if _, noListing := fs.(*onlyFilesFS); noListing {
+ c.Writer.WriteHeader(http.StatusNotFound)
+ }
+
+ file := c.Param("filepath")
+ // Check if file exists and/or if we have permission to access it
+ f, err := fs.Open(file)
+ if err != nil {
+ c.Writer.WriteHeader(http.StatusNotFound)
+ c.handlers = group.engine.noRoute
+ // Reset index
+ c.index = -1
+ return
+ }
+ f.Close()
+
+ fileServer.ServeHTTP(c.Writer, c.Request)
+ }
+}
+
+func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
+ finalSize := len(group.Handlers) + len(handlers)
+ if finalSize >= int(abortIndex) {
+ panic("too many handlers")
+ }
+ mergedHandlers := make(HandlersChain, finalSize)
+ copy(mergedHandlers, group.Handlers)
+ copy(mergedHandlers[len(group.Handlers):], handlers)
+ return mergedHandlers
+}
+
+func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
+ return joinPaths(group.basePath, relativePath)
+}
+
+func (group *RouterGroup) returnObj() IRoutes {
+ if group.root {
+ return group.engine
+ }
+ return group
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go
deleted file mode 100644
index 79c7a98ec0b2..000000000000
--- a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go
+++ /dev/null
@@ -1,682 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/gin-gonic/gin, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/gin-gonic/gin (exports: Context; functions: New)
-
-// Package gin is a stub of github.com/gin-gonic/gin, generated by depstubber.
-package gin
-
-import (
- bufio "bufio"
- template "html/template"
- io "io"
- multipart "mime/multipart"
- net "net"
- http "net/http"
- template0 "text/template"
- time "time"
-)
-
-type Context struct {
- Request *http.Request
- Writer ResponseWriter
- Params Params
- Keys map[string]interface{}
- Errors interface{}
- Accepted []string
-}
-
-func (_ *Context) Abort() {}
-
-func (_ *Context) AbortWithError(_ int, _ error) *Error {
- return nil
-}
-
-func (_ *Context) AbortWithStatus(_ int) {}
-
-func (_ *Context) AbortWithStatusJSON(_ int, _ interface{}) {}
-
-func (_ *Context) AsciiJSON(_ int, _ interface{}) {}
-
-func (_ *Context) Bind(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindHeader(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindJSON(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindQuery(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindUri(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindWith(_ interface{}, _ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindXML(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) BindYAML(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ClientIP() string {
- return ""
-}
-
-func (_ *Context) ContentType() string {
- return ""
-}
-
-func (_ *Context) Cookie(_ string) (string, error) {
- return "", nil
-}
-
-func (_ *Context) Copy() *Context {
- return nil
-}
-
-func (_ *Context) Data(_ int, _ string, _ []byte) {}
-
-func (_ *Context) DataFromReader(_ int, _ int64, _ string, _ io.Reader, _ map[string]string) {}
-
-func (_ *Context) Deadline() (time.Time, bool) {
- return time.Time{}, false
-}
-
-func (_ *Context) DefaultPostForm(_ string, _ string) string {
- return ""
-}
-
-func (_ *Context) DefaultQuery(_ string, _ string) string {
- return ""
-}
-
-func (_ *Context) Done() <-chan struct{} {
- return nil
-}
-
-func (_ *Context) Err() error {
- return nil
-}
-
-func (_ *Context) Error(_ error) *Error {
- return nil
-}
-
-func (_ *Context) File(_ string) {}
-
-func (_ *Context) FileAttachment(_ string, _ string) {}
-
-func (_ *Context) FileFromFS(_ string, _ http.FileSystem) {}
-
-func (_ *Context) FormFile(_ string) (*multipart.FileHeader, error) {
- return nil, nil
-}
-
-func (_ *Context) FullPath() string {
- return ""
-}
-
-func (_ *Context) Get(_ string) (interface{}, bool) {
- return nil, false
-}
-
-func (_ *Context) GetBool(_ string) bool {
- return false
-}
-
-func (_ *Context) GetDuration(_ string) time.Duration {
- return 0
-}
-
-func (_ *Context) GetFloat64(_ string) float64 {
- return 0
-}
-
-func (_ *Context) GetHeader(_ string) string {
- return ""
-}
-
-func (_ *Context) GetInt(_ string) int {
- return 0
-}
-
-func (_ *Context) GetInt64(_ string) int64 {
- return 0
-}
-
-func (_ *Context) GetPostForm(_ string) (string, bool) {
- return "", false
-}
-
-func (_ *Context) GetPostFormArray(_ string) ([]string, bool) {
- return nil, false
-}
-
-func (_ *Context) GetPostFormMap(_ string) (map[string]string, bool) {
- return nil, false
-}
-
-func (_ *Context) GetQuery(_ string) (string, bool) {
- return "", false
-}
-
-func (_ *Context) GetQueryArray(_ string) ([]string, bool) {
- return nil, false
-}
-
-func (_ *Context) GetQueryMap(_ string) (map[string]string, bool) {
- return nil, false
-}
-
-func (_ *Context) GetRawData() ([]byte, error) {
- return nil, nil
-}
-
-func (_ *Context) GetString(_ string) string {
- return ""
-}
-
-func (_ *Context) GetStringMap(_ string) map[string]interface{} {
- return nil
-}
-
-func (_ *Context) GetStringMapString(_ string) map[string]string {
- return nil
-}
-
-func (_ *Context) GetStringMapStringSlice(_ string) map[string][]string {
- return nil
-}
-
-func (_ *Context) GetStringSlice(_ string) []string {
- return nil
-}
-
-func (_ *Context) GetTime(_ string) time.Time {
- return time.Time{}
-}
-
-func (_ *Context) GetUint(_ string) uint {
- return 0
-}
-
-func (_ *Context) GetUint64(_ string) uint64 {
- return 0
-}
-
-func (_ *Context) HTML(_ int, _ string, _ interface{}) {}
-
-func (_ *Context) Handler() HandlerFunc {
- return nil
-}
-
-func (_ *Context) HandlerName() string {
- return ""
-}
-
-func (_ *Context) HandlerNames() []string {
- return nil
-}
-
-func (_ *Context) Header(_ string, _ string) {}
-
-func (_ *Context) IndentedJSON(_ int, _ interface{}) {}
-
-func (_ *Context) IsAborted() bool {
- return false
-}
-
-func (_ *Context) IsWebsocket() bool {
- return false
-}
-
-func (_ *Context) JSON(_ int, _ interface{}) {}
-
-func (_ *Context) JSONP(_ int, _ interface{}) {}
-
-func (_ *Context) MultipartForm() (*multipart.Form, error) {
- return nil, nil
-}
-
-func (_ *Context) MustBindWith(_ interface{}, _ interface{}) error {
- return nil
-}
-
-func (_ *Context) MustGet(_ string) interface{} {
- return nil
-}
-
-func (_ *Context) Negotiate(_ int, _ Negotiate) {}
-
-func (_ *Context) NegotiateFormat(_ ...string) string {
- return ""
-}
-
-func (_ *Context) Next() {}
-
-func (_ *Context) Param(_ string) string {
- return ""
-}
-
-func (_ *Context) PostForm(_ string) string {
- return ""
-}
-
-func (_ *Context) PostFormArray(_ string) []string {
- return nil
-}
-
-func (_ *Context) PostFormMap(_ string) map[string]string {
- return nil
-}
-
-func (_ *Context) ProtoBuf(_ int, _ interface{}) {}
-
-func (_ *Context) PureJSON(_ int, _ interface{}) {}
-
-func (_ *Context) Query(_ string) string {
- return ""
-}
-
-func (_ *Context) QueryArray(_ string) []string {
- return nil
-}
-
-func (_ *Context) QueryMap(_ string) map[string]string {
- return nil
-}
-
-func (_ *Context) Redirect(_ int, _ string) {}
-
-func (_ *Context) RemoteIP() (net.IP, bool) {
- return nil, false
-}
-
-func (_ *Context) Render(_ int, _ interface{}) {}
-
-func (_ *Context) SSEvent(_ string, _ interface{}) {}
-
-func (_ *Context) SaveUploadedFile(_ *multipart.FileHeader, _ string) error {
- return nil
-}
-
-func (_ *Context) SecureJSON(_ int, _ interface{}) {}
-
-func (_ *Context) Set(_ string, _ interface{}) {}
-
-func (_ *Context) SetAccepted(_ ...string) {}
-
-func (_ *Context) SetCookie(_ string, _ string, _ int, _ string, _ string, _ bool, _ bool) {}
-
-func (_ *Context) SetSameSite(_ http.SameSite) {}
-
-func (_ *Context) ShouldBind(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindBodyWith(_ interface{}, _ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindHeader(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindJSON(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindQuery(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindUri(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindWith(_ interface{}, _ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindXML(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) ShouldBindYAML(_ interface{}) error {
- return nil
-}
-
-func (_ *Context) Status(_ int) {}
-
-func (_ *Context) Stream(_ func(io.Writer) bool) bool {
- return false
-}
-
-func (_ *Context) String(_ int, _ string, _ ...interface{}) {}
-
-func (_ *Context) Value(_ interface{}) interface{} {
- return nil
-}
-
-func (_ *Context) XML(_ int, _ interface{}) {}
-
-func (_ *Context) YAML(_ int, _ interface{}) {}
-
-type Engine struct {
- RouterGroup RouterGroup
- RedirectTrailingSlash bool
- RedirectFixedPath bool
- HandleMethodNotAllowed bool
- ForwardedByClientIP bool
- AppEngine bool
- UseRawPath bool
- UnescapePathValues bool
- RemoveExtraSlash bool
- RemoteIPHeaders []string
- TrustedPlatform string
- MaxMultipartMemory int64
- HTMLRender interface{}
- FuncMap template0.FuncMap
-}
-
-func (_ *Engine) Any(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) BasePath() string {
- return ""
-}
-
-func (_ *Engine) DELETE(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) Delims(_ string, _ string) *Engine {
- return nil
-}
-
-func (_ *Engine) GET(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) Group(_ string, _ ...HandlerFunc) *RouterGroup {
- return nil
-}
-
-func (_ *Engine) HEAD(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) Handle(_ string, _ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) HandleContext(_ *Context) {}
-
-func (_ *Engine) LoadHTMLFiles(_ ...string) {}
-
-func (_ *Engine) LoadHTMLGlob(_ string) {}
-
-func (_ *Engine) NoMethod(_ ...HandlerFunc) {}
-
-func (_ *Engine) NoRoute(_ ...HandlerFunc) {}
-
-func (_ *Engine) OPTIONS(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) PATCH(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) POST(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) PUT(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *Engine) Routes() RoutesInfo {
- return nil
-}
-
-func (_ *Engine) Run(_ ...string) error {
- return nil
-}
-
-func (_ *Engine) RunFd(_ int) error {
- return nil
-}
-
-func (_ *Engine) RunListener(_ net.Listener) error {
- return nil
-}
-
-func (_ *Engine) RunTLS(_ string, _ string, _ string) error {
- return nil
-}
-
-func (_ *Engine) RunUnix(_ string) error {
- return nil
-}
-
-func (_ *Engine) SecureJsonPrefix(_ string) *Engine {
- return nil
-}
-
-func (_ *Engine) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {}
-
-func (_ *Engine) SetFuncMap(_ template0.FuncMap) {}
-
-func (_ *Engine) SetHTMLTemplate(_ *template.Template) {}
-
-func (_ *Engine) SetTrustedProxies(_ []string) error {
- return nil
-}
-
-func (_ *Engine) Static(_ string, _ string) IRoutes {
- return nil
-}
-
-func (_ *Engine) StaticFS(_ string, _ http.FileSystem) IRoutes {
- return nil
-}
-
-func (_ *Engine) StaticFile(_ string, _ string) IRoutes {
- return nil
-}
-
-func (_ *Engine) Use(_ ...HandlerFunc) IRoutes {
- return nil
-}
-
-type Error struct {
- Err error
- Type ErrorType
- Meta interface{}
-}
-
-func (_ Error) Error() string {
- return ""
-}
-
-func (_ *Error) IsType(_ ErrorType) bool {
- return false
-}
-
-func (_ *Error) JSON() interface{} {
- return nil
-}
-
-func (_ *Error) MarshalJSON() ([]byte, error) {
- return nil, nil
-}
-
-func (_ *Error) SetMeta(_ interface{}) *Error {
- return nil
-}
-
-func (_ *Error) SetType(_ ErrorType) *Error {
- return nil
-}
-
-func (_ *Error) Unwrap() error {
- return nil
-}
-
-type ErrorType uint64
-
-type HandlerFunc func(*Context)
-
-type HandlersChain []HandlerFunc
-
-func (_ HandlersChain) Last() HandlerFunc {
- return nil
-}
-
-type IRoutes interface {
- Any(_ string, _ ...HandlerFunc) IRoutes
- DELETE(_ string, _ ...HandlerFunc) IRoutes
- GET(_ string, _ ...HandlerFunc) IRoutes
- HEAD(_ string, _ ...HandlerFunc) IRoutes
- Handle(_ string, _ string, _ ...HandlerFunc) IRoutes
- OPTIONS(_ string, _ ...HandlerFunc) IRoutes
- PATCH(_ string, _ ...HandlerFunc) IRoutes
- POST(_ string, _ ...HandlerFunc) IRoutes
- PUT(_ string, _ ...HandlerFunc) IRoutes
- Static(_ string, _ string) IRoutes
- StaticFS(_ string, _ http.FileSystem) IRoutes
- StaticFile(_ string, _ string) IRoutes
- Use(_ ...HandlerFunc) IRoutes
-}
-
-type Negotiate struct {
- Offered []string
- HTMLName string
- HTMLData interface{}
- JSONData interface{}
- XMLData interface{}
- YAMLData interface{}
- Data interface{}
-}
-
-func New() *Engine {
- return nil
-}
-
-type Param struct {
- Key string
- Value string
-}
-
-type Params []Param
-
-func (_ Params) ByName(_ string) string {
- return ""
-}
-
-func (_ Params) Get(_ string) (string, bool) {
- return "", false
-}
-
-type ResponseWriter interface {
- CloseNotify() <-chan bool
- Flush()
- Header() http.Header
- Hijack() (net.Conn, *bufio.ReadWriter, error)
- Pusher() http.Pusher
- Size() int
- Status() int
- Write(_ []byte) (int, error)
- WriteHeader(_ int)
- WriteHeaderNow()
- WriteString(_ string) (int, error)
- Written() bool
-}
-
-type RouteInfo struct {
- Method string
- Path string
- Handler string
- HandlerFunc HandlerFunc
-}
-
-type RouterGroup struct {
- Handlers HandlersChain
-}
-
-func (_ *RouterGroup) Any(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) BasePath() string {
- return ""
-}
-
-func (_ *RouterGroup) DELETE(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) GET(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) Group(_ string, _ ...HandlerFunc) *RouterGroup {
- return nil
-}
-
-func (_ *RouterGroup) HEAD(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) Handle(_ string, _ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) OPTIONS(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) PATCH(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) POST(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) PUT(_ string, _ ...HandlerFunc) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) Static(_ string, _ string) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) StaticFS(_ string, _ http.FileSystem) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) StaticFile(_ string, _ string) IRoutes {
- return nil
-}
-
-func (_ *RouterGroup) Use(_ ...HandlerFunc) IRoutes {
- return nil
-}
-
-type RoutesInfo []RouteInfo
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/test_helpers.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/test_helpers.go
new file mode 100644
index 000000000000..3a7a5ddf69c3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/test_helpers.go
@@ -0,0 +1,16 @@
+// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import "net/http"
+
+// CreateTestContext returns a fresh engine and context for testing purposes
+func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) {
+ r = New()
+ c = r.allocateContext()
+ c.reset()
+ c.writermem.reset(w)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/tree.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/tree.go
new file mode 100644
index 000000000000..158a3390892d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/tree.go
@@ -0,0 +1,867 @@
+// Copyright 2013 Julien Schmidt. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE
+
+package gin
+
+import (
+ "bytes"
+ "net/url"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/gin-gonic/gin/internal/bytesconv"
+)
+
+var (
+ strColon = []byte(":")
+ strStar = []byte("*")
+ strSlash = []byte("/")
+)
+
+// Param is a single URL parameter, consisting of a key and a value.
+type Param struct {
+ Key string
+ Value string
+}
+
+// Params is a Param-slice, as returned by the router.
+// The slice is ordered, the first URL parameter is also the first slice value.
+// It is therefore safe to read values by the index.
+type Params []Param
+
+// Get returns the value of the first Param which key matches the given name.
+// If no matching Param is found, an empty string is returned.
+func (ps Params) Get(name string) (string, bool) {
+ for _, entry := range ps {
+ if entry.Key == name {
+ return entry.Value, true
+ }
+ }
+ return "", false
+}
+
+// ByName returns the value of the first Param which key matches the given name.
+// If no matching Param is found, an empty string is returned.
+func (ps Params) ByName(name string) (va string) {
+ va, _ = ps.Get(name)
+ return
+}
+
+type methodTree struct {
+ method string
+ root *node
+}
+
+type methodTrees []methodTree
+
+func (trees methodTrees) get(method string) *node {
+ for _, tree := range trees {
+ if tree.method == method {
+ return tree.root
+ }
+ }
+ return nil
+}
+
+func min(a, b int) int {
+ if a <= b {
+ return a
+ }
+ return b
+}
+
+func longestCommonPrefix(a, b string) int {
+ i := 0
+ max := min(len(a), len(b))
+ for i < max && a[i] == b[i] {
+ i++
+ }
+ return i
+}
+
+// addChild will add a child node, keeping wildcards at the end
+func (n *node) addChild(child *node) {
+ if n.wildChild && len(n.children) > 0 {
+ wildcardChild := n.children[len(n.children)-1]
+ n.children = append(n.children[:len(n.children)-1], child, wildcardChild)
+ } else {
+ n.children = append(n.children, child)
+ }
+}
+
+func countParams(path string) uint16 {
+ var n uint16
+ s := bytesconv.StringToBytes(path)
+ n += uint16(bytes.Count(s, strColon))
+ n += uint16(bytes.Count(s, strStar))
+ return n
+}
+
+func countSections(path string) uint16 {
+ s := bytesconv.StringToBytes(path)
+ return uint16(bytes.Count(s, strSlash))
+}
+
+type nodeType uint8
+
+const (
+ static nodeType = iota // default
+ root
+ param
+ catchAll
+)
+
+type node struct {
+ path string
+ indices string
+ wildChild bool
+ nType nodeType
+ priority uint32
+ children []*node // child nodes, at most 1 :param style node at the end of the array
+ handlers HandlersChain
+ fullPath string
+}
+
+// Increments priority of the given child and reorders if necessary
+func (n *node) incrementChildPrio(pos int) int {
+ cs := n.children
+ cs[pos].priority++
+ prio := cs[pos].priority
+
+ // Adjust position (move to front)
+ newPos := pos
+ for ; newPos > 0 && cs[newPos-1].priority < prio; newPos-- {
+ // Swap node positions
+ cs[newPos-1], cs[newPos] = cs[newPos], cs[newPos-1]
+ }
+
+ // Build new index char string
+ if newPos != pos {
+ n.indices = n.indices[:newPos] + // Unchanged prefix, might be empty
+ n.indices[pos:pos+1] + // The index char we move
+ n.indices[newPos:pos] + n.indices[pos+1:] // Rest without char at 'pos'
+ }
+
+ return newPos
+}
+
+// addRoute adds a node with the given handle to the path.
+// Not concurrency-safe!
+func (n *node) addRoute(path string, handlers HandlersChain) {
+ fullPath := path
+ n.priority++
+
+ // Empty tree
+ if len(n.path) == 0 && len(n.children) == 0 {
+ n.insertChild(path, fullPath, handlers)
+ n.nType = root
+ return
+ }
+
+ parentFullPathIndex := 0
+
+walk:
+ for {
+ // Find the longest common prefix.
+ // This also implies that the common prefix contains no ':' or '*'
+ // since the existing key can't contain those chars.
+ i := longestCommonPrefix(path, n.path)
+
+ // Split edge
+ if i < len(n.path) {
+ child := node{
+ path: n.path[i:],
+ wildChild: n.wildChild,
+ indices: n.indices,
+ children: n.children,
+ handlers: n.handlers,
+ priority: n.priority - 1,
+ fullPath: n.fullPath,
+ }
+
+ n.children = []*node{&child}
+ // []byte for proper unicode char conversion, see #65
+ n.indices = bytesconv.BytesToString([]byte{n.path[i]})
+ n.path = path[:i]
+ n.handlers = nil
+ n.wildChild = false
+ n.fullPath = fullPath[:parentFullPathIndex+i]
+ }
+
+ // Make new node a child of this node
+ if i < len(path) {
+ path = path[i:]
+ c := path[0]
+
+ // '/' after param
+ if n.nType == param && c == '/' && len(n.children) == 1 {
+ parentFullPathIndex += len(n.path)
+ n = n.children[0]
+ n.priority++
+ continue walk
+ }
+
+ // Check if a child with the next path byte exists
+ for i, max := 0, len(n.indices); i < max; i++ {
+ if c == n.indices[i] {
+ parentFullPathIndex += len(n.path)
+ i = n.incrementChildPrio(i)
+ n = n.children[i]
+ continue walk
+ }
+ }
+
+ // Otherwise insert it
+ if c != ':' && c != '*' && n.nType != catchAll {
+ // []byte for proper unicode char conversion, see #65
+ n.indices += bytesconv.BytesToString([]byte{c})
+ child := &node{
+ fullPath: fullPath,
+ }
+ n.addChild(child)
+ n.incrementChildPrio(len(n.indices) - 1)
+ n = child
+ } else if n.wildChild {
+ // inserting a wildcard node, need to check if it conflicts with the existing wildcard
+ n = n.children[len(n.children)-1]
+ n.priority++
+
+ // Check if the wildcard matches
+ if len(path) >= len(n.path) && n.path == path[:len(n.path)] &&
+ // Adding a child to a catchAll is not possible
+ n.nType != catchAll &&
+ // Check for longer wildcard, e.g. :name and :names
+ (len(n.path) >= len(path) || path[len(n.path)] == '/') {
+ continue walk
+ }
+
+ // Wildcard conflict
+ pathSeg := path
+ if n.nType != catchAll {
+ pathSeg = strings.SplitN(pathSeg, "/", 2)[0]
+ }
+ prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path
+ panic("'" + pathSeg +
+ "' in new path '" + fullPath +
+ "' conflicts with existing wildcard '" + n.path +
+ "' in existing prefix '" + prefix +
+ "'")
+ }
+
+ n.insertChild(path, fullPath, handlers)
+ return
+ }
+
+ // Otherwise add handle to current node
+ if n.handlers != nil {
+ panic("handlers are already registered for path '" + fullPath + "'")
+ }
+ n.handlers = handlers
+ n.fullPath = fullPath
+ return
+ }
+}
+
+// Search for a wildcard segment and check the name for invalid characters.
+// Returns -1 as index, if no wildcard was found.
+func findWildcard(path string) (wildcard string, i int, valid bool) {
+ // Find start
+ for start, c := range []byte(path) {
+ // A wildcard starts with ':' (param) or '*' (catch-all)
+ if c != ':' && c != '*' {
+ continue
+ }
+
+ // Find end and check for invalid characters
+ valid = true
+ for end, c := range []byte(path[start+1:]) {
+ switch c {
+ case '/':
+ return path[start : start+1+end], start, valid
+ case ':', '*':
+ valid = false
+ }
+ }
+ return path[start:], start, valid
+ }
+ return "", -1, false
+}
+
+func (n *node) insertChild(path string, fullPath string, handlers HandlersChain) {
+ for {
+ // Find prefix until first wildcard
+ wildcard, i, valid := findWildcard(path)
+ if i < 0 { // No wildcard found
+ break
+ }
+
+ // The wildcard name must not contain ':' and '*'
+ if !valid {
+ panic("only one wildcard per path segment is allowed, has: '" +
+ wildcard + "' in path '" + fullPath + "'")
+ }
+
+ // check if the wildcard has a name
+ if len(wildcard) < 2 {
+ panic("wildcards must be named with a non-empty name in path '" + fullPath + "'")
+ }
+
+ if wildcard[0] == ':' { // param
+ if i > 0 {
+ // Insert prefix before the current wildcard
+ n.path = path[:i]
+ path = path[i:]
+ }
+
+ child := &node{
+ nType: param,
+ path: wildcard,
+ fullPath: fullPath,
+ }
+ n.addChild(child)
+ n.wildChild = true
+ n = child
+ n.priority++
+
+ // if the path doesn't end with the wildcard, then there
+ // will be another non-wildcard subpath starting with '/'
+ if len(wildcard) < len(path) {
+ path = path[len(wildcard):]
+
+ child := &node{
+ priority: 1,
+ fullPath: fullPath,
+ }
+ n.addChild(child)
+ n = child
+ continue
+ }
+
+ // Otherwise we're done. Insert the handle in the new leaf
+ n.handlers = handlers
+ return
+ }
+
+ // catchAll
+ if i+len(wildcard) != len(path) {
+ panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
+ }
+
+ if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
+ panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'")
+ }
+
+ // currently fixed width 1 for '/'
+ i--
+ if path[i] != '/' {
+ panic("no / before catch-all in path '" + fullPath + "'")
+ }
+
+ n.path = path[:i]
+
+ // First node: catchAll node with empty path
+ child := &node{
+ wildChild: true,
+ nType: catchAll,
+ fullPath: fullPath,
+ }
+
+ n.addChild(child)
+ n.indices = string('/')
+ n = child
+ n.priority++
+
+ // second node: node holding the variable
+ child = &node{
+ path: path[i:],
+ nType: catchAll,
+ handlers: handlers,
+ priority: 1,
+ fullPath: fullPath,
+ }
+ n.children = []*node{child}
+
+ return
+ }
+
+ // If no wildcard was found, simply insert the path and handle
+ n.path = path
+ n.handlers = handlers
+ n.fullPath = fullPath
+}
+
+// nodeValue holds return values of (*Node).getValue method
+type nodeValue struct {
+ handlers HandlersChain
+ params *Params
+ tsr bool
+ fullPath string
+}
+
+type skippedNode struct {
+ path string
+ node *node
+ paramsCount int16
+}
+
+// Returns the handle registered with the given path (key). The values of
+// wildcards are saved to a map.
+// If no handle can be found, a TSR (trailing slash redirect) recommendation is
+// made if a handle exists with an extra (without the) trailing slash for the
+// given path.
+func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) {
+ var globalParamsCount int16
+
+walk: // Outer loop for walking the tree
+ for {
+ prefix := n.path
+ if len(path) > len(prefix) {
+ if path[:len(prefix)] == prefix {
+ path = path[len(prefix):]
+
+ // Try all the non-wildcard children first by matching the indices
+ idxc := path[0]
+ for i, c := range []byte(n.indices) {
+ if c == idxc {
+ // strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild
+ if n.wildChild {
+ index := len(*skippedNodes)
+ *skippedNodes = (*skippedNodes)[:index+1]
+ (*skippedNodes)[index] = skippedNode{
+ path: prefix + path,
+ node: &node{
+ path: n.path,
+ wildChild: n.wildChild,
+ nType: n.nType,
+ priority: n.priority,
+ children: n.children,
+ handlers: n.handlers,
+ fullPath: n.fullPath,
+ },
+ paramsCount: globalParamsCount,
+ }
+ }
+
+ n = n.children[i]
+ continue walk
+ }
+ }
+
+ if !n.wildChild {
+ // If the path at the end of the loop is not equal to '/' and the current node has no child nodes
+ // the current node needs to roll back to last vaild skippedNode
+ if path != "/" {
+ for l := len(*skippedNodes); l > 0; {
+ skippedNode := (*skippedNodes)[l-1]
+ *skippedNodes = (*skippedNodes)[:l-1]
+ if strings.HasSuffix(skippedNode.path, path) {
+ path = skippedNode.path
+ n = skippedNode.node
+ if value.params != nil {
+ *value.params = (*value.params)[:skippedNode.paramsCount]
+ }
+ globalParamsCount = skippedNode.paramsCount
+ continue walk
+ }
+ }
+ }
+
+ // Nothing found.
+ // We can recommend to redirect to the same URL without a
+ // trailing slash if a leaf exists for that path.
+ value.tsr = path == "/" && n.handlers != nil
+ return
+ }
+
+ // Handle wildcard child, which is always at the end of the array
+ n = n.children[len(n.children)-1]
+ globalParamsCount++
+
+ switch n.nType {
+ case param:
+ // fix truncate the parameter
+ // tree_test.go line: 204
+
+ // Find param end (either '/' or path end)
+ end := 0
+ for end < len(path) && path[end] != '/' {
+ end++
+ }
+
+ // Save param value
+ if params != nil && cap(*params) > 0 {
+ if value.params == nil {
+ value.params = params
+ }
+ // Expand slice within preallocated capacity
+ i := len(*value.params)
+ *value.params = (*value.params)[:i+1]
+ val := path[:end]
+ if unescape {
+ if v, err := url.QueryUnescape(val); err == nil {
+ val = v
+ }
+ }
+ (*value.params)[i] = Param{
+ Key: n.path[1:],
+ Value: val,
+ }
+ }
+
+ // we need to go deeper!
+ if end < len(path) {
+ if len(n.children) > 0 {
+ path = path[end:]
+ n = n.children[0]
+ continue walk
+ }
+
+ // ... but we can't
+ value.tsr = len(path) == end+1
+ return
+ }
+
+ if value.handlers = n.handlers; value.handlers != nil {
+ value.fullPath = n.fullPath
+ return
+ }
+ if len(n.children) == 1 {
+ // No handle found. Check if a handle for this path + a
+ // trailing slash exists for TSR recommendation
+ n = n.children[0]
+ value.tsr = n.path == "/" && n.handlers != nil
+ }
+ return
+
+ case catchAll:
+ // Save param value
+ if params != nil {
+ if value.params == nil {
+ value.params = params
+ }
+ // Expand slice within preallocated capacity
+ i := len(*value.params)
+ *value.params = (*value.params)[:i+1]
+ val := path
+ if unescape {
+ if v, err := url.QueryUnescape(path); err == nil {
+ val = v
+ }
+ }
+ (*value.params)[i] = Param{
+ Key: n.path[2:],
+ Value: val,
+ }
+ }
+
+ value.handlers = n.handlers
+ value.fullPath = n.fullPath
+ return
+
+ default:
+ panic("invalid node type")
+ }
+ }
+ }
+
+ if path == prefix {
+ // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
+ // the current node needs to roll back to last vaild skippedNode
+ if n.handlers == nil && path != "/" {
+ for l := len(*skippedNodes); l > 0; {
+ skippedNode := (*skippedNodes)[l-1]
+ *skippedNodes = (*skippedNodes)[:l-1]
+ if strings.HasSuffix(skippedNode.path, path) {
+ path = skippedNode.path
+ n = skippedNode.node
+ if value.params != nil {
+ *value.params = (*value.params)[:skippedNode.paramsCount]
+ }
+ globalParamsCount = skippedNode.paramsCount
+ continue walk
+ }
+ }
+ // n = latestNode.children[len(latestNode.children)-1]
+ }
+ // We should have reached the node containing the handle.
+ // Check if this node has a handle registered.
+ if value.handlers = n.handlers; value.handlers != nil {
+ value.fullPath = n.fullPath
+ return
+ }
+
+ // If there is no handle for this route, but this route has a
+ // wildcard child, there must be a handle for this path with an
+ // additional trailing slash
+ if path == "/" && n.wildChild && n.nType != root {
+ value.tsr = true
+ return
+ }
+
+ // No handle found. Check if a handle for this path + a
+ // trailing slash exists for trailing slash recommendation
+ for i, c := range []byte(n.indices) {
+ if c == '/' {
+ n = n.children[i]
+ value.tsr = (len(n.path) == 1 && n.handlers != nil) ||
+ (n.nType == catchAll && n.children[0].handlers != nil)
+ return
+ }
+ }
+
+ return
+ }
+
+ // Nothing found. We can recommend to redirect to the same URL with an
+ // extra trailing slash if a leaf exists for that path
+ value.tsr = path == "/" ||
+ (len(prefix) == len(path)+1 && prefix[len(path)] == '/' &&
+ path == prefix[:len(prefix)-1] && n.handlers != nil)
+
+ // roll back to last valid skippedNode
+ if !value.tsr && path != "/" {
+ for l := len(*skippedNodes); l > 0; {
+ skippedNode := (*skippedNodes)[l-1]
+ *skippedNodes = (*skippedNodes)[:l-1]
+ if strings.HasSuffix(skippedNode.path, path) {
+ path = skippedNode.path
+ n = skippedNode.node
+ if value.params != nil {
+ *value.params = (*value.params)[:skippedNode.paramsCount]
+ }
+ globalParamsCount = skippedNode.paramsCount
+ continue walk
+ }
+ }
+ }
+
+ return
+ }
+}
+
+// Makes a case-insensitive lookup of the given path and tries to find a handler.
+// It can optionally also fix trailing slashes.
+// It returns the case-corrected path and a bool indicating whether the lookup
+// was successful.
+func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) ([]byte, bool) {
+ const stackBufSize = 128
+
+ // Use a static sized buffer on the stack in the common case.
+ // If the path is too long, allocate a buffer on the heap instead.
+ buf := make([]byte, 0, stackBufSize)
+ if length := len(path) + 1; length > stackBufSize {
+ buf = make([]byte, 0, length)
+ }
+
+ ciPath := n.findCaseInsensitivePathRec(
+ path,
+ buf, // Preallocate enough memory for new path
+ [4]byte{}, // Empty rune buffer
+ fixTrailingSlash,
+ )
+
+ return ciPath, ciPath != nil
+}
+
+// Shift bytes in array by n bytes left
+func shiftNRuneBytes(rb [4]byte, n int) [4]byte {
+ switch n {
+ case 0:
+ return rb
+ case 1:
+ return [4]byte{rb[1], rb[2], rb[3], 0}
+ case 2:
+ return [4]byte{rb[2], rb[3]}
+ case 3:
+ return [4]byte{rb[3]}
+ default:
+ return [4]byte{}
+ }
+}
+
+// Recursive case-insensitive lookup function used by n.findCaseInsensitivePath
+func (n *node) findCaseInsensitivePathRec(path string, ciPath []byte, rb [4]byte, fixTrailingSlash bool) []byte {
+ npLen := len(n.path)
+
+walk: // Outer loop for walking the tree
+ for len(path) >= npLen && (npLen == 0 || strings.EqualFold(path[1:npLen], n.path[1:])) {
+ // Add common prefix to result
+ oldPath := path
+ path = path[npLen:]
+ ciPath = append(ciPath, n.path...)
+
+ if len(path) == 0 {
+ // We should have reached the node containing the handle.
+ // Check if this node has a handle registered.
+ if n.handlers != nil {
+ return ciPath
+ }
+
+ // No handle found.
+ // Try to fix the path by adding a trailing slash
+ if fixTrailingSlash {
+ for i, c := range []byte(n.indices) {
+ if c == '/' {
+ n = n.children[i]
+ if (len(n.path) == 1 && n.handlers != nil) ||
+ (n.nType == catchAll && n.children[0].handlers != nil) {
+ return append(ciPath, '/')
+ }
+ return nil
+ }
+ }
+ }
+ return nil
+ }
+
+ // If this node does not have a wildcard (param or catchAll) child,
+ // we can just look up the next child node and continue to walk down
+ // the tree
+ if !n.wildChild {
+ // Skip rune bytes already processed
+ rb = shiftNRuneBytes(rb, npLen)
+
+ if rb[0] != 0 {
+ // Old rune not finished
+ idxc := rb[0]
+ for i, c := range []byte(n.indices) {
+ if c == idxc {
+ // continue with child node
+ n = n.children[i]
+ npLen = len(n.path)
+ continue walk
+ }
+ }
+ } else {
+ // Process a new rune
+ var rv rune
+
+ // Find rune start.
+ // Runes are up to 4 byte long,
+ // -4 would definitely be another rune.
+ var off int
+ for max := min(npLen, 3); off < max; off++ {
+ if i := npLen - off; utf8.RuneStart(oldPath[i]) {
+ // read rune from cached path
+ rv, _ = utf8.DecodeRuneInString(oldPath[i:])
+ break
+ }
+ }
+
+ // Calculate lowercase bytes of current rune
+ lo := unicode.ToLower(rv)
+ utf8.EncodeRune(rb[:], lo)
+
+ // Skip already processed bytes
+ rb = shiftNRuneBytes(rb, off)
+
+ idxc := rb[0]
+ for i, c := range []byte(n.indices) {
+ // Lowercase matches
+ if c == idxc {
+ // must use a recursive approach since both the
+ // uppercase byte and the lowercase byte might exist
+ // as an index
+ if out := n.children[i].findCaseInsensitivePathRec(
+ path, ciPath, rb, fixTrailingSlash,
+ ); out != nil {
+ return out
+ }
+ break
+ }
+ }
+
+ // If we found no match, the same for the uppercase rune,
+ // if it differs
+ if up := unicode.ToUpper(rv); up != lo {
+ utf8.EncodeRune(rb[:], up)
+ rb = shiftNRuneBytes(rb, off)
+
+ idxc := rb[0]
+ for i, c := range []byte(n.indices) {
+ // Uppercase matches
+ if c == idxc {
+ // Continue with child node
+ n = n.children[i]
+ npLen = len(n.path)
+ continue walk
+ }
+ }
+ }
+ }
+
+ // Nothing found. We can recommend to redirect to the same URL
+ // without a trailing slash if a leaf exists for that path
+ if fixTrailingSlash && path == "/" && n.handlers != nil {
+ return ciPath
+ }
+ return nil
+ }
+
+ n = n.children[0]
+ switch n.nType {
+ case param:
+ // Find param end (either '/' or path end)
+ end := 0
+ for end < len(path) && path[end] != '/' {
+ end++
+ }
+
+ // Add param value to case insensitive path
+ ciPath = append(ciPath, path[:end]...)
+
+ // We need to go deeper!
+ if end < len(path) {
+ if len(n.children) > 0 {
+ // Continue with child node
+ n = n.children[0]
+ npLen = len(n.path)
+ path = path[end:]
+ continue
+ }
+
+ // ... but we can't
+ if fixTrailingSlash && len(path) == end+1 {
+ return ciPath
+ }
+ return nil
+ }
+
+ if n.handlers != nil {
+ return ciPath
+ }
+
+ if fixTrailingSlash && len(n.children) == 1 {
+ // No handle found. Check if a handle for this path + a
+ // trailing slash exists
+ n = n.children[0]
+ if n.path == "/" && n.handlers != nil {
+ return append(ciPath, '/')
+ }
+ }
+
+ return nil
+
+ case catchAll:
+ return append(ciPath, path...)
+
+ default:
+ panic("invalid node type")
+ }
+ }
+
+ // Nothing found.
+ // Try to fix the path by adding / removing a trailing slash
+ if fixTrailingSlash {
+ if path == "/" {
+ return ciPath
+ }
+ if len(path)+1 == npLen && n.path[len(path)] == '/' &&
+ strings.EqualFold(path[1:], n.path[1:len(path)]) && n.handlers != nil {
+ return append(ciPath, n.path...)
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/utils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/utils.go
new file mode 100644
index 000000000000..c32f0eeb0ee6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/utils.go
@@ -0,0 +1,153 @@
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+import (
+ "encoding/xml"
+ "net/http"
+ "os"
+ "path"
+ "reflect"
+ "runtime"
+ "strings"
+)
+
+// BindKey indicates a default bind key.
+const BindKey = "_gin-gonic/gin/bindkey"
+
+// Bind is a helper function for given interface object and returns a Gin middleware.
+func Bind(val interface{}) HandlerFunc {
+ value := reflect.ValueOf(val)
+ if value.Kind() == reflect.Ptr {
+ panic(`Bind struct can not be a pointer. Example:
+ Use: gin.Bind(Struct{}) instead of gin.Bind(&Struct{})
+`)
+ }
+ typ := value.Type()
+
+ return func(c *Context) {
+ obj := reflect.New(typ).Interface()
+ if c.Bind(obj) == nil {
+ c.Set(BindKey, obj)
+ }
+ }
+}
+
+// WrapF is a helper function for wrapping http.HandlerFunc and returns a Gin middleware.
+func WrapF(f http.HandlerFunc) HandlerFunc {
+ return func(c *Context) {
+ f(c.Writer, c.Request)
+ }
+}
+
+// WrapH is a helper function for wrapping http.Handler and returns a Gin middleware.
+func WrapH(h http.Handler) HandlerFunc {
+ return func(c *Context) {
+ h.ServeHTTP(c.Writer, c.Request)
+ }
+}
+
+// H is a shortcut for map[string]interface{}
+type H map[string]interface{}
+
+// MarshalXML allows type H to be used with xml.Marshal.
+func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
+ start.Name = xml.Name{
+ Space: "",
+ Local: "map",
+ }
+ if err := e.EncodeToken(start); err != nil {
+ return err
+ }
+ for key, value := range h {
+ elem := xml.StartElement{
+ Name: xml.Name{Space: "", Local: key},
+ Attr: []xml.Attr{},
+ }
+ if err := e.EncodeElement(value, elem); err != nil {
+ return err
+ }
+ }
+
+ return e.EncodeToken(xml.EndElement{Name: start.Name})
+}
+
+func assert1(guard bool, text string) {
+ if !guard {
+ panic(text)
+ }
+}
+
+func filterFlags(content string) string {
+ for i, char := range content {
+ if char == ' ' || char == ';' {
+ return content[:i]
+ }
+ }
+ return content
+}
+
+func chooseData(custom, wildcard interface{}) interface{} {
+ if custom != nil {
+ return custom
+ }
+ if wildcard != nil {
+ return wildcard
+ }
+ panic("negotiation config is invalid")
+}
+
+func parseAccept(acceptHeader string) []string {
+ parts := strings.Split(acceptHeader, ",")
+ out := make([]string, 0, len(parts))
+ for _, part := range parts {
+ if i := strings.IndexByte(part, ';'); i > 0 {
+ part = part[:i]
+ }
+ if part = strings.TrimSpace(part); part != "" {
+ out = append(out, part)
+ }
+ }
+ return out
+}
+
+func lastChar(str string) uint8 {
+ if str == "" {
+ panic("The length of the string can't be 0")
+ }
+ return str[len(str)-1]
+}
+
+func nameOfFunction(f interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+}
+
+func joinPaths(absolutePath, relativePath string) string {
+ if relativePath == "" {
+ return absolutePath
+ }
+
+ finalPath := path.Join(absolutePath, relativePath)
+ if lastChar(relativePath) == '/' && lastChar(finalPath) != '/' {
+ return finalPath + "/"
+ }
+ return finalPath
+}
+
+func resolveAddress(addr []string) string {
+ switch len(addr) {
+ case 0:
+ if port := os.Getenv("PORT"); port != "" {
+ debugPrint("Environment variable PORT=\"%s\"", port)
+ return ":" + port
+ }
+ debugPrint("Environment variable PORT is undefined. Using port :8080 by default")
+ return ":8080"
+ case 1:
+ return addr[0]
+ default:
+ panic("too many parameters")
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/version.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/version.go
new file mode 100644
index 000000000000..4b69b9b91cfc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/version.go
@@ -0,0 +1,8 @@
+// Copyright 2018 Gin Core Team. All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+package gin
+
+// Version is the current gin framework's version.
+const Version = "v1.7.7"
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/LICENSE
new file mode 100644
index 000000000000..9d83342acdc7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Peter Bourgon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/README.md
new file mode 100644
index 000000000000..58b7d912b2ce
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/README.md
@@ -0,0 +1,122 @@
+# package auth/jwt
+
+`package auth/jwt` provides a set of interfaces for service authorization
+through [JSON Web Tokens](https://jwt.io/).
+
+## Usage
+
+NewParser takes a key function and an expected signing method and returns an
+`endpoint.Middleware`. The middleware will parse a token passed into the
+context via the `jwt.JWTContextKey`. If the token is valid, any claims
+will be added to the context via the `jwt.JWTClaimsContextKey`.
+
+```go
+import (
+ stdjwt "github.com/golang-jwt/jwt/v4"
+
+ "github.com/go-kit/kit/auth/jwt"
+ "github.com/go-kit/kit/endpoint"
+)
+
+func main() {
+ var exampleEndpoint endpoint.Endpoint
+ {
+ kf := func(token *stdjwt.Token) (interface{}, error) { return []byte("SigningString"), nil }
+ exampleEndpoint = MakeExampleEndpoint(service)
+ exampleEndpoint = jwt.NewParser(kf, stdjwt.SigningMethodHS256, jwt.StandardClaimsFactory)(exampleEndpoint)
+ }
+}
+```
+
+NewSigner takes a JWT key ID header, the signing key, signing method, and a
+claims object. It returns an `endpoint.Middleware`. The middleware will build
+the token string and add it to the context via the `jwt.JWTContextKey`.
+
+```go
+import (
+ stdjwt "github.com/golang-jwt/jwt/v4"
+
+ "github.com/go-kit/kit/auth/jwt"
+ "github.com/go-kit/kit/endpoint"
+)
+
+func main() {
+ var exampleEndpoint endpoint.Endpoint
+ {
+ exampleEndpoint = grpctransport.NewClient(...).Endpoint()
+ exampleEndpoint = jwt.NewSigner(
+ "kid-header",
+ []byte("SigningString"),
+ stdjwt.SigningMethodHS256,
+ jwt.Claims{},
+ )(exampleEndpoint)
+ }
+}
+```
+
+In order for the parser and the signer to work, the authorization headers need
+to be passed between the request and the context. `HTTPToContext()`,
+`ContextToHTTP()`, `GRPCToContext()`, and `ContextToGRPC()` are given as
+helpers to do this. These functions implement the correlating transport's
+RequestFunc interface and can be passed as ClientBefore or ServerBefore
+options.
+
+Example of use in a client:
+
+```go
+import (
+ stdjwt "github.com/golang-jwt/jwt/v4"
+
+ grpctransport "github.com/go-kit/kit/transport/grpc"
+ "github.com/go-kit/kit/auth/jwt"
+ "github.com/go-kit/kit/endpoint"
+)
+
+func main() {
+
+ options := []httptransport.ClientOption{}
+ var exampleEndpoint endpoint.Endpoint
+ {
+ exampleEndpoint = grpctransport.NewClient(..., grpctransport.ClientBefore(jwt.ContextToGRPC())).Endpoint()
+ exampleEndpoint = jwt.NewSigner(
+ "kid-header",
+ []byte("SigningString"),
+ stdjwt.SigningMethodHS256,
+ jwt.Claims{},
+ )(exampleEndpoint)
+ }
+}
+```
+
+Example of use in a server:
+
+```go
+import (
+ "context"
+
+ "github.com/go-kit/kit/auth/jwt"
+ "github.com/go-kit/log"
+ grpctransport "github.com/go-kit/kit/transport/grpc"
+)
+
+func MakeGRPCServer(ctx context.Context, endpoints Endpoints, logger log.Logger) pb.ExampleServer {
+ options := []grpctransport.ServerOption{grpctransport.ServerErrorLogger(logger)}
+
+ return &grpcServer{
+ createUser: grpctransport.NewServer(
+ ctx,
+ endpoints.CreateUserEndpoint,
+ DecodeGRPCCreateUserRequest,
+ EncodeGRPCCreateUserResponse,
+ append(options, grpctransport.ServerBefore(jwt.GRPCToContext()))...,
+ ),
+ getUser: grpctransport.NewServer(
+ ctx,
+ endpoints.GetUserEndpoint,
+ DecodeGRPCGetUserRequest,
+ EncodeGRPCGetUserResponse,
+ options...,
+ ),
+ }
+}
+```
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/middleware.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/middleware.go
new file mode 100644
index 000000000000..b7c89ceb875e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/middleware.go
@@ -0,0 +1,146 @@
+package jwt
+
+import (
+ "context"
+ "errors"
+
+ "github.com/go-kit/kit/endpoint"
+ "github.com/golang-jwt/jwt/v4"
+)
+
+type contextKey string
+
+const (
+ // JWTContextKey holds the key used to store a JWT in the context.
+ JWTContextKey contextKey = "JWTToken"
+
+ // JWTTokenContextKey is an alias for JWTContextKey.
+ //
+ // Deprecated: prefer JWTContextKey.
+ JWTTokenContextKey = JWTContextKey
+
+ // JWTClaimsContextKey holds the key used to store the JWT Claims in the
+ // context.
+ JWTClaimsContextKey contextKey = "JWTClaims"
+)
+
+var (
+ // ErrTokenContextMissing denotes a token was not passed into the parsing
+ // middleware's context.
+ ErrTokenContextMissing = errors.New("token up for parsing was not passed through the context")
+
+ // ErrTokenInvalid denotes a token was not able to be validated.
+ ErrTokenInvalid = errors.New("JWT was invalid")
+
+ // ErrTokenExpired denotes a token's expire header (exp) has since passed.
+ ErrTokenExpired = errors.New("JWT is expired")
+
+ // ErrTokenMalformed denotes a token was not formatted as a JWT.
+ ErrTokenMalformed = errors.New("JWT is malformed")
+
+ // ErrTokenNotActive denotes a token's not before header (nbf) is in the
+ // future.
+ ErrTokenNotActive = errors.New("token is not valid yet")
+
+ // ErrUnexpectedSigningMethod denotes a token was signed with an unexpected
+ // signing method.
+ ErrUnexpectedSigningMethod = errors.New("unexpected signing method")
+)
+
+// NewSigner creates a new JWT generating middleware, specifying key ID,
+// signing string, signing method and the claims you would like it to contain.
+// Tokens are signed with a Key ID header (kid) which is useful for determining
+// the key to use for parsing. Particularly useful for clients.
+func NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware {
+ return func(next endpoint.Endpoint) endpoint.Endpoint {
+ return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+ token := jwt.NewWithClaims(method, claims)
+ token.Header["kid"] = kid
+
+ // Sign and get the complete encoded token as a string using the secret
+ tokenString, err := token.SignedString(key)
+ if err != nil {
+ return nil, err
+ }
+ ctx = context.WithValue(ctx, JWTContextKey, tokenString)
+
+ return next(ctx, request)
+ }
+ }
+}
+
+// ClaimsFactory is a factory for jwt.Claims.
+// Useful in NewParser middleware.
+type ClaimsFactory func() jwt.Claims
+
+// MapClaimsFactory is a ClaimsFactory that returns
+// an empty jwt.MapClaims.
+func MapClaimsFactory() jwt.Claims {
+ return jwt.MapClaims{}
+}
+
+// StandardClaimsFactory is a ClaimsFactory that returns
+// an empty jwt.StandardClaims.
+func StandardClaimsFactory() jwt.Claims {
+ return &jwt.StandardClaims{}
+}
+
+// NewParser creates a new JWT parsing middleware, specifying a
+// jwt.Keyfunc interface, the signing method and the claims type to be used. NewParser
+// adds the resulting claims to endpoint context or returns error on invalid token.
+// Particularly useful for servers.
+func NewParser(keyFunc jwt.Keyfunc, method jwt.SigningMethod, newClaims ClaimsFactory) endpoint.Middleware {
+ return func(next endpoint.Endpoint) endpoint.Endpoint {
+ return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+ // tokenString is stored in the context from the transport handlers.
+ tokenString, ok := ctx.Value(JWTContextKey).(string)
+ if !ok {
+ return nil, ErrTokenContextMissing
+ }
+
+ // Parse takes the token string and a function for looking up the
+ // key. The latter is especially useful if you use multiple keys
+ // for your application. The standard is to use 'kid' in the head
+ // of the token to identify which key to use, but the parsed token
+ // (head and claims) is provided to the callback, providing
+ // flexibility.
+ token, err := jwt.ParseWithClaims(tokenString, newClaims(), func(token *jwt.Token) (interface{}, error) {
+ // Don't forget to validate the alg is what you expect:
+ if token.Method != method {
+ return nil, ErrUnexpectedSigningMethod
+ }
+
+ return keyFunc(token)
+ })
+ if err != nil {
+ if e, ok := err.(*jwt.ValidationError); ok {
+ switch {
+ case e.Errors&jwt.ValidationErrorMalformed != 0:
+ // Token is malformed
+ return nil, ErrTokenMalformed
+ case e.Errors&jwt.ValidationErrorExpired != 0:
+ // Token is expired
+ return nil, ErrTokenExpired
+ case e.Errors&jwt.ValidationErrorNotValidYet != 0:
+ // Token is not active yet
+ return nil, ErrTokenNotActive
+ case e.Inner != nil:
+ // report e.Inner
+ return nil, e.Inner
+ }
+ // We have a ValidationError but have no specific Go kit error for it.
+ // Fall through to return original error.
+ }
+ return nil, err
+ }
+
+ if !token.Valid {
+ return nil, ErrTokenInvalid
+ }
+
+ ctx = context.WithValue(ctx, JWTClaimsContextKey, token.Claims)
+
+ return next(ctx, request)
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go
deleted file mode 100644
index b85d079daa57..000000000000
--- a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/go-kit/kit/auth/jwt, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/go-kit/kit/auth/jwt (exports: ; functions: NewSigner)
-
-// Package jwt is a stub of github.com/go-kit/kit/auth/jwt, generated by depstubber.
-package jwt
-
-func NewSigner(_ string, _ []byte, _ interface{}, _ interface{}) interface{} {
- return nil
-}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/transport.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/transport.go
new file mode 100644
index 000000000000..e7d19c180447
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/transport.go
@@ -0,0 +1,89 @@
+package jwt
+
+import (
+ "context"
+ "fmt"
+ stdhttp "net/http"
+ "strings"
+
+ "google.golang.org/grpc/metadata"
+
+ "github.com/go-kit/kit/transport/grpc"
+ "github.com/go-kit/kit/transport/http"
+)
+
+const (
+ bearer string = "bearer"
+ bearerFormat string = "Bearer %s"
+)
+
+// HTTPToContext moves a JWT from request header to context. Particularly
+// useful for servers.
+func HTTPToContext() http.RequestFunc {
+ return func(ctx context.Context, r *stdhttp.Request) context.Context {
+ token, ok := extractTokenFromAuthHeader(r.Header.Get("Authorization"))
+ if !ok {
+ return ctx
+ }
+
+ return context.WithValue(ctx, JWTContextKey, token)
+ }
+}
+
+// ContextToHTTP moves a JWT from context to request header. Particularly
+// useful for clients.
+func ContextToHTTP() http.RequestFunc {
+ return func(ctx context.Context, r *stdhttp.Request) context.Context {
+ token, ok := ctx.Value(JWTContextKey).(string)
+ if ok {
+ r.Header.Add("Authorization", generateAuthHeaderFromToken(token))
+ }
+ return ctx
+ }
+}
+
+// GRPCToContext moves a JWT from grpc metadata to context. Particularly
+// userful for servers.
+func GRPCToContext() grpc.ServerRequestFunc {
+ return func(ctx context.Context, md metadata.MD) context.Context {
+ // capital "Key" is illegal in HTTP/2.
+ authHeader, ok := md["authorization"]
+ if !ok {
+ return ctx
+ }
+
+ token, ok := extractTokenFromAuthHeader(authHeader[0])
+ if ok {
+ ctx = context.WithValue(ctx, JWTContextKey, token)
+ }
+
+ return ctx
+ }
+}
+
+// ContextToGRPC moves a JWT from context to grpc metadata. Particularly
+// useful for clients.
+func ContextToGRPC() grpc.ClientRequestFunc {
+ return func(ctx context.Context, md *metadata.MD) context.Context {
+ token, ok := ctx.Value(JWTContextKey).(string)
+ if ok {
+ // capital "Key" is illegal in HTTP/2.
+ (*md)["authorization"] = []string{generateAuthHeaderFromToken(token)}
+ }
+
+ return ctx
+ }
+}
+
+func extractTokenFromAuthHeader(val string) (token string, ok bool) {
+ authHeaderParts := strings.Split(val, " ")
+ if len(authHeaderParts) != 2 || !strings.EqualFold(authHeaderParts[0], bearer) {
+ return "", false
+ }
+
+ return authHeaderParts[1], true
+}
+
+func generateAuthHeaderFromToken(token string) string {
+ return fmt.Sprintf(bearerFormat, token)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/endpoint/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/endpoint/doc.go
new file mode 100644
index 000000000000..84e27b95d4bd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/endpoint/doc.go
@@ -0,0 +1,5 @@
+// Package endpoint defines an abstraction for RPCs.
+//
+// Endpoints are a fundamental building block for many Go kit components.
+// Endpoints are implemented by servers, and called by clients.
+package endpoint
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/endpoint/endpoint.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/endpoint/endpoint.go
new file mode 100644
index 000000000000..6e9da3679b0e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/endpoint/endpoint.go
@@ -0,0 +1,40 @@
+package endpoint
+
+import (
+ "context"
+)
+
+// Endpoint is the fundamental building block of servers and clients.
+// It represents a single RPC method.
+type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
+
+// Nop is an endpoint that does nothing and returns a nil error.
+// Useful for tests.
+func Nop(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
+
+// Middleware is a chainable behavior modifier for endpoints.
+type Middleware func(Endpoint) Endpoint
+
+// Chain is a helper function for composing middlewares. Requests will
+// traverse them in the order they're declared. That is, the first middleware
+// is treated as the outermost middleware.
+func Chain(outer Middleware, others ...Middleware) Middleware {
+ return func(next Endpoint) Endpoint {
+ for i := len(others) - 1; i >= 0; i-- { // reverse
+ next = others[i](next)
+ }
+ return outer(next)
+ }
+}
+
+// Failer may be implemented by Go kit response types that contain business
+// logic error details. If Failed returns a non-nil error, the Go kit transport
+// layer may interpret this as a business logic error, and may encode it
+// differently than a regular, successful response.
+//
+// It's not necessary for your response types to implement Failer, but it may
+// help for more sophisticated use cases. The addsvc example shows how Failer
+// should be used by a complete application.
+type Failer interface {
+ Failed() error
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/doc.go
new file mode 100644
index 000000000000..f8382ae712f9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/doc.go
@@ -0,0 +1,2 @@
+// Package transport contains helpers applicable to all supported transports.
+package transport
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/error_handler.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/error_handler.go
new file mode 100644
index 000000000000..2456df184976
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/error_handler.go
@@ -0,0 +1,39 @@
+package transport
+
+import (
+ "context"
+
+ "github.com/go-kit/log"
+)
+
+// ErrorHandler receives a transport error to be processed for diagnostic purposes.
+// Usually this means logging the error.
+type ErrorHandler interface {
+ Handle(ctx context.Context, err error)
+}
+
+// LogErrorHandler is a transport error handler implementation which logs an error.
+type LogErrorHandler struct {
+ logger log.Logger
+}
+
+func NewLogErrorHandler(logger log.Logger) *LogErrorHandler {
+ return &LogErrorHandler{
+ logger: logger,
+ }
+}
+
+func (h *LogErrorHandler) Handle(ctx context.Context, err error) {
+ h.logger.Log("err", err)
+}
+
+// The ErrorHandlerFunc type is an adapter to allow the use of
+// ordinary function as ErrorHandler. If f is a function
+// with the appropriate signature, ErrorHandlerFunc(f) is a
+// ErrorHandler that calls f.
+type ErrorHandlerFunc func(ctx context.Context, err error)
+
+// Handle calls f(ctx, err).
+func (f ErrorHandlerFunc) Handle(ctx context.Context, err error) {
+ f(ctx, err)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/README.md
new file mode 100644
index 000000000000..d269cddb2c75
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/README.md
@@ -0,0 +1,54 @@
+# grpc
+
+[gRPC](http://www.grpc.io/) is an excellent, modern IDL and transport for
+microservices. If you're starting a greenfield project, go-kit strongly
+recommends gRPC as your default transport.
+
+One important note is that while gRPC supports streaming requests and replies,
+go-kit does not. You can still use streams in your service, but their
+implementation will not be able to take advantage of many go-kit features like middleware.
+
+Using gRPC and go-kit together is very simple.
+
+First, define your service using protobuf3. This is explained
+[in gRPC documentation](http://www.grpc.io/docs/#defining-a-service).
+See
+[addsvc.proto](https://github.com/go-kit/examples/blob/master/addsvc/pb/addsvc.proto)
+for an example. Make sure the proto definition matches your service's go-kit
+(interface) definition.
+
+Next, get the protoc compiler.
+
+You can download pre-compiled binaries from the
+[protobuf release page](https://github.com/google/protobuf/releases).
+You will unzip a folder called `protoc3` with a subdirectory `bin` containing
+an executable. Move that executable somewhere in your `$PATH` and you're good
+to go!
+
+It can also be built from source.
+
+```sh
+brew install autoconf automake libtool
+git clone https://github.com/google/protobuf
+cd protobuf
+./autogen.sh ; ./configure ; make ; make install
+```
+
+Then, compile your service definition, from .proto to .go.
+
+```sh
+protoc add.proto --go_out=plugins=grpc:.
+```
+
+Finally, write a tiny binding from your service definition to the gRPC
+definition. It's a simple conversion from one domain to another.
+See
+[grpc.go](https://github.com/go-kit/examples/blob/master/addsvc/pkg/addtransport/grpc.go)
+for an example.
+
+That's it!
+The gRPC binding can be bound to a listener and serve normal gRPC requests.
+And within your service, you can use standard go-kit components and idioms.
+See [addsvc](https://github.com/go-kit/examples/tree/master/addsvc/) for
+a complete working example with gRPC support. And remember: go-kit services
+can support multiple transports simultaneously.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/client.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/client.go
new file mode 100644
index 000000000000..5d96c6b4d343
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/client.go
@@ -0,0 +1,140 @@
+package grpc
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/metadata"
+
+ "github.com/go-kit/kit/endpoint"
+)
+
+// Client wraps a gRPC connection and provides a method that implements
+// endpoint.Endpoint.
+type Client struct {
+ client *grpc.ClientConn
+ serviceName string
+ method string
+ enc EncodeRequestFunc
+ dec DecodeResponseFunc
+ grpcReply reflect.Type
+ before []ClientRequestFunc
+ after []ClientResponseFunc
+ finalizer []ClientFinalizerFunc
+}
+
+// NewClient constructs a usable Client for a single remote endpoint.
+// Pass an zero-value protobuf message of the RPC response type as
+// the grpcReply argument.
+func NewClient(
+ cc *grpc.ClientConn,
+ serviceName string,
+ method string,
+ enc EncodeRequestFunc,
+ dec DecodeResponseFunc,
+ grpcReply interface{},
+ options ...ClientOption,
+) *Client {
+ c := &Client{
+ client: cc,
+ method: fmt.Sprintf("/%s/%s", serviceName, method),
+ enc: enc,
+ dec: dec,
+ // We are using reflect.Indirect here to allow both reply structs and
+ // pointers to these reply structs. New consumers of the client should
+ // use structs directly, while existing consumers will not break if they
+ // remain to use pointers to structs.
+ grpcReply: reflect.TypeOf(
+ reflect.Indirect(
+ reflect.ValueOf(grpcReply),
+ ).Interface(),
+ ),
+ before: []ClientRequestFunc{},
+ after: []ClientResponseFunc{},
+ }
+ for _, option := range options {
+ option(c)
+ }
+ return c
+}
+
+// ClientOption sets an optional parameter for clients.
+type ClientOption func(*Client)
+
+// ClientBefore sets the RequestFuncs that are applied to the outgoing gRPC
+// request before it's invoked.
+func ClientBefore(before ...ClientRequestFunc) ClientOption {
+ return func(c *Client) { c.before = append(c.before, before...) }
+}
+
+// ClientAfter sets the ClientResponseFuncs that are applied to the incoming
+// gRPC response prior to it being decoded. This is useful for obtaining
+// response metadata and adding onto the context prior to decoding.
+func ClientAfter(after ...ClientResponseFunc) ClientOption {
+ return func(c *Client) { c.after = append(c.after, after...) }
+}
+
+// ClientFinalizer is executed at the end of every gRPC request.
+// By default, no finalizer is registered.
+func ClientFinalizer(f ...ClientFinalizerFunc) ClientOption {
+ return func(s *Client) { s.finalizer = append(s.finalizer, f...) }
+}
+
+// Endpoint returns a usable endpoint that will invoke the gRPC specified by the
+// client.
+func (c Client) Endpoint() endpoint.Endpoint {
+ return func(ctx context.Context, request interface{}) (response interface{}, err error) {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+
+ if c.finalizer != nil {
+ defer func() {
+ for _, f := range c.finalizer {
+ f(ctx, err)
+ }
+ }()
+ }
+
+ ctx = context.WithValue(ctx, ContextKeyRequestMethod, c.method)
+
+ req, err := c.enc(ctx, request)
+ if err != nil {
+ return nil, err
+ }
+
+ md := &metadata.MD{}
+ for _, f := range c.before {
+ ctx = f(ctx, md)
+ }
+ ctx = metadata.NewOutgoingContext(ctx, *md)
+
+ var header, trailer metadata.MD
+ grpcReply := reflect.New(c.grpcReply).Interface()
+ if err = c.client.Invoke(
+ ctx, c.method, req, grpcReply, grpc.Header(&header),
+ grpc.Trailer(&trailer),
+ ); err != nil {
+ return nil, err
+ }
+
+ for _, f := range c.after {
+ ctx = f(ctx, header, trailer)
+ }
+
+ response, err = c.dec(ctx, grpcReply)
+ if err != nil {
+ return nil, err
+ }
+ return response, nil
+ }
+}
+
+// ClientFinalizerFunc can be used to perform work at the end of a client gRPC
+// request, after the response is returned. The principal
+// intended use is for error logging. Additional response parameters are
+// provided in the context under keys with the ContextKeyResponse prefix.
+// Note: err may be nil. There maybe also no additional response parameters depending on
+// when an error occurs.
+type ClientFinalizerFunc func(ctx context.Context, err error)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/doc.go
new file mode 100644
index 000000000000..a953ba88ef1c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/doc.go
@@ -0,0 +1,2 @@
+// Package grpc provides a gRPC binding for endpoints.
+package grpc
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/encode_decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/encode_decode.go
new file mode 100644
index 000000000000..f2900ed6d309
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/encode_decode.go
@@ -0,0 +1,29 @@
+package grpc
+
+import (
+ "context"
+)
+
+// DecodeRequestFunc extracts a user-domain request object from a gRPC request.
+// It's designed to be used in gRPC servers, for server-side endpoints. One
+// straightforward DecodeRequestFunc could be something that decodes from the
+// gRPC request message to the concrete request type.
+type DecodeRequestFunc func(context.Context, interface{}) (request interface{}, err error)
+
+// EncodeRequestFunc encodes the passed request object into the gRPC request
+// object. It's designed to be used in gRPC clients, for client-side endpoints.
+// One straightforward EncodeRequestFunc could something that encodes the object
+// directly to the gRPC request message.
+type EncodeRequestFunc func(context.Context, interface{}) (request interface{}, err error)
+
+// EncodeResponseFunc encodes the passed response object to the gRPC response
+// message. It's designed to be used in gRPC servers, for server-side endpoints.
+// One straightforward EncodeResponseFunc could be something that encodes the
+// object directly to the gRPC response message.
+type EncodeResponseFunc func(context.Context, interface{}) (response interface{}, err error)
+
+// DecodeResponseFunc extracts a user-domain response object from a gRPC
+// response object. It's designed to be used in gRPC clients, for client-side
+// endpoints. One straightforward DecodeResponseFunc could be something that
+// decodes from the gRPC response message to the concrete response type.
+type DecodeResponseFunc func(context.Context, interface{}) (response interface{}, err error)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/request_response_funcs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/request_response_funcs.go
new file mode 100644
index 000000000000..eb8e3b178b68
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/request_response_funcs.go
@@ -0,0 +1,81 @@
+package grpc
+
+import (
+ "context"
+ "encoding/base64"
+ "strings"
+
+ "google.golang.org/grpc/metadata"
+)
+
+const (
+ binHdrSuffix = "-bin"
+)
+
+// ClientRequestFunc may take information from context and use it to construct
+// metadata headers to be transported to the server. ClientRequestFuncs are
+// executed after creating the request but prior to sending the gRPC request to
+// the server.
+type ClientRequestFunc func(context.Context, *metadata.MD) context.Context
+
+// ServerRequestFunc may take information from the received metadata header and
+// use it to place items in the request scoped context. ServerRequestFuncs are
+// executed prior to invoking the endpoint.
+type ServerRequestFunc func(context.Context, metadata.MD) context.Context
+
+// ServerResponseFunc may take information from a request context and use it to
+// manipulate the gRPC response metadata headers and trailers. ResponseFuncs are
+// only executed in servers, after invoking the endpoint but prior to writing a
+// response.
+type ServerResponseFunc func(ctx context.Context, header *metadata.MD, trailer *metadata.MD) context.Context
+
+// ClientResponseFunc may take information from a gRPC metadata header and/or
+// trailer and make the responses available for consumption. ClientResponseFuncs
+// are only executed in clients, after a request has been made, but prior to it
+// being decoded.
+type ClientResponseFunc func(ctx context.Context, header metadata.MD, trailer metadata.MD) context.Context
+
+// SetRequestHeader returns a ClientRequestFunc that sets the specified metadata
+// key-value pair.
+func SetRequestHeader(key, val string) ClientRequestFunc {
+ return func(ctx context.Context, md *metadata.MD) context.Context {
+ key, val := EncodeKeyValue(key, val)
+ (*md)[key] = append((*md)[key], val)
+ return ctx
+ }
+}
+
+// SetResponseHeader returns a ResponseFunc that sets the specified metadata
+// key-value pair.
+func SetResponseHeader(key, val string) ServerResponseFunc {
+ return func(ctx context.Context, md *metadata.MD, _ *metadata.MD) context.Context {
+ key, val := EncodeKeyValue(key, val)
+ (*md)[key] = append((*md)[key], val)
+ return ctx
+ }
+}
+
+// SetResponseTrailer returns a ResponseFunc that sets the specified metadata
+// key-value pair.
+func SetResponseTrailer(key, val string) ServerResponseFunc {
+ return func(ctx context.Context, _ *metadata.MD, md *metadata.MD) context.Context {
+ key, val := EncodeKeyValue(key, val)
+ (*md)[key] = append((*md)[key], val)
+ return ctx
+ }
+}
+
+// EncodeKeyValue sanitizes a key-value pair for use in gRPC metadata headers.
+func EncodeKeyValue(key, val string) (string, string) {
+ key = strings.ToLower(key)
+ if strings.HasSuffix(key, binHdrSuffix) {
+ val = base64.StdEncoding.EncodeToString([]byte(val))
+ }
+ return key, val
+}
+
+type contextKey int
+
+const (
+ ContextKeyRequestMethod contextKey = iota
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/server.go
new file mode 100644
index 000000000000..e83aeacfc18e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/grpc/server.go
@@ -0,0 +1,168 @@
+package grpc
+
+import (
+ "context"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/metadata"
+
+ "github.com/go-kit/kit/endpoint"
+ "github.com/go-kit/kit/transport"
+ "github.com/go-kit/log"
+)
+
+// Handler which should be called from the gRPC binding of the service
+// implementation. The incoming request parameter, and returned response
+// parameter, are both gRPC types, not user-domain.
+type Handler interface {
+ ServeGRPC(ctx context.Context, request interface{}) (context.Context, interface{}, error)
+}
+
+// Server wraps an endpoint and implements grpc.Handler.
+type Server struct {
+ e endpoint.Endpoint
+ dec DecodeRequestFunc
+ enc EncodeResponseFunc
+ before []ServerRequestFunc
+ after []ServerResponseFunc
+ finalizer []ServerFinalizerFunc
+ errorHandler transport.ErrorHandler
+}
+
+// NewServer constructs a new server, which implements wraps the provided
+// endpoint and implements the Handler interface. Consumers should write
+// bindings that adapt the concrete gRPC methods from their compiled protobuf
+// definitions to individual handlers. Request and response objects are from the
+// caller business domain, not gRPC request and reply types.
+func NewServer(
+ e endpoint.Endpoint,
+ dec DecodeRequestFunc,
+ enc EncodeResponseFunc,
+ options ...ServerOption,
+) *Server {
+ s := &Server{
+ e: e,
+ dec: dec,
+ enc: enc,
+ errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
+ }
+ for _, option := range options {
+ option(s)
+ }
+ return s
+}
+
+// ServerOption sets an optional parameter for servers.
+type ServerOption func(*Server)
+
+// ServerBefore functions are executed on the gRPC request object before the
+// request is decoded.
+func ServerBefore(before ...ServerRequestFunc) ServerOption {
+ return func(s *Server) { s.before = append(s.before, before...) }
+}
+
+// ServerAfter functions are executed on the gRPC response writer after the
+// endpoint is invoked, but before anything is written to the client.
+func ServerAfter(after ...ServerResponseFunc) ServerOption {
+ return func(s *Server) { s.after = append(s.after, after...) }
+}
+
+// ServerErrorLogger is used to log non-terminal errors. By default, no errors
+// are logged.
+// Deprecated: Use ServerErrorHandler instead.
+func ServerErrorLogger(logger log.Logger) ServerOption {
+ return func(s *Server) { s.errorHandler = transport.NewLogErrorHandler(logger) }
+}
+
+// ServerErrorHandler is used to handle non-terminal errors. By default, non-terminal errors
+// are ignored.
+func ServerErrorHandler(errorHandler transport.ErrorHandler) ServerOption {
+ return func(s *Server) { s.errorHandler = errorHandler }
+}
+
+// ServerFinalizer is executed at the end of every gRPC request.
+// By default, no finalizer is registered.
+func ServerFinalizer(f ...ServerFinalizerFunc) ServerOption {
+ return func(s *Server) { s.finalizer = append(s.finalizer, f...) }
+}
+
+// ServeGRPC implements the Handler interface.
+func (s Server) ServeGRPC(ctx context.Context, req interface{}) (retctx context.Context, resp interface{}, err error) {
+ // Retrieve gRPC metadata.
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ md = metadata.MD{}
+ }
+
+ if len(s.finalizer) > 0 {
+ defer func() {
+ for _, f := range s.finalizer {
+ f(ctx, err)
+ }
+ }()
+ }
+
+ for _, f := range s.before {
+ ctx = f(ctx, md)
+ }
+
+ var (
+ request interface{}
+ response interface{}
+ grpcResp interface{}
+ )
+
+ request, err = s.dec(ctx, req)
+ if err != nil {
+ s.errorHandler.Handle(ctx, err)
+ return ctx, nil, err
+ }
+
+ response, err = s.e(ctx, request)
+ if err != nil {
+ s.errorHandler.Handle(ctx, err)
+ return ctx, nil, err
+ }
+
+ var mdHeader, mdTrailer metadata.MD
+ for _, f := range s.after {
+ ctx = f(ctx, &mdHeader, &mdTrailer)
+ }
+
+ grpcResp, err = s.enc(ctx, response)
+ if err != nil {
+ s.errorHandler.Handle(ctx, err)
+ return ctx, nil, err
+ }
+
+ if len(mdHeader) > 0 {
+ if err = grpc.SendHeader(ctx, mdHeader); err != nil {
+ s.errorHandler.Handle(ctx, err)
+ return ctx, nil, err
+ }
+ }
+
+ if len(mdTrailer) > 0 {
+ if err = grpc.SetTrailer(ctx, mdTrailer); err != nil {
+ s.errorHandler.Handle(ctx, err)
+ return ctx, nil, err
+ }
+ }
+
+ return ctx, grpcResp, nil
+}
+
+// ServerFinalizerFunc can be used to perform work at the end of an gRPC
+// request, after the response has been written to the client.
+type ServerFinalizerFunc func(ctx context.Context, err error)
+
+// Interceptor is a grpc UnaryInterceptor that injects the method name into
+// context so it can be consumed by Go kit gRPC middlewares. The Interceptor
+// typically is added at creation time of the grpc-go server.
+// Like this: `grpc.NewServer(grpc.UnaryInterceptor(kitgrpc.Interceptor))`
+func Interceptor(
+ ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,
+) (resp interface{}, err error) {
+ ctx = context.WithValue(ctx, ContextKeyRequestMethod, info.FullMethod)
+ return handler(ctx, req)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/client.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/client.go
new file mode 100644
index 000000000000..7d868eee496b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/client.go
@@ -0,0 +1,219 @@
+package http
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "encoding/xml"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+
+ "github.com/go-kit/kit/endpoint"
+)
+
+// HTTPClient is an interface that models *http.Client.
+type HTTPClient interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client wraps a URL and provides a method that implements endpoint.Endpoint.
+type Client struct {
+ client HTTPClient
+ req CreateRequestFunc
+ dec DecodeResponseFunc
+ before []RequestFunc
+ after []ClientResponseFunc
+ finalizer []ClientFinalizerFunc
+ bufferedStream bool
+}
+
+// NewClient constructs a usable Client for a single remote method.
+func NewClient(method string, tgt *url.URL, enc EncodeRequestFunc, dec DecodeResponseFunc, options ...ClientOption) *Client {
+ return NewExplicitClient(makeCreateRequestFunc(method, tgt, enc), dec, options...)
+}
+
+// NewExplicitClient is like NewClient but uses a CreateRequestFunc instead of a
+// method, target URL, and EncodeRequestFunc, which allows for more control over
+// the outgoing HTTP request.
+func NewExplicitClient(req CreateRequestFunc, dec DecodeResponseFunc, options ...ClientOption) *Client {
+ c := &Client{
+ client: http.DefaultClient,
+ req: req,
+ dec: dec,
+ }
+ for _, option := range options {
+ option(c)
+ }
+ return c
+}
+
+// ClientOption sets an optional parameter for clients.
+type ClientOption func(*Client)
+
+// SetClient sets the underlying HTTP client used for requests.
+// By default, http.DefaultClient is used.
+func SetClient(client HTTPClient) ClientOption {
+ return func(c *Client) { c.client = client }
+}
+
+// ClientBefore adds one or more RequestFuncs to be applied to the outgoing HTTP
+// request before it's invoked.
+func ClientBefore(before ...RequestFunc) ClientOption {
+ return func(c *Client) { c.before = append(c.before, before...) }
+}
+
+// ClientAfter adds one or more ClientResponseFuncs, which are applied to the
+// incoming HTTP response prior to it being decoded. This is useful for
+// obtaining anything off of the response and adding it into the context prior
+// to decoding.
+func ClientAfter(after ...ClientResponseFunc) ClientOption {
+ return func(c *Client) { c.after = append(c.after, after...) }
+}
+
+// ClientFinalizer adds one or more ClientFinalizerFuncs to be executed at the
+// end of every HTTP request. Finalizers are executed in the order in which they
+// were added. By default, no finalizer is registered.
+func ClientFinalizer(f ...ClientFinalizerFunc) ClientOption {
+ return func(s *Client) { s.finalizer = append(s.finalizer, f...) }
+}
+
+// BufferedStream sets whether the HTTP response body is left open, allowing it
+// to be read from later. Useful for transporting a file as a buffered stream.
+// That body has to be drained and closed to properly end the request.
+func BufferedStream(buffered bool) ClientOption {
+ return func(c *Client) { c.bufferedStream = buffered }
+}
+
+// Endpoint returns a usable Go kit endpoint that calls the remote HTTP endpoint.
+func (c Client) Endpoint() endpoint.Endpoint {
+ return func(ctx context.Context, request interface{}) (interface{}, error) {
+ ctx, cancel := context.WithCancel(ctx)
+
+ var (
+ resp *http.Response
+ err error
+ )
+ if c.finalizer != nil {
+ defer func() {
+ if resp != nil {
+ ctx = context.WithValue(ctx, ContextKeyResponseHeaders, resp.Header)
+ ctx = context.WithValue(ctx, ContextKeyResponseSize, resp.ContentLength)
+ }
+ for _, f := range c.finalizer {
+ f(ctx, err)
+ }
+ }()
+ }
+
+ req, err := c.req(ctx, request)
+ if err != nil {
+ cancel()
+ return nil, err
+ }
+
+ for _, f := range c.before {
+ ctx = f(ctx, req)
+ }
+
+ resp, err = c.client.Do(req.WithContext(ctx))
+ if err != nil {
+ cancel()
+ return nil, err
+ }
+
+ // If the caller asked for a buffered stream, we don't cancel the
+ // context when the endpoint returns. Instead, we should call the
+ // cancel func when closing the response body.
+ if c.bufferedStream {
+ resp.Body = bodyWithCancel{ReadCloser: resp.Body, cancel: cancel}
+ } else {
+ defer resp.Body.Close()
+ defer cancel()
+ }
+
+ for _, f := range c.after {
+ ctx = f(ctx, resp)
+ }
+
+ response, err := c.dec(ctx, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return response, nil
+ }
+}
+
+// bodyWithCancel is a wrapper for an io.ReadCloser with also a
+// cancel function which is called when the Close is used
+type bodyWithCancel struct {
+ io.ReadCloser
+
+ cancel context.CancelFunc
+}
+
+func (bwc bodyWithCancel) Close() error {
+ bwc.ReadCloser.Close()
+ bwc.cancel()
+ return nil
+}
+
+// ClientFinalizerFunc can be used to perform work at the end of a client HTTP
+// request, after the response is returned. The principal
+// intended use is for error logging. Additional response parameters are
+// provided in the context under keys with the ContextKeyResponse prefix.
+// Note: err may be nil. There maybe also no additional response parameters
+// depending on when an error occurs.
+type ClientFinalizerFunc func(ctx context.Context, err error)
+
+// EncodeJSONRequest is an EncodeRequestFunc that serializes the request as a
+// JSON object to the Request body. Many JSON-over-HTTP services can use it as
+// a sensible default. If the request implements Headerer, the provided headers
+// will be applied to the request.
+func EncodeJSONRequest(c context.Context, r *http.Request, request interface{}) error {
+ r.Header.Set("Content-Type", "application/json; charset=utf-8")
+ if headerer, ok := request.(Headerer); ok {
+ for k := range headerer.Headers() {
+ r.Header.Set(k, headerer.Headers().Get(k))
+ }
+ }
+ var b bytes.Buffer
+ r.Body = ioutil.NopCloser(&b)
+ return json.NewEncoder(&b).Encode(request)
+}
+
+// EncodeXMLRequest is an EncodeRequestFunc that serializes the request as a
+// XML object to the Request body. If the request implements Headerer,
+// the provided headers will be applied to the request.
+func EncodeXMLRequest(c context.Context, r *http.Request, request interface{}) error {
+ r.Header.Set("Content-Type", "text/xml; charset=utf-8")
+ if headerer, ok := request.(Headerer); ok {
+ for k := range headerer.Headers() {
+ r.Header.Set(k, headerer.Headers().Get(k))
+ }
+ }
+ var b bytes.Buffer
+ r.Body = ioutil.NopCloser(&b)
+ return xml.NewEncoder(&b).Encode(request)
+}
+
+//
+//
+//
+
+func makeCreateRequestFunc(method string, target *url.URL, enc EncodeRequestFunc) CreateRequestFunc {
+ return func(ctx context.Context, request interface{}) (*http.Request, error) {
+ req, err := http.NewRequest(method, target.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = enc(ctx, req, request); err != nil {
+ return nil, err
+ }
+
+ return req, nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/doc.go
new file mode 100644
index 000000000000..e64010358591
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/doc.go
@@ -0,0 +1,2 @@
+// Package http provides a general purpose HTTP binding for endpoints.
+package http
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/encode_decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/encode_decode.go
new file mode 100644
index 000000000000..b3de462b3e9a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/encode_decode.go
@@ -0,0 +1,36 @@
+package http
+
+import (
+ "context"
+ "net/http"
+)
+
+// DecodeRequestFunc extracts a user-domain request object from an HTTP
+// request object. It's designed to be used in HTTP servers, for server-side
+// endpoints. One straightforward DecodeRequestFunc could be something that
+// JSON decodes from the request body to the concrete request type.
+type DecodeRequestFunc func(context.Context, *http.Request) (request interface{}, err error)
+
+// EncodeRequestFunc encodes the passed request object into the HTTP request
+// object. It's designed to be used in HTTP clients, for client-side
+// endpoints. One straightforward EncodeRequestFunc could be something that JSON
+// encodes the object directly to the request body.
+type EncodeRequestFunc func(context.Context, *http.Request, interface{}) error
+
+// CreateRequestFunc creates an outgoing HTTP request based on the passed
+// request object. It's designed to be used in HTTP clients, for client-side
+// endpoints. It's a more powerful version of EncodeRequestFunc, and can be used
+// if more fine-grained control of the HTTP request is required.
+type CreateRequestFunc func(context.Context, interface{}) (*http.Request, error)
+
+// EncodeResponseFunc encodes the passed response object to the HTTP response
+// writer. It's designed to be used in HTTP servers, for server-side
+// endpoints. One straightforward EncodeResponseFunc could be something that
+// JSON encodes the object directly to the response body.
+type EncodeResponseFunc func(context.Context, http.ResponseWriter, interface{}) error
+
+// DecodeResponseFunc extracts a user-domain response object from an HTTP
+// response object. It's designed to be used in HTTP clients, for client-side
+// endpoints. One straightforward DecodeResponseFunc could be something that
+// JSON decodes from the response body to the concrete response type.
+type DecodeResponseFunc func(context.Context, *http.Response) (response interface{}, err error)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/request_response_funcs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/request_response_funcs.go
new file mode 100644
index 000000000000..8f92b3bc7f36
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/request_response_funcs.go
@@ -0,0 +1,133 @@
+package http
+
+import (
+ "context"
+ "net/http"
+)
+
+// RequestFunc may take information from an HTTP request and put it into a
+// request context. In Servers, RequestFuncs are executed prior to invoking the
+// endpoint. In Clients, RequestFuncs are executed after creating the request
+// but prior to invoking the HTTP client.
+type RequestFunc func(context.Context, *http.Request) context.Context
+
+// ServerResponseFunc may take information from a request context and use it to
+// manipulate a ResponseWriter. ServerResponseFuncs are only executed in
+// servers, after invoking the endpoint but prior to writing a response.
+type ServerResponseFunc func(context.Context, http.ResponseWriter) context.Context
+
+// ClientResponseFunc may take information from an HTTP request and make the
+// response available for consumption. ClientResponseFuncs are only executed in
+// clients, after a request has been made, but prior to it being decoded.
+type ClientResponseFunc func(context.Context, *http.Response) context.Context
+
+// SetContentType returns a ServerResponseFunc that sets the Content-Type header
+// to the provided value.
+func SetContentType(contentType string) ServerResponseFunc {
+ return SetResponseHeader("Content-Type", contentType)
+}
+
+// SetResponseHeader returns a ServerResponseFunc that sets the given header.
+func SetResponseHeader(key, val string) ServerResponseFunc {
+ return func(ctx context.Context, w http.ResponseWriter) context.Context {
+ w.Header().Set(key, val)
+ return ctx
+ }
+}
+
+// SetRequestHeader returns a RequestFunc that sets the given header.
+func SetRequestHeader(key, val string) RequestFunc {
+ return func(ctx context.Context, r *http.Request) context.Context {
+ r.Header.Set(key, val)
+ return ctx
+ }
+}
+
+// PopulateRequestContext is a RequestFunc that populates several values into
+// the context from the HTTP request. Those values may be extracted using the
+// corresponding ContextKey type in this package.
+func PopulateRequestContext(ctx context.Context, r *http.Request) context.Context {
+ for k, v := range map[contextKey]string{
+ ContextKeyRequestMethod: r.Method,
+ ContextKeyRequestURI: r.RequestURI,
+ ContextKeyRequestPath: r.URL.Path,
+ ContextKeyRequestProto: r.Proto,
+ ContextKeyRequestHost: r.Host,
+ ContextKeyRequestRemoteAddr: r.RemoteAddr,
+ ContextKeyRequestXForwardedFor: r.Header.Get("X-Forwarded-For"),
+ ContextKeyRequestXForwardedProto: r.Header.Get("X-Forwarded-Proto"),
+ ContextKeyRequestAuthorization: r.Header.Get("Authorization"),
+ ContextKeyRequestReferer: r.Header.Get("Referer"),
+ ContextKeyRequestUserAgent: r.Header.Get("User-Agent"),
+ ContextKeyRequestXRequestID: r.Header.Get("X-Request-Id"),
+ ContextKeyRequestAccept: r.Header.Get("Accept"),
+ } {
+ ctx = context.WithValue(ctx, k, v)
+ }
+ return ctx
+}
+
+type contextKey int
+
+const (
+ // ContextKeyRequestMethod is populated in the context by
+ // PopulateRequestContext. Its value is r.Method.
+ ContextKeyRequestMethod contextKey = iota
+
+ // ContextKeyRequestURI is populated in the context by
+ // PopulateRequestContext. Its value is r.RequestURI.
+ ContextKeyRequestURI
+
+ // ContextKeyRequestPath is populated in the context by
+ // PopulateRequestContext. Its value is r.URL.Path.
+ ContextKeyRequestPath
+
+ // ContextKeyRequestProto is populated in the context by
+ // PopulateRequestContext. Its value is r.Proto.
+ ContextKeyRequestProto
+
+ // ContextKeyRequestHost is populated in the context by
+ // PopulateRequestContext. Its value is r.Host.
+ ContextKeyRequestHost
+
+ // ContextKeyRequestRemoteAddr is populated in the context by
+ // PopulateRequestContext. Its value is r.RemoteAddr.
+ ContextKeyRequestRemoteAddr
+
+ // ContextKeyRequestXForwardedFor is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("X-Forwarded-For").
+ ContextKeyRequestXForwardedFor
+
+ // ContextKeyRequestXForwardedProto is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("X-Forwarded-Proto").
+ ContextKeyRequestXForwardedProto
+
+ // ContextKeyRequestAuthorization is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("Authorization").
+ ContextKeyRequestAuthorization
+
+ // ContextKeyRequestReferer is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("Referer").
+ ContextKeyRequestReferer
+
+ // ContextKeyRequestUserAgent is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("User-Agent").
+ ContextKeyRequestUserAgent
+
+ // ContextKeyRequestXRequestID is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("X-Request-Id").
+ ContextKeyRequestXRequestID
+
+ // ContextKeyRequestAccept is populated in the context by
+ // PopulateRequestContext. Its value is r.Header.Get("Accept").
+ ContextKeyRequestAccept
+
+ // ContextKeyResponseHeaders is populated in the context whenever a
+ // ServerFinalizerFunc is specified. Its value is of type http.Header, and
+ // is captured only once the entire response has been written.
+ ContextKeyResponseHeaders
+
+ // ContextKeyResponseSize is populated in the context whenever a
+ // ServerFinalizerFunc is specified. Its value is of type int64.
+ ContextKeyResponseSize
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/server.go
new file mode 100644
index 000000000000..dfd1ff3d6994
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/transport/http/server.go
@@ -0,0 +1,244 @@
+package http
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+
+ "github.com/go-kit/kit/endpoint"
+ "github.com/go-kit/kit/transport"
+ "github.com/go-kit/log"
+)
+
+// Server wraps an endpoint and implements http.Handler.
+type Server struct {
+ e endpoint.Endpoint
+ dec DecodeRequestFunc
+ enc EncodeResponseFunc
+ before []RequestFunc
+ after []ServerResponseFunc
+ errorEncoder ErrorEncoder
+ finalizer []ServerFinalizerFunc
+ errorHandler transport.ErrorHandler
+}
+
+// NewServer constructs a new server, which implements http.Handler and wraps
+// the provided endpoint.
+func NewServer(
+ e endpoint.Endpoint,
+ dec DecodeRequestFunc,
+ enc EncodeResponseFunc,
+ options ...ServerOption,
+) *Server {
+ s := &Server{
+ e: e,
+ dec: dec,
+ enc: enc,
+ errorEncoder: DefaultErrorEncoder,
+ errorHandler: transport.NewLogErrorHandler(log.NewNopLogger()),
+ }
+ for _, option := range options {
+ option(s)
+ }
+ return s
+}
+
+// ServerOption sets an optional parameter for servers.
+type ServerOption func(*Server)
+
+// ServerBefore functions are executed on the HTTP request object before the
+// request is decoded.
+func ServerBefore(before ...RequestFunc) ServerOption {
+ return func(s *Server) { s.before = append(s.before, before...) }
+}
+
+// ServerAfter functions are executed on the HTTP response writer after the
+// endpoint is invoked, but before anything is written to the client.
+func ServerAfter(after ...ServerResponseFunc) ServerOption {
+ return func(s *Server) { s.after = append(s.after, after...) }
+}
+
+// ServerErrorEncoder is used to encode errors to the http.ResponseWriter
+// whenever they're encountered in the processing of a request. Clients can
+// use this to provide custom error formatting and response codes. By default,
+// errors will be written with the DefaultErrorEncoder.
+func ServerErrorEncoder(ee ErrorEncoder) ServerOption {
+ return func(s *Server) { s.errorEncoder = ee }
+}
+
+// ServerErrorLogger is used to log non-terminal errors. By default, no errors
+// are logged. This is intended as a diagnostic measure. Finer-grained control
+// of error handling, including logging in more detail, should be performed in a
+// custom ServerErrorEncoder or ServerFinalizer, both of which have access to
+// the context.
+// Deprecated: Use ServerErrorHandler instead.
+func ServerErrorLogger(logger log.Logger) ServerOption {
+ return func(s *Server) { s.errorHandler = transport.NewLogErrorHandler(logger) }
+}
+
+// ServerErrorHandler is used to handle non-terminal errors. By default, non-terminal errors
+// are ignored. This is intended as a diagnostic measure. Finer-grained control
+// of error handling, including logging in more detail, should be performed in a
+// custom ServerErrorEncoder or ServerFinalizer, both of which have access to
+// the context.
+func ServerErrorHandler(errorHandler transport.ErrorHandler) ServerOption {
+ return func(s *Server) { s.errorHandler = errorHandler }
+}
+
+// ServerFinalizer is executed at the end of every HTTP request.
+// By default, no finalizer is registered.
+func ServerFinalizer(f ...ServerFinalizerFunc) ServerOption {
+ return func(s *Server) { s.finalizer = append(s.finalizer, f...) }
+}
+
+// ServeHTTP implements http.Handler.
+func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ if len(s.finalizer) > 0 {
+ iw := &interceptingWriter{w, http.StatusOK, 0}
+ defer func() {
+ ctx = context.WithValue(ctx, ContextKeyResponseHeaders, iw.Header())
+ ctx = context.WithValue(ctx, ContextKeyResponseSize, iw.written)
+ for _, f := range s.finalizer {
+ f(ctx, iw.code, r)
+ }
+ }()
+ w = iw
+ }
+
+ for _, f := range s.before {
+ ctx = f(ctx, r)
+ }
+
+ request, err := s.dec(ctx, r)
+ if err != nil {
+ s.errorHandler.Handle(ctx, err)
+ s.errorEncoder(ctx, err, w)
+ return
+ }
+
+ response, err := s.e(ctx, request)
+ if err != nil {
+ s.errorHandler.Handle(ctx, err)
+ s.errorEncoder(ctx, err, w)
+ return
+ }
+
+ for _, f := range s.after {
+ ctx = f(ctx, w)
+ }
+
+ if err := s.enc(ctx, w, response); err != nil {
+ s.errorHandler.Handle(ctx, err)
+ s.errorEncoder(ctx, err, w)
+ return
+ }
+}
+
+// ErrorEncoder is responsible for encoding an error to the ResponseWriter.
+// Users are encouraged to use custom ErrorEncoders to encode HTTP errors to
+// their clients, and will likely want to pass and check for their own error
+// types. See the example shipping/handling service.
+type ErrorEncoder func(ctx context.Context, err error, w http.ResponseWriter)
+
+// ServerFinalizerFunc can be used to perform work at the end of an HTTP
+// request, after the response has been written to the client. The principal
+// intended use is for request logging. In addition to the response code
+// provided in the function signature, additional response parameters are
+// provided in the context under keys with the ContextKeyResponse prefix.
+type ServerFinalizerFunc func(ctx context.Context, code int, r *http.Request)
+
+// NopRequestDecoder is a DecodeRequestFunc that can be used for requests that do not
+// need to be decoded, and simply returns nil, nil.
+func NopRequestDecoder(ctx context.Context, r *http.Request) (interface{}, error) {
+ return nil, nil
+}
+
+// EncodeJSONResponse is a EncodeResponseFunc that serializes the response as a
+// JSON object to the ResponseWriter. Many JSON-over-HTTP services can use it as
+// a sensible default. If the response implements Headerer, the provided headers
+// will be applied to the response. If the response implements StatusCoder, the
+// provided StatusCode will be used instead of 200.
+func EncodeJSONResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ if headerer, ok := response.(Headerer); ok {
+ for k, values := range headerer.Headers() {
+ for _, v := range values {
+ w.Header().Add(k, v)
+ }
+ }
+ }
+ code := http.StatusOK
+ if sc, ok := response.(StatusCoder); ok {
+ code = sc.StatusCode()
+ }
+ w.WriteHeader(code)
+ if code == http.StatusNoContent {
+ return nil
+ }
+ return json.NewEncoder(w).Encode(response)
+}
+
+// DefaultErrorEncoder writes the error to the ResponseWriter, by default a
+// content type of text/plain, a body of the plain text of the error, and a
+// status code of 500. If the error implements Headerer, the provided headers
+// will be applied to the response. If the error implements json.Marshaler, and
+// the marshaling succeeds, a content type of application/json and the JSON
+// encoded form of the error will be used. If the error implements StatusCoder,
+// the provided StatusCode will be used instead of 500.
+func DefaultErrorEncoder(_ context.Context, err error, w http.ResponseWriter) {
+ contentType, body := "text/plain; charset=utf-8", []byte(err.Error())
+ if marshaler, ok := err.(json.Marshaler); ok {
+ if jsonBody, marshalErr := marshaler.MarshalJSON(); marshalErr == nil {
+ contentType, body = "application/json; charset=utf-8", jsonBody
+ }
+ }
+ w.Header().Set("Content-Type", contentType)
+ if headerer, ok := err.(Headerer); ok {
+ for k, values := range headerer.Headers() {
+ for _, v := range values {
+ w.Header().Add(k, v)
+ }
+ }
+ }
+ code := http.StatusInternalServerError
+ if sc, ok := err.(StatusCoder); ok {
+ code = sc.StatusCode()
+ }
+ w.WriteHeader(code)
+ w.Write(body)
+}
+
+// StatusCoder is checked by DefaultErrorEncoder. If an error value implements
+// StatusCoder, the StatusCode will be used when encoding the error. By default,
+// StatusInternalServerError (500) is used.
+type StatusCoder interface {
+ StatusCode() int
+}
+
+// Headerer is checked by DefaultErrorEncoder. If an error value implements
+// Headerer, the provided headers will be applied to the response writer, after
+// the Content-Type is set.
+type Headerer interface {
+ Headers() http.Header
+}
+
+type interceptingWriter struct {
+ http.ResponseWriter
+ code int
+ written int64
+}
+
+// WriteHeader may not be explicitly called, so care must be taken to
+// initialize w.code to its default value of http.StatusOK.
+func (w *interceptingWriter) WriteHeader(code int) {
+ w.code = code
+ w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *interceptingWriter) Write(p []byte) (int, error) {
+ n, err := w.ResponseWriter.Write(p)
+ w.written += int64(n)
+ return n, err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/.gitignore
new file mode 100644
index 000000000000..66fd13c903ca
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/LICENSE
new file mode 100644
index 000000000000..bb5bdb9cb8c9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Go kit
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/README.md
new file mode 100644
index 000000000000..a0931951df8d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/README.md
@@ -0,0 +1,151 @@
+# package log
+
+`package log` provides a minimal interface for structured logging in services.
+It may be wrapped to encode conventions, enforce type-safety, provide leveled
+logging, and so on. It can be used for both typical application log events,
+and log-structured data streams.
+
+## Structured logging
+
+Structured logging is, basically, conceding to the reality that logs are
+_data_, and warrant some level of schematic rigor. Using a stricter,
+key/value-oriented message format for our logs, containing contextual and
+semantic information, makes it much easier to get insight into the
+operational activity of the systems we build. Consequently, `package log` is
+of the strong belief that "[the benefits of structured logging outweigh the
+minimal effort involved](https://www.thoughtworks.com/radar/techniques/structured-logging)".
+
+Migrating from unstructured to structured logging is probably a lot easier
+than you'd expect.
+
+```go
+// Unstructured
+log.Printf("HTTP server listening on %s", addr)
+
+// Structured
+logger.Log("transport", "HTTP", "addr", addr, "msg", "listening")
+```
+
+## Usage
+
+### Typical application logging
+
+```go
+w := log.NewSyncWriter(os.Stderr)
+logger := log.NewLogfmtLogger(w)
+logger.Log("question", "what is the meaning of life?", "answer", 42)
+
+// Output:
+// question="what is the meaning of life?" answer=42
+```
+
+### Contextual Loggers
+
+```go
+func main() {
+ var logger log.Logger
+ logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
+ logger = log.With(logger, "instance_id", 123)
+
+ logger.Log("msg", "starting")
+ NewWorker(log.With(logger, "component", "worker")).Run()
+ NewSlacker(log.With(logger, "component", "slacker")).Run()
+}
+
+// Output:
+// instance_id=123 msg=starting
+// instance_id=123 component=worker msg=running
+// instance_id=123 component=slacker msg=running
+```
+
+### Interact with stdlib logger
+
+Redirect stdlib logger to Go kit logger.
+
+```go
+import (
+ "os"
+ stdlog "log"
+ kitlog "github.com/go-kit/log"
+)
+
+func main() {
+ logger := kitlog.NewJSONLogger(kitlog.NewSyncWriter(os.Stdout))
+ stdlog.SetOutput(kitlog.NewStdlibAdapter(logger))
+ stdlog.Print("I sure like pie")
+}
+
+// Output:
+// {"msg":"I sure like pie","ts":"2016/01/01 12:34:56"}
+```
+
+Or, if, for legacy reasons, you need to pipe all of your logging through the
+stdlib log package, you can redirect Go kit logger to the stdlib logger.
+
+```go
+logger := kitlog.NewLogfmtLogger(kitlog.StdlibWriter{})
+logger.Log("legacy", true, "msg", "at least it's something")
+
+// Output:
+// 2016/01/01 12:34:56 legacy=true msg="at least it's something"
+```
+
+### Timestamps and callers
+
+```go
+var logger log.Logger
+logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
+logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
+
+logger.Log("msg", "hello")
+
+// Output:
+// ts=2016-01-01T12:34:56Z caller=main.go:15 msg=hello
+```
+
+## Levels
+
+Log levels are supported via the [level package](https://godoc.org/github.com/go-kit/log/level).
+
+## Supported output formats
+
+- [Logfmt](https://brandur.org/logfmt) ([see also](https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write))
+- JSON
+
+## Enhancements
+
+`package log` is centered on the one-method Logger interface.
+
+```go
+type Logger interface {
+ Log(keyvals ...interface{}) error
+}
+```
+
+This interface, and its supporting code like is the product of much iteration
+and evaluation. For more details on the evolution of the Logger interface,
+see [The Hunt for a Logger Interface](http://go-talks.appspot.com/github.com/ChrisHines/talks/structured-logging/structured-logging.slide#1),
+a talk by [Chris Hines](https://github.com/ChrisHines).
+Also, please see
+[#63](https://github.com/go-kit/kit/issues/63),
+[#76](https://github.com/go-kit/kit/pull/76),
+[#131](https://github.com/go-kit/kit/issues/131),
+[#157](https://github.com/go-kit/kit/pull/157),
+[#164](https://github.com/go-kit/kit/issues/164), and
+[#252](https://github.com/go-kit/kit/pull/252)
+to review historical conversations about package log and the Logger interface.
+
+Value-add packages and suggestions,
+like improvements to [the leveled logger](https://godoc.org/github.com/go-kit/log/level),
+are of course welcome. Good proposals should
+
+- Be composable with [contextual loggers](https://godoc.org/github.com/go-kit/log#With),
+- Not break the behavior of [log.Caller](https://godoc.org/github.com/go-kit/log#Caller) in any wrapped contextual loggers, and
+- Be friendly to packages that accept only an unadorned log.Logger.
+
+## Benchmarks & comparisons
+
+There are a few Go logging benchmarks and comparisons that include Go kit's package log.
+
+- [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench) includes kit/log
+- [uber-common/zap](https://github.com/uber-common/zap), a zero-alloc logging library, includes a comparison with kit/log
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/doc.go
new file mode 100644
index 000000000000..f744382fe499
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/doc.go
@@ -0,0 +1,116 @@
+// Package log provides a structured logger.
+//
+// Structured logging produces logs easily consumed later by humans or
+// machines. Humans might be interested in debugging errors, or tracing
+// specific requests. Machines might be interested in counting interesting
+// events, or aggregating information for off-line processing. In both cases,
+// it is important that the log messages are structured and actionable.
+// Package log is designed to encourage both of these best practices.
+//
+// Basic Usage
+//
+// The fundamental interface is Logger. Loggers create log events from
+// key/value data. The Logger interface has a single method, Log, which
+// accepts a sequence of alternating key/value pairs, which this package names
+// keyvals.
+//
+// type Logger interface {
+// Log(keyvals ...interface{}) error
+// }
+//
+// Here is an example of a function using a Logger to create log events.
+//
+// func RunTask(task Task, logger log.Logger) string {
+// logger.Log("taskID", task.ID, "event", "starting task")
+// ...
+// logger.Log("taskID", task.ID, "event", "task complete")
+// }
+//
+// The keys in the above example are "taskID" and "event". The values are
+// task.ID, "starting task", and "task complete". Every key is followed
+// immediately by its value.
+//
+// Keys are usually plain strings. Values may be any type that has a sensible
+// encoding in the chosen log format. With structured logging it is a good
+// idea to log simple values without formatting them. This practice allows
+// the chosen logger to encode values in the most appropriate way.
+//
+// Contextual Loggers
+//
+// A contextual logger stores keyvals that it includes in all log events.
+// Building appropriate contextual loggers reduces repetition and aids
+// consistency in the resulting log output. With, WithPrefix, and WithSuffix
+// add context to a logger. We can use With to improve the RunTask example.
+//
+// func RunTask(task Task, logger log.Logger) string {
+// logger = log.With(logger, "taskID", task.ID)
+// logger.Log("event", "starting task")
+// ...
+// taskHelper(task.Cmd, logger)
+// ...
+// logger.Log("event", "task complete")
+// }
+//
+// The improved version emits the same log events as the original for the
+// first and last calls to Log. Passing the contextual logger to taskHelper
+// enables each log event created by taskHelper to include the task.ID even
+// though taskHelper does not have access to that value. Using contextual
+// loggers this way simplifies producing log output that enables tracing the
+// life cycle of individual tasks. (See the Contextual example for the full
+// code of the above snippet.)
+//
+// Dynamic Contextual Values
+//
+// A Valuer function stored in a contextual logger generates a new value each
+// time an event is logged. The Valuer example demonstrates how this feature
+// works.
+//
+// Valuers provide the basis for consistently logging timestamps and source
+// code location. The log package defines several valuers for that purpose.
+// See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and
+// DefaultCaller. A common logger initialization sequence that ensures all log
+// entries contain a timestamp and source location looks like this:
+//
+// logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
+// logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
+//
+// Concurrent Safety
+//
+// Applications with multiple goroutines want each log event written to the
+// same logger to remain separate from other log events. Package log provides
+// two simple solutions for concurrent safe logging.
+//
+// NewSyncWriter wraps an io.Writer and serializes each call to its Write
+// method. Using a SyncWriter has the benefit that the smallest practical
+// portion of the logging logic is performed within a mutex, but it requires
+// the formatting Logger to make only one call to Write per log event.
+//
+// NewSyncLogger wraps any Logger and serializes each call to its Log method.
+// Using a SyncLogger has the benefit that it guarantees each log event is
+// handled atomically within the wrapped logger, but it typically serializes
+// both the formatting and output logic. Use a SyncLogger if the formatting
+// logger may perform multiple writes per log event.
+//
+// Error Handling
+//
+// This package relies on the practice of wrapping or decorating loggers with
+// other loggers to provide composable pieces of functionality. It also means
+// that Logger.Log must return an error because some
+// implementations—especially those that output log data to an io.Writer—may
+// encounter errors that cannot be handled locally. This in turn means that
+// Loggers that wrap other loggers should return errors from the wrapped
+// logger up the stack.
+//
+// Fortunately, the decorator pattern also provides a way to avoid the
+// necessity to check for errors every time an application calls Logger.Log.
+// An application required to panic whenever its Logger encounters
+// an error could initialize its logger as follows.
+//
+// fmtlogger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
+// logger := log.LoggerFunc(func(keyvals ...interface{}) error {
+// if err := fmtlogger.Log(keyvals...); err != nil {
+// panic(err)
+// }
+// return nil
+// })
+package log
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/json_logger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/json_logger.go
new file mode 100644
index 000000000000..0cedbf82478e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/json_logger.go
@@ -0,0 +1,91 @@
+package log
+
+import (
+ "encoding"
+ "encoding/json"
+ "fmt"
+ "io"
+ "reflect"
+)
+
+type jsonLogger struct {
+ io.Writer
+}
+
+// NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
+// single JSON object. Each log event produces no more than one call to
+// w.Write. The passed Writer must be safe for concurrent use by multiple
+// goroutines if the returned Logger will be used concurrently.
+func NewJSONLogger(w io.Writer) Logger {
+ return &jsonLogger{w}
+}
+
+func (l *jsonLogger) Log(keyvals ...interface{}) error {
+ n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
+ m := make(map[string]interface{}, n)
+ for i := 0; i < len(keyvals); i += 2 {
+ k := keyvals[i]
+ var v interface{} = ErrMissingValue
+ if i+1 < len(keyvals) {
+ v = keyvals[i+1]
+ }
+ merge(m, k, v)
+ }
+ enc := json.NewEncoder(l.Writer)
+ enc.SetEscapeHTML(false)
+ return enc.Encode(m)
+}
+
+func merge(dst map[string]interface{}, k, v interface{}) {
+ var key string
+ switch x := k.(type) {
+ case string:
+ key = x
+ case fmt.Stringer:
+ key = safeString(x)
+ default:
+ key = fmt.Sprint(x)
+ }
+
+ // We want json.Marshaler and encoding.TextMarshaller to take priority over
+ // err.Error() and v.String(). But json.Marshall (called later) does that by
+ // default so we force a no-op if it's one of those 2 case.
+ switch x := v.(type) {
+ case json.Marshaler:
+ case encoding.TextMarshaler:
+ case error:
+ v = safeError(x)
+ case fmt.Stringer:
+ v = safeString(x)
+ }
+
+ dst[key] = v
+}
+
+func safeString(str fmt.Stringer) (s string) {
+ defer func() {
+ if panicVal := recover(); panicVal != nil {
+ if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
+ s = "NULL"
+ } else {
+ panic(panicVal)
+ }
+ }
+ }()
+ s = str.String()
+ return
+}
+
+func safeError(err error) (s interface{}) {
+ defer func() {
+ if panicVal := recover(); panicVal != nil {
+ if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
+ s = nil
+ } else {
+ panic(panicVal)
+ }
+ }
+ }()
+ s = err.Error()
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/log.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/log.go
new file mode 100644
index 000000000000..62e11adace59
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/log.go
@@ -0,0 +1,179 @@
+package log
+
+import "errors"
+
+// Logger is the fundamental interface for all log operations. Log creates a
+// log event from keyvals, a variadic sequence of alternating keys and values.
+// Implementations must be safe for concurrent use by multiple goroutines. In
+// particular, any implementation of Logger that appends to keyvals or
+// modifies or retains any of its elements must make a copy first.
+type Logger interface {
+ Log(keyvals ...interface{}) error
+}
+
+// ErrMissingValue is appended to keyvals slices with odd length to substitute
+// the missing value.
+var ErrMissingValue = errors.New("(MISSING)")
+
+// With returns a new contextual logger with keyvals prepended to those passed
+// to calls to Log. If logger is also a contextual logger created by With,
+// WithPrefix, or WithSuffix, keyvals is appended to the existing context.
+//
+// The returned Logger replaces all value elements (odd indexes) containing a
+// Valuer with their generated value for each call to its Log method.
+func With(logger Logger, keyvals ...interface{}) Logger {
+ if len(keyvals) == 0 {
+ return logger
+ }
+ l := newContext(logger)
+ kvs := append(l.keyvals, keyvals...)
+ if len(kvs)%2 != 0 {
+ kvs = append(kvs, ErrMissingValue)
+ }
+ return &context{
+ logger: l.logger,
+ // Limiting the capacity of the stored keyvals ensures that a new
+ // backing array is created if the slice must grow in Log or With.
+ // Using the extra capacity without copying risks a data race that
+ // would violate the Logger interface contract.
+ keyvals: kvs[:len(kvs):len(kvs)],
+ hasValuer: l.hasValuer || containsValuer(keyvals),
+ sKeyvals: l.sKeyvals,
+ sHasValuer: l.sHasValuer,
+ }
+}
+
+// WithPrefix returns a new contextual logger with keyvals prepended to those
+// passed to calls to Log. If logger is also a contextual logger created by
+// With, WithPrefix, or WithSuffix, keyvals is prepended to the existing context.
+//
+// The returned Logger replaces all value elements (odd indexes) containing a
+// Valuer with their generated value for each call to its Log method.
+func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
+ if len(keyvals) == 0 {
+ return logger
+ }
+ l := newContext(logger)
+ // Limiting the capacity of the stored keyvals ensures that a new
+ // backing array is created if the slice must grow in Log or With.
+ // Using the extra capacity without copying risks a data race that
+ // would violate the Logger interface contract.
+ n := len(l.keyvals) + len(keyvals)
+ if len(keyvals)%2 != 0 {
+ n++
+ }
+ kvs := make([]interface{}, 0, n)
+ kvs = append(kvs, keyvals...)
+ if len(kvs)%2 != 0 {
+ kvs = append(kvs, ErrMissingValue)
+ }
+ kvs = append(kvs, l.keyvals...)
+ return &context{
+ logger: l.logger,
+ keyvals: kvs,
+ hasValuer: l.hasValuer || containsValuer(keyvals),
+ sKeyvals: l.sKeyvals,
+ sHasValuer: l.sHasValuer,
+ }
+}
+
+// WithSuffix returns a new contextual logger with keyvals appended to those
+// passed to calls to Log. If logger is also a contextual logger created by
+// With, WithPrefix, or WithSuffix, keyvals is appended to the existing context.
+//
+// The returned Logger replaces all value elements (odd indexes) containing a
+// Valuer with their generated value for each call to its Log method.
+func WithSuffix(logger Logger, keyvals ...interface{}) Logger {
+ if len(keyvals) == 0 {
+ return logger
+ }
+ l := newContext(logger)
+ // Limiting the capacity of the stored keyvals ensures that a new
+ // backing array is created if the slice must grow in Log or With.
+ // Using the extra capacity without copying risks a data race that
+ // would violate the Logger interface contract.
+ n := len(l.sKeyvals) + len(keyvals)
+ if len(keyvals)%2 != 0 {
+ n++
+ }
+ kvs := make([]interface{}, 0, n)
+ kvs = append(kvs, keyvals...)
+ if len(kvs)%2 != 0 {
+ kvs = append(kvs, ErrMissingValue)
+ }
+ kvs = append(l.sKeyvals, kvs...)
+ return &context{
+ logger: l.logger,
+ keyvals: l.keyvals,
+ hasValuer: l.hasValuer,
+ sKeyvals: kvs,
+ sHasValuer: l.sHasValuer || containsValuer(keyvals),
+ }
+}
+
+// context is the Logger implementation returned by With, WithPrefix, and
+// WithSuffix. It wraps a Logger and holds keyvals that it includes in all
+// log events. Its Log method calls bindValues to generate values for each
+// Valuer in the context keyvals.
+//
+// A context must always have the same number of stack frames between calls to
+// its Log method and the eventual binding of Valuers to their value. This
+// requirement comes from the functional requirement to allow a context to
+// resolve application call site information for a Caller stored in the
+// context. To do this we must be able to predict the number of logging
+// functions on the stack when bindValues is called.
+//
+// Two implementation details provide the needed stack depth consistency.
+//
+// 1. newContext avoids introducing an additional layer when asked to
+// wrap another context.
+// 2. With, WithPrefix, and WithSuffix avoid introducing an additional
+// layer by returning a newly constructed context with a merged keyvals
+// rather than simply wrapping the existing context.
+type context struct {
+ logger Logger
+ keyvals []interface{}
+ sKeyvals []interface{} // suffixes
+ hasValuer bool
+ sHasValuer bool
+}
+
+func newContext(logger Logger) *context {
+ if c, ok := logger.(*context); ok {
+ return c
+ }
+ return &context{logger: logger}
+}
+
+// Log replaces all value elements (odd indexes) containing a Valuer in the
+// stored context with their generated value, appends keyvals, and passes the
+// result to the wrapped Logger.
+func (l *context) Log(keyvals ...interface{}) error {
+ kvs := append(l.keyvals, keyvals...)
+ if len(kvs)%2 != 0 {
+ kvs = append(kvs, ErrMissingValue)
+ }
+ if l.hasValuer {
+ // If no keyvals were appended above then we must copy l.keyvals so
+ // that future log events will reevaluate the stored Valuers.
+ if len(keyvals) == 0 {
+ kvs = append([]interface{}{}, l.keyvals...)
+ }
+ bindValues(kvs[:(len(l.keyvals))])
+ }
+ kvs = append(kvs, l.sKeyvals...)
+ if l.sHasValuer {
+ bindValues(kvs[len(kvs)-len(l.sKeyvals):])
+ }
+ return l.logger.Log(kvs...)
+}
+
+// LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
+// f is a function with the appropriate signature, LoggerFunc(f) is a Logger
+// object that calls f.
+type LoggerFunc func(...interface{}) error
+
+// Log implements Logger by calling f(keyvals...).
+func (f LoggerFunc) Log(keyvals ...interface{}) error {
+ return f(keyvals...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/logfmt_logger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/logfmt_logger.go
new file mode 100644
index 000000000000..a00305298b82
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/logfmt_logger.go
@@ -0,0 +1,62 @@
+package log
+
+import (
+ "bytes"
+ "io"
+ "sync"
+
+ "github.com/go-logfmt/logfmt"
+)
+
+type logfmtEncoder struct {
+ *logfmt.Encoder
+ buf bytes.Buffer
+}
+
+func (l *logfmtEncoder) Reset() {
+ l.Encoder.Reset()
+ l.buf.Reset()
+}
+
+var logfmtEncoderPool = sync.Pool{
+ New: func() interface{} {
+ var enc logfmtEncoder
+ enc.Encoder = logfmt.NewEncoder(&enc.buf)
+ return &enc
+ },
+}
+
+type logfmtLogger struct {
+ w io.Writer
+}
+
+// NewLogfmtLogger returns a logger that encodes keyvals to the Writer in
+// logfmt format. Each log event produces no more than one call to w.Write.
+// The passed Writer must be safe for concurrent use by multiple goroutines if
+// the returned Logger will be used concurrently.
+func NewLogfmtLogger(w io.Writer) Logger {
+ return &logfmtLogger{w}
+}
+
+func (l logfmtLogger) Log(keyvals ...interface{}) error {
+ enc := logfmtEncoderPool.Get().(*logfmtEncoder)
+ enc.Reset()
+ defer logfmtEncoderPool.Put(enc)
+
+ if err := enc.EncodeKeyvals(keyvals...); err != nil {
+ return err
+ }
+
+ // Add newline to the end of the buffer
+ if err := enc.EndRecord(); err != nil {
+ return err
+ }
+
+ // The Logger interface requires implementations to be safe for concurrent
+ // use by multiple goroutines. For this implementation that means making
+ // only one call to l.w.Write() for each call to Log.
+ if _, err := l.w.Write(enc.buf.Bytes()); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/nop_logger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/nop_logger.go
new file mode 100644
index 000000000000..1047d626c436
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/nop_logger.go
@@ -0,0 +1,8 @@
+package log
+
+type nopLogger struct{}
+
+// NewNopLogger returns a logger that doesn't do anything.
+func NewNopLogger() Logger { return nopLogger{} }
+
+func (nopLogger) Log(...interface{}) error { return nil }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/stdlib.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/stdlib.go
new file mode 100644
index 000000000000..0338edbe2ba3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/stdlib.go
@@ -0,0 +1,151 @@
+package log
+
+import (
+ "bytes"
+ "io"
+ "log"
+ "regexp"
+ "strings"
+)
+
+// StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
+// designed to be passed to a Go kit logger as the writer, for cases where
+// it's necessary to redirect all Go kit log output to the stdlib logger.
+//
+// If you have any choice in the matter, you shouldn't use this. Prefer to
+// redirect the stdlib log to the Go kit logger via NewStdlibAdapter.
+type StdlibWriter struct{}
+
+// Write implements io.Writer.
+func (w StdlibWriter) Write(p []byte) (int, error) {
+ log.Print(strings.TrimSpace(string(p)))
+ return len(p), nil
+}
+
+// StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
+// logger's SetOutput. It will extract date/timestamps, filenames, and
+// messages, and place them under relevant keys.
+type StdlibAdapter struct {
+ Logger
+ timestampKey string
+ fileKey string
+ messageKey string
+ prefix string
+ joinPrefixToMsg bool
+}
+
+// StdlibAdapterOption sets a parameter for the StdlibAdapter.
+type StdlibAdapterOption func(*StdlibAdapter)
+
+// TimestampKey sets the key for the timestamp field. By default, it's "ts".
+func TimestampKey(key string) StdlibAdapterOption {
+ return func(a *StdlibAdapter) { a.timestampKey = key }
+}
+
+// FileKey sets the key for the file and line field. By default, it's "caller".
+func FileKey(key string) StdlibAdapterOption {
+ return func(a *StdlibAdapter) { a.fileKey = key }
+}
+
+// MessageKey sets the key for the actual log message. By default, it's "msg".
+func MessageKey(key string) StdlibAdapterOption {
+ return func(a *StdlibAdapter) { a.messageKey = key }
+}
+
+// Prefix configures the adapter to parse a prefix from stdlib log events. If
+// you provide a non-empty prefix to the stdlib logger, then your should provide
+// that same prefix to the adapter via this option.
+//
+// By default, the prefix isn't included in the msg key. Set joinPrefixToMsg to
+// true if you want to include the parsed prefix in the msg.
+func Prefix(prefix string, joinPrefixToMsg bool) StdlibAdapterOption {
+ return func(a *StdlibAdapter) { a.prefix = prefix; a.joinPrefixToMsg = joinPrefixToMsg }
+}
+
+// NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
+// logger. It's designed to be passed to log.SetOutput.
+func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
+ a := StdlibAdapter{
+ Logger: logger,
+ timestampKey: "ts",
+ fileKey: "caller",
+ messageKey: "msg",
+ }
+ for _, option := range options {
+ option(&a)
+ }
+ return a
+}
+
+func (a StdlibAdapter) Write(p []byte) (int, error) {
+ p = a.handlePrefix(p)
+
+ result := subexps(p)
+ keyvals := []interface{}{}
+ var timestamp string
+ if date, ok := result["date"]; ok && date != "" {
+ timestamp = date
+ }
+ if time, ok := result["time"]; ok && time != "" {
+ if timestamp != "" {
+ timestamp += " "
+ }
+ timestamp += time
+ }
+ if timestamp != "" {
+ keyvals = append(keyvals, a.timestampKey, timestamp)
+ }
+ if file, ok := result["file"]; ok && file != "" {
+ keyvals = append(keyvals, a.fileKey, file)
+ }
+ if msg, ok := result["msg"]; ok {
+ msg = a.handleMessagePrefix(msg)
+ keyvals = append(keyvals, a.messageKey, msg)
+ }
+ if err := a.Logger.Log(keyvals...); err != nil {
+ return 0, err
+ }
+ return len(p), nil
+}
+
+func (a StdlibAdapter) handlePrefix(p []byte) []byte {
+ if a.prefix != "" {
+ p = bytes.TrimPrefix(p, []byte(a.prefix))
+ }
+ return p
+}
+
+func (a StdlibAdapter) handleMessagePrefix(msg string) string {
+ if a.prefix == "" {
+ return msg
+ }
+
+ msg = strings.TrimPrefix(msg, a.prefix)
+ if a.joinPrefixToMsg {
+ msg = a.prefix + msg
+ }
+ return msg
+}
+
+const (
+ logRegexpDate = `(?P[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
+ logRegexpTime = `(?P[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
+ logRegexpFile = `(?P.+?:[0-9]+)?`
+ logRegexpMsg = `(: )?(?P(?s:.*))`
+)
+
+var (
+ logRegexp = regexp.MustCompile(logRegexpDate + logRegexpTime + logRegexpFile + logRegexpMsg)
+)
+
+func subexps(line []byte) map[string]string {
+ m := logRegexp.FindSubmatch(line)
+ if len(m) < len(logRegexp.SubexpNames()) {
+ return map[string]string{}
+ }
+ result := map[string]string{}
+ for i, name := range logRegexp.SubexpNames() {
+ result[name] = strings.TrimRight(string(m[i]), "\n")
+ }
+ return result
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/sync.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/sync.go
new file mode 100644
index 000000000000..58bd3add1c0f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/sync.go
@@ -0,0 +1,113 @@
+package log
+
+import (
+ "io"
+ "sync"
+ "sync/atomic"
+)
+
+// SwapLogger wraps another logger that may be safely replaced while other
+// goroutines use the SwapLogger concurrently. The zero value for a SwapLogger
+// will discard all log events without error.
+//
+// SwapLogger serves well as a package global logger that can be changed by
+// importers.
+type SwapLogger struct {
+ logger atomic.Value
+}
+
+type loggerStruct struct {
+ Logger
+}
+
+// Log implements the Logger interface by forwarding keyvals to the currently
+// wrapped logger. It does not log anything if the wrapped logger is nil.
+func (l *SwapLogger) Log(keyvals ...interface{}) error {
+ s, ok := l.logger.Load().(loggerStruct)
+ if !ok || s.Logger == nil {
+ return nil
+ }
+ return s.Log(keyvals...)
+}
+
+// Swap replaces the currently wrapped logger with logger. Swap may be called
+// concurrently with calls to Log from other goroutines.
+func (l *SwapLogger) Swap(logger Logger) {
+ l.logger.Store(loggerStruct{logger})
+}
+
+// NewSyncWriter returns a new writer that is safe for concurrent use by
+// multiple goroutines. Writes to the returned writer are passed on to w. If
+// another write is already in progress, the calling goroutine blocks until
+// the writer is available.
+//
+// If w implements the following interface, so does the returned writer.
+//
+// interface {
+// Fd() uintptr
+// }
+func NewSyncWriter(w io.Writer) io.Writer {
+ switch w := w.(type) {
+ case fdWriter:
+ return &fdSyncWriter{fdWriter: w}
+ default:
+ return &syncWriter{Writer: w}
+ }
+}
+
+// syncWriter synchronizes concurrent writes to an io.Writer.
+type syncWriter struct {
+ sync.Mutex
+ io.Writer
+}
+
+// Write writes p to the underlying io.Writer. If another write is already in
+// progress, the calling goroutine blocks until the syncWriter is available.
+func (w *syncWriter) Write(p []byte) (n int, err error) {
+ w.Lock()
+ defer w.Unlock()
+ return w.Writer.Write(p)
+}
+
+// fdWriter is an io.Writer that also has an Fd method. The most common
+// example of an fdWriter is an *os.File.
+type fdWriter interface {
+ io.Writer
+ Fd() uintptr
+}
+
+// fdSyncWriter synchronizes concurrent writes to an fdWriter.
+type fdSyncWriter struct {
+ sync.Mutex
+ fdWriter
+}
+
+// Write writes p to the underlying io.Writer. If another write is already in
+// progress, the calling goroutine blocks until the fdSyncWriter is available.
+func (w *fdSyncWriter) Write(p []byte) (n int, err error) {
+ w.Lock()
+ defer w.Unlock()
+ return w.fdWriter.Write(p)
+}
+
+// syncLogger provides concurrent safe logging for another Logger.
+type syncLogger struct {
+ mu sync.Mutex
+ logger Logger
+}
+
+// NewSyncLogger returns a logger that synchronizes concurrent use of the
+// wrapped logger. When multiple goroutines use the SyncLogger concurrently
+// only one goroutine will be allowed to log to the wrapped logger at a time.
+// The other goroutines will block until the logger is available.
+func NewSyncLogger(logger Logger) Logger {
+ return &syncLogger{logger: logger}
+}
+
+// Log logs keyvals to the underlying Logger. If another log is already in
+// progress, the calling goroutine blocks until the syncLogger is available.
+func (l *syncLogger) Log(keyvals ...interface{}) error {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ return l.logger.Log(keyvals...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/value.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/value.go
new file mode 100644
index 000000000000..3ce197f787f4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/log/value.go
@@ -0,0 +1,110 @@
+package log
+
+import (
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// A Valuer generates a log value. When passed to With, WithPrefix, or
+// WithSuffix in a value element (odd indexes), it represents a dynamic
+// value which is re-evaluated with each log event.
+type Valuer func() interface{}
+
+// bindValues replaces all value elements (odd indexes) containing a Valuer
+// with their generated value.
+func bindValues(keyvals []interface{}) {
+ for i := 1; i < len(keyvals); i += 2 {
+ if v, ok := keyvals[i].(Valuer); ok {
+ keyvals[i] = v()
+ }
+ }
+}
+
+// containsValuer returns true if any of the value elements (odd indexes)
+// contain a Valuer.
+func containsValuer(keyvals []interface{}) bool {
+ for i := 1; i < len(keyvals); i += 2 {
+ if _, ok := keyvals[i].(Valuer); ok {
+ return true
+ }
+ }
+ return false
+}
+
+// Timestamp returns a timestamp Valuer. It invokes the t function to get the
+// time; unless you are doing something tricky, pass time.Now.
+//
+// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
+// are TimestampFormats that use the RFC3339Nano format.
+func Timestamp(t func() time.Time) Valuer {
+ return func() interface{} { return t() }
+}
+
+// TimestampFormat returns a timestamp Valuer with a custom time format. It
+// invokes the t function to get the time to format; unless you are doing
+// something tricky, pass time.Now. The layout string is passed to
+// Time.Format.
+//
+// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
+// are TimestampFormats that use the RFC3339Nano format.
+func TimestampFormat(t func() time.Time, layout string) Valuer {
+ return func() interface{} {
+ return timeFormat{
+ time: t(),
+ layout: layout,
+ }
+ }
+}
+
+// A timeFormat represents an instant in time and a layout used when
+// marshaling to a text format.
+type timeFormat struct {
+ time time.Time
+ layout string
+}
+
+func (tf timeFormat) String() string {
+ return tf.time.Format(tf.layout)
+}
+
+// MarshalText implements encoding.TextMarshaller.
+func (tf timeFormat) MarshalText() (text []byte, err error) {
+ // The following code adapted from the standard library time.Time.Format
+ // method. Using the same undocumented magic constant to extend the size
+ // of the buffer as seen there.
+ b := make([]byte, 0, len(tf.layout)+10)
+ b = tf.time.AppendFormat(b, tf.layout)
+ return b, nil
+}
+
+// Caller returns a Valuer that returns a file and line from a specified depth
+// in the callstack. Users will probably want to use DefaultCaller.
+func Caller(depth int) Valuer {
+ return func() interface{} {
+ _, file, line, _ := runtime.Caller(depth)
+ idx := strings.LastIndexByte(file, '/')
+ // using idx+1 below handles both of following cases:
+ // idx == -1 because no "/" was found, or
+ // idx >= 0 and we want to start at the character after the found "/".
+ return file[idx+1:] + ":" + strconv.Itoa(line)
+ }
+}
+
+var (
+ // DefaultTimestamp is a Valuer that returns the current wallclock time,
+ // respecting time zones, when bound.
+ DefaultTimestamp = TimestampFormat(time.Now, time.RFC3339Nano)
+
+ // DefaultTimestampUTC is a Valuer that returns the current time in UTC
+ // when bound.
+ DefaultTimestampUTC = TimestampFormat(
+ func() time.Time { return time.Now().UTC() },
+ time.RFC3339Nano,
+ )
+
+ // DefaultCaller is a Valuer that returns the file and line where the Log
+ // method was invoked. It can only be used with log.With.
+ DefaultCaller = Caller(3)
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/.gitignore
new file mode 100644
index 000000000000..1d74e21965c4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/.gitignore
@@ -0,0 +1 @@
+.vscode/
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md
new file mode 100644
index 000000000000..1a9a27bcf6e5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md
@@ -0,0 +1,48 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.5.0] - 2020-01-03
+
+### Changed
+- Remove the dependency on github.com/kr/logfmt by [@ChrisHines]
+- Move fuzz code to github.com/go-logfmt/fuzzlogfmt by [@ChrisHines]
+
+## [0.4.0] - 2018-11-21
+
+### Added
+- Go module support by [@ChrisHines]
+- CHANGELOG by [@ChrisHines]
+
+### Changed
+- Drop invalid runes from keys instead of returning ErrInvalidKey by [@ChrisHines]
+- On panic while printing, attempt to print panic value by [@bboreham]
+
+## [0.3.0] - 2016-11-15
+### Added
+- Pool buffers for quoted strings and byte slices by [@nussjustin]
+### Fixed
+- Fuzz fix, quote invalid UTF-8 values by [@judwhite]
+
+## [0.2.0] - 2016-05-08
+### Added
+- Encoder.EncodeKeyvals by [@ChrisHines]
+
+## [0.1.0] - 2016-03-28
+### Added
+- Encoder by [@ChrisHines]
+- Decoder by [@ChrisHines]
+- MarshalKeyvals by [@ChrisHines]
+
+[0.5.0]: https://github.com/go-logfmt/logfmt/compare/v0.4.0...v0.5.0
+[0.4.0]: https://github.com/go-logfmt/logfmt/compare/v0.3.0...v0.4.0
+[0.3.0]: https://github.com/go-logfmt/logfmt/compare/v0.2.0...v0.3.0
+[0.2.0]: https://github.com/go-logfmt/logfmt/compare/v0.1.0...v0.2.0
+[0.1.0]: https://github.com/go-logfmt/logfmt/commits/v0.1.0
+
+[@ChrisHines]: https://github.com/ChrisHines
+[@bboreham]: https://github.com/bboreham
+[@judwhite]: https://github.com/judwhite
+[@nussjustin]: https://github.com/nussjustin
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/LICENSE
new file mode 100644
index 000000000000..c026508962ba
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 go-logfmt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/README.md
new file mode 100644
index 000000000000..8e48fcd3ab70
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/README.md
@@ -0,0 +1,33 @@
+[![Go Reference](https://pkg.go.dev/badge/github.com/go-logfmt/logfmt.svg)](https://pkg.go.dev/github.com/go-logfmt/logfmt)
+[![Go Report Card](https://goreportcard.com/badge/go-logfmt/logfmt)](https://goreportcard.com/report/go-logfmt/logfmt)
+[![Github Actions](https://github.com/go-logfmt/logfmt/actions/workflows/test.yml/badge.svg)](https://github.com/go-logfmt/logfmt/actions/workflows/test.yml)
+[![Coverage Status](https://coveralls.io/repos/github/go-logfmt/logfmt/badge.svg?branch=master)](https://coveralls.io/github/go-logfmt/logfmt?branch=master)
+
+# logfmt
+
+Package logfmt implements utilities to marshal and unmarshal data in the [logfmt
+format](https://brandur.org/logfmt). It provides an API similar to
+[encoding/json](http://golang.org/pkg/encoding/json/) and
+[encoding/xml](http://golang.org/pkg/encoding/xml/).
+
+The logfmt format was first documented by Brandur Leach in [this
+article](https://brandur.org/logfmt). The format has not been formally
+standardized. The most authoritative public specification to date has been the
+documentation of a Go Language [package](http://godoc.org/github.com/kr/logfmt)
+written by Blake Mizerany and Keith Rarick.
+
+## Goals
+
+This project attempts to conform as closely as possible to the prior art, while
+also removing ambiguity where necessary to provide well behaved encoder and
+decoder implementations.
+
+## Non-goals
+
+This project does not attempt to formally standardize the logfmt format. In the
+event that logfmt is standardized this project would take conforming to the
+standard as a goal.
+
+## Versioning
+
+Package logfmt publishes releases via [semver](http://semver.org/) compatible Git tags prefixed with a single 'v'.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/decode.go
new file mode 100644
index 000000000000..2013708e4857
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/decode.go
@@ -0,0 +1,237 @@
+package logfmt
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "unicode/utf8"
+)
+
+// A Decoder reads and decodes logfmt records from an input stream.
+type Decoder struct {
+ pos int
+ key []byte
+ value []byte
+ lineNum int
+ s *bufio.Scanner
+ err error
+}
+
+// NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may read data from r beyond
+// the logfmt records requested.
+func NewDecoder(r io.Reader) *Decoder {
+ dec := &Decoder{
+ s: bufio.NewScanner(r),
+ }
+ return dec
+}
+
+// ScanRecord advances the Decoder to the next record, which can then be
+// parsed with the ScanKeyval method. It returns false when decoding stops,
+// either by reaching the end of the input or an error. After ScanRecord
+// returns false, the Err method will return any error that occurred during
+// decoding, except that if it was io.EOF, Err will return nil.
+func (dec *Decoder) ScanRecord() bool {
+ if dec.err != nil {
+ return false
+ }
+ if !dec.s.Scan() {
+ dec.err = dec.s.Err()
+ return false
+ }
+ dec.lineNum++
+ dec.pos = 0
+ return true
+}
+
+// ScanKeyval advances the Decoder to the next key/value pair of the current
+// record, which can then be retrieved with the Key and Value methods. It
+// returns false when decoding stops, either by reaching the end of the
+// current record or an error.
+func (dec *Decoder) ScanKeyval() bool {
+ dec.key, dec.value = nil, nil
+ if dec.err != nil {
+ return false
+ }
+
+ line := dec.s.Bytes()
+
+ // garbage
+ for p, c := range line[dec.pos:] {
+ if c > ' ' {
+ dec.pos += p
+ goto key
+ }
+ }
+ dec.pos = len(line)
+ return false
+
+key:
+ const invalidKeyError = "invalid key"
+
+ start, multibyte := dec.pos, false
+ for p, c := range line[dec.pos:] {
+ switch {
+ case c == '=':
+ dec.pos += p
+ if dec.pos > start {
+ dec.key = line[start:dec.pos]
+ if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
+ dec.syntaxError(invalidKeyError)
+ return false
+ }
+ }
+ if dec.key == nil {
+ dec.unexpectedByte(c)
+ return false
+ }
+ goto equal
+ case c == '"':
+ dec.pos += p
+ dec.unexpectedByte(c)
+ return false
+ case c <= ' ':
+ dec.pos += p
+ if dec.pos > start {
+ dec.key = line[start:dec.pos]
+ if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
+ dec.syntaxError(invalidKeyError)
+ return false
+ }
+ }
+ return true
+ case c >= utf8.RuneSelf:
+ multibyte = true
+ }
+ }
+ dec.pos = len(line)
+ if dec.pos > start {
+ dec.key = line[start:dec.pos]
+ if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
+ dec.syntaxError(invalidKeyError)
+ return false
+ }
+ }
+ return true
+
+equal:
+ dec.pos++
+ if dec.pos >= len(line) {
+ return true
+ }
+ switch c := line[dec.pos]; {
+ case c <= ' ':
+ return true
+ case c == '"':
+ goto qvalue
+ }
+
+ // value
+ start = dec.pos
+ for p, c := range line[dec.pos:] {
+ switch {
+ case c == '=' || c == '"':
+ dec.pos += p
+ dec.unexpectedByte(c)
+ return false
+ case c <= ' ':
+ dec.pos += p
+ if dec.pos > start {
+ dec.value = line[start:dec.pos]
+ }
+ return true
+ }
+ }
+ dec.pos = len(line)
+ if dec.pos > start {
+ dec.value = line[start:dec.pos]
+ }
+ return true
+
+qvalue:
+ const (
+ untermQuote = "unterminated quoted value"
+ invalidQuote = "invalid quoted value"
+ )
+
+ hasEsc, esc := false, false
+ start = dec.pos
+ for p, c := range line[dec.pos+1:] {
+ switch {
+ case esc:
+ esc = false
+ case c == '\\':
+ hasEsc, esc = true, true
+ case c == '"':
+ dec.pos += p + 2
+ if hasEsc {
+ v, ok := unquoteBytes(line[start:dec.pos])
+ if !ok {
+ dec.syntaxError(invalidQuote)
+ return false
+ }
+ dec.value = v
+ } else {
+ start++
+ end := dec.pos - 1
+ if end > start {
+ dec.value = line[start:end]
+ }
+ }
+ return true
+ }
+ }
+ dec.pos = len(line)
+ dec.syntaxError(untermQuote)
+ return false
+}
+
+// Key returns the most recent key found by a call to ScanKeyval. The returned
+// slice may point to internal buffers and is only valid until the next call
+// to ScanRecord. It does no allocation.
+func (dec *Decoder) Key() []byte {
+ return dec.key
+}
+
+// Value returns the most recent value found by a call to ScanKeyval. The
+// returned slice may point to internal buffers and is only valid until the
+// next call to ScanRecord. It does no allocation when the value has no
+// escape sequences.
+func (dec *Decoder) Value() []byte {
+ return dec.value
+}
+
+// Err returns the first non-EOF error that was encountered by the Scanner.
+func (dec *Decoder) Err() error {
+ return dec.err
+}
+
+func (dec *Decoder) syntaxError(msg string) {
+ dec.err = &SyntaxError{
+ Msg: msg,
+ Line: dec.lineNum,
+ Pos: dec.pos + 1,
+ }
+}
+
+func (dec *Decoder) unexpectedByte(c byte) {
+ dec.err = &SyntaxError{
+ Msg: fmt.Sprintf("unexpected %q", c),
+ Line: dec.lineNum,
+ Pos: dec.pos + 1,
+ }
+}
+
+// A SyntaxError represents a syntax error in the logfmt input stream.
+type SyntaxError struct {
+ Msg string
+ Line int
+ Pos int
+}
+
+func (e *SyntaxError) Error() string {
+ return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/doc.go
new file mode 100644
index 000000000000..378e9ad126a9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/doc.go
@@ -0,0 +1,6 @@
+// Package logfmt implements utilities to marshal and unmarshal data in the
+// logfmt format. The logfmt format records key/value pairs in a way that
+// balances readability for humans and simplicity of computer parsing. It is
+// most commonly used as a more human friendly alternative to JSON for
+// structured logging.
+package logfmt
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/encode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/encode.go
new file mode 100644
index 000000000000..4ea9d23998c8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/encode.go
@@ -0,0 +1,322 @@
+package logfmt
+
+import (
+ "bytes"
+ "encoding"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "strings"
+ "unicode/utf8"
+)
+
+// MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence
+// of alternating keys and values.
+func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) {
+ buf := &bytes.Buffer{}
+ if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// An Encoder writes logfmt data to an output stream.
+type Encoder struct {
+ w io.Writer
+ scratch bytes.Buffer
+ needSep bool
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{
+ w: w,
+ }
+}
+
+var (
+ space = []byte(" ")
+ equals = []byte("=")
+ newline = []byte("\n")
+ null = []byte("null")
+)
+
+// EncodeKeyval writes the logfmt encoding of key and value to the stream. A
+// single space is written before the second and subsequent keys in a record.
+// Nothing is written if a non-nil error is returned.
+func (enc *Encoder) EncodeKeyval(key, value interface{}) error {
+ enc.scratch.Reset()
+ if enc.needSep {
+ if _, err := enc.scratch.Write(space); err != nil {
+ return err
+ }
+ }
+ if err := writeKey(&enc.scratch, key); err != nil {
+ return err
+ }
+ if _, err := enc.scratch.Write(equals); err != nil {
+ return err
+ }
+ if err := writeValue(&enc.scratch, value); err != nil {
+ return err
+ }
+ _, err := enc.w.Write(enc.scratch.Bytes())
+ enc.needSep = true
+ return err
+}
+
+// EncodeKeyvals writes the logfmt encoding of keyvals to the stream. Keyvals
+// is a variadic sequence of alternating keys and values. Keys of unsupported
+// type are skipped along with their corresponding value. Values of
+// unsupported type or that cause a MarshalerError are replaced by their error
+// but do not cause EncodeKeyvals to return an error. If a non-nil error is
+// returned some key/value pairs may not have be written.
+func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error {
+ if len(keyvals) == 0 {
+ return nil
+ }
+ if len(keyvals)%2 == 1 {
+ keyvals = append(keyvals, nil)
+ }
+ for i := 0; i < len(keyvals); i += 2 {
+ k, v := keyvals[i], keyvals[i+1]
+ err := enc.EncodeKeyval(k, v)
+ if err == ErrUnsupportedKeyType {
+ continue
+ }
+ if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType {
+ v = err
+ err = enc.EncodeKeyval(k, v)
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// MarshalerError represents an error encountered while marshaling a value.
+type MarshalerError struct {
+ Type reflect.Type
+ Err error
+}
+
+func (e *MarshalerError) Error() string {
+ return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error()
+}
+
+// ErrNilKey is returned by Marshal functions and Encoder methods if a key is
+// a nil interface or pointer value.
+var ErrNilKey = errors.New("nil key")
+
+// ErrInvalidKey is returned by Marshal functions and Encoder methods if, after
+// dropping invalid runes, a key is empty.
+var ErrInvalidKey = errors.New("invalid key")
+
+// ErrUnsupportedKeyType is returned by Encoder methods if a key has an
+// unsupported type.
+var ErrUnsupportedKeyType = errors.New("unsupported key type")
+
+// ErrUnsupportedValueType is returned by Encoder methods if a value has an
+// unsupported type.
+var ErrUnsupportedValueType = errors.New("unsupported value type")
+
+func writeKey(w io.Writer, key interface{}) error {
+ if key == nil {
+ return ErrNilKey
+ }
+
+ switch k := key.(type) {
+ case string:
+ return writeStringKey(w, k)
+ case []byte:
+ if k == nil {
+ return ErrNilKey
+ }
+ return writeBytesKey(w, k)
+ case encoding.TextMarshaler:
+ kb, err := safeMarshal(k)
+ if err != nil {
+ return err
+ }
+ if kb == nil {
+ return ErrNilKey
+ }
+ return writeBytesKey(w, kb)
+ case fmt.Stringer:
+ ks, ok := safeString(k)
+ if !ok {
+ return ErrNilKey
+ }
+ return writeStringKey(w, ks)
+ default:
+ rkey := reflect.ValueOf(key)
+ switch rkey.Kind() {
+ case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
+ return ErrUnsupportedKeyType
+ case reflect.Ptr:
+ if rkey.IsNil() {
+ return ErrNilKey
+ }
+ return writeKey(w, rkey.Elem().Interface())
+ }
+ return writeStringKey(w, fmt.Sprint(k))
+ }
+}
+
+// keyRuneFilter returns r for all valid key runes, and -1 for all invalid key
+// runes. When used as the mapping function for strings.Map and bytes.Map
+// functions it causes them to remove invalid key runes from strings or byte
+// slices respectively.
+func keyRuneFilter(r rune) rune {
+ if r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError {
+ return -1
+ }
+ return r
+}
+
+func writeStringKey(w io.Writer, key string) error {
+ k := strings.Map(keyRuneFilter, key)
+ if k == "" {
+ return ErrInvalidKey
+ }
+ _, err := io.WriteString(w, k)
+ return err
+}
+
+func writeBytesKey(w io.Writer, key []byte) error {
+ k := bytes.Map(keyRuneFilter, key)
+ if len(k) == 0 {
+ return ErrInvalidKey
+ }
+ _, err := w.Write(k)
+ return err
+}
+
+func writeValue(w io.Writer, value interface{}) error {
+ switch v := value.(type) {
+ case nil:
+ return writeBytesValue(w, null)
+ case string:
+ return writeStringValue(w, v, true)
+ case []byte:
+ return writeBytesValue(w, v)
+ case encoding.TextMarshaler:
+ vb, err := safeMarshal(v)
+ if err != nil {
+ return err
+ }
+ if vb == nil {
+ vb = null
+ }
+ return writeBytesValue(w, vb)
+ case error:
+ se, ok := safeError(v)
+ return writeStringValue(w, se, ok)
+ case fmt.Stringer:
+ ss, ok := safeString(v)
+ return writeStringValue(w, ss, ok)
+ default:
+ rvalue := reflect.ValueOf(value)
+ switch rvalue.Kind() {
+ case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
+ return ErrUnsupportedValueType
+ case reflect.Ptr:
+ if rvalue.IsNil() {
+ return writeBytesValue(w, null)
+ }
+ return writeValue(w, rvalue.Elem().Interface())
+ }
+ return writeStringValue(w, fmt.Sprint(v), true)
+ }
+}
+
+func needsQuotedValueRune(r rune) bool {
+ return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
+}
+
+func writeStringValue(w io.Writer, value string, ok bool) error {
+ var err error
+ if ok && value == "null" {
+ _, err = io.WriteString(w, `"null"`)
+ } else if strings.IndexFunc(value, needsQuotedValueRune) != -1 {
+ _, err = writeQuotedString(w, value)
+ } else {
+ _, err = io.WriteString(w, value)
+ }
+ return err
+}
+
+func writeBytesValue(w io.Writer, value []byte) error {
+ var err error
+ if bytes.IndexFunc(value, needsQuotedValueRune) != -1 {
+ _, err = writeQuotedBytes(w, value)
+ } else {
+ _, err = w.Write(value)
+ }
+ return err
+}
+
+// EndRecord writes a newline character to the stream and resets the encoder
+// to the beginning of a new record.
+func (enc *Encoder) EndRecord() error {
+ _, err := enc.w.Write(newline)
+ if err == nil {
+ enc.needSep = false
+ }
+ return err
+}
+
+// Reset resets the encoder to the beginning of a new record.
+func (enc *Encoder) Reset() {
+ enc.needSep = false
+}
+
+func safeError(err error) (s string, ok bool) {
+ defer func() {
+ if panicVal := recover(); panicVal != nil {
+ if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
+ s, ok = "null", false
+ } else {
+ s, ok = fmt.Sprintf("PANIC:%v", panicVal), false
+ }
+ }
+ }()
+ s, ok = err.Error(), true
+ return
+}
+
+func safeString(str fmt.Stringer) (s string, ok bool) {
+ defer func() {
+ if panicVal := recover(); panicVal != nil {
+ if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
+ s, ok = "null", false
+ } else {
+ s, ok = fmt.Sprintf("PANIC:%v", panicVal), true
+ }
+ }
+ }()
+ s, ok = str.String(), true
+ return
+}
+
+func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) {
+ defer func() {
+ if panicVal := recover(); panicVal != nil {
+ if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() {
+ b, err = nil, nil
+ } else {
+ b, err = nil, fmt.Errorf("panic when marshalling: %s", panicVal)
+ }
+ }
+ }()
+ b, err = tm.MarshalText()
+ if err != nil {
+ return nil, &MarshalerError{
+ Type: reflect.TypeOf(tm),
+ Err: err,
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/jsonstring.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/jsonstring.go
new file mode 100644
index 000000000000..030ac85fcc2e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-logfmt/logfmt/jsonstring.go
@@ -0,0 +1,277 @@
+package logfmt
+
+import (
+ "bytes"
+ "io"
+ "strconv"
+ "sync"
+ "unicode"
+ "unicode/utf16"
+ "unicode/utf8"
+)
+
+// Taken from Go's encoding/json and modified for use here.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var hex = "0123456789abcdef"
+
+var bufferPool = sync.Pool{
+ New: func() interface{} {
+ return &bytes.Buffer{}
+ },
+}
+
+func getBuffer() *bytes.Buffer {
+ return bufferPool.Get().(*bytes.Buffer)
+}
+
+func poolBuffer(buf *bytes.Buffer) {
+ buf.Reset()
+ bufferPool.Put(buf)
+}
+
+// NOTE: keep in sync with writeQuotedBytes below.
+func writeQuotedString(w io.Writer, s string) (int, error) {
+ buf := getBuffer()
+ buf.WriteByte('"')
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ if start < i {
+ buf.WriteString(s[start:i])
+ }
+ switch b {
+ case '\\', '"':
+ buf.WriteByte('\\')
+ buf.WriteByte(b)
+ case '\n':
+ buf.WriteByte('\\')
+ buf.WriteByte('n')
+ case '\r':
+ buf.WriteByte('\\')
+ buf.WriteByte('r')
+ case '\t':
+ buf.WriteByte('\\')
+ buf.WriteByte('t')
+ default:
+ // This encodes bytes < 0x20 except for \n, \r, and \t.
+ buf.WriteString(`\u00`)
+ buf.WriteByte(hex[b>>4])
+ buf.WriteByte(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError {
+ if start < i {
+ buf.WriteString(s[start:i])
+ }
+ buf.WriteString(`\ufffd`)
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ }
+ if start < len(s) {
+ buf.WriteString(s[start:])
+ }
+ buf.WriteByte('"')
+ n, err := w.Write(buf.Bytes())
+ poolBuffer(buf)
+ return n, err
+}
+
+// NOTE: keep in sync with writeQuoteString above.
+func writeQuotedBytes(w io.Writer, s []byte) (int, error) {
+ buf := getBuffer()
+ buf.WriteByte('"')
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ if start < i {
+ buf.Write(s[start:i])
+ }
+ switch b {
+ case '\\', '"':
+ buf.WriteByte('\\')
+ buf.WriteByte(b)
+ case '\n':
+ buf.WriteByte('\\')
+ buf.WriteByte('n')
+ case '\r':
+ buf.WriteByte('\\')
+ buf.WriteByte('r')
+ case '\t':
+ buf.WriteByte('\\')
+ buf.WriteByte('t')
+ default:
+ // This encodes bytes < 0x20 except for \n, \r, and \t.
+ buf.WriteString(`\u00`)
+ buf.WriteByte(hex[b>>4])
+ buf.WriteByte(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRune(s[i:])
+ if c == utf8.RuneError {
+ if start < i {
+ buf.Write(s[start:i])
+ }
+ buf.WriteString(`\ufffd`)
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ }
+ if start < len(s) {
+ buf.Write(s[start:])
+ }
+ buf.WriteByte('"')
+ n, err := w.Write(buf.Bytes())
+ poolBuffer(buf)
+ return n, err
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) rune {
+ if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+ return -1
+ }
+ r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
+ if err != nil {
+ return -1
+ }
+ return rune(r)
+}
+
+func unquoteBytes(s []byte) (t []byte, ok bool) {
+ if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ return
+ }
+ s = s[1 : len(s)-1]
+
+ // Check for unusual characters. If there are none,
+ // then no unquoting is needed, so return a slice of the
+ // original bytes.
+ r := 0
+ for r < len(s) {
+ c := s[r]
+ if c == '\\' || c == '"' || c < ' ' {
+ break
+ }
+ if c < utf8.RuneSelf {
+ r++
+ continue
+ }
+ rr, size := utf8.DecodeRune(s[r:])
+ if rr == utf8.RuneError {
+ break
+ }
+ r += size
+ }
+ if r == len(s) {
+ return s, true
+ }
+
+ b := make([]byte, len(s)+2*utf8.UTFMax)
+ w := copy(b, s[0:r])
+ for r < len(s) {
+ // Out of room? Can only happen if s is full of
+ // malformed UTF-8 and we're replacing each
+ // byte with RuneError.
+ if w >= len(b)-2*utf8.UTFMax {
+ nb := make([]byte, (len(b)+utf8.UTFMax)*2)
+ copy(nb, b[0:w])
+ b = nb
+ }
+ switch c := s[r]; {
+ case c == '\\':
+ r++
+ if r >= len(s) {
+ return
+ }
+ switch s[r] {
+ default:
+ return
+ case '"', '\\', '/', '\'':
+ b[w] = s[r]
+ r++
+ w++
+ case 'b':
+ b[w] = '\b'
+ r++
+ w++
+ case 'f':
+ b[w] = '\f'
+ r++
+ w++
+ case 'n':
+ b[w] = '\n'
+ r++
+ w++
+ case 'r':
+ b[w] = '\r'
+ r++
+ w++
+ case 't':
+ b[w] = '\t'
+ r++
+ w++
+ case 'u':
+ r--
+ rr := getu4(s[r:])
+ if rr < 0 {
+ return
+ }
+ r += 6
+ if utf16.IsSurrogate(rr) {
+ rr1 := getu4(s[r:])
+ if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
+ // A valid pair; consume.
+ r += 6
+ w += utf8.EncodeRune(b[w:], dec)
+ break
+ }
+ // Invalid surrogate; fall back to replacement rune.
+ rr = unicode.ReplacementChar
+ }
+ w += utf8.EncodeRune(b[w:], rr)
+ }
+
+ // Quote, control characters are invalid.
+ case c == '"', c < ' ':
+ return
+
+ // ASCII
+ case c < utf8.RuneSelf:
+ b[w] = c
+ r++
+ w++
+
+ // Coerce to well-formed UTF-8.
+ default:
+ rr, size := utf8.DecodeRune(s[r:])
+ r += size
+ w += utf8.EncodeRune(b[w:], rr)
+ }
+ }
+ return b[0:w], true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/.gitignore
new file mode 100644
index 000000000000..daf913b1b347
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/.travis.yml
new file mode 100644
index 000000000000..d50237a60899
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/.travis.yml
@@ -0,0 +1,26 @@
+language: go
+go:
+ - 1.13.1
+ - tip
+matrix:
+ allow_failures:
+ - go: tip
+
+notifications:
+ email:
+ recipients: dean.karn@gmail.com
+ on_success: change
+ on_failure: always
+
+before_install:
+ - go install github.com/mattn/goveralls
+
+# Only clone the most recent commit.
+git:
+ depth: 1
+
+script:
+ - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./...
+
+after_success: |
+ goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/LICENSE
new file mode 100644
index 000000000000..75854ac4f01f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Go Playground
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/README.md
new file mode 100644
index 000000000000..ba1b0680c97d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/README.md
@@ -0,0 +1,172 @@
+## locales
+ ![Project status](https://img.shields.io/badge/version-0.13.0-green.svg)
+[![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales)
+[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales)
+[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales)
+![License](https://img.shields.io/dub/l/vibe-d.svg)
+[![Gitter](https://badges.gitter.im/go-playground/locales.svg)](https://gitter.im/go-playground/locales?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+Locales is a set of locales generated from the [Unicode CLDR Project](http://cldr.unicode.org/) which can be used independently or within
+an i18n package; these were built for use with, but not exclusive to, [Universal Translator](https://github.com/go-playground/universal-translator).
+
+Features
+--------
+- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v31.0.1
+- [x] Contains Cardinal, Ordinal and Range Plural Rules
+- [x] Contains Month, Weekday and Timezone translations built in
+- [x] Contains Date & Time formatting functions
+- [x] Contains Number, Currency, Accounting and Percent formatting functions
+- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere )
+
+Full Tests
+--------------------
+I could sure use your help adding tests for every locale, it is a huge undertaking and I just don't have the free time to do it all at the moment;
+any help would be **greatly appreciated!!!!** please see [issue](https://github.com/go-playground/locales/issues/1) for details.
+
+Installation
+-----------
+
+Use go get
+
+```shell
+go get github.com/go-playground/locales
+```
+
+NOTES
+--------
+You'll notice most return types are []byte, this is because most of the time the results will be concatenated with a larger body
+of text and can avoid some allocations if already appending to a byte array, otherwise just cast as string.
+
+Usage
+-------
+```go
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/go-playground/locales/currency"
+ "github.com/go-playground/locales/en_CA"
+)
+
+func main() {
+
+ loc, _ := time.LoadLocation("America/Toronto")
+ datetime := time.Date(2016, 02, 03, 9, 0, 1, 0, loc)
+
+ l := en_CA.New()
+
+ // Dates
+ fmt.Println(l.FmtDateFull(datetime))
+ fmt.Println(l.FmtDateLong(datetime))
+ fmt.Println(l.FmtDateMedium(datetime))
+ fmt.Println(l.FmtDateShort(datetime))
+
+ // Times
+ fmt.Println(l.FmtTimeFull(datetime))
+ fmt.Println(l.FmtTimeLong(datetime))
+ fmt.Println(l.FmtTimeMedium(datetime))
+ fmt.Println(l.FmtTimeShort(datetime))
+
+ // Months Wide
+ fmt.Println(l.MonthWide(time.January))
+ fmt.Println(l.MonthWide(time.February))
+ fmt.Println(l.MonthWide(time.March))
+ // ...
+
+ // Months Abbreviated
+ fmt.Println(l.MonthAbbreviated(time.January))
+ fmt.Println(l.MonthAbbreviated(time.February))
+ fmt.Println(l.MonthAbbreviated(time.March))
+ // ...
+
+ // Months Narrow
+ fmt.Println(l.MonthNarrow(time.January))
+ fmt.Println(l.MonthNarrow(time.February))
+ fmt.Println(l.MonthNarrow(time.March))
+ // ...
+
+ // Weekdays Wide
+ fmt.Println(l.WeekdayWide(time.Sunday))
+ fmt.Println(l.WeekdayWide(time.Monday))
+ fmt.Println(l.WeekdayWide(time.Tuesday))
+ // ...
+
+ // Weekdays Abbreviated
+ fmt.Println(l.WeekdayAbbreviated(time.Sunday))
+ fmt.Println(l.WeekdayAbbreviated(time.Monday))
+ fmt.Println(l.WeekdayAbbreviated(time.Tuesday))
+ // ...
+
+ // Weekdays Short
+ fmt.Println(l.WeekdayShort(time.Sunday))
+ fmt.Println(l.WeekdayShort(time.Monday))
+ fmt.Println(l.WeekdayShort(time.Tuesday))
+ // ...
+
+ // Weekdays Narrow
+ fmt.Println(l.WeekdayNarrow(time.Sunday))
+ fmt.Println(l.WeekdayNarrow(time.Monday))
+ fmt.Println(l.WeekdayNarrow(time.Tuesday))
+ // ...
+
+ var f64 float64
+
+ f64 = -10356.4523
+
+ // Number
+ fmt.Println(l.FmtNumber(f64, 2))
+
+ // Currency
+ fmt.Println(l.FmtCurrency(f64, 2, currency.CAD))
+ fmt.Println(l.FmtCurrency(f64, 2, currency.USD))
+
+ // Accounting
+ fmt.Println(l.FmtAccounting(f64, 2, currency.CAD))
+ fmt.Println(l.FmtAccounting(f64, 2, currency.USD))
+
+ f64 = 78.12
+
+ // Percent
+ fmt.Println(l.FmtPercent(f64, 0))
+
+ // Plural Rules for locale, so you know what rules you must cover
+ fmt.Println(l.PluralsCardinal())
+ fmt.Println(l.PluralsOrdinal())
+
+ // Cardinal Plural Rules
+ fmt.Println(l.CardinalPluralRule(1, 0))
+ fmt.Println(l.CardinalPluralRule(1.0, 0))
+ fmt.Println(l.CardinalPluralRule(1.0, 1))
+ fmt.Println(l.CardinalPluralRule(3, 0))
+
+ // Ordinal Plural Rules
+ fmt.Println(l.OrdinalPluralRule(21, 0)) // 21st
+ fmt.Println(l.OrdinalPluralRule(22, 0)) // 22nd
+ fmt.Println(l.OrdinalPluralRule(33, 0)) // 33rd
+ fmt.Println(l.OrdinalPluralRule(34, 0)) // 34th
+
+ // Range Plural Rules
+ fmt.Println(l.RangePluralRule(1, 0, 1, 0)) // 1-1
+ fmt.Println(l.RangePluralRule(1, 0, 2, 0)) // 1-2
+ fmt.Println(l.RangePluralRule(5, 0, 8, 0)) // 5-8
+}
+```
+
+NOTES:
+-------
+These rules were generated from the [Unicode CLDR Project](http://cldr.unicode.org/), if you encounter any issues
+I strongly encourage contributing to the CLDR project to get the locale information corrected and the next time
+these locales are regenerated the fix will come with.
+
+I do however realize that time constraints are often important and so there are two options:
+
+1. Create your own locale, copy, paste and modify, and ensure it complies with the `Translator` interface.
+2. Add an exception in the locale generation code directly and once regenerated, fix will be in place.
+
+Please to not make fixes inside the locale files, they WILL get overwritten when the locales are regenerated.
+
+License
+------
+Distributed under MIT License, please see license file in code for more details.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/currency/currency.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/currency/currency.go
new file mode 100644
index 000000000000..cdaba596b620
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/currency/currency.go
@@ -0,0 +1,308 @@
+package currency
+
+// Type is the currency type associated with the locales currency enum
+type Type int
+
+// locale currencies
+const (
+ ADP Type = iota
+ AED
+ AFA
+ AFN
+ ALK
+ ALL
+ AMD
+ ANG
+ AOA
+ AOK
+ AON
+ AOR
+ ARA
+ ARL
+ ARM
+ ARP
+ ARS
+ ATS
+ AUD
+ AWG
+ AZM
+ AZN
+ BAD
+ BAM
+ BAN
+ BBD
+ BDT
+ BEC
+ BEF
+ BEL
+ BGL
+ BGM
+ BGN
+ BGO
+ BHD
+ BIF
+ BMD
+ BND
+ BOB
+ BOL
+ BOP
+ BOV
+ BRB
+ BRC
+ BRE
+ BRL
+ BRN
+ BRR
+ BRZ
+ BSD
+ BTN
+ BUK
+ BWP
+ BYB
+ BYN
+ BYR
+ BZD
+ CAD
+ CDF
+ CHE
+ CHF
+ CHW
+ CLE
+ CLF
+ CLP
+ CNH
+ CNX
+ CNY
+ COP
+ COU
+ CRC
+ CSD
+ CSK
+ CUC
+ CUP
+ CVE
+ CYP
+ CZK
+ DDM
+ DEM
+ DJF
+ DKK
+ DOP
+ DZD
+ ECS
+ ECV
+ EEK
+ EGP
+ ERN
+ ESA
+ ESB
+ ESP
+ ETB
+ EUR
+ FIM
+ FJD
+ FKP
+ FRF
+ GBP
+ GEK
+ GEL
+ GHC
+ GHS
+ GIP
+ GMD
+ GNF
+ GNS
+ GQE
+ GRD
+ GTQ
+ GWE
+ GWP
+ GYD
+ HKD
+ HNL
+ HRD
+ HRK
+ HTG
+ HUF
+ IDR
+ IEP
+ ILP
+ ILR
+ ILS
+ INR
+ IQD
+ IRR
+ ISJ
+ ISK
+ ITL
+ JMD
+ JOD
+ JPY
+ KES
+ KGS
+ KHR
+ KMF
+ KPW
+ KRH
+ KRO
+ KRW
+ KWD
+ KYD
+ KZT
+ LAK
+ LBP
+ LKR
+ LRD
+ LSL
+ LTL
+ LTT
+ LUC
+ LUF
+ LUL
+ LVL
+ LVR
+ LYD
+ MAD
+ MAF
+ MCF
+ MDC
+ MDL
+ MGA
+ MGF
+ MKD
+ MKN
+ MLF
+ MMK
+ MNT
+ MOP
+ MRO
+ MTL
+ MTP
+ MUR
+ MVP
+ MVR
+ MWK
+ MXN
+ MXP
+ MXV
+ MYR
+ MZE
+ MZM
+ MZN
+ NAD
+ NGN
+ NIC
+ NIO
+ NLG
+ NOK
+ NPR
+ NZD
+ OMR
+ PAB
+ PEI
+ PEN
+ PES
+ PGK
+ PHP
+ PKR
+ PLN
+ PLZ
+ PTE
+ PYG
+ QAR
+ RHD
+ ROL
+ RON
+ RSD
+ RUB
+ RUR
+ RWF
+ SAR
+ SBD
+ SCR
+ SDD
+ SDG
+ SDP
+ SEK
+ SGD
+ SHP
+ SIT
+ SKK
+ SLL
+ SOS
+ SRD
+ SRG
+ SSP
+ STD
+ STN
+ SUR
+ SVC
+ SYP
+ SZL
+ THB
+ TJR
+ TJS
+ TMM
+ TMT
+ TND
+ TOP
+ TPE
+ TRL
+ TRY
+ TTD
+ TWD
+ TZS
+ UAH
+ UAK
+ UGS
+ UGX
+ USD
+ USN
+ USS
+ UYI
+ UYP
+ UYU
+ UZS
+ VEB
+ VEF
+ VND
+ VNN
+ VUV
+ WST
+ XAF
+ XAG
+ XAU
+ XBA
+ XBB
+ XBC
+ XBD
+ XCD
+ XDR
+ XEU
+ XFO
+ XFU
+ XOF
+ XPD
+ XPF
+ XPT
+ XRE
+ XSU
+ XTS
+ XUA
+ XXX
+ YDD
+ YER
+ YUD
+ YUM
+ YUN
+ YUR
+ ZAL
+ ZAR
+ ZMK
+ ZMW
+ ZRN
+ ZRZ
+ ZWD
+ ZWL
+ ZWR
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/logo.png b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/logo.png
new file mode 100644
index 000000000000..3038276e6873
Binary files /dev/null and b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/logo.png differ
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/rules.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/rules.go
new file mode 100644
index 000000000000..920290014969
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/locales/rules.go
@@ -0,0 +1,293 @@
+package locales
+
+import (
+ "strconv"
+ "time"
+
+ "github.com/go-playground/locales/currency"
+)
+
+// // ErrBadNumberValue is returned when the number passed for
+// // plural rule determination cannot be parsed
+// type ErrBadNumberValue struct {
+// NumberValue string
+// InnerError error
+// }
+
+// // Error returns ErrBadNumberValue error string
+// func (e *ErrBadNumberValue) Error() string {
+// return fmt.Sprintf("Invalid Number Value '%s' %s", e.NumberValue, e.InnerError)
+// }
+
+// var _ error = new(ErrBadNumberValue)
+
+// PluralRule denotes the type of plural rules
+type PluralRule int
+
+// PluralRule's
+const (
+ PluralRuleUnknown PluralRule = iota
+ PluralRuleZero // zero
+ PluralRuleOne // one - singular
+ PluralRuleTwo // two - dual
+ PluralRuleFew // few - paucal
+ PluralRuleMany // many - also used for fractions if they have a separate class
+ PluralRuleOther // other - required—general plural form—also used if the language only has a single form
+)
+
+const (
+ pluralsString = "UnknownZeroOneTwoFewManyOther"
+)
+
+// Translator encapsulates an instance of a locale
+// NOTE: some values are returned as a []byte just in case the caller
+// wishes to add more and can help avoid allocations; otherwise just cast as string
+type Translator interface {
+
+ // The following Functions are for overriding, debugging or developing
+ // with a Translator Locale
+
+ // Locale returns the string value of the translator
+ Locale() string
+
+ // returns an array of cardinal plural rules associated
+ // with this translator
+ PluralsCardinal() []PluralRule
+
+ // returns an array of ordinal plural rules associated
+ // with this translator
+ PluralsOrdinal() []PluralRule
+
+ // returns an array of range plural rules associated
+ // with this translator
+ PluralsRange() []PluralRule
+
+ // returns the cardinal PluralRule given 'num' and digits/precision of 'v' for locale
+ CardinalPluralRule(num float64, v uint64) PluralRule
+
+ // returns the ordinal PluralRule given 'num' and digits/precision of 'v' for locale
+ OrdinalPluralRule(num float64, v uint64) PluralRule
+
+ // returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for locale
+ RangePluralRule(num1 float64, v1 uint64, num2 float64, v2 uint64) PluralRule
+
+ // returns the locales abbreviated month given the 'month' provided
+ MonthAbbreviated(month time.Month) string
+
+ // returns the locales abbreviated months
+ MonthsAbbreviated() []string
+
+ // returns the locales narrow month given the 'month' provided
+ MonthNarrow(month time.Month) string
+
+ // returns the locales narrow months
+ MonthsNarrow() []string
+
+ // returns the locales wide month given the 'month' provided
+ MonthWide(month time.Month) string
+
+ // returns the locales wide months
+ MonthsWide() []string
+
+ // returns the locales abbreviated weekday given the 'weekday' provided
+ WeekdayAbbreviated(weekday time.Weekday) string
+
+ // returns the locales abbreviated weekdays
+ WeekdaysAbbreviated() []string
+
+ // returns the locales narrow weekday given the 'weekday' provided
+ WeekdayNarrow(weekday time.Weekday) string
+
+ // WeekdaysNarrowreturns the locales narrow weekdays
+ WeekdaysNarrow() []string
+
+ // returns the locales short weekday given the 'weekday' provided
+ WeekdayShort(weekday time.Weekday) string
+
+ // returns the locales short weekdays
+ WeekdaysShort() []string
+
+ // returns the locales wide weekday given the 'weekday' provided
+ WeekdayWide(weekday time.Weekday) string
+
+ // returns the locales wide weekdays
+ WeekdaysWide() []string
+
+ // The following Functions are common Formatting functionsfor the Translator's Locale
+
+ // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v'
+ FmtNumber(num float64, v uint64) string
+
+ // returns 'num' with digits/precision of 'v' for locale and handles both Whole and Real numbers based on 'v'
+ // NOTE: 'num' passed into FmtPercent is assumed to be in percent already
+ FmtPercent(num float64, v uint64) string
+
+ // returns the currency representation of 'num' with digits/precision of 'v' for locale
+ FmtCurrency(num float64, v uint64, currency currency.Type) string
+
+ // returns the currency representation of 'num' with digits/precision of 'v' for locale
+ // in accounting notation.
+ FmtAccounting(num float64, v uint64, currency currency.Type) string
+
+ // returns the short date representation of 't' for locale
+ FmtDateShort(t time.Time) string
+
+ // returns the medium date representation of 't' for locale
+ FmtDateMedium(t time.Time) string
+
+ // returns the long date representation of 't' for locale
+ FmtDateLong(t time.Time) string
+
+ // returns the full date representation of 't' for locale
+ FmtDateFull(t time.Time) string
+
+ // returns the short time representation of 't' for locale
+ FmtTimeShort(t time.Time) string
+
+ // returns the medium time representation of 't' for locale
+ FmtTimeMedium(t time.Time) string
+
+ // returns the long time representation of 't' for locale
+ FmtTimeLong(t time.Time) string
+
+ // returns the full time representation of 't' for locale
+ FmtTimeFull(t time.Time) string
+}
+
+// String returns the string value of PluralRule
+func (p PluralRule) String() string {
+
+ switch p {
+ case PluralRuleZero:
+ return pluralsString[7:11]
+ case PluralRuleOne:
+ return pluralsString[11:14]
+ case PluralRuleTwo:
+ return pluralsString[14:17]
+ case PluralRuleFew:
+ return pluralsString[17:20]
+ case PluralRuleMany:
+ return pluralsString[20:24]
+ case PluralRuleOther:
+ return pluralsString[24:]
+ default:
+ return pluralsString[:7]
+ }
+}
+
+//
+// Precision Notes:
+//
+// must specify a precision >= 0, and here is why https://play.golang.org/p/LyL90U0Vyh
+//
+// v := float64(3.141)
+// i := float64(int64(v))
+//
+// fmt.Println(v - i)
+//
+// or
+//
+// s := strconv.FormatFloat(v-i, 'f', -1, 64)
+// fmt.Println(s)
+//
+// these will not print what you'd expect: 0.14100000000000001
+// and so this library requires a precision to be specified, or
+// inaccurate plural rules could be applied.
+//
+//
+//
+// n - absolute value of the source number (integer and decimals).
+// i - integer digits of n.
+// v - number of visible fraction digits in n, with trailing zeros.
+// w - number of visible fraction digits in n, without trailing zeros.
+// f - visible fractional digits in n, with trailing zeros.
+// t - visible fractional digits in n, without trailing zeros.
+//
+//
+// Func(num float64, v uint64) // v = digits/precision and prevents -1 as a special case as this can lead to very unexpected behaviour, see precision note's above.
+//
+// n := math.Abs(num)
+// i := int64(n)
+// v := v
+//
+//
+// w := strconv.FormatFloat(num-float64(i), 'f', int(v), 64) // then parse backwards on string until no more zero's....
+// f := strconv.FormatFloat(n, 'f', int(v), 64) // then turn everything after decimal into an int64
+// t := strconv.FormatFloat(n, 'f', int(v), 64) // then parse backwards on string until no more zero's....
+//
+//
+//
+// General Inclusion Rules
+// - v will always be available inherently
+// - all require n
+// - w requires i
+//
+
+// W returns the number of visible fraction digits in N, without trailing zeros.
+func W(n float64, v uint64) (w int64) {
+
+ s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
+
+ // with either be '0' or '0.xxxx', so if 1 then w will be zero
+ // otherwise need to parse
+ if len(s) != 1 {
+
+ s = s[2:]
+ end := len(s) + 1
+
+ for i := end; i >= 0; i-- {
+ if s[i] != '0' {
+ end = i + 1
+ break
+ }
+ }
+
+ w = int64(len(s[:end]))
+ }
+
+ return
+}
+
+// F returns the visible fractional digits in N, with trailing zeros.
+func F(n float64, v uint64) (f int64) {
+
+ s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
+
+ // with either be '0' or '0.xxxx', so if 1 then f will be zero
+ // otherwise need to parse
+ if len(s) != 1 {
+
+ // ignoring error, because it can't fail as we generated
+ // the string internally from a real number
+ f, _ = strconv.ParseInt(s[2:], 10, 64)
+ }
+
+ return
+}
+
+// T returns the visible fractional digits in N, without trailing zeros.
+func T(n float64, v uint64) (t int64) {
+
+ s := strconv.FormatFloat(n-float64(int64(n)), 'f', int(v), 64)
+
+ // with either be '0' or '0.xxxx', so if 1 then t will be zero
+ // otherwise need to parse
+ if len(s) != 1 {
+
+ s = s[2:]
+ end := len(s) + 1
+
+ for i := end; i >= 0; i-- {
+ if s[i] != '0' {
+ end = i + 1
+ break
+ }
+ }
+
+ // ignoring error, because it can't fail as we generated
+ // the string internally from a real number
+ t, _ = strconv.ParseInt(s[:end], 10, 64)
+ }
+
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/.gitignore
new file mode 100644
index 000000000000..bc4e07f34ecb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+*.coverprofile
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/.travis.yml
new file mode 100644
index 000000000000..39b8b923e4b6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/.travis.yml
@@ -0,0 +1,27 @@
+language: go
+go:
+ - 1.13.4
+ - tip
+matrix:
+ allow_failures:
+ - go: tip
+
+notifications:
+ email:
+ recipients: dean.karn@gmail.com
+ on_success: change
+ on_failure: always
+
+before_install:
+ - go install github.com/mattn/goveralls
+
+# Only clone the most recent commit.
+git:
+ depth: 1
+
+script:
+ - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./...
+
+after_success: |
+ [ $TRAVIS_GO_VERSION = 1.13.4 ] &&
+ goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/LICENSE
new file mode 100644
index 000000000000..8d8aba15bab8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Go Playground
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/README.md
new file mode 100644
index 000000000000..071f33ab25ad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/README.md
@@ -0,0 +1,89 @@
+## universal-translator
+ ![Project status](https://img.shields.io/badge/version-0.17.0-green.svg)
+[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator)
+[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator)
+[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator)
+[![GoDoc](https://godoc.org/github.com/go-playground/universal-translator?status.svg)](https://godoc.org/github.com/go-playground/universal-translator)
+![License](https://img.shields.io/dub/l/vibe-d.svg)
+[![Gitter](https://badges.gitter.im/go-playground/universal-translator.svg)](https://gitter.im/go-playground/universal-translator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+Universal Translator is an i18n Translator for Go/Golang using CLDR data + pluralization rules
+
+Why another i18n library?
+--------------------------
+Because none of the plural rules seem to be correct out there, including the previous implementation of this package,
+so I took it upon myself to create [locales](https://github.com/go-playground/locales) for everyone to use; this package
+is a thin wrapper around [locales](https://github.com/go-playground/locales) in order to store and translate text for
+use in your applications.
+
+Features
+--------
+- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v30.0.3
+- [x] Contains Cardinal, Ordinal and Range Plural Rules
+- [x] Contains Month, Weekday and Timezone translations built in
+- [x] Contains Date & Time formatting functions
+- [x] Contains Number, Currency, Accounting and Percent formatting functions
+- [x] Supports the "Gregorian" calendar only ( my time isn't unlimited, had to draw the line somewhere )
+- [x] Support loading translations from files
+- [x] Exporting translations to file(s), mainly for getting them professionally translated
+- [ ] Code Generation for translation files -> Go code.. i.e. after it has been professionally translated
+- [ ] Tests for all languages, I need help with this, please see [here](https://github.com/go-playground/locales/issues/1)
+
+Installation
+-----------
+
+Use go get
+
+```shell
+go get github.com/go-playground/universal-translator
+```
+
+Usage & Documentation
+-------
+
+Please see https://godoc.org/github.com/go-playground/universal-translator for usage docs
+
+##### Examples:
+
+- [Basic](https://github.com/go-playground/universal-translator/tree/master/_examples/basic)
+- [Full - no files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-no-files)
+- [Full - with files](https://github.com/go-playground/universal-translator/tree/master/_examples/full-with-files)
+
+File formatting
+--------------
+All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained withing the same file(s);
+they are only separated for easy viewing.
+
+##### Examples:
+
+- [Formats](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats)
+
+##### Basic Makeup
+NOTE: not all fields are needed for all translation types, see [examples](https://github.com/go-playground/universal-translator/tree/master/_examples/file-formats)
+```json
+{
+ "locale": "en",
+ "key": "days-left",
+ "trans": "You have {0} day left.",
+ "type": "Cardinal",
+ "rule": "One",
+ "override": false
+}
+```
+|Field|Description|
+|---|---|
+|locale|The locale for which the translation is for.|
+|key|The translation key that will be used to store and lookup each translation; normally it is a string or integer.|
+|trans|The actual translation text.|
+|type|The type of translation Cardinal, Ordinal, Range or "" for a plain substitution(not required to be defined if plain used)|
+|rule|The plural rule for which the translation is for eg. One, Two, Few, Many or Other.(not required to be defined if plain used)|
+|override|If you wish to override an existing translation that has already been registered, set this to 'true'. 99% of the time there is no need to define it.|
+
+Help With Tests
+---------------
+To anyone interesting in helping or contributing, I sure could use some help creating tests for each language.
+Please see issue [here](https://github.com/go-playground/locales/issues/1) for details.
+
+License
+------
+Distributed under MIT License, please see license file in code for more details.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/errors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/errors.go
new file mode 100644
index 000000000000..38b163b62690
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/errors.go
@@ -0,0 +1,148 @@
+package ut
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/go-playground/locales"
+)
+
+var (
+ // ErrUnknowTranslation indicates the translation could not be found
+ ErrUnknowTranslation = errors.New("Unknown Translation")
+)
+
+var _ error = new(ErrConflictingTranslation)
+var _ error = new(ErrRangeTranslation)
+var _ error = new(ErrOrdinalTranslation)
+var _ error = new(ErrCardinalTranslation)
+var _ error = new(ErrMissingPluralTranslation)
+var _ error = new(ErrExistingTranslator)
+
+// ErrExistingTranslator is the error representing a conflicting translator
+type ErrExistingTranslator struct {
+ locale string
+}
+
+// Error returns ErrExistingTranslator's internal error text
+func (e *ErrExistingTranslator) Error() string {
+ return fmt.Sprintf("error: conflicting translator for locale '%s'", e.locale)
+}
+
+// ErrConflictingTranslation is the error representing a conflicting translation
+type ErrConflictingTranslation struct {
+ locale string
+ key interface{}
+ rule locales.PluralRule
+ text string
+}
+
+// Error returns ErrConflictingTranslation's internal error text
+func (e *ErrConflictingTranslation) Error() string {
+
+ if _, ok := e.key.(string); !ok {
+ return fmt.Sprintf("error: conflicting key '%#v' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale)
+ }
+
+ return fmt.Sprintf("error: conflicting key '%s' rule '%s' with text '%s' for locale '%s', value being ignored", e.key, e.rule, e.text, e.locale)
+}
+
+// ErrRangeTranslation is the error representing a range translation error
+type ErrRangeTranslation struct {
+ text string
+}
+
+// Error returns ErrRangeTranslation's internal error text
+func (e *ErrRangeTranslation) Error() string {
+ return e.text
+}
+
+// ErrOrdinalTranslation is the error representing an ordinal translation error
+type ErrOrdinalTranslation struct {
+ text string
+}
+
+// Error returns ErrOrdinalTranslation's internal error text
+func (e *ErrOrdinalTranslation) Error() string {
+ return e.text
+}
+
+// ErrCardinalTranslation is the error representing a cardinal translation error
+type ErrCardinalTranslation struct {
+ text string
+}
+
+// Error returns ErrCardinalTranslation's internal error text
+func (e *ErrCardinalTranslation) Error() string {
+ return e.text
+}
+
+// ErrMissingPluralTranslation is the error signifying a missing translation given
+// the locales plural rules.
+type ErrMissingPluralTranslation struct {
+ locale string
+ key interface{}
+ rule locales.PluralRule
+ translationType string
+}
+
+// Error returns ErrMissingPluralTranslation's internal error text
+func (e *ErrMissingPluralTranslation) Error() string {
+
+ if _, ok := e.key.(string); !ok {
+ return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%#v' and locale '%s'", e.translationType, e.rule, e.key, e.locale)
+ }
+
+ return fmt.Sprintf("error: missing '%s' plural rule '%s' for translation with key '%s' and locale '%s'", e.translationType, e.rule, e.key, e.locale)
+}
+
+// ErrMissingBracket is the error representing a missing bracket in a translation
+// eg. This is a {0 <-- missing ending '}'
+type ErrMissingBracket struct {
+ locale string
+ key interface{}
+ text string
+}
+
+// Error returns ErrMissingBracket error message
+func (e *ErrMissingBracket) Error() string {
+ return fmt.Sprintf("error: missing bracket '{}', in translation. locale: '%s' key: '%v' text: '%s'", e.locale, e.key, e.text)
+}
+
+// ErrBadParamSyntax is the error representing a bad parameter definition in a translation
+// eg. This is a {must-be-int}
+type ErrBadParamSyntax struct {
+ locale string
+ param string
+ key interface{}
+ text string
+}
+
+// Error returns ErrBadParamSyntax error message
+func (e *ErrBadParamSyntax) Error() string {
+ return fmt.Sprintf("error: bad parameter syntax, missing parameter '%s' in translation. locale: '%s' key: '%v' text: '%s'", e.param, e.locale, e.key, e.text)
+}
+
+// import/export errors
+
+// ErrMissingLocale is the error representing an expected locale that could
+// not be found aka locale not registered with the UniversalTranslator Instance
+type ErrMissingLocale struct {
+ locale string
+}
+
+// Error returns ErrMissingLocale's internal error text
+func (e *ErrMissingLocale) Error() string {
+ return fmt.Sprintf("error: locale '%s' not registered.", e.locale)
+}
+
+// ErrBadPluralDefinition is the error representing an incorrect plural definition
+// usually found within translations defined within files during the import process.
+type ErrBadPluralDefinition struct {
+ tl translation
+}
+
+// Error returns ErrBadPluralDefinition's internal error text
+func (e *ErrBadPluralDefinition) Error() string {
+ return fmt.Sprintf("error: bad plural definition '%#v'", e.tl)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/import_export.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/import_export.go
new file mode 100644
index 000000000000..7bd76f26b6f3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/import_export.go
@@ -0,0 +1,274 @@
+package ut
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "io"
+
+ "github.com/go-playground/locales"
+)
+
+type translation struct {
+ Locale string `json:"locale"`
+ Key interface{} `json:"key"` // either string or integer
+ Translation string `json:"trans"`
+ PluralType string `json:"type,omitempty"`
+ PluralRule string `json:"rule,omitempty"`
+ OverrideExisting bool `json:"override,omitempty"`
+}
+
+const (
+ cardinalType = "Cardinal"
+ ordinalType = "Ordinal"
+ rangeType = "Range"
+)
+
+// ImportExportFormat is the format of the file import or export
+type ImportExportFormat uint8
+
+// supported Export Formats
+const (
+ FormatJSON ImportExportFormat = iota
+)
+
+// Export writes the translations out to a file on disk.
+//
+// NOTE: this currently only works with string or int translations keys.
+func (t *UniversalTranslator) Export(format ImportExportFormat, dirname string) error {
+
+ _, err := os.Stat(dirname)
+ fmt.Println(dirname, err, os.IsNotExist(err))
+ if err != nil {
+
+ if !os.IsNotExist(err) {
+ return err
+ }
+
+ if err = os.MkdirAll(dirname, 0744); err != nil {
+ return err
+ }
+ }
+
+ // build up translations
+ var trans []translation
+ var b []byte
+ var ext string
+
+ for _, locale := range t.translators {
+
+ for k, v := range locale.(*translator).translations {
+ trans = append(trans, translation{
+ Locale: locale.Locale(),
+ Key: k,
+ Translation: v.text,
+ })
+ }
+
+ for k, pluralTrans := range locale.(*translator).cardinalTanslations {
+
+ for i, plural := range pluralTrans {
+
+ // leave enough for all plural rules
+ // but not all are set for all languages.
+ if plural == nil {
+ continue
+ }
+
+ trans = append(trans, translation{
+ Locale: locale.Locale(),
+ Key: k.(string),
+ Translation: plural.text,
+ PluralType: cardinalType,
+ PluralRule: locales.PluralRule(i).String(),
+ })
+ }
+ }
+
+ for k, pluralTrans := range locale.(*translator).ordinalTanslations {
+
+ for i, plural := range pluralTrans {
+
+ // leave enough for all plural rules
+ // but not all are set for all languages.
+ if plural == nil {
+ continue
+ }
+
+ trans = append(trans, translation{
+ Locale: locale.Locale(),
+ Key: k.(string),
+ Translation: plural.text,
+ PluralType: ordinalType,
+ PluralRule: locales.PluralRule(i).String(),
+ })
+ }
+ }
+
+ for k, pluralTrans := range locale.(*translator).rangeTanslations {
+
+ for i, plural := range pluralTrans {
+
+ // leave enough for all plural rules
+ // but not all are set for all languages.
+ if plural == nil {
+ continue
+ }
+
+ trans = append(trans, translation{
+ Locale: locale.Locale(),
+ Key: k.(string),
+ Translation: plural.text,
+ PluralType: rangeType,
+ PluralRule: locales.PluralRule(i).String(),
+ })
+ }
+ }
+
+ switch format {
+ case FormatJSON:
+ b, err = json.MarshalIndent(trans, "", " ")
+ ext = ".json"
+ }
+
+ if err != nil {
+ return err
+ }
+
+ err = ioutil.WriteFile(filepath.Join(dirname, fmt.Sprintf("%s%s", locale.Locale(), ext)), b, 0644)
+ if err != nil {
+ return err
+ }
+
+ trans = trans[0:0]
+ }
+
+ return nil
+}
+
+// Import reads the translations out of a file or directory on disk.
+//
+// NOTE: this currently only works with string or int translations keys.
+func (t *UniversalTranslator) Import(format ImportExportFormat, dirnameOrFilename string) error {
+
+ fi, err := os.Stat(dirnameOrFilename)
+ if err != nil {
+ return err
+ }
+
+ processFn := func(filename string) error {
+
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ return t.ImportByReader(format, f)
+ }
+
+ if !fi.IsDir() {
+ return processFn(dirnameOrFilename)
+ }
+
+ // recursively go through directory
+ walker := func(path string, info os.FileInfo, err error) error {
+
+ if info.IsDir() {
+ return nil
+ }
+
+ switch format {
+ case FormatJSON:
+ // skip non JSON files
+ if filepath.Ext(info.Name()) != ".json" {
+ return nil
+ }
+ }
+
+ return processFn(path)
+ }
+
+ return filepath.Walk(dirnameOrFilename, walker)
+}
+
+// ImportByReader imports the the translations found within the contents read from the supplied reader.
+//
+// NOTE: generally used when assets have been embedded into the binary and are already in memory.
+func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader io.Reader) error {
+
+ b, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return err
+ }
+
+ var trans []translation
+
+ switch format {
+ case FormatJSON:
+ err = json.Unmarshal(b, &trans)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ for _, tl := range trans {
+
+ locale, found := t.FindTranslator(tl.Locale)
+ if !found {
+ return &ErrMissingLocale{locale: tl.Locale}
+ }
+
+ pr := stringToPR(tl.PluralRule)
+
+ if pr == locales.PluralRuleUnknown {
+
+ err = locale.Add(tl.Key, tl.Translation, tl.OverrideExisting)
+ if err != nil {
+ return err
+ }
+
+ continue
+ }
+
+ switch tl.PluralType {
+ case cardinalType:
+ err = locale.AddCardinal(tl.Key, tl.Translation, pr, tl.OverrideExisting)
+ case ordinalType:
+ err = locale.AddOrdinal(tl.Key, tl.Translation, pr, tl.OverrideExisting)
+ case rangeType:
+ err = locale.AddRange(tl.Key, tl.Translation, pr, tl.OverrideExisting)
+ default:
+ return &ErrBadPluralDefinition{tl: tl}
+ }
+
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func stringToPR(s string) locales.PluralRule {
+
+ switch s {
+ case "One":
+ return locales.PluralRuleOne
+ case "Two":
+ return locales.PluralRuleTwo
+ case "Few":
+ return locales.PluralRuleFew
+ case "Many":
+ return locales.PluralRuleMany
+ case "Other":
+ return locales.PluralRuleOther
+ default:
+ return locales.PluralRuleUnknown
+ }
+
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/logo.png b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/logo.png
new file mode 100644
index 000000000000..a37aa8c0cd0f
Binary files /dev/null and b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/logo.png differ
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/translator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/translator.go
new file mode 100644
index 000000000000..cfafce8a09da
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/translator.go
@@ -0,0 +1,420 @@
+package ut
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/go-playground/locales"
+)
+
+const (
+ paramZero = "{0}"
+ paramOne = "{1}"
+ unknownTranslation = ""
+)
+
+// Translator is universal translators
+// translator instance which is a thin wrapper
+// around locales.Translator instance providing
+// some extra functionality
+type Translator interface {
+ locales.Translator
+
+ // adds a normal translation for a particular language/locale
+ // {#} is the only replacement type accepted and are ad infinitum
+ // eg. one: '{0} day left' other: '{0} days left'
+ Add(key interface{}, text string, override bool) error
+
+ // adds a cardinal plural translation for a particular language/locale
+ // {0} is the only replacement type accepted and only one variable is accepted as
+ // multiple cannot be used for a plural rule determination, unless it is a range;
+ // see AddRange below.
+ // eg. in locale 'en' one: '{0} day left' other: '{0} days left'
+ AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error
+
+ // adds an ordinal plural translation for a particular language/locale
+ // {0} is the only replacement type accepted and only one variable is accepted as
+ // multiple cannot be used for a plural rule determination, unless it is a range;
+ // see AddRange below.
+ // eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring'
+ // - 1st, 2nd, 3rd...
+ AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error
+
+ // adds a range plural translation for a particular language/locale
+ // {0} and {1} are the only replacement types accepted and only these are accepted.
+ // eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
+ AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error
+
+ // creates the translation for the locale given the 'key' and params passed in
+ T(key interface{}, params ...string) (string, error)
+
+ // creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments
+ // and param passed in
+ C(key interface{}, num float64, digits uint64, param string) (string, error)
+
+ // creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments
+ // and param passed in
+ O(key interface{}, num float64, digits uint64, param string) (string, error)
+
+ // creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and
+ // 'digit2' arguments and 'param1' and 'param2' passed in
+ R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error)
+
+ // VerifyTranslations checks to ensures that no plural rules have been
+ // missed within the translations.
+ VerifyTranslations() error
+}
+
+var _ Translator = new(translator)
+var _ locales.Translator = new(translator)
+
+type translator struct {
+ locales.Translator
+ translations map[interface{}]*transText
+ cardinalTanslations map[interface{}][]*transText // array index is mapped to locales.PluralRule index + the locales.PluralRuleUnknown
+ ordinalTanslations map[interface{}][]*transText
+ rangeTanslations map[interface{}][]*transText
+}
+
+type transText struct {
+ text string
+ indexes []int
+}
+
+func newTranslator(trans locales.Translator) Translator {
+ return &translator{
+ Translator: trans,
+ translations: make(map[interface{}]*transText), // translation text broken up by byte index
+ cardinalTanslations: make(map[interface{}][]*transText),
+ ordinalTanslations: make(map[interface{}][]*transText),
+ rangeTanslations: make(map[interface{}][]*transText),
+ }
+}
+
+// Add adds a normal translation for a particular language/locale
+// {#} is the only replacement type accepted and are ad infinitum
+// eg. one: '{0} day left' other: '{0} days left'
+func (t *translator) Add(key interface{}, text string, override bool) error {
+
+ if _, ok := t.translations[key]; ok && !override {
+ return &ErrConflictingTranslation{locale: t.Locale(), key: key, text: text}
+ }
+
+ lb := strings.Count(text, "{")
+ rb := strings.Count(text, "}")
+
+ if lb != rb {
+ return &ErrMissingBracket{locale: t.Locale(), key: key, text: text}
+ }
+
+ trans := &transText{
+ text: text,
+ }
+
+ var idx int
+
+ for i := 0; i < lb; i++ {
+ s := "{" + strconv.Itoa(i) + "}"
+ idx = strings.Index(text, s)
+ if idx == -1 {
+ return &ErrBadParamSyntax{locale: t.Locale(), param: s, key: key, text: text}
+ }
+
+ trans.indexes = append(trans.indexes, idx)
+ trans.indexes = append(trans.indexes, idx+len(s))
+ }
+
+ t.translations[key] = trans
+
+ return nil
+}
+
+// AddCardinal adds a cardinal plural translation for a particular language/locale
+// {0} is the only replacement type accepted and only one variable is accepted as
+// multiple cannot be used for a plural rule determination, unless it is a range;
+// see AddRange below.
+// eg. in locale 'en' one: '{0} day left' other: '{0} days left'
+func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error {
+
+ var verified bool
+
+ // verify plural rule exists for locale
+ for _, pr := range t.PluralsCardinal() {
+ if pr == rule {
+ verified = true
+ break
+ }
+ }
+
+ if !verified {
+ return &ErrCardinalTranslation{text: fmt.Sprintf("error: cardinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)}
+ }
+
+ tarr, ok := t.cardinalTanslations[key]
+ if ok {
+ // verify not adding a conflicting record
+ if len(tarr) > 0 && tarr[rule] != nil && !override {
+ return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text}
+ }
+
+ } else {
+ tarr = make([]*transText, 7, 7)
+ t.cardinalTanslations[key] = tarr
+ }
+
+ trans := &transText{
+ text: text,
+ indexes: make([]int, 2, 2),
+ }
+
+ tarr[rule] = trans
+
+ idx := strings.Index(text, paramZero)
+ if idx == -1 {
+ tarr[rule] = nil
+ return &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)}
+ }
+
+ trans.indexes[0] = idx
+ trans.indexes[1] = idx + len(paramZero)
+
+ return nil
+}
+
+// AddOrdinal adds an ordinal plural translation for a particular language/locale
+// {0} is the only replacement type accepted and only one variable is accepted as
+// multiple cannot be used for a plural rule determination, unless it is a range;
+// see AddRange below.
+// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd...
+func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error {
+
+ var verified bool
+
+ // verify plural rule exists for locale
+ for _, pr := range t.PluralsOrdinal() {
+ if pr == rule {
+ verified = true
+ break
+ }
+ }
+
+ if !verified {
+ return &ErrOrdinalTranslation{text: fmt.Sprintf("error: ordinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)}
+ }
+
+ tarr, ok := t.ordinalTanslations[key]
+ if ok {
+ // verify not adding a conflicting record
+ if len(tarr) > 0 && tarr[rule] != nil && !override {
+ return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text}
+ }
+
+ } else {
+ tarr = make([]*transText, 7, 7)
+ t.ordinalTanslations[key] = tarr
+ }
+
+ trans := &transText{
+ text: text,
+ indexes: make([]int, 2, 2),
+ }
+
+ tarr[rule] = trans
+
+ idx := strings.Index(text, paramZero)
+ if idx == -1 {
+ tarr[rule] = nil
+ return &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)}
+ }
+
+ trans.indexes[0] = idx
+ trans.indexes[1] = idx + len(paramZero)
+
+ return nil
+}
+
+// AddRange adds a range plural translation for a particular language/locale
+// {0} and {1} are the only replacement types accepted and only these are accepted.
+// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
+func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error {
+
+ var verified bool
+
+ // verify plural rule exists for locale
+ for _, pr := range t.PluralsRange() {
+ if pr == rule {
+ verified = true
+ break
+ }
+ }
+
+ if !verified {
+ return &ErrRangeTranslation{text: fmt.Sprintf("error: range plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)}
+ }
+
+ tarr, ok := t.rangeTanslations[key]
+ if ok {
+ // verify not adding a conflicting record
+ if len(tarr) > 0 && tarr[rule] != nil && !override {
+ return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text}
+ }
+
+ } else {
+ tarr = make([]*transText, 7, 7)
+ t.rangeTanslations[key] = tarr
+ }
+
+ trans := &transText{
+ text: text,
+ indexes: make([]int, 4, 4),
+ }
+
+ tarr[rule] = trans
+
+ idx := strings.Index(text, paramZero)
+ if idx == -1 {
+ tarr[rule] = nil
+ return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)}
+ }
+
+ trans.indexes[0] = idx
+ trans.indexes[1] = idx + len(paramZero)
+
+ idx = strings.Index(text, paramOne)
+ if idx == -1 {
+ tarr[rule] = nil
+ return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%v' text: '%s'", paramOne, t.Locale(), key, text)}
+ }
+
+ trans.indexes[2] = idx
+ trans.indexes[3] = idx + len(paramOne)
+
+ return nil
+}
+
+// T creates the translation for the locale given the 'key' and params passed in
+func (t *translator) T(key interface{}, params ...string) (string, error) {
+
+ trans, ok := t.translations[key]
+ if !ok {
+ return unknownTranslation, ErrUnknowTranslation
+ }
+
+ b := make([]byte, 0, 64)
+
+ var start, end, count int
+
+ for i := 0; i < len(trans.indexes); i++ {
+ end = trans.indexes[i]
+ b = append(b, trans.text[start:end]...)
+ b = append(b, params[count]...)
+ i++
+ start = trans.indexes[i]
+ count++
+ }
+
+ b = append(b, trans.text[start:]...)
+
+ return string(b), nil
+}
+
+// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in
+func (t *translator) C(key interface{}, num float64, digits uint64, param string) (string, error) {
+
+ tarr, ok := t.cardinalTanslations[key]
+ if !ok {
+ return unknownTranslation, ErrUnknowTranslation
+ }
+
+ rule := t.CardinalPluralRule(num, digits)
+
+ trans := tarr[rule]
+
+ b := make([]byte, 0, 64)
+ b = append(b, trans.text[:trans.indexes[0]]...)
+ b = append(b, param...)
+ b = append(b, trans.text[trans.indexes[1]:]...)
+
+ return string(b), nil
+}
+
+// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in
+func (t *translator) O(key interface{}, num float64, digits uint64, param string) (string, error) {
+
+ tarr, ok := t.ordinalTanslations[key]
+ if !ok {
+ return unknownTranslation, ErrUnknowTranslation
+ }
+
+ rule := t.OrdinalPluralRule(num, digits)
+
+ trans := tarr[rule]
+
+ b := make([]byte, 0, 64)
+ b = append(b, trans.text[:trans.indexes[0]]...)
+ b = append(b, param...)
+ b = append(b, trans.text[trans.indexes[1]:]...)
+
+ return string(b), nil
+}
+
+// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2' arguments
+// and 'param1' and 'param2' passed in
+func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) {
+
+ tarr, ok := t.rangeTanslations[key]
+ if !ok {
+ return unknownTranslation, ErrUnknowTranslation
+ }
+
+ rule := t.RangePluralRule(num1, digits1, num2, digits2)
+
+ trans := tarr[rule]
+
+ b := make([]byte, 0, 64)
+ b = append(b, trans.text[:trans.indexes[0]]...)
+ b = append(b, param1...)
+ b = append(b, trans.text[trans.indexes[1]:trans.indexes[2]]...)
+ b = append(b, param2...)
+ b = append(b, trans.text[trans.indexes[3]:]...)
+
+ return string(b), nil
+}
+
+// VerifyTranslations checks to ensures that no plural rules have been
+// missed within the translations.
+func (t *translator) VerifyTranslations() error {
+
+ for k, v := range t.cardinalTanslations {
+
+ for _, rule := range t.PluralsCardinal() {
+
+ if v[rule] == nil {
+ return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "plural", rule: rule, key: k}
+ }
+ }
+ }
+
+ for k, v := range t.ordinalTanslations {
+
+ for _, rule := range t.PluralsOrdinal() {
+
+ if v[rule] == nil {
+ return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "ordinal", rule: rule, key: k}
+ }
+ }
+ }
+
+ for k, v := range t.rangeTanslations {
+
+ for _, rule := range t.PluralsRange() {
+
+ if v[rule] == nil {
+ return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "range", rule: rule, key: k}
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/universal_translator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/universal_translator.go
new file mode 100644
index 000000000000..dbf707f5c7cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/universal-translator/universal_translator.go
@@ -0,0 +1,113 @@
+package ut
+
+import (
+ "strings"
+
+ "github.com/go-playground/locales"
+)
+
+// UniversalTranslator holds all locale & translation data
+type UniversalTranslator struct {
+ translators map[string]Translator
+ fallback Translator
+}
+
+// New returns a new UniversalTranslator instance set with
+// the fallback locale and locales it should support
+func New(fallback locales.Translator, supportedLocales ...locales.Translator) *UniversalTranslator {
+
+ t := &UniversalTranslator{
+ translators: make(map[string]Translator),
+ }
+
+ for _, v := range supportedLocales {
+
+ trans := newTranslator(v)
+ t.translators[strings.ToLower(trans.Locale())] = trans
+
+ if fallback.Locale() == v.Locale() {
+ t.fallback = trans
+ }
+ }
+
+ if t.fallback == nil && fallback != nil {
+ t.fallback = newTranslator(fallback)
+ }
+
+ return t
+}
+
+// FindTranslator trys to find a Translator based on an array of locales
+// and returns the first one it can find, otherwise returns the
+// fallback translator.
+func (t *UniversalTranslator) FindTranslator(locales ...string) (trans Translator, found bool) {
+
+ for _, locale := range locales {
+
+ if trans, found = t.translators[strings.ToLower(locale)]; found {
+ return
+ }
+ }
+
+ return t.fallback, false
+}
+
+// GetTranslator returns the specified translator for the given locale,
+// or fallback if not found
+func (t *UniversalTranslator) GetTranslator(locale string) (trans Translator, found bool) {
+
+ if trans, found = t.translators[strings.ToLower(locale)]; found {
+ return
+ }
+
+ return t.fallback, false
+}
+
+// GetFallback returns the fallback locale
+func (t *UniversalTranslator) GetFallback() Translator {
+ return t.fallback
+}
+
+// AddTranslator adds the supplied translator, if it already exists the override param
+// will be checked and if false an error will be returned, otherwise the translator will be
+// overridden; if the fallback matches the supplied translator it will be overridden as well
+// NOTE: this is normally only used when translator is embedded within a library
+func (t *UniversalTranslator) AddTranslator(translator locales.Translator, override bool) error {
+
+ lc := strings.ToLower(translator.Locale())
+ _, ok := t.translators[lc]
+ if ok && !override {
+ return &ErrExistingTranslator{locale: translator.Locale()}
+ }
+
+ trans := newTranslator(translator)
+
+ if t.fallback.Locale() == translator.Locale() {
+
+ // because it's optional to have a fallback, I don't impose that limitation
+ // don't know why you wouldn't but...
+ if !override {
+ return &ErrExistingTranslator{locale: translator.Locale()}
+ }
+
+ t.fallback = trans
+ }
+
+ t.translators[lc] = trans
+
+ return nil
+}
+
+// VerifyTranslations runs through all locales and identifies any issues
+// eg. missing plural rules for a locale
+func (t *UniversalTranslator) VerifyTranslations() (err error) {
+
+ for _, trans := range t.translators {
+ err = trans.VerifyTranslations()
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/.gitignore
new file mode 100644
index 000000000000..6e43fac0d5ad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/.gitignore
@@ -0,0 +1,30 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+bin
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+*.test
+*.out
+*.txt
+cover.html
+README.html
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/.travis.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/.travis.yml
new file mode 100644
index 000000000000..85a7be34b110
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/.travis.yml
@@ -0,0 +1,29 @@
+language: go
+go:
+ - 1.15.2
+ - tip
+matrix:
+ allow_failures:
+ - go: tip
+
+notifications:
+ email:
+ recipients: dean.karn@gmail.com
+ on_success: change
+ on_failure: always
+
+before_install:
+ - go install github.com/mattn/goveralls
+ - mkdir -p $GOPATH/src/gopkg.in
+ - ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/validator.v9
+
+# Only clone the most recent commit.
+git:
+ depth: 1
+
+script:
+ - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./...
+
+after_success: |
+ [ $TRAVIS_GO_VERSION = 1.15.2 ] &&
+ goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/LICENSE
new file mode 100644
index 000000000000..6a2ae9aa4da8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Dean Karn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/Makefile b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/Makefile
new file mode 100644
index 000000000000..19c91ed73e97
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/Makefile
@@ -0,0 +1,18 @@
+GOCMD=GO111MODULE=on go
+
+linters-install:
+ @golangci-lint --version >/dev/null 2>&1 || { \
+ echo "installing linting tools..."; \
+ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0; \
+ }
+
+lint: linters-install
+ $(PWD)/bin/golangci-lint run
+
+test:
+ $(GOCMD) test -cover -race ./...
+
+bench:
+ $(GOCMD) test -bench=. -benchmem ./...
+
+.PHONY: test lint linters-install
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/README.md
new file mode 100644
index 000000000000..04fbb3c86993
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/README.md
@@ -0,0 +1,299 @@
+Package validator
+================
+ [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+![Project status](https://img.shields.io/badge/version-10.4.1-green.svg)
+[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator)
+[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
+[![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10)
+![License](https://img.shields.io/dub/l/vibe-d.svg)
+
+Package validator implements value validations for structs and individual fields based on tags.
+
+It has the following **unique** features:
+
+- Cross Field and Cross Struct validations by using validation tags or custom validators.
+- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
+- Ability to dive into both map keys and values for validation
+- Handles type interface by determining it's underlying type prior to validation.
+- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29)
+- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs
+- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError
+- Customizable i18n aware error messages.
+- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding)
+
+Installation
+------------
+
+Use go get.
+
+ go get github.com/go-playground/validator/v10
+
+Then import the validator package into your own code.
+
+ import "github.com/go-playground/validator/v10"
+
+Error Return Value
+-------
+
+Validation functions return type error
+
+They return type error to avoid the issue discussed in the following, where err is always != nil:
+
+* http://stackoverflow.com/a/29138676/3158232
+* https://github.com/go-playground/validator/issues/134
+
+Validator only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so:
+
+```go
+err := validate.Struct(mystruct)
+validationErrors := err.(validator.ValidationErrors)
+ ```
+
+Usage and documentation
+------
+
+Please see https://godoc.org/github.com/go-playground/validator for detailed usage docs.
+
+##### Examples:
+
+- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go)
+- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go)
+- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go)
+- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go)
+- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding)
+- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash)
+
+Baked-in Validations
+------
+
+### Fields:
+
+| Tag | Description |
+| - | - |
+| eqcsfield | Field Equals Another Field (relative)|
+| eqfield | Field Equals Another Field |
+| fieldcontains | NOT DOCUMENTED IN doc.go |
+| fieldexcludes | NOT DOCUMENTED IN doc.go |
+| gtcsfield | Field Greater Than Another Relative Field |
+| gtecsfield | Field Greater Than or Equal To Another Relative Field |
+| gtefield | Field Greater Than or Equal To Another Field |
+| gtfield | Field Greater Than Another Field |
+| ltcsfield | Less Than Another Relative Field |
+| ltecsfield | Less Than or Equal To Another Relative Field |
+| ltefield | Less Than or Equal To Another Field |
+| ltfield | Less Than Another Field |
+| necsfield | Field Does Not Equal Another Field (relative) |
+| nefield | Field Does Not Equal Another Field |
+
+### Network:
+
+| Tag | Description |
+| - | - |
+| cidr | Classless Inter-Domain Routing CIDR |
+| cidrv4 | Classless Inter-Domain Routing CIDRv4 |
+| cidrv6 | Classless Inter-Domain Routing CIDRv6 |
+| datauri | Data URL |
+| fqdn | Full Qualified Domain Name (FQDN) |
+| hostname | Hostname RFC 952 |
+| hostname_port | HostPort |
+| hostname_rfc1123 | Hostname RFC 1123 |
+| ip | Internet Protocol Address IP |
+| ip4_addr | Internet Protocol Address IPv4 |
+| ip6_addr |Internet Protocol Address IPv6 |
+| ip_addr | Internet Protocol Address IP |
+| ipv4 | Internet Protocol Address IPv4 |
+| ipv6 | Internet Protocol Address IPv6 |
+| mac | Media Access Control Address MAC |
+| tcp4_addr | Transmission Control Protocol Address TCPv4 |
+| tcp6_addr | Transmission Control Protocol Address TCPv6 |
+| tcp_addr | Transmission Control Protocol Address TCP |
+| udp4_addr | User Datagram Protocol Address UDPv4 |
+| udp6_addr | User Datagram Protocol Address UDPv6 |
+| udp_addr | User Datagram Protocol Address UDP |
+| unix_addr | Unix domain socket end point Address |
+| uri | URI String |
+| url | URL String |
+| url_encoded | URL Encoded |
+| urn_rfc2141 | Urn RFC 2141 String |
+
+### Strings:
+
+| Tag | Description |
+| - | - |
+| alpha | Alpha Only |
+| alphanum | Alphanumeric |
+| alphanumunicode | Alphanumeric Unicode |
+| alphaunicode | Alpha Unicode |
+| ascii | ASCII |
+| contains | Contains |
+| containsany | Contains Any |
+| containsrune | Contains Rune |
+| endswith | Ends With |
+| lowercase | Lowercase |
+| multibyte | Multi-Byte Characters |
+| number | NOT DOCUMENTED IN doc.go |
+| numeric | Numeric |
+| printascii | Printable ASCII |
+| startswith | Starts With |
+| uppercase | Uppercase |
+
+### Format:
+| Tag | Description |
+| - | - |
+| base64 | Base64 String |
+| base64url | Base64URL String |
+| btc_addr | Bitcoin Address |
+| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
+| datetime | Datetime |
+| e164 | e164 formatted phone number |
+| email | E-mail String
+| eth_addr | Ethereum Address |
+| hexadecimal | Hexadecimal String |
+| hexcolor | Hexcolor String |
+| hsl | HSL String |
+| hsla | HSLA String |
+| html | HTML Tags |
+| html_encoded | HTML Encoded |
+| isbn | International Standard Book Number |
+| isbn10 | International Standard Book Number 10 |
+| isbn13 | International Standard Book Number 13 |
+| json | JSON |
+| latitude | Latitude |
+| longitude | Longitude |
+| rgb | RGB String |
+| rgba | RGBA String |
+| ssn | Social Security Number SSN |
+| uuid | Universally Unique Identifier UUID |
+| uuid3 | Universally Unique Identifier UUID v3 |
+| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 |
+| uuid4 | Universally Unique Identifier UUID v4 |
+| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 |
+| uuid5 | Universally Unique Identifier UUID v5 |
+| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
+| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
+
+### Comparisons:
+| Tag | Description |
+| - | - |
+| eq | Equals |
+| gt | Greater than|
+| gte |Greater than or equal |
+| lt | Less Than |
+| lte | Less Than or Equal |
+| ne | Not Equal |
+
+### Other:
+| Tag | Description |
+| - | - |
+| dir | Directory |
+| endswith | Ends With |
+| excludes | Excludes |
+| excludesall | Excludes All |
+| excludesrune | Excludes Rune |
+| file | File path |
+| isdefault | Is Default |
+| len | Length |
+| max | Maximum |
+| min | Minimum |
+| oneof | One Of |
+| required | Required |
+| required_if | Required If |
+| required_unless | Required Unless |
+| required_with | Required With |
+| required_with_all | Required With All |
+| required_without | Required Without |
+| required_without_all | Required Without All |
+| excluded_with | Excluded With |
+| excluded_with_all | Excluded With All |
+| excluded_without | Excluded Without |
+| excluded_without_all | Excluded Without All |
+| unique | Unique |
+
+Benchmarks
+------
+###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64
+```go
+goos: darwin
+goarch: amd64
+pkg: github.com/go-playground/validator
+BenchmarkFieldSuccess-8 20000000 83.6 ns/op 0 B/op 0 allocs/op
+BenchmarkFieldSuccessParallel-8 50000000 26.8 ns/op 0 B/op 0 allocs/op
+BenchmarkFieldFailure-8 5000000 291 ns/op 208 B/op 4 allocs/op
+BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op
+BenchmarkFieldArrayDiveSuccess-8 2000000 623 ns/op 201 B/op 11 allocs/op
+BenchmarkFieldArrayDiveSuccessParallel-8 10000000 237 ns/op 201 B/op 11 allocs/op
+BenchmarkFieldArrayDiveFailure-8 2000000 859 ns/op 412 B/op 16 allocs/op
+BenchmarkFieldArrayDiveFailureParallel-8 5000000 335 ns/op 413 B/op 16 allocs/op
+BenchmarkFieldMapDiveSuccess-8 1000000 1292 ns/op 432 B/op 18 allocs/op
+BenchmarkFieldMapDiveSuccessParallel-8 3000000 467 ns/op 432 B/op 18 allocs/op
+BenchmarkFieldMapDiveFailure-8 1000000 1082 ns/op 512 B/op 16 allocs/op
+BenchmarkFieldMapDiveFailureParallel-8 5000000 425 ns/op 512 B/op 16 allocs/op
+BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1539 ns/op 480 B/op 21 allocs/op
+BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 613 ns/op 480 B/op 21 allocs/op
+BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1413 ns/op 721 B/op 21 allocs/op
+BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 575 ns/op 721 B/op 21 allocs/op
+BenchmarkFieldCustomTypeSuccess-8 10000000 216 ns/op 32 B/op 2 allocs/op
+BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.2 ns/op 32 B/op 2 allocs/op
+BenchmarkFieldCustomTypeFailure-8 5000000 274 ns/op 208 B/op 4 allocs/op
+BenchmarkFieldCustomTypeFailureParallel-8 20000000 116 ns/op 208 B/op 4 allocs/op
+BenchmarkFieldOrTagSuccess-8 2000000 740 ns/op 16 B/op 1 allocs/op
+BenchmarkFieldOrTagSuccessParallel-8 3000000 474 ns/op 16 B/op 1 allocs/op
+BenchmarkFieldOrTagFailure-8 3000000 471 ns/op 224 B/op 5 allocs/op
+BenchmarkFieldOrTagFailureParallel-8 3000000 414 ns/op 224 B/op 5 allocs/op
+BenchmarkStructLevelValidationSuccess-8 10000000 213 ns/op 32 B/op 2 allocs/op
+BenchmarkStructLevelValidationSuccessParallel-8 20000000 91.8 ns/op 32 B/op 2 allocs/op
+BenchmarkStructLevelValidationFailure-8 3000000 473 ns/op 304 B/op 8 allocs/op
+BenchmarkStructLevelValidationFailureParallel-8 10000000 234 ns/op 304 B/op 8 allocs/op
+BenchmarkStructSimpleCustomTypeSuccess-8 5000000 385 ns/op 32 B/op 2 allocs/op
+BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 161 ns/op 32 B/op 2 allocs/op
+BenchmarkStructSimpleCustomTypeFailure-8 2000000 640 ns/op 424 B/op 9 allocs/op
+BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 318 ns/op 440 B/op 10 allocs/op
+BenchmarkStructFilteredSuccess-8 2000000 597 ns/op 288 B/op 9 allocs/op
+BenchmarkStructFilteredSuccessParallel-8 10000000 266 ns/op 288 B/op 9 allocs/op
+BenchmarkStructFilteredFailure-8 3000000 454 ns/op 256 B/op 7 allocs/op
+BenchmarkStructFilteredFailureParallel-8 10000000 214 ns/op 256 B/op 7 allocs/op
+BenchmarkStructPartialSuccess-8 3000000 502 ns/op 256 B/op 6 allocs/op
+BenchmarkStructPartialSuccessParallel-8 10000000 225 ns/op 256 B/op 6 allocs/op
+BenchmarkStructPartialFailure-8 2000000 702 ns/op 480 B/op 11 allocs/op
+BenchmarkStructPartialFailureParallel-8 5000000 329 ns/op 480 B/op 11 allocs/op
+BenchmarkStructExceptSuccess-8 2000000 793 ns/op 496 B/op 12 allocs/op
+BenchmarkStructExceptSuccessParallel-8 10000000 193 ns/op 240 B/op 5 allocs/op
+BenchmarkStructExceptFailure-8 2000000 639 ns/op 464 B/op 10 allocs/op
+BenchmarkStructExceptFailureParallel-8 5000000 300 ns/op 464 B/op 10 allocs/op
+BenchmarkStructSimpleCrossFieldSuccess-8 3000000 417 ns/op 72 B/op 3 allocs/op
+BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 163 ns/op 72 B/op 3 allocs/op
+BenchmarkStructSimpleCrossFieldFailure-8 2000000 645 ns/op 304 B/op 8 allocs/op
+BenchmarkStructSimpleCrossFieldFailureParallel-8 5000000 285 ns/op 304 B/op 8 allocs/op
+BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 588 ns/op 80 B/op 4 allocs/op
+BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 221 ns/op 80 B/op 4 allocs/op
+BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 868 ns/op 320 B/op 9 allocs/op
+BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 337 ns/op 320 B/op 9 allocs/op
+BenchmarkStructSimpleSuccess-8 5000000 260 ns/op 0 B/op 0 allocs/op
+BenchmarkStructSimpleSuccessParallel-8 20000000 90.6 ns/op 0 B/op 0 allocs/op
+BenchmarkStructSimpleFailure-8 2000000 619 ns/op 424 B/op 9 allocs/op
+BenchmarkStructSimpleFailureParallel-8 5000000 296 ns/op 424 B/op 9 allocs/op
+BenchmarkStructComplexSuccess-8 1000000 1454 ns/op 128 B/op 8 allocs/op
+BenchmarkStructComplexSuccessParallel-8 3000000 579 ns/op 128 B/op 8 allocs/op
+BenchmarkStructComplexFailure-8 300000 4140 ns/op 3041 B/op 53 allocs/op
+BenchmarkStructComplexFailureParallel-8 1000000 2127 ns/op 3041 B/op 53 allocs/op
+BenchmarkOneof-8 10000000 140 ns/op 0 B/op 0 allocs/op
+BenchmarkOneofParallel-8 20000000 70.1 ns/op 0 B/op 0 allocs/op
+```
+
+Complementary Software
+----------------------
+
+Here is a list of software that complements using this library either pre or post validation.
+
+* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.
+* [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects
+
+How to Contribute
+------
+
+Make a pull request...
+
+License
+------
+Distributed under MIT License, please see license file within the code for more details.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/baked_in.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/baked_in.go
new file mode 100644
index 000000000000..6ce762d152a3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/baked_in.go
@@ -0,0 +1,2285 @@
+package validator
+
+import (
+ "bytes"
+ "context"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "net"
+ "net/url"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+ "unicode/utf8"
+
+ "golang.org/x/crypto/sha3"
+
+ urn "github.com/leodido/go-urn"
+)
+
+// Func accepts a FieldLevel interface for all validation needs. The return
+// value should be true when validation succeeds.
+type Func func(fl FieldLevel) bool
+
+// FuncCtx accepts a context.Context and FieldLevel interface for all
+// validation needs. The return value should be true when validation succeeds.
+type FuncCtx func(ctx context.Context, fl FieldLevel) bool
+
+// wrapFunc wraps noramal Func makes it compatible with FuncCtx
+func wrapFunc(fn Func) FuncCtx {
+ if fn == nil {
+ return nil // be sure not to wrap a bad function.
+ }
+ return func(ctx context.Context, fl FieldLevel) bool {
+ return fn(fl)
+ }
+}
+
+var (
+ restrictedTags = map[string]struct{}{
+ diveTag: {},
+ keysTag: {},
+ endKeysTag: {},
+ structOnlyTag: {},
+ omitempty: {},
+ skipValidationTag: {},
+ utf8HexComma: {},
+ utf8Pipe: {},
+ noStructLevelTag: {},
+ requiredTag: {},
+ isdefault: {},
+ }
+
+ // BakedInAliasValidators is a default mapping of a single validation tag that
+ // defines a common or complex set of validation(s) to simplify
+ // adding validation to structs.
+ bakedInAliases = map[string]string{
+ "iscolor": "hexcolor|rgb|rgba|hsl|hsla",
+ "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric",
+ }
+
+ // BakedInValidators is the default map of ValidationFunc
+ // you can add, remove or even replace items to suite your needs,
+ // or even disregard and use your own map if so desired.
+ bakedInValidators = map[string]Func{
+ "required": hasValue,
+ "required_if": requiredIf,
+ "required_unless": requiredUnless,
+ "required_with": requiredWith,
+ "required_with_all": requiredWithAll,
+ "required_without": requiredWithout,
+ "required_without_all": requiredWithoutAll,
+ "excluded_with": excludedWith,
+ "excluded_with_all": excludedWithAll,
+ "excluded_without": excludedWithout,
+ "excluded_without_all": excludedWithoutAll,
+ "isdefault": isDefault,
+ "len": hasLengthOf,
+ "min": hasMinOf,
+ "max": hasMaxOf,
+ "eq": isEq,
+ "ne": isNe,
+ "lt": isLt,
+ "lte": isLte,
+ "gt": isGt,
+ "gte": isGte,
+ "eqfield": isEqField,
+ "eqcsfield": isEqCrossStructField,
+ "necsfield": isNeCrossStructField,
+ "gtcsfield": isGtCrossStructField,
+ "gtecsfield": isGteCrossStructField,
+ "ltcsfield": isLtCrossStructField,
+ "ltecsfield": isLteCrossStructField,
+ "nefield": isNeField,
+ "gtefield": isGteField,
+ "gtfield": isGtField,
+ "ltefield": isLteField,
+ "ltfield": isLtField,
+ "fieldcontains": fieldContains,
+ "fieldexcludes": fieldExcludes,
+ "alpha": isAlpha,
+ "alphanum": isAlphanum,
+ "alphaunicode": isAlphaUnicode,
+ "alphanumunicode": isAlphanumUnicode,
+ "numeric": isNumeric,
+ "number": isNumber,
+ "hexadecimal": isHexadecimal,
+ "hexcolor": isHEXColor,
+ "rgb": isRGB,
+ "rgba": isRGBA,
+ "hsl": isHSL,
+ "hsla": isHSLA,
+ "e164": isE164,
+ "email": isEmail,
+ "url": isURL,
+ "uri": isURI,
+ "urn_rfc2141": isUrnRFC2141, // RFC 2141
+ "file": isFile,
+ "base64": isBase64,
+ "base64url": isBase64URL,
+ "contains": contains,
+ "containsany": containsAny,
+ "containsrune": containsRune,
+ "excludes": excludes,
+ "excludesall": excludesAll,
+ "excludesrune": excludesRune,
+ "startswith": startsWith,
+ "endswith": endsWith,
+ "startsnotwith": startsNotWith,
+ "endsnotwith": endsNotWith,
+ "isbn": isISBN,
+ "isbn10": isISBN10,
+ "isbn13": isISBN13,
+ "eth_addr": isEthereumAddress,
+ "btc_addr": isBitcoinAddress,
+ "btc_addr_bech32": isBitcoinBech32Address,
+ "uuid": isUUID,
+ "uuid3": isUUID3,
+ "uuid4": isUUID4,
+ "uuid5": isUUID5,
+ "uuid_rfc4122": isUUIDRFC4122,
+ "uuid3_rfc4122": isUUID3RFC4122,
+ "uuid4_rfc4122": isUUID4RFC4122,
+ "uuid5_rfc4122": isUUID5RFC4122,
+ "ascii": isASCII,
+ "printascii": isPrintableASCII,
+ "multibyte": hasMultiByteCharacter,
+ "datauri": isDataURI,
+ "latitude": isLatitude,
+ "longitude": isLongitude,
+ "ssn": isSSN,
+ "ipv4": isIPv4,
+ "ipv6": isIPv6,
+ "ip": isIP,
+ "cidrv4": isCIDRv4,
+ "cidrv6": isCIDRv6,
+ "cidr": isCIDR,
+ "tcp4_addr": isTCP4AddrResolvable,
+ "tcp6_addr": isTCP6AddrResolvable,
+ "tcp_addr": isTCPAddrResolvable,
+ "udp4_addr": isUDP4AddrResolvable,
+ "udp6_addr": isUDP6AddrResolvable,
+ "udp_addr": isUDPAddrResolvable,
+ "ip4_addr": isIP4AddrResolvable,
+ "ip6_addr": isIP6AddrResolvable,
+ "ip_addr": isIPAddrResolvable,
+ "unix_addr": isUnixAddrResolvable,
+ "mac": isMAC,
+ "hostname": isHostnameRFC952, // RFC 952
+ "hostname_rfc1123": isHostnameRFC1123, // RFC 1123
+ "fqdn": isFQDN,
+ "unique": isUnique,
+ "oneof": isOneOf,
+ "html": isHTML,
+ "html_encoded": isHTMLEncoded,
+ "url_encoded": isURLEncoded,
+ "dir": isDir,
+ "json": isJSON,
+ "hostname_port": isHostnamePort,
+ "lowercase": isLowercase,
+ "uppercase": isUppercase,
+ "datetime": isDatetime,
+ "timezone": isTimeZone,
+ "iso3166_1_alpha2": isIso3166Alpha2,
+ "iso3166_1_alpha3": isIso3166Alpha3,
+ "iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
+ }
+)
+
+var oneofValsCache = map[string][]string{}
+var oneofValsCacheRWLock = sync.RWMutex{}
+
+func parseOneOfParam2(s string) []string {
+ oneofValsCacheRWLock.RLock()
+ vals, ok := oneofValsCache[s]
+ oneofValsCacheRWLock.RUnlock()
+ if !ok {
+ oneofValsCacheRWLock.Lock()
+ vals = splitParamsRegex.FindAllString(s, -1)
+ for i := 0; i < len(vals); i++ {
+ vals[i] = strings.Replace(vals[i], "'", "", -1)
+ }
+ oneofValsCache[s] = vals
+ oneofValsCacheRWLock.Unlock()
+ }
+ return vals
+}
+
+func isURLEncoded(fl FieldLevel) bool {
+ return uRLEncodedRegex.MatchString(fl.Field().String())
+}
+
+func isHTMLEncoded(fl FieldLevel) bool {
+ return hTMLEncodedRegex.MatchString(fl.Field().String())
+}
+
+func isHTML(fl FieldLevel) bool {
+ return hTMLRegex.MatchString(fl.Field().String())
+}
+
+func isOneOf(fl FieldLevel) bool {
+ vals := parseOneOfParam2(fl.Param())
+
+ field := fl.Field()
+
+ var v string
+ switch field.Kind() {
+ case reflect.String:
+ v = field.String()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ v = strconv.FormatInt(field.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ v = strconv.FormatUint(field.Uint(), 10)
+ default:
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+ }
+ for i := 0; i < len(vals); i++ {
+ if vals[i] == v {
+ return true
+ }
+ }
+ return false
+}
+
+// isUnique is the validation function for validating if each array|slice|map value is unique
+func isUnique(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+ v := reflect.ValueOf(struct{}{})
+
+ switch field.Kind() {
+ case reflect.Slice, reflect.Array:
+ elem := field.Type().Elem()
+ if elem.Kind() == reflect.Ptr {
+ elem = elem.Elem()
+ }
+
+ if param == "" {
+ m := reflect.MakeMap(reflect.MapOf(elem, v.Type()))
+
+ for i := 0; i < field.Len(); i++ {
+ m.SetMapIndex(reflect.Indirect(field.Index(i)), v)
+ }
+ return field.Len() == m.Len()
+ }
+
+ sf, ok := elem.FieldByName(param)
+ if !ok {
+ panic(fmt.Sprintf("Bad field name %s", param))
+ }
+
+ sfTyp := sf.Type
+ if sfTyp.Kind() == reflect.Ptr {
+ sfTyp = sfTyp.Elem()
+ }
+
+ m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type()))
+ for i := 0; i < field.Len(); i++ {
+ m.SetMapIndex(reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param)), v)
+ }
+ return field.Len() == m.Len()
+ case reflect.Map:
+ m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
+
+ for _, k := range field.MapKeys() {
+ m.SetMapIndex(field.MapIndex(k), v)
+ }
+ return field.Len() == m.Len()
+ default:
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+ }
+}
+
+// IsMAC is the validation function for validating if the field's value is a valid MAC address.
+func isMAC(fl FieldLevel) bool {
+
+ _, err := net.ParseMAC(fl.Field().String())
+
+ return err == nil
+}
+
+// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
+func isCIDRv4(fl FieldLevel) bool {
+
+ ip, _, err := net.ParseCIDR(fl.Field().String())
+
+ return err == nil && ip.To4() != nil
+}
+
+// IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
+func isCIDRv6(fl FieldLevel) bool {
+
+ ip, _, err := net.ParseCIDR(fl.Field().String())
+
+ return err == nil && ip.To4() == nil
+}
+
+// IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
+func isCIDR(fl FieldLevel) bool {
+
+ _, _, err := net.ParseCIDR(fl.Field().String())
+
+ return err == nil
+}
+
+// IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
+func isIPv4(fl FieldLevel) bool {
+
+ ip := net.ParseIP(fl.Field().String())
+
+ return ip != nil && ip.To4() != nil
+}
+
+// IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
+func isIPv6(fl FieldLevel) bool {
+
+ ip := net.ParseIP(fl.Field().String())
+
+ return ip != nil && ip.To4() == nil
+}
+
+// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
+func isIP(fl FieldLevel) bool {
+
+ ip := net.ParseIP(fl.Field().String())
+
+ return ip != nil
+}
+
+// IsSSN is the validation function for validating if the field's value is a valid SSN.
+func isSSN(fl FieldLevel) bool {
+
+ field := fl.Field()
+
+ if field.Len() != 11 {
+ return false
+ }
+
+ return sSNRegex.MatchString(field.String())
+}
+
+// IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
+func isLongitude(fl FieldLevel) bool {
+ field := fl.Field()
+
+ var v string
+ switch field.Kind() {
+ case reflect.String:
+ v = field.String()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ v = strconv.FormatInt(field.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ v = strconv.FormatUint(field.Uint(), 10)
+ case reflect.Float32:
+ v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
+ case reflect.Float64:
+ v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
+ default:
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+ }
+
+ return longitudeRegex.MatchString(v)
+}
+
+// IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
+func isLatitude(fl FieldLevel) bool {
+ field := fl.Field()
+
+ var v string
+ switch field.Kind() {
+ case reflect.String:
+ v = field.String()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ v = strconv.FormatInt(field.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ v = strconv.FormatUint(field.Uint(), 10)
+ case reflect.Float32:
+ v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
+ case reflect.Float64:
+ v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
+ default:
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+ }
+
+ return latitudeRegex.MatchString(v)
+}
+
+// IsDataURI is the validation function for validating if the field's value is a valid data URI.
+func isDataURI(fl FieldLevel) bool {
+
+ uri := strings.SplitN(fl.Field().String(), ",", 2)
+
+ if len(uri) != 2 {
+ return false
+ }
+
+ if !dataURIRegex.MatchString(uri[0]) {
+ return false
+ }
+
+ return base64Regex.MatchString(uri[1])
+}
+
+// HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
+func hasMultiByteCharacter(fl FieldLevel) bool {
+
+ field := fl.Field()
+
+ if field.Len() == 0 {
+ return true
+ }
+
+ return multibyteRegex.MatchString(field.String())
+}
+
+// IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
+func isPrintableASCII(fl FieldLevel) bool {
+ return printableASCIIRegex.MatchString(fl.Field().String())
+}
+
+// IsASCII is the validation function for validating if the field's value is a valid ASCII character.
+func isASCII(fl FieldLevel) bool {
+ return aSCIIRegex.MatchString(fl.Field().String())
+}
+
+// IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
+func isUUID5(fl FieldLevel) bool {
+ return uUID5Regex.MatchString(fl.Field().String())
+}
+
+// IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
+func isUUID4(fl FieldLevel) bool {
+ return uUID4Regex.MatchString(fl.Field().String())
+}
+
+// IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
+func isUUID3(fl FieldLevel) bool {
+ return uUID3Regex.MatchString(fl.Field().String())
+}
+
+// IsUUID is the validation function for validating if the field's value is a valid UUID of any version.
+func isUUID(fl FieldLevel) bool {
+ return uUIDRegex.MatchString(fl.Field().String())
+}
+
+// IsUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID.
+func isUUID5RFC4122(fl FieldLevel) bool {
+ return uUID5RFC4122Regex.MatchString(fl.Field().String())
+}
+
+// IsUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID.
+func isUUID4RFC4122(fl FieldLevel) bool {
+ return uUID4RFC4122Regex.MatchString(fl.Field().String())
+}
+
+// IsUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID.
+func isUUID3RFC4122(fl FieldLevel) bool {
+ return uUID3RFC4122Regex.MatchString(fl.Field().String())
+}
+
+// IsUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version.
+func isUUIDRFC4122(fl FieldLevel) bool {
+ return uUIDRFC4122Regex.MatchString(fl.Field().String())
+}
+
+// IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
+func isISBN(fl FieldLevel) bool {
+ return isISBN10(fl) || isISBN13(fl)
+}
+
+// IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
+func isISBN13(fl FieldLevel) bool {
+
+ s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
+
+ if !iSBN13Regex.MatchString(s) {
+ return false
+ }
+
+ var checksum int32
+ var i int32
+
+ factor := []int32{1, 3}
+
+ for i = 0; i < 12; i++ {
+ checksum += factor[i%2] * int32(s[i]-'0')
+ }
+
+ return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
+}
+
+// IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
+func isISBN10(fl FieldLevel) bool {
+
+ s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
+
+ if !iSBN10Regex.MatchString(s) {
+ return false
+ }
+
+ var checksum int32
+ var i int32
+
+ for i = 0; i < 9; i++ {
+ checksum += (i + 1) * int32(s[i]-'0')
+ }
+
+ if s[9] == 'X' {
+ checksum += 10 * 10
+ } else {
+ checksum += 10 * int32(s[9]-'0')
+ }
+
+ return checksum%11 == 0
+}
+
+// IsEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address.
+func isEthereumAddress(fl FieldLevel) bool {
+ address := fl.Field().String()
+
+ if !ethAddressRegex.MatchString(address) {
+ return false
+ }
+
+ if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) {
+ return true
+ }
+
+ // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
+ address = address[2:] // Skip "0x" prefix.
+ h := sha3.NewLegacyKeccak256()
+ // hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash
+ _, _ = h.Write([]byte(strings.ToLower(address)))
+ hash := hex.EncodeToString(h.Sum(nil))
+
+ for i := 0; i < len(address); i++ {
+ if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case.
+ continue
+ }
+ if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' {
+ return false
+ }
+ }
+
+ return true
+}
+
+// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address
+func isBitcoinAddress(fl FieldLevel) bool {
+ address := fl.Field().String()
+
+ if !btcAddressRegex.MatchString(address) {
+ return false
+ }
+
+ alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
+
+ decode := [25]byte{}
+
+ for _, n := range []byte(address) {
+ d := bytes.IndexByte(alphabet, n)
+
+ for i := 24; i >= 0; i-- {
+ d += 58 * int(decode[i])
+ decode[i] = byte(d % 256)
+ d /= 256
+ }
+ }
+
+ h := sha256.New()
+ _, _ = h.Write(decode[:21])
+ d := h.Sum([]byte{})
+ h = sha256.New()
+ _, _ = h.Write(d)
+
+ validchecksum := [4]byte{}
+ computedchecksum := [4]byte{}
+
+ copy(computedchecksum[:], h.Sum(d[:0]))
+ copy(validchecksum[:], decode[21:])
+
+ return validchecksum == computedchecksum
+}
+
+// IsBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address
+func isBitcoinBech32Address(fl FieldLevel) bool {
+ address := fl.Field().String()
+
+ if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) {
+ return false
+ }
+
+ am := len(address) % 8
+
+ if am == 0 || am == 3 || am == 5 {
+ return false
+ }
+
+ address = strings.ToLower(address)
+
+ alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+
+ hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc
+ addr := address[3:]
+ dp := make([]int, 0, len(addr))
+
+ for _, c := range addr {
+ dp = append(dp, strings.IndexRune(alphabet, c))
+ }
+
+ ver := dp[0]
+
+ if ver < 0 || ver > 16 {
+ return false
+ }
+
+ if ver == 0 {
+ if len(address) != 42 && len(address) != 62 {
+ return false
+ }
+ }
+
+ values := append(hr, dp...)
+
+ GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
+
+ p := 1
+
+ for _, v := range values {
+ b := p >> 25
+ p = (p&0x1ffffff)<<5 ^ v
+
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ p ^= GEN[i]
+ }
+ }
+ }
+
+ if p != 1 {
+ return false
+ }
+
+ b := uint(0)
+ acc := 0
+ mv := (1 << 5) - 1
+ var sw []int
+
+ for _, v := range dp[1 : len(dp)-6] {
+ acc = (acc << 5) | v
+ b += 5
+ for b >= 8 {
+ b -= 8
+ sw = append(sw, (acc>>b)&mv)
+ }
+ }
+
+ if len(sw) < 2 || len(sw) > 40 {
+ return false
+ }
+
+ return true
+}
+
+// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
+func excludesRune(fl FieldLevel) bool {
+ return !containsRune(fl)
+}
+
+// ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
+func excludesAll(fl FieldLevel) bool {
+ return !containsAny(fl)
+}
+
+// Excludes is the validation function for validating that the field's value does not contain the text specified within the param.
+func excludes(fl FieldLevel) bool {
+ return !contains(fl)
+}
+
+// ContainsRune is the validation function for validating that the field's value contains the rune specified within the param.
+func containsRune(fl FieldLevel) bool {
+
+ r, _ := utf8.DecodeRuneInString(fl.Param())
+
+ return strings.ContainsRune(fl.Field().String(), r)
+}
+
+// ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
+func containsAny(fl FieldLevel) bool {
+ return strings.ContainsAny(fl.Field().String(), fl.Param())
+}
+
+// Contains is the validation function for validating that the field's value contains the text specified within the param.
+func contains(fl FieldLevel) bool {
+ return strings.Contains(fl.Field().String(), fl.Param())
+}
+
+// StartsWith is the validation function for validating that the field's value starts with the text specified within the param.
+func startsWith(fl FieldLevel) bool {
+ return strings.HasPrefix(fl.Field().String(), fl.Param())
+}
+
+// EndsWith is the validation function for validating that the field's value ends with the text specified within the param.
+func endsWith(fl FieldLevel) bool {
+ return strings.HasSuffix(fl.Field().String(), fl.Param())
+}
+
+// StartsNotWith is the validation function for validating that the field's value does not start with the text specified within the param.
+func startsNotWith(fl FieldLevel) bool {
+ return !startsWith(fl)
+}
+
+// EndsNotWith is the validation function for validating that the field's value does not end with the text specified within the param.
+func endsNotWith(fl FieldLevel) bool {
+ return !endsWith(fl)
+}
+
+// FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value.
+func fieldContains(fl FieldLevel) bool {
+ field := fl.Field()
+
+ currentField, _, ok := fl.GetStructFieldOK()
+
+ if !ok {
+ return false
+ }
+
+ return strings.Contains(field.String(), currentField.String())
+}
+
+// FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value.
+func fieldExcludes(fl FieldLevel) bool {
+ field := fl.Field()
+
+ currentField, _, ok := fl.GetStructFieldOK()
+ if !ok {
+ return true
+ }
+
+ return !strings.Contains(field.String(), currentField.String())
+}
+
+// IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
+func isNeField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ currentField, currentKind, ok := fl.GetStructFieldOK()
+
+ if !ok || currentKind != kind {
+ return true
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() != currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() != currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() != currentField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) != int64(currentField.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return true
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return !fieldTime.Equal(t)
+ }
+
+ }
+
+ // default reflect.String:
+ return field.String() != currentField.String()
+}
+
+// IsNe is the validation function for validating that the field's value does not equal the provided param value.
+func isNe(fl FieldLevel) bool {
+ return !isEq(fl)
+}
+
+// IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
+func isLteCrossStructField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ topField, topKind, ok := fl.GetStructFieldOK()
+ if !ok || topKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() <= topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() <= topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() <= topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) <= int64(topField.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() <= topField.String()
+}
+
+// IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func isLtCrossStructField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ topField, topKind, ok := fl.GetStructFieldOK()
+ if !ok || topKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() < topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() < topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() < topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) < int64(topField.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.Before(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() < topField.String()
+}
+
+// IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
+func isGteCrossStructField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ topField, topKind, ok := fl.GetStructFieldOK()
+ if !ok || topKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() >= topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() >= topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() >= topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) >= int64(topField.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.After(topTime) || fieldTime.Equal(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() >= topField.String()
+}
+
+// IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
+func isGtCrossStructField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ topField, topKind, ok := fl.GetStructFieldOK()
+ if !ok || topKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() > topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() > topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() > topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) > int64(topField.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.After(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() > topField.String()
+}
+
+// IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
+func isNeCrossStructField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ topField, currentKind, ok := fl.GetStructFieldOK()
+ if !ok || currentKind != kind {
+ return true
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return topField.Int() != field.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return topField.Uint() != field.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return topField.Float() != field.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(topField.Len()) != int64(field.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return true
+ }
+
+ if fieldType == timeType {
+
+ t := field.Interface().(time.Time)
+ fieldTime := topField.Interface().(time.Time)
+
+ return !fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String:
+ return topField.String() != field.String()
+}
+
+// IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
+func isEqCrossStructField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ topField, topKind, ok := fl.GetStructFieldOK()
+ if !ok || topKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return topField.Int() == field.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return topField.Uint() == field.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return topField.Float() == field.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(topField.Len()) == int64(field.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := field.Interface().(time.Time)
+ fieldTime := topField.Interface().(time.Time)
+
+ return fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String:
+ return topField.String() == field.String()
+}
+
+// IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
+func isEqField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ currentField, currentKind, ok := fl.GetStructFieldOK()
+ if !ok || currentKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() == currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() == currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() == currentField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) == int64(currentField.Len())
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.Equal(t)
+ }
+
+ }
+
+ // default reflect.String:
+ return field.String() == currentField.String()
+}
+
+// IsEq is the validation function for validating if the current field's value is equal to the param's value.
+func isEq(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+
+ switch field.Kind() {
+
+ case reflect.String:
+ return field.String() == param
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) == p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asIntFromType(field.Type(), param)
+
+ return field.Int() == p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() == p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() == p
+
+ case reflect.Bool:
+ p := asBool(param)
+
+ return field.Bool() == p
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsBase64 is the validation function for validating if the current field's value is a valid base 64.
+func isBase64(fl FieldLevel) bool {
+ return base64Regex.MatchString(fl.Field().String())
+}
+
+// IsBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string.
+func isBase64URL(fl FieldLevel) bool {
+ return base64URLRegex.MatchString(fl.Field().String())
+}
+
+// IsURI is the validation function for validating if the current field's value is a valid URI.
+func isURI(fl FieldLevel) bool {
+
+ field := fl.Field()
+
+ switch field.Kind() {
+
+ case reflect.String:
+
+ s := field.String()
+
+ // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
+ // emulate browser and strip the '#' suffix prior to validation. see issue-#237
+ if i := strings.Index(s, "#"); i > -1 {
+ s = s[:i]
+ }
+
+ if len(s) == 0 {
+ return false
+ }
+
+ _, err := url.ParseRequestURI(s)
+
+ return err == nil
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsURL is the validation function for validating if the current field's value is a valid URL.
+func isURL(fl FieldLevel) bool {
+
+ field := fl.Field()
+
+ switch field.Kind() {
+
+ case reflect.String:
+
+ var i int
+ s := field.String()
+
+ // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
+ // emulate browser and strip the '#' suffix prior to validation. see issue-#237
+ if i = strings.Index(s, "#"); i > -1 {
+ s = s[:i]
+ }
+
+ if len(s) == 0 {
+ return false
+ }
+
+ url, err := url.ParseRequestURI(s)
+
+ if err != nil || url.Scheme == "" {
+ return false
+ }
+
+ return true
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
+func isUrnRFC2141(fl FieldLevel) bool {
+ field := fl.Field()
+
+ switch field.Kind() {
+
+ case reflect.String:
+
+ str := field.String()
+
+ _, match := urn.Parse([]byte(str))
+
+ return match
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsFile is the validation function for validating if the current field's value is a valid file path.
+func isFile(fl FieldLevel) bool {
+ field := fl.Field()
+
+ switch field.Kind() {
+ case reflect.String:
+ fileInfo, err := os.Stat(field.String())
+ if err != nil {
+ return false
+ }
+
+ return !fileInfo.IsDir()
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number.
+func isE164(fl FieldLevel) bool {
+ return e164Regex.MatchString(fl.Field().String())
+}
+
+// IsEmail is the validation function for validating if the current field's value is a valid email address.
+func isEmail(fl FieldLevel) bool {
+ return emailRegex.MatchString(fl.Field().String())
+}
+
+// IsHSLA is the validation function for validating if the current field's value is a valid HSLA color.
+func isHSLA(fl FieldLevel) bool {
+ return hslaRegex.MatchString(fl.Field().String())
+}
+
+// IsHSL is the validation function for validating if the current field's value is a valid HSL color.
+func isHSL(fl FieldLevel) bool {
+ return hslRegex.MatchString(fl.Field().String())
+}
+
+// IsRGBA is the validation function for validating if the current field's value is a valid RGBA color.
+func isRGBA(fl FieldLevel) bool {
+ return rgbaRegex.MatchString(fl.Field().String())
+}
+
+// IsRGB is the validation function for validating if the current field's value is a valid RGB color.
+func isRGB(fl FieldLevel) bool {
+ return rgbRegex.MatchString(fl.Field().String())
+}
+
+// IsHEXColor is the validation function for validating if the current field's value is a valid HEX color.
+func isHEXColor(fl FieldLevel) bool {
+ return hexcolorRegex.MatchString(fl.Field().String())
+}
+
+// IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
+func isHexadecimal(fl FieldLevel) bool {
+ return hexadecimalRegex.MatchString(fl.Field().String())
+}
+
+// IsNumber is the validation function for validating if the current field's value is a valid number.
+func isNumber(fl FieldLevel) bool {
+ switch fl.Field().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
+ return true
+ default:
+ return numberRegex.MatchString(fl.Field().String())
+ }
+}
+
+// IsNumeric is the validation function for validating if the current field's value is a valid numeric value.
+func isNumeric(fl FieldLevel) bool {
+ switch fl.Field().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
+ return true
+ default:
+ return numericRegex.MatchString(fl.Field().String())
+ }
+}
+
+// IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
+func isAlphanum(fl FieldLevel) bool {
+ return alphaNumericRegex.MatchString(fl.Field().String())
+}
+
+// IsAlpha is the validation function for validating if the current field's value is a valid alpha value.
+func isAlpha(fl FieldLevel) bool {
+ return alphaRegex.MatchString(fl.Field().String())
+}
+
+// IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
+func isAlphanumUnicode(fl FieldLevel) bool {
+ return alphaUnicodeNumericRegex.MatchString(fl.Field().String())
+}
+
+// IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
+func isAlphaUnicode(fl FieldLevel) bool {
+ return alphaUnicodeRegex.MatchString(fl.Field().String())
+}
+
+// isDefault is the opposite of required aka hasValue
+func isDefault(fl FieldLevel) bool {
+ return !hasValue(fl)
+}
+
+// HasValue is the validation function for validating if the current field's value is not the default static value.
+func hasValue(fl FieldLevel) bool {
+ field := fl.Field()
+ switch field.Kind() {
+ case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
+ return !field.IsNil()
+ default:
+ if fl.(*validate).fldIsPointer && field.Interface() != nil {
+ return true
+ }
+ return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
+ }
+}
+
+// requireCheckField is a func for check field kind
+func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
+ field := fl.Field()
+ kind := field.Kind()
+ var nullable, found bool
+ if len(param) > 0 {
+ field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
+ if !found {
+ return defaultNotFoundValue
+ }
+ }
+ switch kind {
+ case reflect.Invalid:
+ return defaultNotFoundValue
+ case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
+ return field.IsNil()
+ default:
+ if nullable && field.Interface() != nil {
+ return false
+ }
+ return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface()
+ }
+}
+
+// requireCheckFieldValue is a func for check field value
+func requireCheckFieldValue(fl FieldLevel, param string, value string, defaultNotFoundValue bool) bool {
+ field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
+ if !found {
+ return defaultNotFoundValue
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() == asInt(value)
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() == asUint(value)
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() == asFloat(value)
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) == asInt(value)
+ }
+
+ // default reflect.String:
+ return field.String() == value
+}
+
+// requiredIf is the validation function
+// The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field.
+func requiredIf(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ if len(params)%2 != 0 {
+ panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName()))
+ }
+ for i := 0; i < len(params); i += 2 {
+ if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
+ return true
+ }
+ }
+ return hasValue(fl)
+}
+
+// requiredUnless is the validation function
+// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
+func requiredUnless(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ if len(params)%2 != 0 {
+ panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName()))
+ }
+
+ for i := 0; i < len(params); i += 2 {
+ if requireCheckFieldValue(fl, params[i], params[i+1], false) {
+ return true
+ }
+ }
+ return hasValue(fl)
+}
+
+// ExcludedWith is the validation function
+// The field under validation must not be present or is empty if any of the other specified fields are present.
+func excludedWith(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ for _, param := range params {
+ if !requireCheckFieldKind(fl, param, true) {
+ return !hasValue(fl)
+ }
+ }
+ return true
+}
+
+// RequiredWith is the validation function
+// The field under validation must be present and not empty only if any of the other specified fields are present.
+func requiredWith(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ for _, param := range params {
+ if !requireCheckFieldKind(fl, param, true) {
+ return hasValue(fl)
+ }
+ }
+ return true
+}
+
+// ExcludedWithAll is the validation function
+// The field under validation must not be present or is empty if all of the other specified fields are present.
+func excludedWithAll(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ for _, param := range params {
+ if requireCheckFieldKind(fl, param, true) {
+ return true
+ }
+ }
+ return !hasValue(fl)
+}
+
+// RequiredWithAll is the validation function
+// The field under validation must be present and not empty only if all of the other specified fields are present.
+func requiredWithAll(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ for _, param := range params {
+ if requireCheckFieldKind(fl, param, true) {
+ return true
+ }
+ }
+ return hasValue(fl)
+}
+
+// ExcludedWithout is the validation function
+// The field under validation must not be present or is empty when any of the other specified fields are not present.
+func excludedWithout(fl FieldLevel) bool {
+ if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
+ return !hasValue(fl)
+ }
+ return true
+}
+
+// RequiredWithout is the validation function
+// The field under validation must be present and not empty only when any of the other specified fields are not present.
+func requiredWithout(fl FieldLevel) bool {
+ if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
+ return hasValue(fl)
+ }
+ return true
+}
+
+// RequiredWithoutAll is the validation function
+// The field under validation must not be present or is empty when all of the other specified fields are not present.
+func excludedWithoutAll(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ for _, param := range params {
+ if !requireCheckFieldKind(fl, param, true) {
+ return true
+ }
+ }
+ return !hasValue(fl)
+}
+
+// RequiredWithoutAll is the validation function
+// The field under validation must be present and not empty only when all of the other specified fields are not present.
+func requiredWithoutAll(fl FieldLevel) bool {
+ params := parseOneOfParam2(fl.Param())
+ for _, param := range params {
+ if !requireCheckFieldKind(fl, param, true) {
+ return true
+ }
+ }
+ return hasValue(fl)
+}
+
+// IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
+func isGteField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ currentField, currentKind, ok := fl.GetStructFieldOK()
+ if !ok || currentKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() >= currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() >= currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() >= currentField.Float()
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.After(t) || fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) >= len(currentField.String())
+}
+
+// IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
+func isGtField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ currentField, currentKind, ok := fl.GetStructFieldOK()
+ if !ok || currentKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() > currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() > currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() > currentField.Float()
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.After(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) > len(currentField.String())
+}
+
+// IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
+func isGte(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+
+ switch field.Kind() {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) >= p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) >= p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asIntFromType(field.Type(), param)
+
+ return field.Int() >= p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() >= p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() >= p
+
+ case reflect.Struct:
+
+ if field.Type() == timeType {
+
+ now := time.Now().UTC()
+ t := field.Interface().(time.Time)
+
+ return t.After(now) || t.Equal(now)
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsGt is the validation function for validating if the current field's value is greater than the param's value.
+func isGt(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+
+ switch field.Kind() {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) > p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) > p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asIntFromType(field.Type(), param)
+
+ return field.Int() > p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() > p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() > p
+ case reflect.Struct:
+
+ if field.Type() == timeType {
+
+ return field.Interface().(time.Time).After(time.Now().UTC())
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// HasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
+func hasLengthOf(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+
+ switch field.Kind() {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) == p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) == p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asIntFromType(field.Type(), param)
+
+ return field.Int() == p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() == p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() == p
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
+func hasMinOf(fl FieldLevel) bool {
+ return isGte(fl)
+}
+
+// IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
+func isLteField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ currentField, currentKind, ok := fl.GetStructFieldOK()
+ if !ok || currentKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() <= currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() <= currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() <= currentField.Float()
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.Before(t) || fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) <= len(currentField.String())
+}
+
+// IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
+func isLtField(fl FieldLevel) bool {
+
+ field := fl.Field()
+ kind := field.Kind()
+
+ currentField, currentKind, ok := fl.GetStructFieldOK()
+ if !ok || currentKind != kind {
+ return false
+ }
+
+ switch kind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() < currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() < currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() < currentField.Float()
+
+ case reflect.Struct:
+
+ fieldType := field.Type()
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.Before(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) < len(currentField.String())
+}
+
+// IsLte is the validation function for validating if the current field's value is less than or equal to the param's value.
+func isLte(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+
+ switch field.Kind() {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) <= p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) <= p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asIntFromType(field.Type(), param)
+
+ return field.Int() <= p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() <= p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() <= p
+
+ case reflect.Struct:
+
+ if field.Type() == timeType {
+
+ now := time.Now().UTC()
+ t := field.Interface().(time.Time)
+
+ return t.Before(now) || t.Equal(now)
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsLt is the validation function for validating if the current field's value is less than the param's value.
+func isLt(fl FieldLevel) bool {
+
+ field := fl.Field()
+ param := fl.Param()
+
+ switch field.Kind() {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) < p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) < p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asIntFromType(field.Type(), param)
+
+ return field.Int() < p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() < p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() < p
+
+ case reflect.Struct:
+
+ if field.Type() == timeType {
+
+ return field.Interface().(time.Time).Before(time.Now().UTC())
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
+func hasMaxOf(fl FieldLevel) bool {
+ return isLte(fl)
+}
+
+// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
+func isTCP4AddrResolvable(fl FieldLevel) bool {
+
+ if !isIP4Addr(fl) {
+ return false
+ }
+
+ _, err := net.ResolveTCPAddr("tcp4", fl.Field().String())
+ return err == nil
+}
+
+// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
+func isTCP6AddrResolvable(fl FieldLevel) bool {
+
+ if !isIP6Addr(fl) {
+ return false
+ }
+
+ _, err := net.ResolveTCPAddr("tcp6", fl.Field().String())
+
+ return err == nil
+}
+
+// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
+func isTCPAddrResolvable(fl FieldLevel) bool {
+
+ if !isIP4Addr(fl) && !isIP6Addr(fl) {
+ return false
+ }
+
+ _, err := net.ResolveTCPAddr("tcp", fl.Field().String())
+
+ return err == nil
+}
+
+// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
+func isUDP4AddrResolvable(fl FieldLevel) bool {
+
+ if !isIP4Addr(fl) {
+ return false
+ }
+
+ _, err := net.ResolveUDPAddr("udp4", fl.Field().String())
+
+ return err == nil
+}
+
+// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
+func isUDP6AddrResolvable(fl FieldLevel) bool {
+
+ if !isIP6Addr(fl) {
+ return false
+ }
+
+ _, err := net.ResolveUDPAddr("udp6", fl.Field().String())
+
+ return err == nil
+}
+
+// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
+func isUDPAddrResolvable(fl FieldLevel) bool {
+
+ if !isIP4Addr(fl) && !isIP6Addr(fl) {
+ return false
+ }
+
+ _, err := net.ResolveUDPAddr("udp", fl.Field().String())
+
+ return err == nil
+}
+
+// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
+func isIP4AddrResolvable(fl FieldLevel) bool {
+
+ if !isIPv4(fl) {
+ return false
+ }
+
+ _, err := net.ResolveIPAddr("ip4", fl.Field().String())
+
+ return err == nil
+}
+
+// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
+func isIP6AddrResolvable(fl FieldLevel) bool {
+
+ if !isIPv6(fl) {
+ return false
+ }
+
+ _, err := net.ResolveIPAddr("ip6", fl.Field().String())
+
+ return err == nil
+}
+
+// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
+func isIPAddrResolvable(fl FieldLevel) bool {
+
+ if !isIP(fl) {
+ return false
+ }
+
+ _, err := net.ResolveIPAddr("ip", fl.Field().String())
+
+ return err == nil
+}
+
+// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
+func isUnixAddrResolvable(fl FieldLevel) bool {
+
+ _, err := net.ResolveUnixAddr("unix", fl.Field().String())
+
+ return err == nil
+}
+
+func isIP4Addr(fl FieldLevel) bool {
+
+ val := fl.Field().String()
+
+ if idx := strings.LastIndex(val, ":"); idx != -1 {
+ val = val[0:idx]
+ }
+
+ ip := net.ParseIP(val)
+
+ return ip != nil && ip.To4() != nil
+}
+
+func isIP6Addr(fl FieldLevel) bool {
+
+ val := fl.Field().String()
+
+ if idx := strings.LastIndex(val, ":"); idx != -1 {
+ if idx != 0 && val[idx-1:idx] == "]" {
+ val = val[1 : idx-1]
+ }
+ }
+
+ ip := net.ParseIP(val)
+
+ return ip != nil && ip.To4() == nil
+}
+
+func isHostnameRFC952(fl FieldLevel) bool {
+ return hostnameRegexRFC952.MatchString(fl.Field().String())
+}
+
+func isHostnameRFC1123(fl FieldLevel) bool {
+ return hostnameRegexRFC1123.MatchString(fl.Field().String())
+}
+
+func isFQDN(fl FieldLevel) bool {
+ val := fl.Field().String()
+
+ if val == "" {
+ return false
+ }
+
+ return fqdnRegexRFC1123.MatchString(val)
+}
+
+// IsDir is the validation function for validating if the current field's value is a valid directory.
+func isDir(fl FieldLevel) bool {
+ field := fl.Field()
+
+ if field.Kind() == reflect.String {
+ fileInfo, err := os.Stat(field.String())
+ if err != nil {
+ return false
+ }
+
+ return fileInfo.IsDir()
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isJSON is the validation function for validating if the current field's value is a valid json string.
+func isJSON(fl FieldLevel) bool {
+ field := fl.Field()
+
+ if field.Kind() == reflect.String {
+ val := field.String()
+ return json.Valid([]byte(val))
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isHostnamePort validates a : combination for fields typically used for socket address.
+func isHostnamePort(fl FieldLevel) bool {
+ val := fl.Field().String()
+ host, port, err := net.SplitHostPort(val)
+ if err != nil {
+ return false
+ }
+ // Port must be a iny <= 65535.
+ if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 {
+ return false
+ }
+
+ // If host is specified, it should match a DNS name
+ if host != "" {
+ return hostnameRegexRFC1123.MatchString(host)
+ }
+ return true
+}
+
+// isLowercase is the validation function for validating if the current field's value is a lowercase string.
+func isLowercase(fl FieldLevel) bool {
+ field := fl.Field()
+
+ if field.Kind() == reflect.String {
+ if field.String() == "" {
+ return false
+ }
+ return field.String() == strings.ToLower(field.String())
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isUppercase is the validation function for validating if the current field's value is an uppercase string.
+func isUppercase(fl FieldLevel) bool {
+ field := fl.Field()
+
+ if field.Kind() == reflect.String {
+ if field.String() == "" {
+ return false
+ }
+ return field.String() == strings.ToUpper(field.String())
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isDatetime is the validation function for validating if the current field's value is a valid datetime string.
+func isDatetime(fl FieldLevel) bool {
+ field := fl.Field()
+ param := fl.Param()
+
+ if field.Kind() == reflect.String {
+ _, err := time.Parse(param, field.String())
+
+ return err == nil
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isTimeZone is the validation function for validating if the current field's value is a valid time zone string.
+func isTimeZone(fl FieldLevel) bool {
+ field := fl.Field()
+
+ if field.Kind() == reflect.String {
+ // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name
+ if field.String() == "" {
+ return false
+ }
+
+ // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name
+ if strings.ToLower(field.String()) == "local" {
+ return false
+ }
+
+ _, err := time.LoadLocation(field.String())
+ return err == nil
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code.
+func isIso3166Alpha2(fl FieldLevel) bool {
+ val := fl.Field().String()
+ return iso3166_1_alpha2[val]
+}
+
+// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code.
+func isIso3166Alpha3(fl FieldLevel) bool {
+ val := fl.Field().String()
+ return iso3166_1_alpha3[val]
+}
+
+// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code.
+func isIso3166AlphaNumeric(fl FieldLevel) bool {
+ field := fl.Field()
+
+ var code int
+ switch field.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ code = int(field.Int() % 1000)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ code = int(field.Uint() % 1000)
+ default:
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+ }
+ return iso3166_1_alpha_numeric[code]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/cache.go
new file mode 100644
index 000000000000..0d18d6ec49ca
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/cache.go
@@ -0,0 +1,322 @@
+package validator
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+ "sync/atomic"
+)
+
+type tagType uint8
+
+const (
+ typeDefault tagType = iota
+ typeOmitEmpty
+ typeIsDefault
+ typeNoStructLevel
+ typeStructOnly
+ typeDive
+ typeOr
+ typeKeys
+ typeEndKeys
+)
+
+const (
+ invalidValidation = "Invalid validation tag on field '%s'"
+ undefinedValidation = "Undefined validation function '%s' on field '%s'"
+ keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag"
+)
+
+type structCache struct {
+ lock sync.Mutex
+ m atomic.Value // map[reflect.Type]*cStruct
+}
+
+func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) {
+ c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key]
+ return
+}
+
+func (sc *structCache) Set(key reflect.Type, value *cStruct) {
+ m := sc.m.Load().(map[reflect.Type]*cStruct)
+ nm := make(map[reflect.Type]*cStruct, len(m)+1)
+ for k, v := range m {
+ nm[k] = v
+ }
+ nm[key] = value
+ sc.m.Store(nm)
+}
+
+type tagCache struct {
+ lock sync.Mutex
+ m atomic.Value // map[string]*cTag
+}
+
+func (tc *tagCache) Get(key string) (c *cTag, found bool) {
+ c, found = tc.m.Load().(map[string]*cTag)[key]
+ return
+}
+
+func (tc *tagCache) Set(key string, value *cTag) {
+ m := tc.m.Load().(map[string]*cTag)
+ nm := make(map[string]*cTag, len(m)+1)
+ for k, v := range m {
+ nm[k] = v
+ }
+ nm[key] = value
+ tc.m.Store(nm)
+}
+
+type cStruct struct {
+ name string
+ fields []*cField
+ fn StructLevelFuncCtx
+}
+
+type cField struct {
+ idx int
+ name string
+ altName string
+ namesEqual bool
+ cTags *cTag
+}
+
+type cTag struct {
+ tag string
+ aliasTag string
+ actualAliasTag string
+ param string
+ keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation
+ next *cTag
+ fn FuncCtx
+ typeof tagType
+ hasTag bool
+ hasAlias bool
+ hasParam bool // true if parameter used eg. eq= where the equal sign has been set
+ isBlockEnd bool // indicates the current tag represents the last validation in the block
+ runValidationWhenNil bool
+}
+
+func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct {
+ v.structCache.lock.Lock()
+ defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise!
+
+ typ := current.Type()
+
+ // could have been multiple trying to access, but once first is done this ensures struct
+ // isn't parsed again.
+ cs, ok := v.structCache.Get(typ)
+ if ok {
+ return cs
+ }
+
+ cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]}
+
+ numFields := current.NumField()
+
+ var ctag *cTag
+ var fld reflect.StructField
+ var tag string
+ var customName string
+
+ for i := 0; i < numFields; i++ {
+
+ fld = typ.Field(i)
+
+ if !fld.Anonymous && len(fld.PkgPath) > 0 {
+ continue
+ }
+
+ tag = fld.Tag.Get(v.tagName)
+
+ if tag == skipValidationTag {
+ continue
+ }
+
+ customName = fld.Name
+
+ if v.hasTagNameFunc {
+ name := v.tagNameFunc(fld)
+ if len(name) > 0 {
+ customName = name
+ }
+ }
+
+ // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different
+ // and so only struct level caching can be used instead of combined with Field tag caching
+
+ if len(tag) > 0 {
+ ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false)
+ } else {
+ // even if field doesn't have validations need cTag for traversing to potential inner/nested
+ // elements of the field.
+ ctag = new(cTag)
+ }
+
+ cs.fields = append(cs.fields, &cField{
+ idx: i,
+ name: fld.Name,
+ altName: customName,
+ cTags: ctag,
+ namesEqual: fld.Name == customName,
+ })
+ }
+ v.structCache.Set(typ, cs)
+ return cs
+}
+
+func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) {
+ var t string
+ noAlias := len(alias) == 0
+ tags := strings.Split(tag, tagSeparator)
+
+ for i := 0; i < len(tags); i++ {
+ t = tags[i]
+ if noAlias {
+ alias = t
+ }
+
+ // check map for alias and process new tags, otherwise process as usual
+ if tagsVal, found := v.aliases[t]; found {
+ if i == 0 {
+ firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
+ } else {
+ next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
+ current.next, current = next, curr
+
+ }
+ continue
+ }
+
+ var prevTag tagType
+
+ if i == 0 {
+ current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault}
+ firstCtag = current
+ } else {
+ prevTag = current.typeof
+ current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true}
+ current = current.next
+ }
+
+ switch t {
+ case diveTag:
+ current.typeof = typeDive
+ continue
+
+ case keysTag:
+ current.typeof = typeKeys
+
+ if i == 0 || prevTag != typeDive {
+ panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag))
+ }
+
+ current.typeof = typeKeys
+
+ // need to pass along only keys tag
+ // need to increment i to skip over the keys tags
+ b := make([]byte, 0, 64)
+
+ i++
+
+ for ; i < len(tags); i++ {
+
+ b = append(b, tags[i]...)
+ b = append(b, ',')
+
+ if tags[i] == endKeysTag {
+ break
+ }
+ }
+
+ current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false)
+ continue
+
+ case endKeysTag:
+ current.typeof = typeEndKeys
+
+ // if there are more in tags then there was no keysTag defined
+ // and an error should be thrown
+ if i != len(tags)-1 {
+ panic(keysTagNotDefined)
+ }
+ return
+
+ case omitempty:
+ current.typeof = typeOmitEmpty
+ continue
+
+ case structOnlyTag:
+ current.typeof = typeStructOnly
+ continue
+
+ case noStructLevelTag:
+ current.typeof = typeNoStructLevel
+ continue
+
+ default:
+ if t == isdefault {
+ current.typeof = typeIsDefault
+ }
+ // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
+ orVals := strings.Split(t, orSeparator)
+
+ for j := 0; j < len(orVals); j++ {
+ vals := strings.SplitN(orVals[j], tagKeySeparator, 2)
+ if noAlias {
+ alias = vals[0]
+ current.aliasTag = alias
+ } else {
+ current.actualAliasTag = t
+ }
+
+ if j > 0 {
+ current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true}
+ current = current.next
+ }
+ current.hasParam = len(vals) > 1
+
+ current.tag = vals[0]
+ if len(current.tag) == 0 {
+ panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName)))
+ }
+
+ if wrapper, ok := v.validations[current.tag]; ok {
+ current.fn = wrapper.fn
+ current.runValidationWhenNil = wrapper.runValidatinOnNil
+ } else {
+ panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName)))
+ }
+
+ if len(orVals) > 1 {
+ current.typeof = typeOr
+ }
+
+ if len(vals) > 1 {
+ current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1)
+ }
+ }
+ current.isBlockEnd = true
+ }
+ }
+ return
+}
+
+func (v *Validate) fetchCacheTag(tag string) *cTag {
+ // find cached tag
+ ctag, found := v.tagCache.Get(tag)
+ if !found {
+ v.tagCache.lock.Lock()
+ defer v.tagCache.lock.Unlock()
+
+ // could have been multiple trying to access, but once first is done this ensures tag
+ // isn't parsed again.
+ ctag, found = v.tagCache.Get(tag)
+ if !found {
+ ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false)
+ v.tagCache.Set(tag, ctag)
+ }
+ }
+ return ctag
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/country_codes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/country_codes.go
new file mode 100644
index 000000000000..ef81eada88f2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/country_codes.go
@@ -0,0 +1,162 @@
+package validator
+
+var iso3166_1_alpha2 = map[string]bool{
+ // see: https://www.iso.org/iso-3166-country-codes.html
+ "AF": true, "AX": true, "AL": true, "DZ": true, "AS": true,
+ "AD": true, "AO": true, "AI": true, "AQ": true, "AG": true,
+ "AR": true, "AM": true, "AW": true, "AU": true, "AT": true,
+ "AZ": true, "BS": true, "BH": true, "BD": true, "BB": true,
+ "BY": true, "BE": true, "BZ": true, "BJ": true, "BM": true,
+ "BT": true, "BO": true, "BQ": true, "BA": true, "BW": true,
+ "BV": true, "BR": true, "IO": true, "BN": true, "BG": true,
+ "BF": true, "BI": true, "KH": true, "CM": true, "CA": true,
+ "CV": true, "KY": true, "CF": true, "TD": true, "CL": true,
+ "CN": true, "CX": true, "CC": true, "CO": true, "KM": true,
+ "CG": true, "CD": true, "CK": true, "CR": true, "CI": true,
+ "HR": true, "CU": true, "CW": true, "CY": true, "CZ": true,
+ "DK": true, "DJ": true, "DM": true, "DO": true, "EC": true,
+ "EG": true, "SV": true, "GQ": true, "ER": true, "EE": true,
+ "ET": true, "FK": true, "FO": true, "FJ": true, "FI": true,
+ "FR": true, "GF": true, "PF": true, "TF": true, "GA": true,
+ "GM": true, "GE": true, "DE": true, "GH": true, "GI": true,
+ "GR": true, "GL": true, "GD": true, "GP": true, "GU": true,
+ "GT": true, "GG": true, "GN": true, "GW": true, "GY": true,
+ "HT": true, "HM": true, "VA": true, "HN": true, "HK": true,
+ "HU": true, "IS": true, "IN": true, "ID": true, "IR": true,
+ "IQ": true, "IE": true, "IM": true, "IL": true, "IT": true,
+ "JM": true, "JP": true, "JE": true, "JO": true, "KZ": true,
+ "KE": true, "KI": true, "KP": true, "KR": true, "KW": true,
+ "KG": true, "LA": true, "LV": true, "LB": true, "LS": true,
+ "LR": true, "LY": true, "LI": true, "LT": true, "LU": true,
+ "MO": true, "MK": true, "MG": true, "MW": true, "MY": true,
+ "MV": true, "ML": true, "MT": true, "MH": true, "MQ": true,
+ "MR": true, "MU": true, "YT": true, "MX": true, "FM": true,
+ "MD": true, "MC": true, "MN": true, "ME": true, "MS": true,
+ "MA": true, "MZ": true, "MM": true, "NA": true, "NR": true,
+ "NP": true, "NL": true, "NC": true, "NZ": true, "NI": true,
+ "NE": true, "NG": true, "NU": true, "NF": true, "MP": true,
+ "NO": true, "OM": true, "PK": true, "PW": true, "PS": true,
+ "PA": true, "PG": true, "PY": true, "PE": true, "PH": true,
+ "PN": true, "PL": true, "PT": true, "PR": true, "QA": true,
+ "RE": true, "RO": true, "RU": true, "RW": true, "BL": true,
+ "SH": true, "KN": true, "LC": true, "MF": true, "PM": true,
+ "VC": true, "WS": true, "SM": true, "ST": true, "SA": true,
+ "SN": true, "RS": true, "SC": true, "SL": true, "SG": true,
+ "SX": true, "SK": true, "SI": true, "SB": true, "SO": true,
+ "ZA": true, "GS": true, "SS": true, "ES": true, "LK": true,
+ "SD": true, "SR": true, "SJ": true, "SZ": true, "SE": true,
+ "CH": true, "SY": true, "TW": true, "TJ": true, "TZ": true,
+ "TH": true, "TL": true, "TG": true, "TK": true, "TO": true,
+ "TT": true, "TN": true, "TR": true, "TM": true, "TC": true,
+ "TV": true, "UG": true, "UA": true, "AE": true, "GB": true,
+ "US": true, "UM": true, "UY": true, "UZ": true, "VU": true,
+ "VE": true, "VN": true, "VG": true, "VI": true, "WF": true,
+ "EH": true, "YE": true, "ZM": true, "ZW": true,
+}
+
+var iso3166_1_alpha3 = map[string]bool{
+ // see: https://www.iso.org/iso-3166-country-codes.html
+ "AFG": true, "ALB": true, "DZA": true, "ASM": true, "AND": true,
+ "AGO": true, "AIA": true, "ATA": true, "ATG": true, "ARG": true,
+ "ARM": true, "ABW": true, "AUS": true, "AUT": true, "AZE": true,
+ "BHS": true, "BHR": true, "BGD": true, "BRB": true, "BLR": true,
+ "BEL": true, "BLZ": true, "BEN": true, "BMU": true, "BTN": true,
+ "BOL": true, "BES": true, "BIH": true, "BWA": true, "BVT": true,
+ "BRA": true, "IOT": true, "BRN": true, "BGR": true, "BFA": true,
+ "BDI": true, "CPV": true, "KHM": true, "CMR": true, "CAN": true,
+ "CYM": true, "CAF": true, "TCD": true, "CHL": true, "CHN": true,
+ "CXR": true, "CCK": true, "COL": true, "COM": true, "COD": true,
+ "COG": true, "COK": true, "CRI": true, "HRV": true, "CUB": true,
+ "CUW": true, "CYP": true, "CZE": true, "CIV": true, "DNK": true,
+ "DJI": true, "DMA": true, "DOM": true, "ECU": true, "EGY": true,
+ "SLV": true, "GNQ": true, "ERI": true, "EST": true, "SWZ": true,
+ "ETH": true, "FLK": true, "FRO": true, "FJI": true, "FIN": true,
+ "FRA": true, "GUF": true, "PYF": true, "ATF": true, "GAB": true,
+ "GMB": true, "GEO": true, "DEU": true, "GHA": true, "GIB": true,
+ "GRC": true, "GRL": true, "GRD": true, "GLP": true, "GUM": true,
+ "GTM": true, "GGY": true, "GIN": true, "GNB": true, "GUY": true,
+ "HTI": true, "HMD": true, "VAT": true, "HND": true, "HKG": true,
+ "HUN": true, "ISL": true, "IND": true, "IDN": true, "IRN": true,
+ "IRQ": true, "IRL": true, "IMN": true, "ISR": true, "ITA": true,
+ "JAM": true, "JPN": true, "JEY": true, "JOR": true, "KAZ": true,
+ "KEN": true, "KIR": true, "PRK": true, "KOR": true, "KWT": true,
+ "KGZ": true, "LAO": true, "LVA": true, "LBN": true, "LSO": true,
+ "LBR": true, "LBY": true, "LIE": true, "LTU": true, "LUX": true,
+ "MAC": true, "MDG": true, "MWI": true, "MYS": true, "MDV": true,
+ "MLI": true, "MLT": true, "MHL": true, "MTQ": true, "MRT": true,
+ "MUS": true, "MYT": true, "MEX": true, "FSM": true, "MDA": true,
+ "MCO": true, "MNG": true, "MNE": true, "MSR": true, "MAR": true,
+ "MOZ": true, "MMR": true, "NAM": true, "NRU": true, "NPL": true,
+ "NLD": true, "NCL": true, "NZL": true, "NIC": true, "NER": true,
+ "NGA": true, "NIU": true, "NFK": true, "MKD": true, "MNP": true,
+ "NOR": true, "OMN": true, "PAK": true, "PLW": true, "PSE": true,
+ "PAN": true, "PNG": true, "PRY": true, "PER": true, "PHL": true,
+ "PCN": true, "POL": true, "PRT": true, "PRI": true, "QAT": true,
+ "ROU": true, "RUS": true, "RWA": true, "REU": true, "BLM": true,
+ "SHN": true, "KNA": true, "LCA": true, "MAF": true, "SPM": true,
+ "VCT": true, "WSM": true, "SMR": true, "STP": true, "SAU": true,
+ "SEN": true, "SRB": true, "SYC": true, "SLE": true, "SGP": true,
+ "SXM": true, "SVK": true, "SVN": true, "SLB": true, "SOM": true,
+ "ZAF": true, "SGS": true, "SSD": true, "ESP": true, "LKA": true,
+ "SDN": true, "SUR": true, "SJM": true, "SWE": true, "CHE": true,
+ "SYR": true, "TWN": true, "TJK": true, "TZA": true, "THA": true,
+ "TLS": true, "TGO": true, "TKL": true, "TON": true, "TTO": true,
+ "TUN": true, "TUR": true, "TKM": true, "TCA": true, "TUV": true,
+ "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true,
+ "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true,
+ "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true,
+ "YEM": true, "ZMB": true, "ZWE": true, "ALA": true,
+}
+var iso3166_1_alpha_numeric = map[int]bool{
+ // see: https://www.iso.org/iso-3166-country-codes.html
+ 4: true, 8: true, 12: true, 16: true, 20: true,
+ 24: true, 660: true, 10: true, 28: true, 32: true,
+ 51: true, 533: true, 36: true, 40: true, 31: true,
+ 44: true, 48: true, 50: true, 52: true, 112: true,
+ 56: true, 84: true, 204: true, 60: true, 64: true,
+ 68: true, 535: true, 70: true, 72: true, 74: true,
+ 76: true, 86: true, 96: true, 100: true, 854: true,
+ 108: true, 132: true, 116: true, 120: true, 124: true,
+ 136: true, 140: true, 148: true, 152: true, 156: true,
+ 162: true, 166: true, 170: true, 174: true, 180: true,
+ 178: true, 184: true, 188: true, 191: true, 192: true,
+ 531: true, 196: true, 203: true, 384: true, 208: true,
+ 262: true, 212: true, 214: true, 218: true, 818: true,
+ 222: true, 226: true, 232: true, 233: true, 748: true,
+ 231: true, 238: true, 234: true, 242: true, 246: true,
+ 250: true, 254: true, 258: true, 260: true, 266: true,
+ 270: true, 268: true, 276: true, 288: true, 292: true,
+ 300: true, 304: true, 308: true, 312: true, 316: true,
+ 320: true, 831: true, 324: true, 624: true, 328: true,
+ 332: true, 334: true, 336: true, 340: true, 344: true,
+ 348: true, 352: true, 356: true, 360: true, 364: true,
+ 368: true, 372: true, 833: true, 376: true, 380: true,
+ 388: true, 392: true, 832: true, 400: true, 398: true,
+ 404: true, 296: true, 408: true, 410: true, 414: true,
+ 417: true, 418: true, 428: true, 422: true, 426: true,
+ 430: true, 434: true, 438: true, 440: true, 442: true,
+ 446: true, 450: true, 454: true, 458: true, 462: true,
+ 466: true, 470: true, 584: true, 474: true, 478: true,
+ 480: true, 175: true, 484: true, 583: true, 498: true,
+ 492: true, 496: true, 499: true, 500: true, 504: true,
+ 508: true, 104: true, 516: true, 520: true, 524: true,
+ 528: true, 540: true, 554: true, 558: true, 562: true,
+ 566: true, 570: true, 574: true, 807: true, 580: true,
+ 578: true, 512: true, 586: true, 585: true, 275: true,
+ 591: true, 598: true, 600: true, 604: true, 608: true,
+ 612: true, 616: true, 620: true, 630: true, 634: true,
+ 642: true, 643: true, 646: true, 638: true, 652: true,
+ 654: true, 659: true, 662: true, 663: true, 666: true,
+ 670: true, 882: true, 674: true, 678: true, 682: true,
+ 686: true, 688: true, 690: true, 694: true, 702: true,
+ 534: true, 703: true, 705: true, 90: true, 706: true,
+ 710: true, 239: true, 728: true, 724: true, 144: true,
+ 729: true, 740: true, 744: true, 752: true, 756: true,
+ 760: true, 158: true, 762: true, 834: true, 764: true,
+ 626: true, 768: true, 772: true, 776: true, 780: true,
+ 788: true, 792: true, 795: true, 796: true, 798: true,
+ 800: true, 804: true, 784: true, 826: true, 581: true,
+ 840: true, 858: true, 860: true, 548: true, 862: true,
+ 704: true, 92: true, 850: true, 876: true, 732: true,
+ 887: true, 894: true, 716: true, 248: true,
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/doc.go
new file mode 100644
index 000000000000..a816c20a418b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/doc.go
@@ -0,0 +1,1308 @@
+/*
+Package validator implements value validations for structs and individual fields
+based on tags.
+
+It can also handle Cross-Field and Cross-Struct validation for nested structs
+and has the ability to dive into arrays and maps of any type.
+
+see more examples https://github.com/go-playground/validator/tree/master/_examples
+
+Validation Functions Return Type error
+
+Doing things this way is actually the way the standard library does, see the
+file.Open method here:
+
+ https://golang.org/pkg/os/#Open.
+
+The authors return type "error" to avoid the issue discussed in the following,
+where err is always != nil:
+
+ http://stackoverflow.com/a/29138676/3158232
+ https://github.com/go-playground/validator/issues/134
+
+Validator only InvalidValidationError for bad validation input, nil or
+ValidationErrors as type error; so, in your code all you need to do is check
+if the error returned is not nil, and if it's not check if error is
+InvalidValidationError ( if necessary, most of the time it isn't ) type cast
+it to type ValidationErrors like so err.(validator.ValidationErrors).
+
+Custom Validation Functions
+
+Custom Validation functions can be added. Example:
+
+ // Structure
+ func customFunc(fl validator.FieldLevel) bool {
+
+ if fl.Field().String() == "invalid" {
+ return false
+ }
+
+ return true
+ }
+
+ validate.RegisterValidation("custom tag name", customFunc)
+ // NOTES: using the same tag name as an existing function
+ // will overwrite the existing one
+
+Cross-Field Validation
+
+Cross-Field Validation can be done via the following tags:
+ - eqfield
+ - nefield
+ - gtfield
+ - gtefield
+ - ltfield
+ - ltefield
+ - eqcsfield
+ - necsfield
+ - gtcsfield
+ - gtecsfield
+ - ltcsfield
+ - ltecsfield
+
+If, however, some custom cross-field validation is required, it can be done
+using a custom validation.
+
+Why not just have cross-fields validation tags (i.e. only eqcsfield and not
+eqfield)?
+
+The reason is efficiency. If you want to check a field within the same struct
+"eqfield" only has to find the field on the same struct (1 level). But, if we
+used "eqcsfield" it could be multiple levels down. Example:
+
+ type Inner struct {
+ StartDate time.Time
+ }
+
+ type Outer struct {
+ InnerStructField *Inner
+ CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"`
+ }
+
+ now := time.Now()
+
+ inner := &Inner{
+ StartDate: now,
+ }
+
+ outer := &Outer{
+ InnerStructField: inner,
+ CreatedAt: now,
+ }
+
+ errs := validate.Struct(outer)
+
+ // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed
+ // into the function
+ // when calling validate.VarWithValue(val, field, tag) val will be
+ // whatever you pass, struct, field...
+ // when calling validate.Field(field, tag) val will be nil
+
+Multiple Validators
+
+Multiple validators on a field will process in the order defined. Example:
+
+ type Test struct {
+ Field `validate:"max=10,min=1"`
+ }
+
+ // max will be checked then min
+
+Bad Validator definitions are not handled by the library. Example:
+
+ type Test struct {
+ Field `validate:"min=10,max=0"`
+ }
+
+ // this definition of min max will never succeed
+
+Using Validator Tags
+
+Baked In Cross-Field validation only compares fields on the same struct.
+If Cross-Field + Cross-Struct validation is needed you should implement your
+own custom validator.
+
+Comma (",") is the default separator of validation tags. If you wish to
+have a comma included within the parameter (i.e. excludesall=,) you will need to
+use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma,
+so the above will become excludesall=0x2C.
+
+ type Test struct {
+ Field `validate:"excludesall=,"` // BAD! Do not include a comma.
+ Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation.
+ }
+
+Pipe ("|") is the 'or' validation tags deparator. If you wish to
+have a pipe included within the parameter i.e. excludesall=| you will need to
+use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe,
+so the above will become excludesall=0x7C
+
+ type Test struct {
+ Field `validate:"excludesall=|"` // BAD! Do not include a a pipe!
+ Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation.
+ }
+
+
+Baked In Validators and Tags
+
+Here is a list of the current built in validators:
+
+
+Skip Field
+
+Tells the validation to skip this struct field; this is particularly
+handy in ignoring embedded structs from being validated. (Usage: -)
+ Usage: -
+
+
+Or Operator
+
+This is the 'or' operator allowing multiple validators to be used and
+accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba
+colors to be accepted. This can also be combined with 'and' for example
+( Usage: omitempty,rgb|rgba)
+
+ Usage: |
+
+StructOnly
+
+When a field that is a nested struct is encountered, and contains this flag
+any validation on the nested struct will be run, but none of the nested
+struct fields will be validated. This is useful if inside of your program
+you know the struct will be valid, but need to verify it has been assigned.
+NOTE: only "required" and "omitempty" can be used on a struct itself.
+
+ Usage: structonly
+
+NoStructLevel
+
+Same as structonly tag except that any struct level validations will not run.
+
+ Usage: nostructlevel
+
+Omit Empty
+
+Allows conditional validation, for example if a field is not set with
+a value (Determined by the "required" validator) then other validation
+such as min or max won't run, but if a value is set validation will run.
+
+ Usage: omitempty
+
+Dive
+
+This tells the validator to dive into a slice, array or map and validate that
+level of the slice, array or map with the validation tags that follow.
+Multidimensional nesting is also supported, each level you wish to dive will
+require another dive tag. dive has some sub-tags, 'keys' & 'endkeys', please see
+the Keys & EndKeys section just below.
+
+ Usage: dive
+
+Example #1
+
+ [][]string with validation tag "gt=0,dive,len=1,dive,required"
+ // gt=0 will be applied to []
+ // len=1 will be applied to []string
+ // required will be applied to string
+
+Example #2
+
+ [][]string with validation tag "gt=0,dive,dive,required"
+ // gt=0 will be applied to []
+ // []string will be spared validation
+ // required will be applied to string
+
+Keys & EndKeys
+
+These are to be used together directly after the dive tag and tells the validator
+that anything between 'keys' and 'endkeys' applies to the keys of a map and not the
+values; think of it like the 'dive' tag, but for map keys instead of values.
+Multidimensional nesting is also supported, each level you wish to validate will
+require another 'keys' and 'endkeys' tag. These tags are only valid for maps.
+
+ Usage: dive,keys,othertagvalidation(s),endkeys,valuevalidationtags
+
+Example #1
+
+ map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required"
+ // gt=0 will be applied to the map itself
+ // eg=1|eq=2 will be applied to the map keys
+ // required will be applied to map values
+
+Example #2
+
+ map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required"
+ // gt=0 will be applied to the map itself
+ // eg=1|eq=2 will be applied to each array element in the the map keys
+ // required will be applied to map values
+
+Required
+
+This validates that the value is not the data types default zero value.
+For numbers ensures value is not zero. For strings ensures value is
+not "". For slices, maps, pointers, interfaces, channels and functions
+ensures the value is not nil.
+
+ Usage: required
+
+Required If
+
+The field under validation must be present and not empty only if all
+the other specified fields are equal to the value following the specified
+field. For strings ensures value is not "". For slices, maps, pointers,
+interfaces, channels and functions ensures the value is not nil.
+
+ Usage: required_if
+
+Examples:
+
+ // require the field if the Field1 is equal to the parameter given:
+ Usage: required_if=Field1 foobar
+
+ // require the field if the Field1 and Field2 is equal to the value respectively:
+ Usage: required_if=Field1 foo Field2 bar
+
+Required Unless
+
+The field under validation must be present and not empty unless all
+the other specified fields are equal to the value following the specified
+field. For strings ensures value is not "". For slices, maps, pointers,
+interfaces, channels and functions ensures the value is not nil.
+
+ Usage: required_unless
+
+Examples:
+
+ // require the field unless the Field1 is equal to the parameter given:
+ Usage: required_unless=Field1 foobar
+
+ // require the field unless the Field1 and Field2 is equal to the value respectively:
+ Usage: required_unless=Field1 foo Field2 bar
+
+Required With
+
+The field under validation must be present and not empty only if any
+of the other specified fields are present. For strings ensures value is
+not "". For slices, maps, pointers, interfaces, channels and functions
+ensures the value is not nil.
+
+ Usage: required_with
+
+Examples:
+
+ // require the field if the Field1 is present:
+ Usage: required_with=Field1
+
+ // require the field if the Field1 or Field2 is present:
+ Usage: required_with=Field1 Field2
+
+Required With All
+
+The field under validation must be present and not empty only if all
+of the other specified fields are present. For strings ensures value is
+not "". For slices, maps, pointers, interfaces, channels and functions
+ensures the value is not nil.
+
+ Usage: required_with_all
+
+Example:
+
+ // require the field if the Field1 and Field2 is present:
+ Usage: required_with_all=Field1 Field2
+
+Required Without
+
+The field under validation must be present and not empty only when any
+of the other specified fields are not present. For strings ensures value is
+not "". For slices, maps, pointers, interfaces, channels and functions
+ensures the value is not nil.
+
+ Usage: required_without
+
+Examples:
+
+ // require the field if the Field1 is not present:
+ Usage: required_without=Field1
+
+ // require the field if the Field1 or Field2 is not present:
+ Usage: required_without=Field1 Field2
+
+Required Without All
+
+The field under validation must be present and not empty only when all
+of the other specified fields are not present. For strings ensures value is
+not "". For slices, maps, pointers, interfaces, channels and functions
+ensures the value is not nil.
+
+ Usage: required_without_all
+
+Example:
+
+ // require the field if the Field1 and Field2 is not present:
+ Usage: required_without_all=Field1 Field2
+
+Is Default
+
+This validates that the value is the default value and is almost the
+opposite of required.
+
+ Usage: isdefault
+
+Length
+
+For numbers, length will ensure that the value is
+equal to the parameter given. For strings, it checks that
+the string length is exactly that number of characters. For slices,
+arrays, and maps, validates the number of items.
+
+Example #1
+
+ Usage: len=10
+
+Example #2 (time.Duration)
+
+For time.Duration, len will ensure that the value is equal to the duration given
+in the parameter.
+
+ Usage: len=1h30m
+
+Maximum
+
+For numbers, max will ensure that the value is
+less than or equal to the parameter given. For strings, it checks
+that the string length is at most that number of characters. For
+slices, arrays, and maps, validates the number of items.
+
+Example #1
+
+ Usage: max=10
+
+Example #2 (time.Duration)
+
+For time.Duration, max will ensure that the value is less than or equal to the
+duration given in the parameter.
+
+ Usage: max=1h30m
+
+Minimum
+
+For numbers, min will ensure that the value is
+greater or equal to the parameter given. For strings, it checks that
+the string length is at least that number of characters. For slices,
+arrays, and maps, validates the number of items.
+
+Example #1
+
+ Usage: min=10
+
+Example #2 (time.Duration)
+
+For time.Duration, min will ensure that the value is greater than or equal to
+the duration given in the parameter.
+
+ Usage: min=1h30m
+
+Equals
+
+For strings & numbers, eq will ensure that the value is
+equal to the parameter given. For slices, arrays, and maps,
+validates the number of items.
+
+Example #1
+
+ Usage: eq=10
+
+Example #2 (time.Duration)
+
+For time.Duration, eq will ensure that the value is equal to the duration given
+in the parameter.
+
+ Usage: eq=1h30m
+
+Not Equal
+
+For strings & numbers, ne will ensure that the value is not
+equal to the parameter given. For slices, arrays, and maps,
+validates the number of items.
+
+Example #1
+
+ Usage: ne=10
+
+Example #2 (time.Duration)
+
+For time.Duration, ne will ensure that the value is not equal to the duration
+given in the parameter.
+
+ Usage: ne=1h30m
+
+One Of
+
+For strings, ints, and uints, oneof will ensure that the value
+is one of the values in the parameter. The parameter should be
+a list of values separated by whitespace. Values may be
+strings or numbers. To match strings with spaces in them, include
+the target string between single quotes.
+
+ Usage: oneof=red green
+ oneof='red green' 'blue yellow'
+ oneof=5 7 9
+
+Greater Than
+
+For numbers, this will ensure that the value is greater than the
+parameter given. For strings, it checks that the string length
+is greater than that number of characters. For slices, arrays
+and maps it validates the number of items.
+
+Example #1
+
+ Usage: gt=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is greater than time.Now.UTC().
+
+ Usage: gt
+
+Example #3 (time.Duration)
+
+For time.Duration, gt will ensure that the value is greater than the duration
+given in the parameter.
+
+ Usage: gt=1h30m
+
+Greater Than or Equal
+
+Same as 'min' above. Kept both to make terminology with 'len' easier.
+
+Example #1
+
+ Usage: gte=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is greater than or equal to time.Now.UTC().
+
+ Usage: gte
+
+Example #3 (time.Duration)
+
+For time.Duration, gte will ensure that the value is greater than or equal to
+the duration given in the parameter.
+
+ Usage: gte=1h30m
+
+Less Than
+
+For numbers, this will ensure that the value is less than the parameter given.
+For strings, it checks that the string length is less than that number of
+characters. For slices, arrays, and maps it validates the number of items.
+
+Example #1
+
+ Usage: lt=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is less than time.Now.UTC().
+
+ Usage: lt
+
+Example #3 (time.Duration)
+
+For time.Duration, lt will ensure that the value is less than the duration given
+in the parameter.
+
+ Usage: lt=1h30m
+
+Less Than or Equal
+
+Same as 'max' above. Kept both to make terminology with 'len' easier.
+
+Example #1
+
+ Usage: lte=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is less than or equal to time.Now.UTC().
+
+ Usage: lte
+
+Example #3 (time.Duration)
+
+For time.Duration, lte will ensure that the value is less than or equal to the
+duration given in the parameter.
+
+ Usage: lte=1h30m
+
+Field Equals Another Field
+
+This will validate the field value against another fields value either within
+a struct or passed in field.
+
+Example #1:
+
+ // Validation on Password field using:
+ Usage: eqfield=ConfirmPassword
+
+Example #2:
+
+ // Validating by field:
+ validate.VarWithValue(password, confirmpassword, "eqfield")
+
+Field Equals Another Field (relative)
+
+This does the same as eqfield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: eqcsfield=InnerStructField.Field)
+
+Field Does Not Equal Another Field
+
+This will validate the field value against another fields value either within
+a struct or passed in field.
+
+Examples:
+
+ // Confirm two colors are not the same:
+ //
+ // Validation on Color field:
+ Usage: nefield=Color2
+
+ // Validating by field:
+ validate.VarWithValue(color1, color2, "nefield")
+
+Field Does Not Equal Another Field (relative)
+
+This does the same as nefield except that it validates the field provided
+relative to the top level struct.
+
+ Usage: necsfield=InnerStructField.Field
+
+Field Greater Than Another Field
+
+Only valid for Numbers, time.Duration and time.Time types, this will validate
+the field value against another fields value either within a struct or passed in
+field. usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(gtfield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.VarWithValue(start, end, "gtfield")
+
+Field Greater Than Another Relative Field
+
+This does the same as gtfield except that it validates the field provided
+relative to the top level struct.
+
+ Usage: gtcsfield=InnerStructField.Field
+
+Field Greater Than or Equal To Another Field
+
+Only valid for Numbers, time.Duration and time.Time types, this will validate
+the field value against another fields value either within a struct or passed in
+field. usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(gtefield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.VarWithValue(start, end, "gtefield")
+
+Field Greater Than or Equal To Another Relative Field
+
+This does the same as gtefield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: gtecsfield=InnerStructField.Field
+
+Less Than Another Field
+
+Only valid for Numbers, time.Duration and time.Time types, this will validate
+the field value against another fields value either within a struct or passed in
+field. usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(ltfield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.VarWithValue(start, end, "ltfield")
+
+Less Than Another Relative Field
+
+This does the same as ltfield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: ltcsfield=InnerStructField.Field
+
+Less Than or Equal To Another Field
+
+Only valid for Numbers, time.Duration and time.Time types, this will validate
+the field value against another fields value either within a struct or passed in
+field. usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(ltefield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.VarWithValue(start, end, "ltefield")
+
+Less Than or Equal To Another Relative Field
+
+This does the same as ltefield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: ltecsfield=InnerStructField.Field
+
+Field Contains Another Field
+
+This does the same as contains except for struct fields. It should only be used
+with string types. See the behavior of reflect.Value.String() for behavior on
+other types.
+
+ Usage: containsfield=InnerStructField.Field
+
+Field Excludes Another Field
+
+This does the same as excludes except for struct fields. It should only be used
+with string types. See the behavior of reflect.Value.String() for behavior on
+other types.
+
+ Usage: excludesfield=InnerStructField.Field
+
+Unique
+
+For arrays & slices, unique will ensure that there are no duplicates.
+For maps, unique will ensure that there are no duplicate values.
+For slices of struct, unique will ensure that there are no duplicate values
+in a field of the struct specified via a parameter.
+
+ // For arrays, slices, and maps:
+ Usage: unique
+
+ // For slices of struct:
+ Usage: unique=field
+
+Alpha Only
+
+This validates that a string value contains ASCII alpha characters only
+
+ Usage: alpha
+
+Alphanumeric
+
+This validates that a string value contains ASCII alphanumeric characters only
+
+ Usage: alphanum
+
+Alpha Unicode
+
+This validates that a string value contains unicode alpha characters only
+
+ Usage: alphaunicode
+
+Alphanumeric Unicode
+
+This validates that a string value contains unicode alphanumeric characters only
+
+ Usage: alphanumunicode
+
+Number
+
+This validates that a string value contains number values only.
+For integers or float it returns true.
+
+ Usage: number
+
+Numeric
+
+This validates that a string value contains a basic numeric value.
+basic excludes exponents etc...
+for integers or float it returns true.
+
+ Usage: numeric
+
+Hexadecimal String
+
+This validates that a string value contains a valid hexadecimal.
+
+ Usage: hexadecimal
+
+Hexcolor String
+
+This validates that a string value contains a valid hex color including
+hashtag (#)
+
+ Usage: hexcolor
+
+Lowercase String
+
+This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string.
+
+ Usage: lowercase
+
+Uppercase String
+
+This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string.
+
+ Usage: uppercase
+
+RGB String
+
+This validates that a string value contains a valid rgb color
+
+ Usage: rgb
+
+RGBA String
+
+This validates that a string value contains a valid rgba color
+
+ Usage: rgba
+
+HSL String
+
+This validates that a string value contains a valid hsl color
+
+ Usage: hsl
+
+HSLA String
+
+This validates that a string value contains a valid hsla color
+
+ Usage: hsla
+
+E.164 Phone Number String
+
+This validates that a string value contains a valid E.164 Phone number
+https://en.wikipedia.org/wiki/E.164 (ex. +1123456789)
+
+ Usage: e164
+
+E-mail String
+
+This validates that a string value contains a valid email
+This may not conform to all possibilities of any rfc standard, but neither
+does any email provider accept all possibilities.
+
+ Usage: email
+
+JSON String
+
+This validates that a string value is valid JSON
+
+ Usage: json
+
+File path
+
+This validates that a string value contains a valid file path and that
+the file exists on the machine.
+This is done using os.Stat, which is a platform independent function.
+
+ Usage: file
+
+URL String
+
+This validates that a string value contains a valid url
+This will accept any url the golang request uri accepts but must contain
+a schema for example http:// or rtmp://
+
+ Usage: url
+
+URI String
+
+This validates that a string value contains a valid uri
+This will accept any uri the golang request uri accepts
+
+ Usage: uri
+
+Urn RFC 2141 String
+
+This validataes that a string value contains a valid URN
+according to the RFC 2141 spec.
+
+ Usage: urn_rfc2141
+
+Base64 String
+
+This validates that a string value contains a valid base64 value.
+Although an empty string is valid base64 this will report an empty string
+as an error, if you wish to accept an empty string as valid you can use
+this with the omitempty tag.
+
+ Usage: base64
+
+Base64URL String
+
+This validates that a string value contains a valid base64 URL safe value
+according the the RFC4648 spec.
+Although an empty string is a valid base64 URL safe value, this will report
+an empty string as an error, if you wish to accept an empty string as valid
+you can use this with the omitempty tag.
+
+ Usage: base64url
+
+Bitcoin Address
+
+This validates that a string value contains a valid bitcoin address.
+The format of the string is checked to ensure it matches one of the three formats
+P2PKH, P2SH and performs checksum validation.
+
+ Usage: btc_addr
+
+Bitcoin Bech32 Address (segwit)
+
+This validates that a string value contains a valid bitcoin Bech32 address as defined
+by bip-0173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)
+Special thanks to Pieter Wuille for providng reference implementations.
+
+ Usage: btc_addr_bech32
+
+Ethereum Address
+
+This validates that a string value contains a valid ethereum address.
+The format of the string is checked to ensure it matches the standard Ethereum address format.
+
+ Usage: eth_addr
+
+Contains
+
+This validates that a string value contains the substring value.
+
+ Usage: contains=@
+
+Contains Any
+
+This validates that a string value contains any Unicode code points
+in the substring value.
+
+ Usage: containsany=!@#?
+
+Contains Rune
+
+This validates that a string value contains the supplied rune value.
+
+ Usage: containsrune=@
+
+Excludes
+
+This validates that a string value does not contain the substring value.
+
+ Usage: excludes=@
+
+Excludes All
+
+This validates that a string value does not contain any Unicode code
+points in the substring value.
+
+ Usage: excludesall=!@#?
+
+Excludes Rune
+
+This validates that a string value does not contain the supplied rune value.
+
+ Usage: excludesrune=@
+
+Starts With
+
+This validates that a string value starts with the supplied string value
+
+ Usage: startswith=hello
+
+Ends With
+
+This validates that a string value ends with the supplied string value
+
+ Usage: endswith=goodbye
+
+Does Not Start With
+
+This validates that a string value does not start with the supplied string value
+
+ Usage: startsnotwith=hello
+
+Does Not End With
+
+This validates that a string value does not end with the supplied string value
+
+ Usage: endsnotwith=goodbye
+
+International Standard Book Number
+
+This validates that a string value contains a valid isbn10 or isbn13 value.
+
+ Usage: isbn
+
+International Standard Book Number 10
+
+This validates that a string value contains a valid isbn10 value.
+
+ Usage: isbn10
+
+International Standard Book Number 13
+
+This validates that a string value contains a valid isbn13 value.
+
+ Usage: isbn13
+
+Universally Unique Identifier UUID
+
+This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead.
+
+ Usage: uuid
+
+Universally Unique Identifier UUID v3
+
+This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead.
+
+ Usage: uuid3
+
+Universally Unique Identifier UUID v4
+
+This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead.
+
+ Usage: uuid4
+
+Universally Unique Identifier UUID v5
+
+This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead.
+
+ Usage: uuid5
+
+ASCII
+
+This validates that a string value contains only ASCII characters.
+NOTE: if the string is blank, this validates as true.
+
+ Usage: ascii
+
+Printable ASCII
+
+This validates that a string value contains only printable ASCII characters.
+NOTE: if the string is blank, this validates as true.
+
+ Usage: printascii
+
+Multi-Byte Characters
+
+This validates that a string value contains one or more multibyte characters.
+NOTE: if the string is blank, this validates as true.
+
+ Usage: multibyte
+
+Data URL
+
+This validates that a string value contains a valid DataURI.
+NOTE: this will also validate that the data portion is valid base64
+
+ Usage: datauri
+
+Latitude
+
+This validates that a string value contains a valid latitude.
+
+ Usage: latitude
+
+Longitude
+
+This validates that a string value contains a valid longitude.
+
+ Usage: longitude
+
+Social Security Number SSN
+
+This validates that a string value contains a valid U.S. Social Security Number.
+
+ Usage: ssn
+
+Internet Protocol Address IP
+
+This validates that a string value contains a valid IP Address.
+
+ Usage: ip
+
+Internet Protocol Address IPv4
+
+This validates that a string value contains a valid v4 IP Address.
+
+ Usage: ipv4
+
+Internet Protocol Address IPv6
+
+This validates that a string value contains a valid v6 IP Address.
+
+ Usage: ipv6
+
+Classless Inter-Domain Routing CIDR
+
+This validates that a string value contains a valid CIDR Address.
+
+ Usage: cidr
+
+Classless Inter-Domain Routing CIDRv4
+
+This validates that a string value contains a valid v4 CIDR Address.
+
+ Usage: cidrv4
+
+Classless Inter-Domain Routing CIDRv6
+
+This validates that a string value contains a valid v6 CIDR Address.
+
+ Usage: cidrv6
+
+Transmission Control Protocol Address TCP
+
+This validates that a string value contains a valid resolvable TCP Address.
+
+ Usage: tcp_addr
+
+Transmission Control Protocol Address TCPv4
+
+This validates that a string value contains a valid resolvable v4 TCP Address.
+
+ Usage: tcp4_addr
+
+Transmission Control Protocol Address TCPv6
+
+This validates that a string value contains a valid resolvable v6 TCP Address.
+
+ Usage: tcp6_addr
+
+User Datagram Protocol Address UDP
+
+This validates that a string value contains a valid resolvable UDP Address.
+
+ Usage: udp_addr
+
+User Datagram Protocol Address UDPv4
+
+This validates that a string value contains a valid resolvable v4 UDP Address.
+
+ Usage: udp4_addr
+
+User Datagram Protocol Address UDPv6
+
+This validates that a string value contains a valid resolvable v6 UDP Address.
+
+ Usage: udp6_addr
+
+Internet Protocol Address IP
+
+This validates that a string value contains a valid resolvable IP Address.
+
+ Usage: ip_addr
+
+Internet Protocol Address IPv4
+
+This validates that a string value contains a valid resolvable v4 IP Address.
+
+ Usage: ip4_addr
+
+Internet Protocol Address IPv6
+
+This validates that a string value contains a valid resolvable v6 IP Address.
+
+ Usage: ip6_addr
+
+Unix domain socket end point Address
+
+This validates that a string value contains a valid Unix Address.
+
+ Usage: unix_addr
+
+Media Access Control Address MAC
+
+This validates that a string value contains a valid MAC Address.
+
+ Usage: mac
+
+Note: See Go's ParseMAC for accepted formats and types:
+
+ http://golang.org/src/net/mac.go?s=866:918#L29
+
+Hostname RFC 952
+
+This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952
+
+ Usage: hostname
+
+Hostname RFC 1123
+
+This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123
+
+ Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias.
+
+Full Qualified Domain Name (FQDN)
+
+This validates that a string value contains a valid FQDN.
+
+ Usage: fqdn
+
+HTML Tags
+
+This validates that a string value appears to be an HTML element tag
+including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element
+
+ Usage: html
+
+HTML Encoded
+
+This validates that a string value is a proper character reference in decimal
+or hexadecimal format
+
+ Usage: html_encoded
+
+URL Encoded
+
+This validates that a string value is percent-encoded (URL encoded) according
+to https://tools.ietf.org/html/rfc3986#section-2.1
+
+ Usage: url_encoded
+
+Directory
+
+This validates that a string value contains a valid directory and that
+it exists on the machine.
+This is done using os.Stat, which is a platform independent function.
+
+ Usage: dir
+
+HostPort
+
+This validates that a string value contains a valid DNS hostname and port that
+can be used to valiate fields typically passed to sockets and connections.
+
+ Usage: hostname_port
+
+Datetime
+
+This validates that a string value is a valid datetime based on the supplied datetime format.
+Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/
+
+ Usage: datetime=2006-01-02
+
+Iso3166-1 alpha-2
+
+This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard.
+see: https://www.iso.org/iso-3166-country-codes.html
+
+ Usage: iso3166_1_alpha2
+
+Iso3166-1 alpha-3
+
+This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard.
+see: https://www.iso.org/iso-3166-country-codes.html
+
+ Usage: iso3166_1_alpha3
+
+Iso3166-1 alpha-numeric
+
+This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard.
+see: https://www.iso.org/iso-3166-country-codes.html
+
+ Usage: iso3166_1_alpha3
+
+TimeZone
+
+This validates that a string value is a valid time zone based on the time zone database present on the system.
+Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator.
+More information on https://golang.org/pkg/time/#LoadLocation
+
+ Usage: timezone
+
+
+Alias Validators and Tags
+
+NOTE: When returning an error, the tag returned in "FieldError" will be
+the alias tag unless the dive tag is part of the alias. Everything after the
+dive tag is not reported as the alias tag. Also, the "ActualTag" in the before
+case will be the actual tag within the alias that failed.
+
+Here is a list of the current built in alias tags:
+
+ "iscolor"
+ alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor)
+ "country_code"
+ alias is "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric" (Usage: country_code)
+
+Validator notes:
+
+ regex
+ a regex validator won't be added because commas and = signs can be part
+ of a regex which conflict with the validation definitions. Although
+ workarounds can be made, they take away from using pure regex's.
+ Furthermore it's quick and dirty but the regex's become harder to
+ maintain and are not reusable, so it's as much a programming philosophy
+ as anything.
+
+ In place of this new validator functions should be created; a regex can
+ be used within the validator function and even be precompiled for better
+ efficiency within regexes.go.
+
+ And the best reason, you can submit a pull request and we can keep on
+ adding to the validation library of this package!
+
+Non standard validators
+
+A collection of validation rules that are frequently needed but are more
+complex than the ones found in the baked in validators.
+A non standard validator must be registered manually like you would
+with your own custom validation functions.
+
+Example of registration and use:
+
+ type Test struct {
+ TestField string `validate:"yourtag"`
+ }
+
+ t := &Test{
+ TestField: "Test"
+ }
+
+ validate := validator.New()
+ validate.RegisterValidation("yourtag", validators.NotBlank)
+
+Here is a list of the current non standard validators:
+
+ NotBlank
+ This validates that the value is not blank or with length zero.
+ For strings ensures they do not contain only spaces. For channels, maps, slices and arrays
+ ensures they don't have zero length. For others, a non empty value is required.
+
+ Usage: notblank
+
+Panics
+
+This package panics when bad input is provided, this is by design, bad code like
+that should not make it to production.
+
+ type Test struct {
+ TestField string `validate:"nonexistantfunction=1"`
+ }
+
+ t := &Test{
+ TestField: "Test"
+ }
+
+ validate.Struct(t) // this will panic
+*/
+package validator
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/errors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/errors.go
new file mode 100644
index 000000000000..63293cf9edcb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/errors.go
@@ -0,0 +1,275 @@
+package validator
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strings"
+
+ ut "github.com/go-playground/universal-translator"
+)
+
+const (
+ fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"
+)
+
+// ValidationErrorsTranslations is the translation return type
+type ValidationErrorsTranslations map[string]string
+
+// InvalidValidationError describes an invalid argument passed to
+// `Struct`, `StructExcept`, StructPartial` or `Field`
+type InvalidValidationError struct {
+ Type reflect.Type
+}
+
+// Error returns InvalidValidationError message
+func (e *InvalidValidationError) Error() string {
+
+ if e.Type == nil {
+ return "validator: (nil)"
+ }
+
+ return "validator: (nil " + e.Type.String() + ")"
+}
+
+// ValidationErrors is an array of FieldError's
+// for use in custom error messages post validation.
+type ValidationErrors []FieldError
+
+// Error is intended for use in development + debugging and not intended to be a production error message.
+// It allows ValidationErrors to subscribe to the Error interface.
+// All information to create an error message specific to your application is contained within
+// the FieldError found within the ValidationErrors array
+func (ve ValidationErrors) Error() string {
+
+ buff := bytes.NewBufferString("")
+
+ var fe *fieldError
+
+ for i := 0; i < len(ve); i++ {
+
+ fe = ve[i].(*fieldError)
+ buff.WriteString(fe.Error())
+ buff.WriteString("\n")
+ }
+
+ return strings.TrimSpace(buff.String())
+}
+
+// Translate translates all of the ValidationErrors
+func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations {
+
+ trans := make(ValidationErrorsTranslations)
+
+ var fe *fieldError
+
+ for i := 0; i < len(ve); i++ {
+ fe = ve[i].(*fieldError)
+
+ // // in case an Anonymous struct was used, ensure that the key
+ // // would be 'Username' instead of ".Username"
+ // if len(fe.ns) > 0 && fe.ns[:1] == "." {
+ // trans[fe.ns[1:]] = fe.Translate(ut)
+ // continue
+ // }
+
+ trans[fe.ns] = fe.Translate(ut)
+ }
+
+ return trans
+}
+
+// FieldError contains all functions to get error details
+type FieldError interface {
+
+ // returns the validation tag that failed. if the
+ // validation was an alias, this will return the
+ // alias name and not the underlying tag that failed.
+ //
+ // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla"
+ // will return "iscolor"
+ Tag() string
+
+ // returns the validation tag that failed, even if an
+ // alias the actual tag within the alias will be returned.
+ // If an 'or' validation fails the entire or will be returned.
+ //
+ // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla"
+ // will return "hexcolor|rgb|rgba|hsl|hsla"
+ ActualTag() string
+
+ // returns the namespace for the field error, with the tag
+ // name taking precedence over the field's actual name.
+ //
+ // eg. JSON name "User.fname"
+ //
+ // See StructNamespace() for a version that returns actual names.
+ //
+ // NOTE: this field can be blank when validating a single primitive field
+ // using validate.Field(...) as there is no way to extract it's name
+ Namespace() string
+
+ // returns the namespace for the field error, with the field's
+ // actual name.
+ //
+ // eq. "User.FirstName" see Namespace for comparison
+ //
+ // NOTE: this field can be blank when validating a single primitive field
+ // using validate.Field(...) as there is no way to extract its name
+ StructNamespace() string
+
+ // returns the fields name with the tag name taking precedence over the
+ // field's actual name.
+ //
+ // eq. JSON name "fname"
+ // see StructField for comparison
+ Field() string
+
+ // returns the field's actual name from the struct, when able to determine.
+ //
+ // eq. "FirstName"
+ // see Field for comparison
+ StructField() string
+
+ // returns the actual field's value in case needed for creating the error
+ // message
+ Value() interface{}
+
+ // returns the param value, in string form for comparison; this will also
+ // help with generating an error message
+ Param() string
+
+ // Kind returns the Field's reflect Kind
+ //
+ // eg. time.Time's kind is a struct
+ Kind() reflect.Kind
+
+ // Type returns the Field's reflect Type
+ //
+ // // eg. time.Time's type is time.Time
+ Type() reflect.Type
+
+ // returns the FieldError's translated error
+ // from the provided 'ut.Translator' and registered 'TranslationFunc'
+ //
+ // NOTE: if no registered translator can be found it returns the same as
+ // calling fe.Error()
+ Translate(ut ut.Translator) string
+
+ // Error returns the FieldError's message
+ Error() string
+}
+
+// compile time interface checks
+var _ FieldError = new(fieldError)
+var _ error = new(fieldError)
+
+// fieldError contains a single field's validation error along
+// with other properties that may be needed for error message creation
+// it complies with the FieldError interface
+type fieldError struct {
+ v *Validate
+ tag string
+ actualTag string
+ ns string
+ structNs string
+ fieldLen uint8
+ structfieldLen uint8
+ value interface{}
+ param string
+ kind reflect.Kind
+ typ reflect.Type
+}
+
+// Tag returns the validation tag that failed.
+func (fe *fieldError) Tag() string {
+ return fe.tag
+}
+
+// ActualTag returns the validation tag that failed, even if an
+// alias the actual tag within the alias will be returned.
+func (fe *fieldError) ActualTag() string {
+ return fe.actualTag
+}
+
+// Namespace returns the namespace for the field error, with the tag
+// name taking precedence over the field's actual name.
+func (fe *fieldError) Namespace() string {
+ return fe.ns
+}
+
+// StructNamespace returns the namespace for the field error, with the field's
+// actual name.
+func (fe *fieldError) StructNamespace() string {
+ return fe.structNs
+}
+
+// Field returns the field's name with the tag name taking precedence over the
+// field's actual name.
+func (fe *fieldError) Field() string {
+
+ return fe.ns[len(fe.ns)-int(fe.fieldLen):]
+ // // return fe.field
+ // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):]
+
+ // log.Println("FLD:", fld)
+
+ // if len(fld) > 0 && fld[:1] == "." {
+ // return fld[1:]
+ // }
+
+ // return fld
+}
+
+// returns the field's actual name from the struct, when able to determine.
+func (fe *fieldError) StructField() string {
+ // return fe.structField
+ return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):]
+}
+
+// Value returns the actual field's value in case needed for creating the error
+// message
+func (fe *fieldError) Value() interface{} {
+ return fe.value
+}
+
+// Param returns the param value, in string form for comparison; this will
+// also help with generating an error message
+func (fe *fieldError) Param() string {
+ return fe.param
+}
+
+// Kind returns the Field's reflect Kind
+func (fe *fieldError) Kind() reflect.Kind {
+ return fe.kind
+}
+
+// Type returns the Field's reflect Type
+func (fe *fieldError) Type() reflect.Type {
+ return fe.typ
+}
+
+// Error returns the fieldError's error message
+func (fe *fieldError) Error() string {
+ return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag)
+}
+
+// Translate returns the FieldError's translated error
+// from the provided 'ut.Translator' and registered 'TranslationFunc'
+//
+// NOTE: if no registered translation can be found, it returns the original
+// untranslated error message.
+func (fe *fieldError) Translate(ut ut.Translator) string {
+
+ m, ok := fe.v.transTagFunc[ut]
+ if !ok {
+ return fe.Error()
+ }
+
+ fn, ok := m[fe.tag]
+ if !ok {
+ return fe.Error()
+ }
+
+ return fn(ut, fe)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/field_level.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/field_level.go
new file mode 100644
index 000000000000..f0e2a9a855e0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/field_level.go
@@ -0,0 +1,119 @@
+package validator
+
+import "reflect"
+
+// FieldLevel contains all the information and helper functions
+// to validate a field
+type FieldLevel interface {
+ // returns the top level struct, if any
+ Top() reflect.Value
+
+ // returns the current fields parent struct, if any or
+ // the comparison value if called 'VarWithValue'
+ Parent() reflect.Value
+
+ // returns current field for validation
+ Field() reflect.Value
+
+ // returns the field's name with the tag
+ // name taking precedence over the fields actual name.
+ FieldName() string
+
+ // returns the struct field's name
+ StructFieldName() string
+
+ // returns param for validation against current field
+ Param() string
+
+ // GetTag returns the current validations tag name
+ GetTag() string
+
+ // ExtractType gets the actual underlying type of field value.
+ // It will dive into pointers, customTypes and return you the
+ // underlying value and it's kind.
+ ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool)
+
+ // traverses the parent struct to retrieve a specific field denoted by the provided namespace
+ // in the param and returns the field, field kind and whether is was successful in retrieving
+ // the field at all.
+ //
+ // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
+ // could not be retrieved because it didn't exist.
+ //
+ // Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable.
+ GetStructFieldOK() (reflect.Value, reflect.Kind, bool)
+
+ // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
+ // the field and namespace allowing more extensibility for validators.
+ //
+ // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
+ GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool)
+
+ // traverses the parent struct to retrieve a specific field denoted by the provided namespace
+ // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving
+ // the field at all.
+ //
+ // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
+ // could not be retrieved because it didn't exist.
+ GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool)
+
+ // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
+ // the field and namespace allowing more extensibility for validators.
+ GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool)
+}
+
+var _ FieldLevel = new(validate)
+
+// Field returns current field for validation
+func (v *validate) Field() reflect.Value {
+ return v.flField
+}
+
+// FieldName returns the field's name with the tag
+// name taking precedence over the fields actual name.
+func (v *validate) FieldName() string {
+ return v.cf.altName
+}
+
+// GetTag returns the current validations tag name
+func (v *validate) GetTag() string {
+ return v.ct.tag
+}
+
+// StructFieldName returns the struct field's name
+func (v *validate) StructFieldName() string {
+ return v.cf.name
+}
+
+// Param returns param for validation against current field
+func (v *validate) Param() string {
+ return v.ct.param
+}
+
+// GetStructFieldOK returns Param returns param for validation against current field
+//
+// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable.
+func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) {
+ current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param)
+ return current, kind, found
+}
+
+// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
+// the field and namespace allowing more extensibility for validators.
+//
+// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
+func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) {
+ current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace)
+ return current, kind, found
+}
+
+// GetStructFieldOK returns Param returns param for validation against current field
+func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) {
+ return v.getStructFieldOKInternal(v.slflParent, v.ct.param)
+}
+
+// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
+// the field and namespace allowing more extensibility for validators.
+func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) {
+ return v.getStructFieldOKInternal(val, namespace)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/logo.png b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/logo.png
new file mode 100644
index 000000000000..355000f5247d
Binary files /dev/null and b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/logo.png differ
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/regexes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/regexes.go
new file mode 100644
index 000000000000..b741f4e17672
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/regexes.go
@@ -0,0 +1,101 @@
+package validator
+
+import "regexp"
+
+const (
+ alphaRegexString = "^[a-zA-Z]+$"
+ alphaNumericRegexString = "^[a-zA-Z0-9]+$"
+ alphaUnicodeRegexString = "^[\\p{L}]+$"
+ alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$"
+ numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
+ numberRegexString = "^[0-9]+$"
+ hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$"
+ hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
+ rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$"
+ rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
+ hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$"
+ hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
+ emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
+ e164RegexString = "^\\+[1-9]?[0-9]{7,14}$"
+ base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
+ base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$"
+ iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
+ iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
+ uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
+ uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
+ uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ uUID3RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
+ uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
+ uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
+ uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
+ aSCIIRegexString = "^[\x00-\x7F]*$"
+ printableASCIIRegexString = "^[\x20-\x7E]*$"
+ multibyteRegexString = "[^\x00-\x7F]"
+ dataURIRegexString = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)`
+ latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
+ longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
+ sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$`
+ hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
+ hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
+ fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
+ btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
+ btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
+ btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
+ ethAddressRegexString = `^0x[0-9a-fA-F]{40}$`
+ ethAddressUpperRegexString = `^0x[0-9A-F]{40}$`
+ ethAddressLowerRegexString = `^0x[0-9a-f]{40}$`
+ uRLEncodedRegexString = `(%[A-Fa-f0-9]{2})`
+ hTMLEncodedRegexString = `[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?`
+ hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
+ splitParamsRegexString = `'[^']*'|\S+`
+)
+
+var (
+ alphaRegex = regexp.MustCompile(alphaRegexString)
+ alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString)
+ alphaUnicodeRegex = regexp.MustCompile(alphaUnicodeRegexString)
+ alphaUnicodeNumericRegex = regexp.MustCompile(alphaUnicodeNumericRegexString)
+ numericRegex = regexp.MustCompile(numericRegexString)
+ numberRegex = regexp.MustCompile(numberRegexString)
+ hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString)
+ hexcolorRegex = regexp.MustCompile(hexcolorRegexString)
+ rgbRegex = regexp.MustCompile(rgbRegexString)
+ rgbaRegex = regexp.MustCompile(rgbaRegexString)
+ hslRegex = regexp.MustCompile(hslRegexString)
+ hslaRegex = regexp.MustCompile(hslaRegexString)
+ e164Regex = regexp.MustCompile(e164RegexString)
+ emailRegex = regexp.MustCompile(emailRegexString)
+ base64Regex = regexp.MustCompile(base64RegexString)
+ base64URLRegex = regexp.MustCompile(base64URLRegexString)
+ iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
+ iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
+ uUID3Regex = regexp.MustCompile(uUID3RegexString)
+ uUID4Regex = regexp.MustCompile(uUID4RegexString)
+ uUID5Regex = regexp.MustCompile(uUID5RegexString)
+ uUIDRegex = regexp.MustCompile(uUIDRegexString)
+ uUID3RFC4122Regex = regexp.MustCompile(uUID3RFC4122RegexString)
+ uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString)
+ uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString)
+ uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString)
+ aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
+ printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
+ multibyteRegex = regexp.MustCompile(multibyteRegexString)
+ dataURIRegex = regexp.MustCompile(dataURIRegexString)
+ latitudeRegex = regexp.MustCompile(latitudeRegexString)
+ longitudeRegex = regexp.MustCompile(longitudeRegexString)
+ sSNRegex = regexp.MustCompile(sSNRegexString)
+ hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952)
+ hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123)
+ fqdnRegexRFC1123 = regexp.MustCompile(fqdnRegexStringRFC1123)
+ btcAddressRegex = regexp.MustCompile(btcAddressRegexString)
+ btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32)
+ btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32)
+ ethAddressRegex = regexp.MustCompile(ethAddressRegexString)
+ ethaddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString)
+ ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString)
+ uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString)
+ hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString)
+ hTMLRegex = regexp.MustCompile(hTMLRegexString)
+ splitParamsRegex = regexp.MustCompile(splitParamsRegexString)
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/struct_level.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/struct_level.go
new file mode 100644
index 000000000000..57691ee380c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/struct_level.go
@@ -0,0 +1,175 @@
+package validator
+
+import (
+ "context"
+ "reflect"
+)
+
+// StructLevelFunc accepts all values needed for struct level validation
+type StructLevelFunc func(sl StructLevel)
+
+// StructLevelFuncCtx accepts all values needed for struct level validation
+// but also allows passing of contextual validation information via context.Context.
+type StructLevelFuncCtx func(ctx context.Context, sl StructLevel)
+
+// wrapStructLevelFunc wraps normal StructLevelFunc makes it compatible with StructLevelFuncCtx
+func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
+ return func(ctx context.Context, sl StructLevel) {
+ fn(sl)
+ }
+}
+
+// StructLevel contains all the information and helper functions
+// to validate a struct
+type StructLevel interface {
+
+ // returns the main validation object, in case one wants to call validations internally.
+ // this is so you don't have to use anonymous functions to get access to the validate
+ // instance.
+ Validator() *Validate
+
+ // returns the top level struct, if any
+ Top() reflect.Value
+
+ // returns the current fields parent struct, if any
+ Parent() reflect.Value
+
+ // returns the current struct.
+ Current() reflect.Value
+
+ // ExtractType gets the actual underlying type of field value.
+ // It will dive into pointers, customTypes and return you the
+ // underlying value and its kind.
+ ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool)
+
+ // reports an error just by passing the field and tag information
+ //
+ // NOTES:
+ //
+ // fieldName and altName get appended to the existing namespace that
+ // validator is on. e.g. pass 'FirstName' or 'Names[0]' depending
+ // on the nesting
+ //
+ // tag can be an existing validation tag or just something you make up
+ // and process on the flip side it's up to you.
+ ReportError(field interface{}, fieldName, structFieldName string, tag, param string)
+
+ // reports an error just by passing ValidationErrors
+ //
+ // NOTES:
+ //
+ // relativeNamespace and relativeActualNamespace get appended to the
+ // existing namespace that validator is on.
+ // e.g. pass 'User.FirstName' or 'Users[0].FirstName' depending
+ // on the nesting. most of the time they will be blank, unless you validate
+ // at a level lower the the current field depth
+ ReportValidationErrors(relativeNamespace, relativeActualNamespace string, errs ValidationErrors)
+}
+
+var _ StructLevel = new(validate)
+
+// Top returns the top level struct
+//
+// NOTE: this can be the same as the current struct being validated
+// if not is a nested struct.
+//
+// this is only called when within Struct and Field Level validation and
+// should not be relied upon for an acurate value otherwise.
+func (v *validate) Top() reflect.Value {
+ return v.top
+}
+
+// Parent returns the current structs parent
+//
+// NOTE: this can be the same as the current struct being validated
+// if not is a nested struct.
+//
+// this is only called when within Struct and Field Level validation and
+// should not be relied upon for an acurate value otherwise.
+func (v *validate) Parent() reflect.Value {
+ return v.slflParent
+}
+
+// Current returns the current struct.
+func (v *validate) Current() reflect.Value {
+ return v.slCurrent
+}
+
+// Validator returns the main validation object, in case one want to call validations internally.
+func (v *validate) Validator() *Validate {
+ return v.v
+}
+
+// ExtractType gets the actual underlying type of field value.
+func (v *validate) ExtractType(field reflect.Value) (reflect.Value, reflect.Kind, bool) {
+ return v.extractTypeInternal(field, false)
+}
+
+// ReportError reports an error just by passing the field and tag information
+func (v *validate) ReportError(field interface{}, fieldName, structFieldName, tag, param string) {
+
+ fv, kind, _ := v.extractTypeInternal(reflect.ValueOf(field), false)
+
+ if len(structFieldName) == 0 {
+ structFieldName = fieldName
+ }
+
+ v.str1 = string(append(v.ns, fieldName...))
+
+ if v.v.hasTagNameFunc || fieldName != structFieldName {
+ v.str2 = string(append(v.actualNs, structFieldName...))
+ } else {
+ v.str2 = v.str1
+ }
+
+ if kind == reflect.Invalid {
+
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: tag,
+ actualTag: tag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(fieldName)),
+ structfieldLen: uint8(len(structFieldName)),
+ param: param,
+ kind: kind,
+ },
+ )
+ return
+ }
+
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: tag,
+ actualTag: tag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(fieldName)),
+ structfieldLen: uint8(len(structFieldName)),
+ value: fv.Interface(),
+ param: param,
+ kind: kind,
+ typ: fv.Type(),
+ },
+ )
+}
+
+// ReportValidationErrors reports ValidationErrors obtained from running validations within the Struct Level validation.
+//
+// NOTE: this function prepends the current namespace to the relative ones.
+func (v *validate) ReportValidationErrors(relativeNamespace, relativeStructNamespace string, errs ValidationErrors) {
+
+ var err *fieldError
+
+ for i := 0; i < len(errs); i++ {
+
+ err = errs[i].(*fieldError)
+ err.ns = string(append(append(v.ns, relativeNamespace...), err.ns...))
+ err.structNs = string(append(append(v.actualNs, relativeStructNamespace...), err.structNs...))
+
+ v.errs = append(v.errs, err)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/translations.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/translations.go
new file mode 100644
index 000000000000..4d9d75c13a0f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/translations.go
@@ -0,0 +1,11 @@
+package validator
+
+import ut "github.com/go-playground/universal-translator"
+
+// TranslationFunc is the function type used to register or override
+// custom translations
+type TranslationFunc func(ut ut.Translator, fe FieldError) string
+
+// RegisterTranslationsFunc allows for registering of translations
+// for a 'ut.Translator' for use within the 'TranslationFunc'
+type RegisterTranslationsFunc func(ut ut.Translator) error
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/util.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/util.go
new file mode 100644
index 000000000000..56420f4301ff
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/util.go
@@ -0,0 +1,288 @@
+package validator
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// extractTypeInternal gets the actual underlying type of field value.
+// It will dive into pointers, customTypes and return you the
+// underlying value and it's kind.
+func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
+
+BEGIN:
+ switch current.Kind() {
+ case reflect.Ptr:
+
+ nullable = true
+
+ if current.IsNil() {
+ return current, reflect.Ptr, nullable
+ }
+
+ current = current.Elem()
+ goto BEGIN
+
+ case reflect.Interface:
+
+ nullable = true
+
+ if current.IsNil() {
+ return current, reflect.Interface, nullable
+ }
+
+ current = current.Elem()
+ goto BEGIN
+
+ case reflect.Invalid:
+ return current, reflect.Invalid, nullable
+
+ default:
+
+ if v.v.hasCustomFuncs {
+
+ if fn, ok := v.v.customFuncs[current.Type()]; ok {
+ current = reflect.ValueOf(fn(current))
+ goto BEGIN
+ }
+ }
+
+ return current, current.Kind(), nullable
+ }
+}
+
+// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
+// returns the field, field kind and whether is was successful in retrieving the field at all.
+//
+// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
+// could not be retrieved because it didn't exist.
+func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) {
+
+BEGIN:
+ current, kind, nullable = v.ExtractType(val)
+ if kind == reflect.Invalid {
+ return
+ }
+
+ if namespace == "" {
+ found = true
+ return
+ }
+
+ switch kind {
+
+ case reflect.Ptr, reflect.Interface:
+ return
+
+ case reflect.Struct:
+
+ typ := current.Type()
+ fld := namespace
+ var ns string
+
+ if typ != timeType {
+
+ idx := strings.Index(namespace, namespaceSeparator)
+
+ if idx != -1 {
+ fld = namespace[:idx]
+ ns = namespace[idx+1:]
+ } else {
+ ns = ""
+ }
+
+ bracketIdx := strings.Index(fld, leftBracket)
+ if bracketIdx != -1 {
+ fld = fld[:bracketIdx]
+
+ ns = namespace[bracketIdx:]
+ }
+
+ val = current.FieldByName(fld)
+ namespace = ns
+ goto BEGIN
+ }
+
+ case reflect.Array, reflect.Slice:
+ idx := strings.Index(namespace, leftBracket)
+ idx2 := strings.Index(namespace, rightBracket)
+
+ arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
+
+ if arrIdx >= current.Len() {
+ return
+ }
+
+ startIdx := idx2 + 1
+
+ if startIdx < len(namespace) {
+ if namespace[startIdx:startIdx+1] == namespaceSeparator {
+ startIdx++
+ }
+ }
+
+ val = current.Index(arrIdx)
+ namespace = namespace[startIdx:]
+ goto BEGIN
+
+ case reflect.Map:
+ idx := strings.Index(namespace, leftBracket) + 1
+ idx2 := strings.Index(namespace, rightBracket)
+
+ endIdx := idx2
+
+ if endIdx+1 < len(namespace) {
+ if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
+ endIdx++
+ }
+ }
+
+ key := namespace[idx:idx2]
+
+ switch current.Type().Key().Kind() {
+ case reflect.Int:
+ i, _ := strconv.Atoi(key)
+ val = current.MapIndex(reflect.ValueOf(i))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Int8:
+ i, _ := strconv.ParseInt(key, 10, 8)
+ val = current.MapIndex(reflect.ValueOf(int8(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Int16:
+ i, _ := strconv.ParseInt(key, 10, 16)
+ val = current.MapIndex(reflect.ValueOf(int16(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Int32:
+ i, _ := strconv.ParseInt(key, 10, 32)
+ val = current.MapIndex(reflect.ValueOf(int32(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Int64:
+ i, _ := strconv.ParseInt(key, 10, 64)
+ val = current.MapIndex(reflect.ValueOf(i))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Uint:
+ i, _ := strconv.ParseUint(key, 10, 0)
+ val = current.MapIndex(reflect.ValueOf(uint(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Uint8:
+ i, _ := strconv.ParseUint(key, 10, 8)
+ val = current.MapIndex(reflect.ValueOf(uint8(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Uint16:
+ i, _ := strconv.ParseUint(key, 10, 16)
+ val = current.MapIndex(reflect.ValueOf(uint16(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Uint32:
+ i, _ := strconv.ParseUint(key, 10, 32)
+ val = current.MapIndex(reflect.ValueOf(uint32(i)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Uint64:
+ i, _ := strconv.ParseUint(key, 10, 64)
+ val = current.MapIndex(reflect.ValueOf(i))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Float32:
+ f, _ := strconv.ParseFloat(key, 32)
+ val = current.MapIndex(reflect.ValueOf(float32(f)))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Float64:
+ f, _ := strconv.ParseFloat(key, 64)
+ val = current.MapIndex(reflect.ValueOf(f))
+ namespace = namespace[endIdx+1:]
+
+ case reflect.Bool:
+ b, _ := strconv.ParseBool(key)
+ val = current.MapIndex(reflect.ValueOf(b))
+ namespace = namespace[endIdx+1:]
+
+ // reflect.Type = string
+ default:
+ val = current.MapIndex(reflect.ValueOf(key))
+ namespace = namespace[endIdx+1:]
+ }
+
+ goto BEGIN
+ }
+
+ // if got here there was more namespace, cannot go any deeper
+ panic("Invalid field namespace")
+}
+
+// asInt returns the parameter as a int64
+// or panics if it can't convert
+func asInt(param string) int64 {
+ i, err := strconv.ParseInt(param, 0, 64)
+ panicIf(err)
+
+ return i
+}
+
+// asIntFromTimeDuration parses param as time.Duration and returns it as int64
+// or panics on error.
+func asIntFromTimeDuration(param string) int64 {
+ d, err := time.ParseDuration(param)
+ if err != nil {
+ // attempt parsing as an an integer assuming nanosecond precision
+ return asInt(param)
+ }
+ return int64(d)
+}
+
+// asIntFromType calls the proper function to parse param as int64,
+// given a field's Type t.
+func asIntFromType(t reflect.Type, param string) int64 {
+ switch t {
+ case timeDurationType:
+ return asIntFromTimeDuration(param)
+ default:
+ return asInt(param)
+ }
+}
+
+// asUint returns the parameter as a uint64
+// or panics if it can't convert
+func asUint(param string) uint64 {
+
+ i, err := strconv.ParseUint(param, 0, 64)
+ panicIf(err)
+
+ return i
+}
+
+// asFloat returns the parameter as a float64
+// or panics if it can't convert
+func asFloat(param string) float64 {
+
+ i, err := strconv.ParseFloat(param, 64)
+ panicIf(err)
+
+ return i
+}
+
+// asBool returns the parameter as a bool
+// or panics if it can't convert
+func asBool(param string) bool {
+
+ i, err := strconv.ParseBool(param)
+ panicIf(err)
+
+ return i
+}
+
+func panicIf(err error) {
+ if err != nil {
+ panic(err.Error())
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/validator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/validator.go
new file mode 100644
index 000000000000..f097f394296f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/validator.go
@@ -0,0 +1,477 @@
+package validator
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+// per validate construct
+type validate struct {
+ v *Validate
+ top reflect.Value
+ ns []byte
+ actualNs []byte
+ errs ValidationErrors
+ includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise
+ ffn FilterFunc
+ slflParent reflect.Value // StructLevel & FieldLevel
+ slCurrent reflect.Value // StructLevel & FieldLevel
+ flField reflect.Value // StructLevel & FieldLevel
+ cf *cField // StructLevel & FieldLevel
+ ct *cTag // StructLevel & FieldLevel
+ misc []byte // misc reusable
+ str1 string // misc reusable
+ str2 string // misc reusable
+ fldIsPointer bool // StructLevel & FieldLevel
+ isPartial bool
+ hasExcludes bool
+}
+
+// parent and current will be the same the first run of validateStruct
+func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) {
+
+ cs, ok := v.v.structCache.Get(typ)
+ if !ok {
+ cs = v.v.extractStructCache(current, typ.Name())
+ }
+
+ if len(ns) == 0 && len(cs.name) != 0 {
+
+ ns = append(ns, cs.name...)
+ ns = append(ns, '.')
+
+ structNs = append(structNs, cs.name...)
+ structNs = append(structNs, '.')
+ }
+
+ // ct is nil on top level struct, and structs as fields that have no tag info
+ // so if nil or if not nil and the structonly tag isn't present
+ if ct == nil || ct.typeof != typeStructOnly {
+
+ var f *cField
+
+ for i := 0; i < len(cs.fields); i++ {
+
+ f = cs.fields[i]
+
+ if v.isPartial {
+
+ if v.ffn != nil {
+ // used with StructFiltered
+ if v.ffn(append(structNs, f.name...)) {
+ continue
+ }
+
+ } else {
+ // used with StructPartial & StructExcept
+ _, ok = v.includeExclude[string(append(structNs, f.name...))]
+
+ if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) {
+ continue
+ }
+ }
+ }
+
+ v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags)
+ }
+ }
+
+ // check if any struct level validations, after all field validations already checked.
+ // first iteration will have no info about nostructlevel tag, and is checked prior to
+ // calling the next iteration of validateStruct called from traverseField.
+ if cs.fn != nil {
+
+ v.slflParent = parent
+ v.slCurrent = current
+ v.ns = ns
+ v.actualNs = structNs
+
+ cs.fn(ctx, v)
+ }
+}
+
+// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
+func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) {
+ var typ reflect.Type
+ var kind reflect.Kind
+
+ current, kind, v.fldIsPointer = v.extractTypeInternal(current, false)
+
+ switch kind {
+ case reflect.Ptr, reflect.Interface, reflect.Invalid:
+
+ if ct == nil {
+ return
+ }
+
+ if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault {
+ return
+ }
+
+ if ct.hasTag {
+ if kind == reflect.Invalid {
+ v.str1 = string(append(ns, cf.altName...))
+ if v.v.hasTagNameFunc {
+ v.str2 = string(append(structNs, cf.name...))
+ } else {
+ v.str2 = v.str1
+ }
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: ct.aliasTag,
+ actualTag: ct.tag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(cf.altName)),
+ structfieldLen: uint8(len(cf.name)),
+ param: ct.param,
+ kind: kind,
+ },
+ )
+ return
+ }
+
+ v.str1 = string(append(ns, cf.altName...))
+ if v.v.hasTagNameFunc {
+ v.str2 = string(append(structNs, cf.name...))
+ } else {
+ v.str2 = v.str1
+ }
+ if !ct.runValidationWhenNil {
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: ct.aliasTag,
+ actualTag: ct.tag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(cf.altName)),
+ structfieldLen: uint8(len(cf.name)),
+ value: current.Interface(),
+ param: ct.param,
+ kind: kind,
+ typ: current.Type(),
+ },
+ )
+ return
+ }
+ }
+
+ case reflect.Struct:
+
+ typ = current.Type()
+
+ if typ != timeType {
+
+ if ct != nil {
+
+ if ct.typeof == typeStructOnly {
+ goto CONTINUE
+ } else if ct.typeof == typeIsDefault {
+ // set Field Level fields
+ v.slflParent = parent
+ v.flField = current
+ v.cf = cf
+ v.ct = ct
+
+ if !ct.fn(ctx, v) {
+ v.str1 = string(append(ns, cf.altName...))
+
+ if v.v.hasTagNameFunc {
+ v.str2 = string(append(structNs, cf.name...))
+ } else {
+ v.str2 = v.str1
+ }
+
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: ct.aliasTag,
+ actualTag: ct.tag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(cf.altName)),
+ structfieldLen: uint8(len(cf.name)),
+ value: current.Interface(),
+ param: ct.param,
+ kind: kind,
+ typ: typ,
+ },
+ )
+ return
+ }
+ }
+
+ ct = ct.next
+ }
+
+ if ct != nil && ct.typeof == typeNoStructLevel {
+ return
+ }
+
+ CONTINUE:
+ // if len == 0 then validating using 'Var' or 'VarWithValue'
+ // Var - doesn't make much sense to do it that way, should call 'Struct', but no harm...
+ // VarWithField - this allows for validating against each field within the struct against a specific value
+ // pretty handy in certain situations
+ if len(cf.name) > 0 {
+ ns = append(append(ns, cf.altName...), '.')
+ structNs = append(append(structNs, cf.name...), '.')
+ }
+
+ v.validateStruct(ctx, current, current, typ, ns, structNs, ct)
+ return
+ }
+ }
+
+ if !ct.hasTag {
+ return
+ }
+
+ typ = current.Type()
+
+OUTER:
+ for {
+ if ct == nil {
+ return
+ }
+
+ switch ct.typeof {
+
+ case typeOmitEmpty:
+
+ // set Field Level fields
+ v.slflParent = parent
+ v.flField = current
+ v.cf = cf
+ v.ct = ct
+
+ if !hasValue(v) {
+ return
+ }
+
+ ct = ct.next
+ continue
+
+ case typeEndKeys:
+ return
+
+ case typeDive:
+
+ ct = ct.next
+
+ // traverse slice or map here
+ // or panic ;)
+ switch kind {
+ case reflect.Slice, reflect.Array:
+
+ var i64 int64
+ reusableCF := &cField{}
+
+ for i := 0; i < current.Len(); i++ {
+
+ i64 = int64(i)
+
+ v.misc = append(v.misc[0:0], cf.name...)
+ v.misc = append(v.misc, '[')
+ v.misc = strconv.AppendInt(v.misc, i64, 10)
+ v.misc = append(v.misc, ']')
+
+ reusableCF.name = string(v.misc)
+
+ if cf.namesEqual {
+ reusableCF.altName = reusableCF.name
+ } else {
+
+ v.misc = append(v.misc[0:0], cf.altName...)
+ v.misc = append(v.misc, '[')
+ v.misc = strconv.AppendInt(v.misc, i64, 10)
+ v.misc = append(v.misc, ']')
+
+ reusableCF.altName = string(v.misc)
+ }
+ v.traverseField(ctx, parent, current.Index(i), ns, structNs, reusableCF, ct)
+ }
+
+ case reflect.Map:
+
+ var pv string
+ reusableCF := &cField{}
+
+ for _, key := range current.MapKeys() {
+
+ pv = fmt.Sprintf("%v", key.Interface())
+
+ v.misc = append(v.misc[0:0], cf.name...)
+ v.misc = append(v.misc, '[')
+ v.misc = append(v.misc, pv...)
+ v.misc = append(v.misc, ']')
+
+ reusableCF.name = string(v.misc)
+
+ if cf.namesEqual {
+ reusableCF.altName = reusableCF.name
+ } else {
+ v.misc = append(v.misc[0:0], cf.altName...)
+ v.misc = append(v.misc, '[')
+ v.misc = append(v.misc, pv...)
+ v.misc = append(v.misc, ']')
+
+ reusableCF.altName = string(v.misc)
+ }
+
+ if ct != nil && ct.typeof == typeKeys && ct.keys != nil {
+ v.traverseField(ctx, parent, key, ns, structNs, reusableCF, ct.keys)
+ // can be nil when just keys being validated
+ if ct.next != nil {
+ v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct.next)
+ }
+ } else {
+ v.traverseField(ctx, parent, current.MapIndex(key), ns, structNs, reusableCF, ct)
+ }
+ }
+
+ default:
+ // throw error, if not a slice or map then should not have gotten here
+ // bad dive tag
+ panic("dive error! can't dive on a non slice or map")
+ }
+
+ return
+
+ case typeOr:
+
+ v.misc = v.misc[0:0]
+
+ for {
+
+ // set Field Level fields
+ v.slflParent = parent
+ v.flField = current
+ v.cf = cf
+ v.ct = ct
+
+ if ct.fn(ctx, v) {
+
+ // drain rest of the 'or' values, then continue or leave
+ for {
+
+ ct = ct.next
+
+ if ct == nil {
+ return
+ }
+
+ if ct.typeof != typeOr {
+ continue OUTER
+ }
+ }
+ }
+
+ v.misc = append(v.misc, '|')
+ v.misc = append(v.misc, ct.tag...)
+
+ if ct.hasParam {
+ v.misc = append(v.misc, '=')
+ v.misc = append(v.misc, ct.param...)
+ }
+
+ if ct.isBlockEnd || ct.next == nil {
+ // if we get here, no valid 'or' value and no more tags
+ v.str1 = string(append(ns, cf.altName...))
+
+ if v.v.hasTagNameFunc {
+ v.str2 = string(append(structNs, cf.name...))
+ } else {
+ v.str2 = v.str1
+ }
+
+ if ct.hasAlias {
+
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: ct.aliasTag,
+ actualTag: ct.actualAliasTag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(cf.altName)),
+ structfieldLen: uint8(len(cf.name)),
+ value: current.Interface(),
+ param: ct.param,
+ kind: kind,
+ typ: typ,
+ },
+ )
+
+ } else {
+
+ tVal := string(v.misc)[1:]
+
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: tVal,
+ actualTag: tVal,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(cf.altName)),
+ structfieldLen: uint8(len(cf.name)),
+ value: current.Interface(),
+ param: ct.param,
+ kind: kind,
+ typ: typ,
+ },
+ )
+ }
+
+ return
+ }
+
+ ct = ct.next
+ }
+
+ default:
+
+ // set Field Level fields
+ v.slflParent = parent
+ v.flField = current
+ v.cf = cf
+ v.ct = ct
+
+ if !ct.fn(ctx, v) {
+
+ v.str1 = string(append(ns, cf.altName...))
+
+ if v.v.hasTagNameFunc {
+ v.str2 = string(append(structNs, cf.name...))
+ } else {
+ v.str2 = v.str1
+ }
+
+ v.errs = append(v.errs,
+ &fieldError{
+ v: v.v,
+ tag: ct.aliasTag,
+ actualTag: ct.tag,
+ ns: v.str1,
+ structNs: v.str2,
+ fieldLen: uint8(len(cf.altName)),
+ structfieldLen: uint8(len(cf.name)),
+ value: current.Interface(),
+ param: ct.param,
+ kind: kind,
+ typ: typ,
+ },
+ )
+
+ return
+ }
+ ct = ct.next
+ }
+ }
+
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/validator_instance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/validator_instance.go
new file mode 100644
index 000000000000..fe6a48775f86
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-playground/validator/v10/validator_instance.go
@@ -0,0 +1,619 @@
+package validator
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+ "time"
+
+ ut "github.com/go-playground/universal-translator"
+)
+
+const (
+ defaultTagName = "validate"
+ utf8HexComma = "0x2C"
+ utf8Pipe = "0x7C"
+ tagSeparator = ","
+ orSeparator = "|"
+ tagKeySeparator = "="
+ structOnlyTag = "structonly"
+ noStructLevelTag = "nostructlevel"
+ omitempty = "omitempty"
+ isdefault = "isdefault"
+ requiredWithoutAllTag = "required_without_all"
+ requiredWithoutTag = "required_without"
+ requiredWithTag = "required_with"
+ requiredWithAllTag = "required_with_all"
+ requiredIfTag = "required_if"
+ requiredUnlessTag = "required_unless"
+ skipValidationTag = "-"
+ diveTag = "dive"
+ keysTag = "keys"
+ endKeysTag = "endkeys"
+ requiredTag = "required"
+ namespaceSeparator = "."
+ leftBracket = "["
+ rightBracket = "]"
+ restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
+ restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
+ restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
+)
+
+var (
+ timeDurationType = reflect.TypeOf(time.Duration(0))
+ timeType = reflect.TypeOf(time.Time{})
+
+ defaultCField = &cField{namesEqual: true}
+)
+
+// FilterFunc is the type used to filter fields using
+// StructFiltered(...) function.
+// returning true results in the field being filtered/skiped from
+// validation
+type FilterFunc func(ns []byte) bool
+
+// CustomTypeFunc allows for overriding or adding custom field type handler functions
+// field = field value of the type to return a value to be validated
+// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29
+type CustomTypeFunc func(field reflect.Value) interface{}
+
+// TagNameFunc allows for adding of a custom tag name parser
+type TagNameFunc func(field reflect.StructField) string
+
+type internalValidationFuncWrapper struct {
+ fn FuncCtx
+ runValidatinOnNil bool
+}
+
+// Validate contains the validator settings and cache
+type Validate struct {
+ tagName string
+ pool *sync.Pool
+ hasCustomFuncs bool
+ hasTagNameFunc bool
+ tagNameFunc TagNameFunc
+ structLevelFuncs map[reflect.Type]StructLevelFuncCtx
+ customFuncs map[reflect.Type]CustomTypeFunc
+ aliases map[string]string
+ validations map[string]internalValidationFuncWrapper
+ transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc
+ tagCache *tagCache
+ structCache *structCache
+}
+
+// New returns a new instance of 'validate' with sane defaults.
+func New() *Validate {
+
+ tc := new(tagCache)
+ tc.m.Store(make(map[string]*cTag))
+
+ sc := new(structCache)
+ sc.m.Store(make(map[reflect.Type]*cStruct))
+
+ v := &Validate{
+ tagName: defaultTagName,
+ aliases: make(map[string]string, len(bakedInAliases)),
+ validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)),
+ tagCache: tc,
+ structCache: sc,
+ }
+
+ // must copy alias validators for separate validations to be used in each validator instance
+ for k, val := range bakedInAliases {
+ v.RegisterAlias(k, val)
+ }
+
+ // must copy validators for separate validations to be used in each instance
+ for k, val := range bakedInValidators {
+
+ switch k {
+ // these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
+ case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag:
+ _ = v.registerValidation(k, wrapFunc(val), true, true)
+ default:
+ // no need to error check here, baked in will always be valid
+ _ = v.registerValidation(k, wrapFunc(val), true, false)
+ }
+ }
+
+ v.pool = &sync.Pool{
+ New: func() interface{} {
+ return &validate{
+ v: v,
+ ns: make([]byte, 0, 64),
+ actualNs: make([]byte, 0, 64),
+ misc: make([]byte, 32),
+ }
+ },
+ }
+
+ return v
+}
+
+// SetTagName allows for changing of the default tag name of 'validate'
+func (v *Validate) SetTagName(name string) {
+ v.tagName = name
+}
+
+// RegisterTagNameFunc registers a function to get alternate names for StructFields.
+//
+// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
+//
+// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
+// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
+// if name == "-" {
+// return ""
+// }
+// return name
+// })
+func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
+ v.tagNameFunc = fn
+ v.hasTagNameFunc = true
+}
+
+// RegisterValidation adds a validation with the given tag
+//
+// NOTES:
+// - if the key already exists, the previous validation function will be replaced.
+// - this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error {
+ return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...)
+}
+
+// RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation
+// allowing context.Context validation support.
+func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error {
+ var nilCheckable bool
+ if len(callValidationEvenIfNull) > 0 {
+ nilCheckable = callValidationEvenIfNull[0]
+ }
+ return v.registerValidation(tag, fn, false, nilCheckable)
+}
+
+func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error {
+ if len(tag) == 0 {
+ return errors.New("Function Key cannot be empty")
+ }
+
+ if fn == nil {
+ return errors.New("Function cannot be empty")
+ }
+
+ _, ok := restrictedTags[tag]
+ if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) {
+ panic(fmt.Sprintf(restrictedTagErr, tag))
+ }
+ v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable}
+ return nil
+}
+
+// RegisterAlias registers a mapping of a single validation tag that
+// defines a common or complex set of validation(s) to simplify adding validation
+// to structs.
+//
+// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterAlias(alias, tags string) {
+
+ _, ok := restrictedTags[alias]
+
+ if ok || strings.ContainsAny(alias, restrictedTagChars) {
+ panic(fmt.Sprintf(restrictedAliasErr, alias))
+ }
+
+ v.aliases[alias] = tags
+}
+
+// RegisterStructValidation registers a StructLevelFunc against a number of types.
+//
+// NOTE:
+// - this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) {
+ v.RegisterStructValidationCtx(wrapStructLevelFunc(fn), types...)
+}
+
+// RegisterStructValidationCtx registers a StructLevelFuncCtx against a number of types and allows passing
+// of contextual validation information via context.Context.
+//
+// NOTE:
+// - this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) {
+
+ if v.structLevelFuncs == nil {
+ v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx)
+ }
+
+ for _, t := range types {
+ tv := reflect.ValueOf(t)
+ if tv.Kind() == reflect.Ptr {
+ t = reflect.Indirect(tv).Interface()
+ }
+
+ v.structLevelFuncs[reflect.TypeOf(t)] = fn
+ }
+}
+
+// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
+//
+// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {
+
+ if v.customFuncs == nil {
+ v.customFuncs = make(map[reflect.Type]CustomTypeFunc)
+ }
+
+ for _, t := range types {
+ v.customFuncs[reflect.TypeOf(t)] = fn
+ }
+
+ v.hasCustomFuncs = true
+}
+
+// RegisterTranslation registers translations against the provided tag.
+func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) {
+
+ if v.transTagFunc == nil {
+ v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc)
+ }
+
+ if err = registerFn(trans); err != nil {
+ return
+ }
+
+ m, ok := v.transTagFunc[trans]
+ if !ok {
+ m = make(map[string]TranslationFunc)
+ v.transTagFunc[trans] = m
+ }
+
+ m[tag] = translationFn
+
+ return
+}
+
+// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified.
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) Struct(s interface{}) error {
+ return v.StructCtx(context.Background(), s)
+}
+
+// StructCtx validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified
+// and also allows passing of context.Context for contextual validation information.
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
+
+ val := reflect.ValueOf(s)
+ top := val
+
+ if val.Kind() == reflect.Ptr && !val.IsNil() {
+ val = val.Elem()
+ }
+
+ if val.Kind() != reflect.Struct || val.Type() == timeType {
+ return &InvalidValidationError{Type: reflect.TypeOf(s)}
+ }
+
+ // good to validate
+ vd := v.pool.Get().(*validate)
+ vd.top = top
+ vd.isPartial = false
+ // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
+
+ vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
+
+ if len(vd.errs) > 0 {
+ err = vd.errs
+ vd.errs = nil
+ }
+
+ v.pool.Put(vd)
+
+ return
+}
+
+// StructFiltered validates a structs exposed fields, that pass the FilterFunc check and automatically validates
+// nested structs, unless otherwise specified.
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error {
+ return v.StructFilteredCtx(context.Background(), s, fn)
+}
+
+// StructFilteredCtx validates a structs exposed fields, that pass the FilterFunc check and automatically validates
+// nested structs, unless otherwise specified and also allows passing of contextual validation information via
+// context.Context
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn FilterFunc) (err error) {
+ val := reflect.ValueOf(s)
+ top := val
+
+ if val.Kind() == reflect.Ptr && !val.IsNil() {
+ val = val.Elem()
+ }
+
+ if val.Kind() != reflect.Struct || val.Type() == timeType {
+ return &InvalidValidationError{Type: reflect.TypeOf(s)}
+ }
+
+ // good to validate
+ vd := v.pool.Get().(*validate)
+ vd.top = top
+ vd.isPartial = true
+ vd.ffn = fn
+ // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept
+
+ vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
+
+ if len(vd.errs) > 0 {
+ err = vd.errs
+ vd.errs = nil
+ }
+
+ v.pool.Put(vd)
+
+ return
+}
+
+// StructPartial validates the fields passed in only, ignoring all others.
+// Fields may be provided in a namespaced fashion relative to the struct provided
+// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructPartial(s interface{}, fields ...string) error {
+ return v.StructPartialCtx(context.Background(), s, fields...)
+}
+
+// StructPartialCtx validates the fields passed in only, ignoring all others and allows passing of contextual
+// validation validation information via context.Context
+// Fields may be provided in a namespaced fashion relative to the struct provided
+// eg. NestedStruct.Field or NestedArrayField[0].Struct.Name
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields ...string) (err error) {
+ val := reflect.ValueOf(s)
+ top := val
+
+ if val.Kind() == reflect.Ptr && !val.IsNil() {
+ val = val.Elem()
+ }
+
+ if val.Kind() != reflect.Struct || val.Type() == timeType {
+ return &InvalidValidationError{Type: reflect.TypeOf(s)}
+ }
+
+ // good to validate
+ vd := v.pool.Get().(*validate)
+ vd.top = top
+ vd.isPartial = true
+ vd.ffn = nil
+ vd.hasExcludes = false
+ vd.includeExclude = make(map[string]struct{})
+
+ typ := val.Type()
+ name := typ.Name()
+
+ for _, k := range fields {
+
+ flds := strings.Split(k, namespaceSeparator)
+ if len(flds) > 0 {
+
+ vd.misc = append(vd.misc[0:0], name...)
+ vd.misc = append(vd.misc, '.')
+
+ for _, s := range flds {
+
+ idx := strings.Index(s, leftBracket)
+
+ if idx != -1 {
+ for idx != -1 {
+ vd.misc = append(vd.misc, s[:idx]...)
+ vd.includeExclude[string(vd.misc)] = struct{}{}
+
+ idx2 := strings.Index(s, rightBracket)
+ idx2++
+ vd.misc = append(vd.misc, s[idx:idx2]...)
+ vd.includeExclude[string(vd.misc)] = struct{}{}
+ s = s[idx2:]
+ idx = strings.Index(s, leftBracket)
+ }
+ } else {
+
+ vd.misc = append(vd.misc, s...)
+ vd.includeExclude[string(vd.misc)] = struct{}{}
+ }
+
+ vd.misc = append(vd.misc, '.')
+ }
+ }
+ }
+
+ vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
+
+ if len(vd.errs) > 0 {
+ err = vd.errs
+ vd.errs = nil
+ }
+
+ v.pool.Put(vd)
+
+ return
+}
+
+// StructExcept validates all fields except the ones passed in.
+// Fields may be provided in a namespaced fashion relative to the struct provided
+// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructExcept(s interface{}, fields ...string) error {
+ return v.StructExceptCtx(context.Background(), s, fields...)
+}
+
+// StructExceptCtx validates all fields except the ones passed in and allows passing of contextual
+// validation validation information via context.Context
+// Fields may be provided in a namespaced fashion relative to the struct provided
+// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ...string) (err error) {
+ val := reflect.ValueOf(s)
+ top := val
+
+ if val.Kind() == reflect.Ptr && !val.IsNil() {
+ val = val.Elem()
+ }
+
+ if val.Kind() != reflect.Struct || val.Type() == timeType {
+ return &InvalidValidationError{Type: reflect.TypeOf(s)}
+ }
+
+ // good to validate
+ vd := v.pool.Get().(*validate)
+ vd.top = top
+ vd.isPartial = true
+ vd.ffn = nil
+ vd.hasExcludes = true
+ vd.includeExclude = make(map[string]struct{})
+
+ typ := val.Type()
+ name := typ.Name()
+
+ for _, key := range fields {
+
+ vd.misc = vd.misc[0:0]
+
+ if len(name) > 0 {
+ vd.misc = append(vd.misc, name...)
+ vd.misc = append(vd.misc, '.')
+ }
+
+ vd.misc = append(vd.misc, key...)
+ vd.includeExclude[string(vd.misc)] = struct{}{}
+ }
+
+ vd.validateStruct(ctx, top, val, typ, vd.ns[0:0], vd.actualNs[0:0], nil)
+
+ if len(vd.errs) > 0 {
+ err = vd.errs
+ vd.errs = nil
+ }
+
+ v.pool.Put(vd)
+
+ return
+}
+
+// Var validates a single variable using tag style validation.
+// eg.
+// var i int
+// validate.Var(i, "gt=1,lt=10")
+//
+// WARNING: a struct can be passed for validation eg. time.Time is a struct or
+// if you have a custom type and have registered a custom type handler, so must
+// allow it; however unforeseen validations will occur if trying to validate a
+// struct that is meant to be passed to 'validate.Struct'
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+// validate Array, Slice and maps fields which may contain more than one error
+func (v *Validate) Var(field interface{}, tag string) error {
+ return v.VarCtx(context.Background(), field, tag)
+}
+
+// VarCtx validates a single variable using tag style validation and allows passing of contextual
+// validation validation information via context.Context.
+// eg.
+// var i int
+// validate.Var(i, "gt=1,lt=10")
+//
+// WARNING: a struct can be passed for validation eg. time.Time is a struct or
+// if you have a custom type and have registered a custom type handler, so must
+// allow it; however unforeseen validations will occur if trying to validate a
+// struct that is meant to be passed to 'validate.Struct'
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+// validate Array, Slice and maps fields which may contain more than one error
+func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) {
+ if len(tag) == 0 || tag == skipValidationTag {
+ return nil
+ }
+
+ ctag := v.fetchCacheTag(tag)
+ val := reflect.ValueOf(field)
+ vd := v.pool.Get().(*validate)
+ vd.top = val
+ vd.isPartial = false
+ vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
+
+ if len(vd.errs) > 0 {
+ err = vd.errs
+ vd.errs = nil
+ }
+ v.pool.Put(vd)
+ return
+}
+
+// VarWithValue validates a single variable, against another variable/field's value using tag style validation
+// eg.
+// s1 := "abcd"
+// s2 := "abcd"
+// validate.VarWithValue(s1, s2, "eqcsfield") // returns true
+//
+// WARNING: a struct can be passed for validation eg. time.Time is a struct or
+// if you have a custom type and have registered a custom type handler, so must
+// allow it; however unforeseen validations will occur if trying to validate a
+// struct that is meant to be passed to 'validate.Struct'
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+// validate Array, Slice and maps fields which may contain more than one error
+func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error {
+ return v.VarWithValueCtx(context.Background(), field, other, tag)
+}
+
+// VarWithValueCtx validates a single variable, against another variable/field's value using tag style validation and
+// allows passing of contextual validation validation information via context.Context.
+// eg.
+// s1 := "abcd"
+// s2 := "abcd"
+// validate.VarWithValue(s1, s2, "eqcsfield") // returns true
+//
+// WARNING: a struct can be passed for validation eg. time.Time is a struct or
+// if you have a custom type and have registered a custom type handler, so must
+// allow it; however unforeseen validations will occur if trying to validate a
+// struct that is meant to be passed to 'validate.Struct'
+//
+// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
+// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
+// validate Array, Slice and maps fields which may contain more than one error
+func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other interface{}, tag string) (err error) {
+ if len(tag) == 0 || tag == skipValidationTag {
+ return nil
+ }
+ ctag := v.fetchCacheTag(tag)
+ otherVal := reflect.ValueOf(other)
+ vd := v.pool.Get().(*validate)
+ vd.top = otherVal
+ vd.isPartial = false
+ vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag)
+
+ if len(vd.errs) > 0 {
+ err = vd.errs
+ vd.errs = nil
+ }
+ v.pool.Put(vd)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.gitignore
new file mode 100644
index 000000000000..b975a7b4c326
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.gitignore
@@ -0,0 +1,3 @@
+*.rdb
+testdata/*/
+.idea/
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.golangci.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.golangci.yml
new file mode 100644
index 000000000000..de514554a9cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.golangci.yml
@@ -0,0 +1,4 @@
+run:
+ concurrency: 8
+ deadline: 5m
+ tests: false
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.prettierrc.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.prettierrc.yml
new file mode 100644
index 000000000000..8b7f044ad1f5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/.prettierrc.yml
@@ -0,0 +1,4 @@
+semi: false
+singleQuote: true
+proseWrap: always
+printWidth: 100
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/CHANGELOG.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/CHANGELOG.md
new file mode 100644
index 000000000000..195e51933866
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/CHANGELOG.md
@@ -0,0 +1,177 @@
+## [8.11.5](https://github.com/go-redis/redis/compare/v8.11.4...v8.11.5) (2022-03-17)
+
+
+### Bug Fixes
+
+* add missing Expire methods to Cmdable ([17e3b43](https://github.com/go-redis/redis/commit/17e3b43879d516437ada71cf9c0deac6a382ed9a))
+* add whitespace for avoid unlikely colisions ([7f7c181](https://github.com/go-redis/redis/commit/7f7c1817617cfec909efb13d14ad22ef05a6ad4c))
+* example/otel compile error ([#2028](https://github.com/go-redis/redis/issues/2028)) ([187c07c](https://github.com/go-redis/redis/commit/187c07c41bf68dc3ab280bc3a925e960bbef6475))
+* **extra/redisotel:** set span.kind attribute to client ([065b200](https://github.com/go-redis/redis/commit/065b200070b41e6e949710b4f9e01b50ccc60ab2))
+* format ([96f53a0](https://github.com/go-redis/redis/commit/96f53a0159a28affa94beec1543a62234e7f8b32))
+* invalid type assert in stringArg ([de6c131](https://github.com/go-redis/redis/commit/de6c131865b8263400c8491777b295035f2408e4))
+* rename Golang to Go ([#2030](https://github.com/go-redis/redis/issues/2030)) ([b82a2d9](https://github.com/go-redis/redis/commit/b82a2d9d4d2de7b7cbe8fcd4895be62dbcacacbc))
+* set timeout for WAIT command. Fixes [#1963](https://github.com/go-redis/redis/issues/1963) ([333fee1](https://github.com/go-redis/redis/commit/333fee1a8fd98a2fbff1ab187c1b03246a7eb01f))
+* update some argument counts in pre-allocs ([f6974eb](https://github.com/go-redis/redis/commit/f6974ebb5c40a8adf90d2cacab6dc297f4eba4c2))
+
+
+### Features
+
+* Add redis v7's NX, XX, GT, LT expire variants ([e19bbb2](https://github.com/go-redis/redis/commit/e19bbb26e2e395c6e077b48d80d79e99f729a8b8))
+* add support for acl sentinel auth in universal client ([ab0ccc4](https://github.com/go-redis/redis/commit/ab0ccc47413f9b2a6eabc852fed5005a3ee1af6e))
+* add support for COPY command ([#2016](https://github.com/go-redis/redis/issues/2016)) ([730afbc](https://github.com/go-redis/redis/commit/730afbcffb93760e8a36cc06cfe55ab102b693a7))
+* add support for passing extra attributes added to spans ([39faaa1](https://github.com/go-redis/redis/commit/39faaa171523834ba527c9789710c4fde87f5a2e))
+* add support for time.Duration write and scan ([2f1b74e](https://github.com/go-redis/redis/commit/2f1b74e20cdd7719b2aecf0768d3e3ae7c3e781b))
+* **redisotel:** ability to override TracerProvider ([#1998](https://github.com/go-redis/redis/issues/1998)) ([bf8d4aa](https://github.com/go-redis/redis/commit/bf8d4aa60c00366cda2e98c3ddddc8cf68507417))
+* set net.peer.name and net.peer.port in otel example ([69bf454](https://github.com/go-redis/redis/commit/69bf454f706204211cd34835f76b2e8192d3766d))
+
+
+
+## [8.11.4](https://github.com/go-redis/redis/compare/v8.11.3...v8.11.4) (2021-10-04)
+
+
+### Features
+
+* add acl auth support for sentinels ([f66582f](https://github.com/go-redis/redis/commit/f66582f44f3dc3a4705a5260f982043fde4aa634))
+* add Cmd.{String,Int,Float,Bool}Slice helpers and an example ([5d3d293](https://github.com/go-redis/redis/commit/5d3d293cc9c60b90871e2420602001463708ce24))
+* add SetVal method for each command ([168981d](https://github.com/go-redis/redis/commit/168981da2d84ee9e07d15d3e74d738c162e264c4))
+
+
+
+## v8.11
+
+- Remove OpenTelemetry metrics.
+- Supports more redis commands and options.
+
+## v8.10
+
+- Removed extra OpenTelemetry spans from go-redis core. Now go-redis instrumentation only adds a
+ single span with a Redis command (instead of 4 spans). There are multiple reasons behind this
+ decision:
+
+ - Traces become smaller and less noisy.
+ - It may be costly to process those 3 extra spans for each query.
+ - go-redis no longer depends on OpenTelemetry.
+
+ Eventually we hope to replace the information that we no longer collect with OpenTelemetry
+ Metrics.
+
+## v8.9
+
+- Changed `PubSub.Channel` to only rely on `Ping` result. You can now use `WithChannelSize`,
+ `WithChannelHealthCheckInterval`, and `WithChannelSendTimeout` to override default settings.
+
+## v8.8
+
+- To make updating easier, extra modules now have the same version as go-redis does. That means that
+ you need to update your imports:
+
+```
+github.com/go-redis/redis/extra/redisotel -> github.com/go-redis/redis/extra/redisotel/v8
+github.com/go-redis/redis/extra/rediscensus -> github.com/go-redis/redis/extra/rediscensus/v8
+```
+
+## v8.5
+
+- [knadh](https://github.com/knadh) contributed long-awaited ability to scan Redis Hash into a
+ struct:
+
+```go
+err := rdb.HGetAll(ctx, "hash").Scan(&data)
+
+err := rdb.MGet(ctx, "key1", "key2").Scan(&data)
+```
+
+- Please check [redismock](https://github.com/go-redis/redismock) by
+ [monkey92t](https://github.com/monkey92t) if you are looking for mocking Redis Client.
+
+## v8
+
+- All commands require `context.Context` as a first argument, e.g. `rdb.Ping(ctx)`. If you are not
+ using `context.Context` yet, the simplest option is to define global package variable
+ `var ctx = context.TODO()` and use it when `ctx` is required.
+
+- Full support for `context.Context` canceling.
+
+- Added `redis.NewFailoverClusterClient` that supports routing read-only commands to a slave node.
+
+- Added `redisext.OpenTemetryHook` that adds
+ [Redis OpenTelemetry instrumentation](https://redis.uptrace.dev/tracing/).
+
+- Redis slow log support.
+
+- Ring uses Rendezvous Hashing by default which provides better distribution. You need to move
+ existing keys to a new location or keys will be inaccessible / lost. To use old hashing scheme:
+
+```go
+import "github.com/golang/groupcache/consistenthash"
+
+ring := redis.NewRing(&redis.RingOptions{
+ NewConsistentHash: func() {
+ return consistenthash.New(100, crc32.ChecksumIEEE)
+ },
+})
+```
+
+- `ClusterOptions.MaxRedirects` default value is changed from 8 to 3.
+- `Options.MaxRetries` default value is changed from 0 to 3.
+
+- `Cluster.ForEachNode` is renamed to `ForEachShard` for consistency with `Ring`.
+
+## v7.3
+
+- New option `Options.Username` which causes client to use `AuthACL`. Be aware if your connection
+ URL contains username.
+
+## v7.2
+
+- Existing `HMSet` is renamed to `HSet` and old deprecated `HMSet` is restored for Redis 3 users.
+
+## v7.1
+
+- Existing `Cmd.String` is renamed to `Cmd.Text`. New `Cmd.String` implements `fmt.Stringer`
+ interface.
+
+## v7
+
+- _Important_. Tx.Pipeline now returns a non-transactional pipeline. Use Tx.TxPipeline for a
+ transactional pipeline.
+- WrapProcess is replaced with more convenient AddHook that has access to context.Context.
+- WithContext now can not be used to create a shallow copy of the client.
+- New methods ProcessContext, DoContext, and ExecContext.
+- Client respects Context.Deadline when setting net.Conn deadline.
+- Client listens on Context.Done while waiting for a connection from the pool and returns an error
+ when context context is cancelled.
+- Add PubSub.ChannelWithSubscriptions that sends `*Subscription` in addition to `*Message` to allow
+ detecting reconnections.
+- `time.Time` is now marshalled in RFC3339 format. `rdb.Get("foo").Time()` helper is added to parse
+ the time.
+- `SetLimiter` is removed and added `Options.Limiter` instead.
+- `HMSet` is deprecated as of Redis v4.
+
+## v6.15
+
+- Cluster and Ring pipelines process commands for each node in its own goroutine.
+
+## 6.14
+
+- Added Options.MinIdleConns.
+- Added Options.MaxConnAge.
+- PoolStats.FreeConns is renamed to PoolStats.IdleConns.
+- Add Client.Do to simplify creating custom commands.
+- Add Cmd.String, Cmd.Int, Cmd.Int64, Cmd.Uint64, Cmd.Float64, and Cmd.Bool helpers.
+- Lower memory usage.
+
+## v6.13
+
+- Ring got new options called `HashReplicas` and `Hash`. It is recommended to set
+ `HashReplicas = 1000` for better keys distribution between shards.
+- Cluster client was optimized to use much less memory when reloading cluster state.
+- PubSub.ReceiveMessage is re-worked to not use ReceiveTimeout so it does not lose data when timeout
+ occurres. In most cases it is recommended to use PubSub.Channel instead.
+- Dialer.KeepAlive is set to 5 minutes by default.
+
+## v6.12
+
+- ClusterClient got new option called `ClusterSlots` which allows to build cluster of normal Redis
+ Servers that don't have cluster mode enabled. See
+ https://godoc.org/github.com/go-redis/redis#example-NewClusterClient--ManualSetup
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/LICENSE
new file mode 100644
index 000000000000..298bed9beaf7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2013 The github.com/go-redis/redis 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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/Makefile b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/Makefile
new file mode 100644
index 000000000000..a4cfe0576e68
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/Makefile
@@ -0,0 +1,35 @@
+PACKAGE_DIRS := $(shell find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | sort)
+
+test: testdeps
+ go test ./...
+ go test ./... -short -race
+ go test ./... -run=NONE -bench=. -benchmem
+ env GOOS=linux GOARCH=386 go test ./...
+ go vet
+
+testdeps: testdata/redis/src/redis-server
+
+bench: testdeps
+ go test ./... -test.run=NONE -test.bench=. -test.benchmem
+
+.PHONY: all test testdeps bench
+
+testdata/redis:
+ mkdir -p $@
+ wget -qO- https://download.redis.io/releases/redis-6.2.5.tar.gz | tar xvz --strip-components=1 -C $@
+
+testdata/redis/src/redis-server: testdata/redis
+ cd $< && make all
+
+fmt:
+ gofmt -w -s ./
+ goimports -w -local github.com/go-redis/redis ./
+
+go_mod_tidy:
+ go get -u && go mod tidy
+ set -e; for dir in $(PACKAGE_DIRS); do \
+ echo "go mod tidy in $${dir}"; \
+ (cd "$${dir}" && \
+ go get -u && \
+ go mod tidy); \
+ done
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/README.md
new file mode 100644
index 000000000000..f3b6a018cb54
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/README.md
@@ -0,0 +1,175 @@
+# Redis client for Go
+
+![build workflow](https://github.com/go-redis/redis/actions/workflows/build.yml/badge.svg)
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/go-redis/redis/v8)](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc)
+[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.uptrace.dev/)
+
+go-redis is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace).
+Uptrace is an open source and blazingly fast **distributed tracing** backend powered by
+OpenTelemetry and ClickHouse. Give it a star as well!
+
+## Resources
+
+- [Discussions](https://github.com/go-redis/redis/discussions)
+- [Documentation](https://redis.uptrace.dev)
+- [Reference](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc)
+- [Examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples)
+- [RealWorld example app](https://github.com/uptrace/go-treemux-realworld-example-app)
+
+Other projects you may like:
+
+- [Bun](https://bun.uptrace.dev) - fast and simple SQL client for PostgreSQL, MySQL, and SQLite.
+- [BunRouter](https://bunrouter.uptrace.dev/) - fast and flexible HTTP router for Go.
+
+## Ecosystem
+
+- [Redis Mock](https://github.com/go-redis/redismock)
+- [Distributed Locks](https://github.com/bsm/redislock)
+- [Redis Cache](https://github.com/go-redis/cache)
+- [Rate limiting](https://github.com/go-redis/redis_rate)
+
+## Features
+
+- Redis 3 commands except QUIT, MONITOR, and SYNC.
+- Automatic connection pooling with
+ [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support.
+- [Pub/Sub](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#PubSub).
+- [Transactions](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-TxPipeline).
+- [Pipeline](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client.Pipeline) and
+ [TxPipeline](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client.TxPipeline).
+- [Scripting](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#Script).
+- [Timeouts](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#Options).
+- [Redis Sentinel](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewFailoverClient).
+- [Redis Cluster](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewClusterClient).
+- [Cluster of Redis Servers](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-NewClusterClient-ManualSetup)
+ without using cluster mode and Redis Sentinel.
+- [Ring](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewRing).
+- [Instrumentation](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-package-Instrumentation).
+
+## Installation
+
+go-redis supports 2 last Go versions and requires a Go version with
+[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go
+module:
+
+```shell
+go mod init github.com/my/repo
+```
+
+And then install go-redis/v8 (note _v8_ in the import; omitting it is a popular mistake):
+
+```shell
+go get github.com/go-redis/redis/v8
+```
+
+## Quickstart
+
+```go
+import (
+ "context"
+ "github.com/go-redis/redis/v8"
+ "fmt"
+)
+
+var ctx = context.Background()
+
+func ExampleClient() {
+ rdb := redis.NewClient(&redis.Options{
+ Addr: "localhost:6379",
+ Password: "", // no password set
+ DB: 0, // use default DB
+ })
+
+ err := rdb.Set(ctx, "key", "value", 0).Err()
+ if err != nil {
+ panic(err)
+ }
+
+ val, err := rdb.Get(ctx, "key").Result()
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("key", val)
+
+ val2, err := rdb.Get(ctx, "key2").Result()
+ if err == redis.Nil {
+ fmt.Println("key2 does not exist")
+ } else if err != nil {
+ panic(err)
+ } else {
+ fmt.Println("key2", val2)
+ }
+ // Output: key value
+ // key2 does not exist
+}
+```
+
+## Look and feel
+
+Some corner cases:
+
+```go
+// SET key value EX 10 NX
+set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result()
+
+// SET key value keepttl NX
+set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result()
+
+// SORT list LIMIT 0 2 ASC
+vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()
+
+// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
+vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{
+ Min: "-inf",
+ Max: "+inf",
+ Offset: 0,
+ Count: 2,
+}).Result()
+
+// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
+vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{
+ Keys: []string{"zset1", "zset2"},
+ Weights: []int64{2, 3}
+}).Result()
+
+// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
+vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()
+
+// custom command
+res, err := rdb.Do(ctx, "set", "key", "value").Result()
+```
+
+## Run the test
+
+go-redis will start a redis-server and run the test cases.
+
+The paths of redis-server bin file and redis config file are defined in `main_test.go`:
+
+```
+var (
+ redisServerBin, _ = filepath.Abs(filepath.Join("testdata", "redis", "src", "redis-server"))
+ redisServerConf, _ = filepath.Abs(filepath.Join("testdata", "redis", "redis.conf"))
+)
+```
+
+For local testing, you can change the variables to refer to your local files, or create a soft link
+to the corresponding folder for redis-server and copy the config file to `testdata/redis/`:
+
+```
+ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src
+cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/
+```
+
+Lastly, run:
+
+```
+go test
+```
+
+## Contributors
+
+Thanks to all the people who already contributed!
+
+
+
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/RELEASING.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/RELEASING.md
new file mode 100644
index 000000000000..1115db4e3e57
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/RELEASING.md
@@ -0,0 +1,15 @@
+# Releasing
+
+1. Run `release.sh` script which updates versions in go.mod files and pushes a new branch to GitHub:
+
+```shell
+TAG=v1.0.0 ./scripts/release.sh
+```
+
+2. Open a pull request and wait for the build to finish.
+
+3. Merge the pull request and run `tag.sh` to create tags for packages:
+
+```shell
+TAG=v1.0.0 ./scripts/tag.sh
+```
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/cluster.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/cluster.go
new file mode 100644
index 000000000000..a54f2f37ed9c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/cluster.go
@@ -0,0 +1,1750 @@
+package redis
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "math"
+ "net"
+ "runtime"
+ "sort"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+ "github.com/go-redis/redis/v8/internal/hashtag"
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/proto"
+ "github.com/go-redis/redis/v8/internal/rand"
+)
+
+var errClusterNoNodes = fmt.Errorf("redis: cluster has no nodes")
+
+// ClusterOptions are used to configure a cluster client and should be
+// passed to NewClusterClient.
+type ClusterOptions struct {
+ // A seed list of host:port addresses of cluster nodes.
+ Addrs []string
+
+ // NewClient creates a cluster node client with provided name and options.
+ NewClient func(opt *Options) *Client
+
+ // The maximum number of retries before giving up. Command is retried
+ // on network errors and MOVED/ASK redirects.
+ // Default is 3 retries.
+ MaxRedirects int
+
+ // Enables read-only commands on slave nodes.
+ ReadOnly bool
+ // Allows routing read-only commands to the closest master or slave node.
+ // It automatically enables ReadOnly.
+ RouteByLatency bool
+ // Allows routing read-only commands to the random master or slave node.
+ // It automatically enables ReadOnly.
+ RouteRandomly bool
+
+ // Optional function that returns cluster slots information.
+ // It is useful to manually create cluster of standalone Redis servers
+ // and load-balance read/write operations between master and slaves.
+ // It can use service like ZooKeeper to maintain configuration information
+ // and Cluster.ReloadState to manually trigger state reloading.
+ ClusterSlots func(context.Context) ([]ClusterSlot, error)
+
+ // Following options are copied from Options struct.
+
+ Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ OnConnect func(ctx context.Context, cn *Conn) error
+
+ Username string
+ Password string
+
+ MaxRetries int
+ MinRetryBackoff time.Duration
+ MaxRetryBackoff time.Duration
+
+ DialTimeout time.Duration
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+
+ // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
+ PoolFIFO bool
+
+ // PoolSize applies per cluster node and not for the whole cluster.
+ PoolSize int
+ MinIdleConns int
+ MaxConnAge time.Duration
+ PoolTimeout time.Duration
+ IdleTimeout time.Duration
+ IdleCheckFrequency time.Duration
+
+ TLSConfig *tls.Config
+}
+
+func (opt *ClusterOptions) init() {
+ if opt.MaxRedirects == -1 {
+ opt.MaxRedirects = 0
+ } else if opt.MaxRedirects == 0 {
+ opt.MaxRedirects = 3
+ }
+
+ if opt.RouteByLatency || opt.RouteRandomly {
+ opt.ReadOnly = true
+ }
+
+ if opt.PoolSize == 0 {
+ opt.PoolSize = 5 * runtime.GOMAXPROCS(0)
+ }
+
+ switch opt.ReadTimeout {
+ case -1:
+ opt.ReadTimeout = 0
+ case 0:
+ opt.ReadTimeout = 3 * time.Second
+ }
+ switch opt.WriteTimeout {
+ case -1:
+ opt.WriteTimeout = 0
+ case 0:
+ opt.WriteTimeout = opt.ReadTimeout
+ }
+
+ if opt.MaxRetries == 0 {
+ opt.MaxRetries = -1
+ }
+ switch opt.MinRetryBackoff {
+ case -1:
+ opt.MinRetryBackoff = 0
+ case 0:
+ opt.MinRetryBackoff = 8 * time.Millisecond
+ }
+ switch opt.MaxRetryBackoff {
+ case -1:
+ opt.MaxRetryBackoff = 0
+ case 0:
+ opt.MaxRetryBackoff = 512 * time.Millisecond
+ }
+
+ if opt.NewClient == nil {
+ opt.NewClient = NewClient
+ }
+}
+
+func (opt *ClusterOptions) clientOptions() *Options {
+ const disableIdleCheck = -1
+
+ return &Options{
+ Dialer: opt.Dialer,
+ OnConnect: opt.OnConnect,
+
+ Username: opt.Username,
+ Password: opt.Password,
+
+ MaxRetries: opt.MaxRetries,
+ MinRetryBackoff: opt.MinRetryBackoff,
+ MaxRetryBackoff: opt.MaxRetryBackoff,
+
+ DialTimeout: opt.DialTimeout,
+ ReadTimeout: opt.ReadTimeout,
+ WriteTimeout: opt.WriteTimeout,
+
+ PoolFIFO: opt.PoolFIFO,
+ PoolSize: opt.PoolSize,
+ MinIdleConns: opt.MinIdleConns,
+ MaxConnAge: opt.MaxConnAge,
+ PoolTimeout: opt.PoolTimeout,
+ IdleTimeout: opt.IdleTimeout,
+ IdleCheckFrequency: disableIdleCheck,
+
+ TLSConfig: opt.TLSConfig,
+ // If ClusterSlots is populated, then we probably have an artificial
+ // cluster whose nodes are not in clustering mode (otherwise there isn't
+ // much use for ClusterSlots config). This means we cannot execute the
+ // READONLY command against that node -- setting readOnly to false in such
+ // situations in the options below will prevent that from happening.
+ readOnly: opt.ReadOnly && opt.ClusterSlots == nil,
+ }
+}
+
+//------------------------------------------------------------------------------
+
+type clusterNode struct {
+ Client *Client
+
+ latency uint32 // atomic
+ generation uint32 // atomic
+ failing uint32 // atomic
+}
+
+func newClusterNode(clOpt *ClusterOptions, addr string) *clusterNode {
+ opt := clOpt.clientOptions()
+ opt.Addr = addr
+ node := clusterNode{
+ Client: clOpt.NewClient(opt),
+ }
+
+ node.latency = math.MaxUint32
+ if clOpt.RouteByLatency {
+ go node.updateLatency()
+ }
+
+ return &node
+}
+
+func (n *clusterNode) String() string {
+ return n.Client.String()
+}
+
+func (n *clusterNode) Close() error {
+ return n.Client.Close()
+}
+
+func (n *clusterNode) updateLatency() {
+ const numProbe = 10
+ var dur uint64
+
+ for i := 0; i < numProbe; i++ {
+ time.Sleep(time.Duration(10+rand.Intn(10)) * time.Millisecond)
+
+ start := time.Now()
+ n.Client.Ping(context.TODO())
+ dur += uint64(time.Since(start) / time.Microsecond)
+ }
+
+ latency := float64(dur) / float64(numProbe)
+ atomic.StoreUint32(&n.latency, uint32(latency+0.5))
+}
+
+func (n *clusterNode) Latency() time.Duration {
+ latency := atomic.LoadUint32(&n.latency)
+ return time.Duration(latency) * time.Microsecond
+}
+
+func (n *clusterNode) MarkAsFailing() {
+ atomic.StoreUint32(&n.failing, uint32(time.Now().Unix()))
+}
+
+func (n *clusterNode) Failing() bool {
+ const timeout = 15 // 15 seconds
+
+ failing := atomic.LoadUint32(&n.failing)
+ if failing == 0 {
+ return false
+ }
+ if time.Now().Unix()-int64(failing) < timeout {
+ return true
+ }
+ atomic.StoreUint32(&n.failing, 0)
+ return false
+}
+
+func (n *clusterNode) Generation() uint32 {
+ return atomic.LoadUint32(&n.generation)
+}
+
+func (n *clusterNode) SetGeneration(gen uint32) {
+ for {
+ v := atomic.LoadUint32(&n.generation)
+ if gen < v || atomic.CompareAndSwapUint32(&n.generation, v, gen) {
+ break
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+type clusterNodes struct {
+ opt *ClusterOptions
+
+ mu sync.RWMutex
+ addrs []string
+ nodes map[string]*clusterNode
+ activeAddrs []string
+ closed bool
+
+ _generation uint32 // atomic
+}
+
+func newClusterNodes(opt *ClusterOptions) *clusterNodes {
+ return &clusterNodes{
+ opt: opt,
+
+ addrs: opt.Addrs,
+ nodes: make(map[string]*clusterNode),
+ }
+}
+
+func (c *clusterNodes) Close() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.closed {
+ return nil
+ }
+ c.closed = true
+
+ var firstErr error
+ for _, node := range c.nodes {
+ if err := node.Client.Close(); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+
+ c.nodes = nil
+ c.activeAddrs = nil
+
+ return firstErr
+}
+
+func (c *clusterNodes) Addrs() ([]string, error) {
+ var addrs []string
+
+ c.mu.RLock()
+ closed := c.closed //nolint:ifshort
+ if !closed {
+ if len(c.activeAddrs) > 0 {
+ addrs = c.activeAddrs
+ } else {
+ addrs = c.addrs
+ }
+ }
+ c.mu.RUnlock()
+
+ if closed {
+ return nil, pool.ErrClosed
+ }
+ if len(addrs) == 0 {
+ return nil, errClusterNoNodes
+ }
+ return addrs, nil
+}
+
+func (c *clusterNodes) NextGeneration() uint32 {
+ return atomic.AddUint32(&c._generation, 1)
+}
+
+// GC removes unused nodes.
+func (c *clusterNodes) GC(generation uint32) {
+ //nolint:prealloc
+ var collected []*clusterNode
+
+ c.mu.Lock()
+
+ c.activeAddrs = c.activeAddrs[:0]
+ for addr, node := range c.nodes {
+ if node.Generation() >= generation {
+ c.activeAddrs = append(c.activeAddrs, addr)
+ if c.opt.RouteByLatency {
+ go node.updateLatency()
+ }
+ continue
+ }
+
+ delete(c.nodes, addr)
+ collected = append(collected, node)
+ }
+
+ c.mu.Unlock()
+
+ for _, node := range collected {
+ _ = node.Client.Close()
+ }
+}
+
+func (c *clusterNodes) GetOrCreate(addr string) (*clusterNode, error) {
+ node, err := c.get(addr)
+ if err != nil {
+ return nil, err
+ }
+ if node != nil {
+ return node, nil
+ }
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.closed {
+ return nil, pool.ErrClosed
+ }
+
+ node, ok := c.nodes[addr]
+ if ok {
+ return node, nil
+ }
+
+ node = newClusterNode(c.opt, addr)
+
+ c.addrs = appendIfNotExists(c.addrs, addr)
+ c.nodes[addr] = node
+
+ return node, nil
+}
+
+func (c *clusterNodes) get(addr string) (*clusterNode, error) {
+ var node *clusterNode
+ var err error
+ c.mu.RLock()
+ if c.closed {
+ err = pool.ErrClosed
+ } else {
+ node = c.nodes[addr]
+ }
+ c.mu.RUnlock()
+ return node, err
+}
+
+func (c *clusterNodes) All() ([]*clusterNode, error) {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ if c.closed {
+ return nil, pool.ErrClosed
+ }
+
+ cp := make([]*clusterNode, 0, len(c.nodes))
+ for _, node := range c.nodes {
+ cp = append(cp, node)
+ }
+ return cp, nil
+}
+
+func (c *clusterNodes) Random() (*clusterNode, error) {
+ addrs, err := c.Addrs()
+ if err != nil {
+ return nil, err
+ }
+
+ n := rand.Intn(len(addrs))
+ return c.GetOrCreate(addrs[n])
+}
+
+//------------------------------------------------------------------------------
+
+type clusterSlot struct {
+ start, end int
+ nodes []*clusterNode
+}
+
+type clusterSlotSlice []*clusterSlot
+
+func (p clusterSlotSlice) Len() int {
+ return len(p)
+}
+
+func (p clusterSlotSlice) Less(i, j int) bool {
+ return p[i].start < p[j].start
+}
+
+func (p clusterSlotSlice) Swap(i, j int) {
+ p[i], p[j] = p[j], p[i]
+}
+
+type clusterState struct {
+ nodes *clusterNodes
+ Masters []*clusterNode
+ Slaves []*clusterNode
+
+ slots []*clusterSlot
+
+ generation uint32
+ createdAt time.Time
+}
+
+func newClusterState(
+ nodes *clusterNodes, slots []ClusterSlot, origin string,
+) (*clusterState, error) {
+ c := clusterState{
+ nodes: nodes,
+
+ slots: make([]*clusterSlot, 0, len(slots)),
+
+ generation: nodes.NextGeneration(),
+ createdAt: time.Now(),
+ }
+
+ originHost, _, _ := net.SplitHostPort(origin)
+ isLoopbackOrigin := isLoopback(originHost)
+
+ for _, slot := range slots {
+ var nodes []*clusterNode
+ for i, slotNode := range slot.Nodes {
+ addr := slotNode.Addr
+ if !isLoopbackOrigin {
+ addr = replaceLoopbackHost(addr, originHost)
+ }
+
+ node, err := c.nodes.GetOrCreate(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ node.SetGeneration(c.generation)
+ nodes = append(nodes, node)
+
+ if i == 0 {
+ c.Masters = appendUniqueNode(c.Masters, node)
+ } else {
+ c.Slaves = appendUniqueNode(c.Slaves, node)
+ }
+ }
+
+ c.slots = append(c.slots, &clusterSlot{
+ start: slot.Start,
+ end: slot.End,
+ nodes: nodes,
+ })
+ }
+
+ sort.Sort(clusterSlotSlice(c.slots))
+
+ time.AfterFunc(time.Minute, func() {
+ nodes.GC(c.generation)
+ })
+
+ return &c, nil
+}
+
+func replaceLoopbackHost(nodeAddr, originHost string) string {
+ nodeHost, nodePort, err := net.SplitHostPort(nodeAddr)
+ if err != nil {
+ return nodeAddr
+ }
+
+ nodeIP := net.ParseIP(nodeHost)
+ if nodeIP == nil {
+ return nodeAddr
+ }
+
+ if !nodeIP.IsLoopback() {
+ return nodeAddr
+ }
+
+ // Use origin host which is not loopback and node port.
+ return net.JoinHostPort(originHost, nodePort)
+}
+
+func isLoopback(host string) bool {
+ ip := net.ParseIP(host)
+ if ip == nil {
+ return true
+ }
+ return ip.IsLoopback()
+}
+
+func (c *clusterState) slotMasterNode(slot int) (*clusterNode, error) {
+ nodes := c.slotNodes(slot)
+ if len(nodes) > 0 {
+ return nodes[0], nil
+ }
+ return c.nodes.Random()
+}
+
+func (c *clusterState) slotSlaveNode(slot int) (*clusterNode, error) {
+ nodes := c.slotNodes(slot)
+ switch len(nodes) {
+ case 0:
+ return c.nodes.Random()
+ case 1:
+ return nodes[0], nil
+ case 2:
+ if slave := nodes[1]; !slave.Failing() {
+ return slave, nil
+ }
+ return nodes[0], nil
+ default:
+ var slave *clusterNode
+ for i := 0; i < 10; i++ {
+ n := rand.Intn(len(nodes)-1) + 1
+ slave = nodes[n]
+ if !slave.Failing() {
+ return slave, nil
+ }
+ }
+
+ // All slaves are loading - use master.
+ return nodes[0], nil
+ }
+}
+
+func (c *clusterState) slotClosestNode(slot int) (*clusterNode, error) {
+ nodes := c.slotNodes(slot)
+ if len(nodes) == 0 {
+ return c.nodes.Random()
+ }
+
+ var node *clusterNode
+ for _, n := range nodes {
+ if n.Failing() {
+ continue
+ }
+ if node == nil || n.Latency() < node.Latency() {
+ node = n
+ }
+ }
+ if node != nil {
+ return node, nil
+ }
+
+ // If all nodes are failing - return random node
+ return c.nodes.Random()
+}
+
+func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) {
+ nodes := c.slotNodes(slot)
+ if len(nodes) == 0 {
+ return c.nodes.Random()
+ }
+ if len(nodes) == 1 {
+ return nodes[0], nil
+ }
+ randomNodes := rand.Perm(len(nodes))
+ for _, idx := range randomNodes {
+ if node := nodes[idx]; !node.Failing() {
+ return node, nil
+ }
+ }
+ return nodes[randomNodes[0]], nil
+}
+
+func (c *clusterState) slotNodes(slot int) []*clusterNode {
+ i := sort.Search(len(c.slots), func(i int) bool {
+ return c.slots[i].end >= slot
+ })
+ if i >= len(c.slots) {
+ return nil
+ }
+ x := c.slots[i]
+ if slot >= x.start && slot <= x.end {
+ return x.nodes
+ }
+ return nil
+}
+
+//------------------------------------------------------------------------------
+
+type clusterStateHolder struct {
+ load func(ctx context.Context) (*clusterState, error)
+
+ state atomic.Value
+ reloading uint32 // atomic
+}
+
+func newClusterStateHolder(fn func(ctx context.Context) (*clusterState, error)) *clusterStateHolder {
+ return &clusterStateHolder{
+ load: fn,
+ }
+}
+
+func (c *clusterStateHolder) Reload(ctx context.Context) (*clusterState, error) {
+ state, err := c.load(ctx)
+ if err != nil {
+ return nil, err
+ }
+ c.state.Store(state)
+ return state, nil
+}
+
+func (c *clusterStateHolder) LazyReload() {
+ if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) {
+ return
+ }
+ go func() {
+ defer atomic.StoreUint32(&c.reloading, 0)
+
+ _, err := c.Reload(context.Background())
+ if err != nil {
+ return
+ }
+ time.Sleep(200 * time.Millisecond)
+ }()
+}
+
+func (c *clusterStateHolder) Get(ctx context.Context) (*clusterState, error) {
+ v := c.state.Load()
+ if v == nil {
+ return c.Reload(ctx)
+ }
+
+ state := v.(*clusterState)
+ if time.Since(state.createdAt) > 10*time.Second {
+ c.LazyReload()
+ }
+ return state, nil
+}
+
+func (c *clusterStateHolder) ReloadOrGet(ctx context.Context) (*clusterState, error) {
+ state, err := c.Reload(ctx)
+ if err == nil {
+ return state, nil
+ }
+ return c.Get(ctx)
+}
+
+//------------------------------------------------------------------------------
+
+type clusterClient struct {
+ opt *ClusterOptions
+ nodes *clusterNodes
+ state *clusterStateHolder //nolint:structcheck
+ cmdsInfoCache *cmdsInfoCache //nolint:structcheck
+}
+
+// ClusterClient is a Redis Cluster client representing a pool of zero
+// or more underlying connections. It's safe for concurrent use by
+// multiple goroutines.
+type ClusterClient struct {
+ *clusterClient
+ cmdable
+ hooks
+ ctx context.Context
+}
+
+// NewClusterClient returns a Redis Cluster client as described in
+// http://redis.io/topics/cluster-spec.
+func NewClusterClient(opt *ClusterOptions) *ClusterClient {
+ opt.init()
+
+ c := &ClusterClient{
+ clusterClient: &clusterClient{
+ opt: opt,
+ nodes: newClusterNodes(opt),
+ },
+ ctx: context.Background(),
+ }
+ c.state = newClusterStateHolder(c.loadState)
+ c.cmdsInfoCache = newCmdsInfoCache(c.cmdsInfo)
+ c.cmdable = c.Process
+
+ if opt.IdleCheckFrequency > 0 {
+ go c.reaper(opt.IdleCheckFrequency)
+ }
+
+ return c
+}
+
+func (c *ClusterClient) Context() context.Context {
+ return c.ctx
+}
+
+func (c *ClusterClient) WithContext(ctx context.Context) *ClusterClient {
+ if ctx == nil {
+ panic("nil context")
+ }
+ clone := *c
+ clone.cmdable = clone.Process
+ clone.hooks.lock()
+ clone.ctx = ctx
+ return &clone
+}
+
+// Options returns read-only Options that were used to create the client.
+func (c *ClusterClient) Options() *ClusterOptions {
+ return c.opt
+}
+
+// ReloadState reloads cluster state. If available it calls ClusterSlots func
+// to get cluster slots information.
+func (c *ClusterClient) ReloadState(ctx context.Context) {
+ c.state.LazyReload()
+}
+
+// Close closes the cluster client, releasing any open resources.
+//
+// It is rare to Close a ClusterClient, as the ClusterClient is meant
+// to be long-lived and shared between many goroutines.
+func (c *ClusterClient) Close() error {
+ return c.nodes.Close()
+}
+
+// Do creates a Cmd from the args and processes the cmd.
+func (c *ClusterClient) Do(ctx context.Context, args ...interface{}) *Cmd {
+ cmd := NewCmd(ctx, args...)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+func (c *ClusterClient) Process(ctx context.Context, cmd Cmder) error {
+ return c.hooks.process(ctx, cmd, c.process)
+}
+
+func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
+ cmdInfo := c.cmdInfo(cmd.Name())
+ slot := c.cmdSlot(cmd)
+
+ var node *clusterNode
+ var ask bool
+ var lastErr error
+ for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ return err
+ }
+ }
+
+ if node == nil {
+ var err error
+ node, err = c.cmdNode(ctx, cmdInfo, slot)
+ if err != nil {
+ return err
+ }
+ }
+
+ if ask {
+ pipe := node.Client.Pipeline()
+ _ = pipe.Process(ctx, NewCmd(ctx, "asking"))
+ _ = pipe.Process(ctx, cmd)
+ _, lastErr = pipe.Exec(ctx)
+ _ = pipe.Close()
+ ask = false
+ } else {
+ lastErr = node.Client.Process(ctx, cmd)
+ }
+
+ // If there is no error - we are done.
+ if lastErr == nil {
+ return nil
+ }
+ if isReadOnly := isReadOnlyError(lastErr); isReadOnly || lastErr == pool.ErrClosed {
+ if isReadOnly {
+ c.state.LazyReload()
+ }
+ node = nil
+ continue
+ }
+
+ // If slave is loading - pick another node.
+ if c.opt.ReadOnly && isLoadingError(lastErr) {
+ node.MarkAsFailing()
+ node = nil
+ continue
+ }
+
+ var moved bool
+ var addr string
+ moved, ask, addr = isMovedError(lastErr)
+ if moved || ask {
+ c.state.LazyReload()
+
+ var err error
+ node, err = c.nodes.GetOrCreate(addr)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ if shouldRetry(lastErr, cmd.readTimeout() == nil) {
+ // First retry the same node.
+ if attempt == 0 {
+ continue
+ }
+
+ // Second try another node.
+ node.MarkAsFailing()
+ node = nil
+ continue
+ }
+
+ return lastErr
+ }
+ return lastErr
+}
+
+// ForEachMaster concurrently calls the fn on each master node in the cluster.
+// It returns the first error if any.
+func (c *ClusterClient) ForEachMaster(
+ ctx context.Context,
+ fn func(ctx context.Context, client *Client) error,
+) error {
+ state, err := c.state.ReloadOrGet(ctx)
+ if err != nil {
+ return err
+ }
+
+ var wg sync.WaitGroup
+ errCh := make(chan error, 1)
+
+ for _, master := range state.Masters {
+ wg.Add(1)
+ go func(node *clusterNode) {
+ defer wg.Done()
+ err := fn(ctx, node.Client)
+ if err != nil {
+ select {
+ case errCh <- err:
+ default:
+ }
+ }
+ }(master)
+ }
+
+ wg.Wait()
+
+ select {
+ case err := <-errCh:
+ return err
+ default:
+ return nil
+ }
+}
+
+// ForEachSlave concurrently calls the fn on each slave node in the cluster.
+// It returns the first error if any.
+func (c *ClusterClient) ForEachSlave(
+ ctx context.Context,
+ fn func(ctx context.Context, client *Client) error,
+) error {
+ state, err := c.state.ReloadOrGet(ctx)
+ if err != nil {
+ return err
+ }
+
+ var wg sync.WaitGroup
+ errCh := make(chan error, 1)
+
+ for _, slave := range state.Slaves {
+ wg.Add(1)
+ go func(node *clusterNode) {
+ defer wg.Done()
+ err := fn(ctx, node.Client)
+ if err != nil {
+ select {
+ case errCh <- err:
+ default:
+ }
+ }
+ }(slave)
+ }
+
+ wg.Wait()
+
+ select {
+ case err := <-errCh:
+ return err
+ default:
+ return nil
+ }
+}
+
+// ForEachShard concurrently calls the fn on each known node in the cluster.
+// It returns the first error if any.
+func (c *ClusterClient) ForEachShard(
+ ctx context.Context,
+ fn func(ctx context.Context, client *Client) error,
+) error {
+ state, err := c.state.ReloadOrGet(ctx)
+ if err != nil {
+ return err
+ }
+
+ var wg sync.WaitGroup
+ errCh := make(chan error, 1)
+
+ worker := func(node *clusterNode) {
+ defer wg.Done()
+ err := fn(ctx, node.Client)
+ if err != nil {
+ select {
+ case errCh <- err:
+ default:
+ }
+ }
+ }
+
+ for _, node := range state.Masters {
+ wg.Add(1)
+ go worker(node)
+ }
+ for _, node := range state.Slaves {
+ wg.Add(1)
+ go worker(node)
+ }
+
+ wg.Wait()
+
+ select {
+ case err := <-errCh:
+ return err
+ default:
+ return nil
+ }
+}
+
+// PoolStats returns accumulated connection pool stats.
+func (c *ClusterClient) PoolStats() *PoolStats {
+ var acc PoolStats
+
+ state, _ := c.state.Get(context.TODO())
+ if state == nil {
+ return &acc
+ }
+
+ for _, node := range state.Masters {
+ s := node.Client.connPool.Stats()
+ acc.Hits += s.Hits
+ acc.Misses += s.Misses
+ acc.Timeouts += s.Timeouts
+
+ acc.TotalConns += s.TotalConns
+ acc.IdleConns += s.IdleConns
+ acc.StaleConns += s.StaleConns
+ }
+
+ for _, node := range state.Slaves {
+ s := node.Client.connPool.Stats()
+ acc.Hits += s.Hits
+ acc.Misses += s.Misses
+ acc.Timeouts += s.Timeouts
+
+ acc.TotalConns += s.TotalConns
+ acc.IdleConns += s.IdleConns
+ acc.StaleConns += s.StaleConns
+ }
+
+ return &acc
+}
+
+func (c *ClusterClient) loadState(ctx context.Context) (*clusterState, error) {
+ if c.opt.ClusterSlots != nil {
+ slots, err := c.opt.ClusterSlots(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return newClusterState(c.nodes, slots, "")
+ }
+
+ addrs, err := c.nodes.Addrs()
+ if err != nil {
+ return nil, err
+ }
+
+ var firstErr error
+
+ for _, idx := range rand.Perm(len(addrs)) {
+ addr := addrs[idx]
+
+ node, err := c.nodes.GetOrCreate(addr)
+ if err != nil {
+ if firstErr == nil {
+ firstErr = err
+ }
+ continue
+ }
+
+ slots, err := node.Client.ClusterSlots(ctx).Result()
+ if err != nil {
+ if firstErr == nil {
+ firstErr = err
+ }
+ continue
+ }
+
+ return newClusterState(c.nodes, slots, node.Client.opt.Addr)
+ }
+
+ /*
+ * No node is connectable. It's possible that all nodes' IP has changed.
+ * Clear activeAddrs to let client be able to re-connect using the initial
+ * setting of the addresses (e.g. [redis-cluster-0:6379, redis-cluster-1:6379]),
+ * which might have chance to resolve domain name and get updated IP address.
+ */
+ c.nodes.mu.Lock()
+ c.nodes.activeAddrs = nil
+ c.nodes.mu.Unlock()
+
+ return nil, firstErr
+}
+
+// reaper closes idle connections to the cluster.
+func (c *ClusterClient) reaper(idleCheckFrequency time.Duration) {
+ ticker := time.NewTicker(idleCheckFrequency)
+ defer ticker.Stop()
+
+ for range ticker.C {
+ nodes, err := c.nodes.All()
+ if err != nil {
+ break
+ }
+
+ for _, node := range nodes {
+ _, err := node.Client.connPool.(*pool.ConnPool).ReapStaleConns()
+ if err != nil {
+ internal.Logger.Printf(c.Context(), "ReapStaleConns failed: %s", err)
+ }
+ }
+ }
+}
+
+func (c *ClusterClient) Pipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *ClusterClient) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.Pipeline().Pipelined(ctx, fn)
+}
+
+func (c *ClusterClient) processPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processPipeline(ctx, cmds, c._processPipeline)
+}
+
+func (c *ClusterClient) _processPipeline(ctx context.Context, cmds []Cmder) error {
+ cmdsMap := newCmdsMap()
+ err := c.mapCmdsByNode(ctx, cmdsMap, cmds)
+ if err != nil {
+ setCmdsErr(cmds, err)
+ return err
+ }
+
+ for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ setCmdsErr(cmds, err)
+ return err
+ }
+ }
+
+ failedCmds := newCmdsMap()
+ var wg sync.WaitGroup
+
+ for node, cmds := range cmdsMap.m {
+ wg.Add(1)
+ go func(node *clusterNode, cmds []Cmder) {
+ defer wg.Done()
+
+ err := c._processPipelineNode(ctx, node, cmds, failedCmds)
+ if err == nil {
+ return
+ }
+ if attempt < c.opt.MaxRedirects {
+ if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil {
+ setCmdsErr(cmds, err)
+ }
+ } else {
+ setCmdsErr(cmds, err)
+ }
+ }(node, cmds)
+ }
+
+ wg.Wait()
+ if len(failedCmds.m) == 0 {
+ break
+ }
+ cmdsMap = failedCmds
+ }
+
+ return cmdsFirstErr(cmds)
+}
+
+func (c *ClusterClient) mapCmdsByNode(ctx context.Context, cmdsMap *cmdsMap, cmds []Cmder) error {
+ state, err := c.state.Get(ctx)
+ if err != nil {
+ return err
+ }
+
+ if c.opt.ReadOnly && c.cmdsAreReadOnly(cmds) {
+ for _, cmd := range cmds {
+ slot := c.cmdSlot(cmd)
+ node, err := c.slotReadOnlyNode(state, slot)
+ if err != nil {
+ return err
+ }
+ cmdsMap.Add(node, cmd)
+ }
+ return nil
+ }
+
+ for _, cmd := range cmds {
+ slot := c.cmdSlot(cmd)
+ node, err := state.slotMasterNode(slot)
+ if err != nil {
+ return err
+ }
+ cmdsMap.Add(node, cmd)
+ }
+ return nil
+}
+
+func (c *ClusterClient) cmdsAreReadOnly(cmds []Cmder) bool {
+ for _, cmd := range cmds {
+ cmdInfo := c.cmdInfo(cmd.Name())
+ if cmdInfo == nil || !cmdInfo.ReadOnly {
+ return false
+ }
+ }
+ return true
+}
+
+func (c *ClusterClient) _processPipelineNode(
+ ctx context.Context, node *clusterNode, cmds []Cmder, failedCmds *cmdsMap,
+) error {
+ return node.Client.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
+ return node.Client.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
+ err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
+ return writeCmds(wr, cmds)
+ })
+ if err != nil {
+ return err
+ }
+
+ return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
+ return c.pipelineReadCmds(ctx, node, rd, cmds, failedCmds)
+ })
+ })
+ })
+}
+
+func (c *ClusterClient) pipelineReadCmds(
+ ctx context.Context,
+ node *clusterNode,
+ rd *proto.Reader,
+ cmds []Cmder,
+ failedCmds *cmdsMap,
+) error {
+ for _, cmd := range cmds {
+ err := cmd.readReply(rd)
+ cmd.SetErr(err)
+
+ if err == nil {
+ continue
+ }
+
+ if c.checkMovedErr(ctx, cmd, err, failedCmds) {
+ continue
+ }
+
+ if c.opt.ReadOnly && isLoadingError(err) {
+ node.MarkAsFailing()
+ return err
+ }
+ if isRedisError(err) {
+ continue
+ }
+ return err
+ }
+ return nil
+}
+
+func (c *ClusterClient) checkMovedErr(
+ ctx context.Context, cmd Cmder, err error, failedCmds *cmdsMap,
+) bool {
+ moved, ask, addr := isMovedError(err)
+ if !moved && !ask {
+ return false
+ }
+
+ node, err := c.nodes.GetOrCreate(addr)
+ if err != nil {
+ return false
+ }
+
+ if moved {
+ c.state.LazyReload()
+ failedCmds.Add(node, cmd)
+ return true
+ }
+
+ if ask {
+ failedCmds.Add(node, NewCmd(ctx, "asking"), cmd)
+ return true
+ }
+
+ panic("not reached")
+}
+
+// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
+func (c *ClusterClient) TxPipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processTxPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *ClusterClient) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.TxPipeline().Pipelined(ctx, fn)
+}
+
+func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processTxPipeline(ctx, cmds, c._processTxPipeline)
+}
+
+func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) error {
+ // Trim multi .. exec.
+ cmds = cmds[1 : len(cmds)-1]
+
+ state, err := c.state.Get(ctx)
+ if err != nil {
+ setCmdsErr(cmds, err)
+ return err
+ }
+
+ cmdsMap := c.mapCmdsBySlot(cmds)
+ for slot, cmds := range cmdsMap {
+ node, err := state.slotMasterNode(slot)
+ if err != nil {
+ setCmdsErr(cmds, err)
+ continue
+ }
+
+ cmdsMap := map[*clusterNode][]Cmder{node: cmds}
+ for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ setCmdsErr(cmds, err)
+ return err
+ }
+ }
+
+ failedCmds := newCmdsMap()
+ var wg sync.WaitGroup
+
+ for node, cmds := range cmdsMap {
+ wg.Add(1)
+ go func(node *clusterNode, cmds []Cmder) {
+ defer wg.Done()
+
+ err := c._processTxPipelineNode(ctx, node, cmds, failedCmds)
+ if err == nil {
+ return
+ }
+
+ if attempt < c.opt.MaxRedirects {
+ if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil {
+ setCmdsErr(cmds, err)
+ }
+ } else {
+ setCmdsErr(cmds, err)
+ }
+ }(node, cmds)
+ }
+
+ wg.Wait()
+ if len(failedCmds.m) == 0 {
+ break
+ }
+ cmdsMap = failedCmds.m
+ }
+ }
+
+ return cmdsFirstErr(cmds)
+}
+
+func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
+ cmdsMap := make(map[int][]Cmder)
+ for _, cmd := range cmds {
+ slot := c.cmdSlot(cmd)
+ cmdsMap[slot] = append(cmdsMap[slot], cmd)
+ }
+ return cmdsMap
+}
+
+func (c *ClusterClient) _processTxPipelineNode(
+ ctx context.Context, node *clusterNode, cmds []Cmder, failedCmds *cmdsMap,
+) error {
+ return node.Client.hooks.processTxPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
+ return node.Client.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
+ err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
+ return writeCmds(wr, cmds)
+ })
+ if err != nil {
+ return err
+ }
+
+ return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
+ statusCmd := cmds[0].(*StatusCmd)
+ // Trim multi and exec.
+ cmds = cmds[1 : len(cmds)-1]
+
+ err := c.txPipelineReadQueued(ctx, rd, statusCmd, cmds, failedCmds)
+ if err != nil {
+ moved, ask, addr := isMovedError(err)
+ if moved || ask {
+ return c.cmdsMoved(ctx, cmds, moved, ask, addr, failedCmds)
+ }
+ return err
+ }
+
+ return pipelineReadCmds(rd, cmds)
+ })
+ })
+ })
+}
+
+func (c *ClusterClient) txPipelineReadQueued(
+ ctx context.Context,
+ rd *proto.Reader,
+ statusCmd *StatusCmd,
+ cmds []Cmder,
+ failedCmds *cmdsMap,
+) error {
+ // Parse queued replies.
+ if err := statusCmd.readReply(rd); err != nil {
+ return err
+ }
+
+ for _, cmd := range cmds {
+ err := statusCmd.readReply(rd)
+ if err == nil || c.checkMovedErr(ctx, cmd, err, failedCmds) || isRedisError(err) {
+ continue
+ }
+ return err
+ }
+
+ // Parse number of replies.
+ line, err := rd.ReadLine()
+ if err != nil {
+ if err == Nil {
+ err = TxFailedErr
+ }
+ return err
+ }
+
+ switch line[0] {
+ case proto.ErrorReply:
+ return proto.ParseErrorReply(line)
+ case proto.ArrayReply:
+ // ok
+ default:
+ return fmt.Errorf("redis: expected '*', but got line %q", line)
+ }
+
+ return nil
+}
+
+func (c *ClusterClient) cmdsMoved(
+ ctx context.Context, cmds []Cmder,
+ moved, ask bool,
+ addr string,
+ failedCmds *cmdsMap,
+) error {
+ node, err := c.nodes.GetOrCreate(addr)
+ if err != nil {
+ return err
+ }
+
+ if moved {
+ c.state.LazyReload()
+ for _, cmd := range cmds {
+ failedCmds.Add(node, cmd)
+ }
+ return nil
+ }
+
+ if ask {
+ for _, cmd := range cmds {
+ failedCmds.Add(node, NewCmd(ctx, "asking"), cmd)
+ }
+ return nil
+ }
+
+ return nil
+}
+
+func (c *ClusterClient) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
+ if len(keys) == 0 {
+ return fmt.Errorf("redis: Watch requires at least one key")
+ }
+
+ slot := hashtag.Slot(keys[0])
+ for _, key := range keys[1:] {
+ if hashtag.Slot(key) != slot {
+ err := fmt.Errorf("redis: Watch requires all keys to be in the same slot")
+ return err
+ }
+ }
+
+ node, err := c.slotMasterNode(ctx, slot)
+ if err != nil {
+ return err
+ }
+
+ for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ return err
+ }
+ }
+
+ err = node.Client.Watch(ctx, fn, keys...)
+ if err == nil {
+ break
+ }
+
+ moved, ask, addr := isMovedError(err)
+ if moved || ask {
+ node, err = c.nodes.GetOrCreate(addr)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ if isReadOnly := isReadOnlyError(err); isReadOnly || err == pool.ErrClosed {
+ if isReadOnly {
+ c.state.LazyReload()
+ }
+ node, err = c.slotMasterNode(ctx, slot)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ if shouldRetry(err, true) {
+ continue
+ }
+
+ return err
+ }
+
+ return err
+}
+
+func (c *ClusterClient) pubSub() *PubSub {
+ var node *clusterNode
+ pubsub := &PubSub{
+ opt: c.opt.clientOptions(),
+
+ newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) {
+ if node != nil {
+ panic("node != nil")
+ }
+
+ var err error
+ if len(channels) > 0 {
+ slot := hashtag.Slot(channels[0])
+ node, err = c.slotMasterNode(ctx, slot)
+ } else {
+ node, err = c.nodes.Random()
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ cn, err := node.Client.newConn(context.TODO())
+ if err != nil {
+ node = nil
+
+ return nil, err
+ }
+
+ return cn, nil
+ },
+ closeConn: func(cn *pool.Conn) error {
+ err := node.Client.connPool.CloseConn(cn)
+ node = nil
+ return err
+ },
+ }
+ pubsub.init()
+
+ return pubsub
+}
+
+// Subscribe subscribes the client to the specified channels.
+// Channels can be omitted to create empty subscription.
+func (c *ClusterClient) Subscribe(ctx context.Context, channels ...string) *PubSub {
+ pubsub := c.pubSub()
+ if len(channels) > 0 {
+ _ = pubsub.Subscribe(ctx, channels...)
+ }
+ return pubsub
+}
+
+// PSubscribe subscribes the client to the given patterns.
+// Patterns can be omitted to create empty subscription.
+func (c *ClusterClient) PSubscribe(ctx context.Context, channels ...string) *PubSub {
+ pubsub := c.pubSub()
+ if len(channels) > 0 {
+ _ = pubsub.PSubscribe(ctx, channels...)
+ }
+ return pubsub
+}
+
+func (c *ClusterClient) retryBackoff(attempt int) time.Duration {
+ return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
+}
+
+func (c *ClusterClient) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) {
+ // Try 3 random nodes.
+ const nodeLimit = 3
+
+ addrs, err := c.nodes.Addrs()
+ if err != nil {
+ return nil, err
+ }
+
+ var firstErr error
+
+ perm := rand.Perm(len(addrs))
+ if len(perm) > nodeLimit {
+ perm = perm[:nodeLimit]
+ }
+
+ for _, idx := range perm {
+ addr := addrs[idx]
+
+ node, err := c.nodes.GetOrCreate(addr)
+ if err != nil {
+ if firstErr == nil {
+ firstErr = err
+ }
+ continue
+ }
+
+ info, err := node.Client.Command(ctx).Result()
+ if err == nil {
+ return info, nil
+ }
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+
+ if firstErr == nil {
+ panic("not reached")
+ }
+ return nil, firstErr
+}
+
+func (c *ClusterClient) cmdInfo(name string) *CommandInfo {
+ cmdsInfo, err := c.cmdsInfoCache.Get(c.ctx)
+ if err != nil {
+ return nil
+ }
+
+ info := cmdsInfo[name]
+ if info == nil {
+ internal.Logger.Printf(c.Context(), "info for cmd=%s not found", name)
+ }
+ return info
+}
+
+func (c *ClusterClient) cmdSlot(cmd Cmder) int {
+ args := cmd.Args()
+ if args[0] == "cluster" && args[1] == "getkeysinslot" {
+ return args[2].(int)
+ }
+
+ cmdInfo := c.cmdInfo(cmd.Name())
+ return cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo))
+}
+
+func cmdSlot(cmd Cmder, pos int) int {
+ if pos == 0 {
+ return hashtag.RandomSlot()
+ }
+ firstKey := cmd.stringArg(pos)
+ return hashtag.Slot(firstKey)
+}
+
+func (c *ClusterClient) cmdNode(
+ ctx context.Context,
+ cmdInfo *CommandInfo,
+ slot int,
+) (*clusterNode, error) {
+ state, err := c.state.Get(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ if c.opt.ReadOnly && cmdInfo != nil && cmdInfo.ReadOnly {
+ return c.slotReadOnlyNode(state, slot)
+ }
+ return state.slotMasterNode(slot)
+}
+
+func (c *clusterClient) slotReadOnlyNode(state *clusterState, slot int) (*clusterNode, error) {
+ if c.opt.RouteByLatency {
+ return state.slotClosestNode(slot)
+ }
+ if c.opt.RouteRandomly {
+ return state.slotRandomNode(slot)
+ }
+ return state.slotSlaveNode(slot)
+}
+
+func (c *ClusterClient) slotMasterNode(ctx context.Context, slot int) (*clusterNode, error) {
+ state, err := c.state.Get(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return state.slotMasterNode(slot)
+}
+
+// SlaveForKey gets a client for a replica node to run any command on it.
+// This is especially useful if we want to run a particular lua script which has
+// only read only commands on the replica.
+// This is because other redis commands generally have a flag that points that
+// they are read only and automatically run on the replica nodes
+// if ClusterOptions.ReadOnly flag is set to true.
+func (c *ClusterClient) SlaveForKey(ctx context.Context, key string) (*Client, error) {
+ state, err := c.state.Get(ctx)
+ if err != nil {
+ return nil, err
+ }
+ slot := hashtag.Slot(key)
+ node, err := c.slotReadOnlyNode(state, slot)
+ if err != nil {
+ return nil, err
+ }
+ return node.Client, err
+}
+
+// MasterForKey return a client to the master node for a particular key.
+func (c *ClusterClient) MasterForKey(ctx context.Context, key string) (*Client, error) {
+ slot := hashtag.Slot(key)
+ node, err := c.slotMasterNode(ctx, slot)
+ if err != nil {
+ return nil, err
+ }
+ return node.Client, err
+}
+
+func appendUniqueNode(nodes []*clusterNode, node *clusterNode) []*clusterNode {
+ for _, n := range nodes {
+ if n == node {
+ return nodes
+ }
+ }
+ return append(nodes, node)
+}
+
+func appendIfNotExists(ss []string, es ...string) []string {
+loop:
+ for _, e := range es {
+ for _, s := range ss {
+ if s == e {
+ continue loop
+ }
+ }
+ ss = append(ss, e)
+ }
+ return ss
+}
+
+//------------------------------------------------------------------------------
+
+type cmdsMap struct {
+ mu sync.Mutex
+ m map[*clusterNode][]Cmder
+}
+
+func newCmdsMap() *cmdsMap {
+ return &cmdsMap{
+ m: make(map[*clusterNode][]Cmder),
+ }
+}
+
+func (m *cmdsMap) Add(node *clusterNode, cmds ...Cmder) {
+ m.mu.Lock()
+ m.m[node] = append(m.m[node], cmds...)
+ m.mu.Unlock()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/cluster_commands.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/cluster_commands.go
new file mode 100644
index 000000000000..085bce83d567
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/cluster_commands.go
@@ -0,0 +1,109 @@
+package redis
+
+import (
+ "context"
+ "sync"
+ "sync/atomic"
+)
+
+func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd {
+ cmd := NewIntCmd(ctx, "dbsize")
+ _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error {
+ var size int64
+ err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error {
+ n, err := master.DBSize(ctx).Result()
+ if err != nil {
+ return err
+ }
+ atomic.AddInt64(&size, n)
+ return nil
+ })
+ if err != nil {
+ cmd.SetErr(err)
+ } else {
+ cmd.val = size
+ }
+ return nil
+ })
+ return cmd
+}
+
+func (c *ClusterClient) ScriptLoad(ctx context.Context, script string) *StringCmd {
+ cmd := NewStringCmd(ctx, "script", "load", script)
+ _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error {
+ mu := &sync.Mutex{}
+ err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
+ val, err := shard.ScriptLoad(ctx, script).Result()
+ if err != nil {
+ return err
+ }
+
+ mu.Lock()
+ if cmd.Val() == "" {
+ cmd.val = val
+ }
+ mu.Unlock()
+
+ return nil
+ })
+ if err != nil {
+ cmd.SetErr(err)
+ }
+ return nil
+ })
+ return cmd
+}
+
+func (c *ClusterClient) ScriptFlush(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "script", "flush")
+ _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error {
+ err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
+ return shard.ScriptFlush(ctx).Err()
+ })
+ if err != nil {
+ cmd.SetErr(err)
+ }
+ return nil
+ })
+ return cmd
+}
+
+func (c *ClusterClient) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
+ args := make([]interface{}, 2+len(hashes))
+ args[0] = "script"
+ args[1] = "exists"
+ for i, hash := range hashes {
+ args[2+i] = hash
+ }
+ cmd := NewBoolSliceCmd(ctx, args...)
+
+ result := make([]bool, len(hashes))
+ for i := range result {
+ result[i] = true
+ }
+
+ _ = c.hooks.process(ctx, cmd, func(ctx context.Context, _ Cmder) error {
+ mu := &sync.Mutex{}
+ err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
+ val, err := shard.ScriptExists(ctx, hashes...).Result()
+ if err != nil {
+ return err
+ }
+
+ mu.Lock()
+ for i, v := range val {
+ result[i] = result[i] && v
+ }
+ mu.Unlock()
+
+ return nil
+ })
+ if err != nil {
+ cmd.SetErr(err)
+ } else {
+ cmd.val = result
+ }
+ return nil
+ })
+ return cmd
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/command.go
new file mode 100644
index 000000000000..4bb12a85be43
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/command.go
@@ -0,0 +1,3478 @@
+package redis
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "strconv"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+ "github.com/go-redis/redis/v8/internal/hscan"
+ "github.com/go-redis/redis/v8/internal/proto"
+ "github.com/go-redis/redis/v8/internal/util"
+)
+
+type Cmder interface {
+ Name() string
+ FullName() string
+ Args() []interface{}
+ String() string
+ stringArg(int) string
+ firstKeyPos() int8
+ SetFirstKeyPos(int8)
+
+ readTimeout() *time.Duration
+ readReply(rd *proto.Reader) error
+
+ SetErr(error)
+ Err() error
+}
+
+func setCmdsErr(cmds []Cmder, e error) {
+ for _, cmd := range cmds {
+ if cmd.Err() == nil {
+ cmd.SetErr(e)
+ }
+ }
+}
+
+func cmdsFirstErr(cmds []Cmder) error {
+ for _, cmd := range cmds {
+ if err := cmd.Err(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func writeCmds(wr *proto.Writer, cmds []Cmder) error {
+ for _, cmd := range cmds {
+ if err := writeCmd(wr, cmd); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func writeCmd(wr *proto.Writer, cmd Cmder) error {
+ return wr.WriteArgs(cmd.Args())
+}
+
+func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
+ if pos := cmd.firstKeyPos(); pos != 0 {
+ return int(pos)
+ }
+
+ switch cmd.Name() {
+ case "eval", "evalsha":
+ if cmd.stringArg(2) != "0" {
+ return 3
+ }
+
+ return 0
+ case "publish":
+ return 1
+ case "memory":
+ // https://github.com/redis/redis/issues/7493
+ if cmd.stringArg(1) == "usage" {
+ return 2
+ }
+ }
+
+ if info != nil {
+ return int(info.FirstKeyPos)
+ }
+ return 0
+}
+
+func cmdString(cmd Cmder, val interface{}) string {
+ b := make([]byte, 0, 64)
+
+ for i, arg := range cmd.Args() {
+ if i > 0 {
+ b = append(b, ' ')
+ }
+ b = internal.AppendArg(b, arg)
+ }
+
+ if err := cmd.Err(); err != nil {
+ b = append(b, ": "...)
+ b = append(b, err.Error()...)
+ } else if val != nil {
+ b = append(b, ": "...)
+ b = internal.AppendArg(b, val)
+ }
+
+ return internal.String(b)
+}
+
+//------------------------------------------------------------------------------
+
+type baseCmd struct {
+ ctx context.Context
+ args []interface{}
+ err error
+ keyPos int8
+
+ _readTimeout *time.Duration
+}
+
+var _ Cmder = (*Cmd)(nil)
+
+func (cmd *baseCmd) Name() string {
+ if len(cmd.args) == 0 {
+ return ""
+ }
+ // Cmd name must be lower cased.
+ return internal.ToLower(cmd.stringArg(0))
+}
+
+func (cmd *baseCmd) FullName() string {
+ switch name := cmd.Name(); name {
+ case "cluster", "command":
+ if len(cmd.args) == 1 {
+ return name
+ }
+ if s2, ok := cmd.args[1].(string); ok {
+ return name + " " + s2
+ }
+ return name
+ default:
+ return name
+ }
+}
+
+func (cmd *baseCmd) Args() []interface{} {
+ return cmd.args
+}
+
+func (cmd *baseCmd) stringArg(pos int) string {
+ if pos < 0 || pos >= len(cmd.args) {
+ return ""
+ }
+ arg := cmd.args[pos]
+ switch v := arg.(type) {
+ case string:
+ return v
+ default:
+ // TODO: consider using appendArg
+ return fmt.Sprint(v)
+ }
+}
+
+func (cmd *baseCmd) firstKeyPos() int8 {
+ return cmd.keyPos
+}
+
+func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
+ cmd.keyPos = keyPos
+}
+
+func (cmd *baseCmd) SetErr(e error) {
+ cmd.err = e
+}
+
+func (cmd *baseCmd) Err() error {
+ return cmd.err
+}
+
+func (cmd *baseCmd) readTimeout() *time.Duration {
+ return cmd._readTimeout
+}
+
+func (cmd *baseCmd) setReadTimeout(d time.Duration) {
+ cmd._readTimeout = &d
+}
+
+//------------------------------------------------------------------------------
+
+type Cmd struct {
+ baseCmd
+
+ val interface{}
+}
+
+func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
+ return &Cmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *Cmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *Cmd) SetVal(val interface{}) {
+ cmd.val = val
+}
+
+func (cmd *Cmd) Val() interface{} {
+ return cmd.val
+}
+
+func (cmd *Cmd) Result() (interface{}, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *Cmd) Text() (string, error) {
+ if cmd.err != nil {
+ return "", cmd.err
+ }
+ return toString(cmd.val)
+}
+
+func toString(val interface{}) (string, error) {
+ switch val := val.(type) {
+ case string:
+ return val, nil
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for String", val)
+ return "", err
+ }
+}
+
+func (cmd *Cmd) Int() (int, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ switch val := cmd.val.(type) {
+ case int64:
+ return int(val), nil
+ case string:
+ return strconv.Atoi(val)
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for Int", val)
+ return 0, err
+ }
+}
+
+func (cmd *Cmd) Int64() (int64, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return toInt64(cmd.val)
+}
+
+func toInt64(val interface{}) (int64, error) {
+ switch val := val.(type) {
+ case int64:
+ return val, nil
+ case string:
+ return strconv.ParseInt(val, 10, 64)
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
+ return 0, err
+ }
+}
+
+func (cmd *Cmd) Uint64() (uint64, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return toUint64(cmd.val)
+}
+
+func toUint64(val interface{}) (uint64, error) {
+ switch val := val.(type) {
+ case int64:
+ return uint64(val), nil
+ case string:
+ return strconv.ParseUint(val, 10, 64)
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
+ return 0, err
+ }
+}
+
+func (cmd *Cmd) Float32() (float32, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return toFloat32(cmd.val)
+}
+
+func toFloat32(val interface{}) (float32, error) {
+ switch val := val.(type) {
+ case int64:
+ return float32(val), nil
+ case string:
+ f, err := strconv.ParseFloat(val, 32)
+ if err != nil {
+ return 0, err
+ }
+ return float32(f), nil
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
+ return 0, err
+ }
+}
+
+func (cmd *Cmd) Float64() (float64, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return toFloat64(cmd.val)
+}
+
+func toFloat64(val interface{}) (float64, error) {
+ switch val := val.(type) {
+ case int64:
+ return float64(val), nil
+ case string:
+ return strconv.ParseFloat(val, 64)
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
+ return 0, err
+ }
+}
+
+func (cmd *Cmd) Bool() (bool, error) {
+ if cmd.err != nil {
+ return false, cmd.err
+ }
+ return toBool(cmd.val)
+}
+
+func toBool(val interface{}) (bool, error) {
+ switch val := val.(type) {
+ case int64:
+ return val != 0, nil
+ case string:
+ return strconv.ParseBool(val)
+ default:
+ err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
+ return false, err
+ }
+}
+
+func (cmd *Cmd) Slice() ([]interface{}, error) {
+ if cmd.err != nil {
+ return nil, cmd.err
+ }
+ switch val := cmd.val.(type) {
+ case []interface{}:
+ return val, nil
+ default:
+ return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val)
+ }
+}
+
+func (cmd *Cmd) StringSlice() ([]string, error) {
+ slice, err := cmd.Slice()
+ if err != nil {
+ return nil, err
+ }
+
+ ss := make([]string, len(slice))
+ for i, iface := range slice {
+ val, err := toString(iface)
+ if err != nil {
+ return nil, err
+ }
+ ss[i] = val
+ }
+ return ss, nil
+}
+
+func (cmd *Cmd) Int64Slice() ([]int64, error) {
+ slice, err := cmd.Slice()
+ if err != nil {
+ return nil, err
+ }
+
+ nums := make([]int64, len(slice))
+ for i, iface := range slice {
+ val, err := toInt64(iface)
+ if err != nil {
+ return nil, err
+ }
+ nums[i] = val
+ }
+ return nums, nil
+}
+
+func (cmd *Cmd) Uint64Slice() ([]uint64, error) {
+ slice, err := cmd.Slice()
+ if err != nil {
+ return nil, err
+ }
+
+ nums := make([]uint64, len(slice))
+ for i, iface := range slice {
+ val, err := toUint64(iface)
+ if err != nil {
+ return nil, err
+ }
+ nums[i] = val
+ }
+ return nums, nil
+}
+
+func (cmd *Cmd) Float32Slice() ([]float32, error) {
+ slice, err := cmd.Slice()
+ if err != nil {
+ return nil, err
+ }
+
+ floats := make([]float32, len(slice))
+ for i, iface := range slice {
+ val, err := toFloat32(iface)
+ if err != nil {
+ return nil, err
+ }
+ floats[i] = val
+ }
+ return floats, nil
+}
+
+func (cmd *Cmd) Float64Slice() ([]float64, error) {
+ slice, err := cmd.Slice()
+ if err != nil {
+ return nil, err
+ }
+
+ floats := make([]float64, len(slice))
+ for i, iface := range slice {
+ val, err := toFloat64(iface)
+ if err != nil {
+ return nil, err
+ }
+ floats[i] = val
+ }
+ return floats, nil
+}
+
+func (cmd *Cmd) BoolSlice() ([]bool, error) {
+ slice, err := cmd.Slice()
+ if err != nil {
+ return nil, err
+ }
+
+ bools := make([]bool, len(slice))
+ for i, iface := range slice {
+ val, err := toBool(iface)
+ if err != nil {
+ return nil, err
+ }
+ bools[i] = val
+ }
+ return bools, nil
+}
+
+func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
+ cmd.val, err = rd.ReadReply(sliceParser)
+ return err
+}
+
+// sliceParser implements proto.MultiBulkParse.
+func sliceParser(rd *proto.Reader, n int64) (interface{}, error) {
+ vals := make([]interface{}, n)
+ for i := 0; i < len(vals); i++ {
+ v, err := rd.ReadReply(sliceParser)
+ if err != nil {
+ if err == Nil {
+ vals[i] = nil
+ continue
+ }
+ if err, ok := err.(proto.RedisError); ok {
+ vals[i] = err
+ continue
+ }
+ return nil, err
+ }
+ vals[i] = v
+ }
+ return vals, nil
+}
+
+//------------------------------------------------------------------------------
+
+type SliceCmd struct {
+ baseCmd
+
+ val []interface{}
+}
+
+var _ Cmder = (*SliceCmd)(nil)
+
+func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
+ return &SliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *SliceCmd) SetVal(val []interface{}) {
+ cmd.val = val
+}
+
+func (cmd *SliceCmd) Val() []interface{} {
+ return cmd.val
+}
+
+func (cmd *SliceCmd) Result() ([]interface{}, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *SliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+// Scan scans the results from the map into a destination struct. The map keys
+// are matched in the Redis struct fields by the `redis:"field"` tag.
+func (cmd *SliceCmd) Scan(dst interface{}) error {
+ if cmd.err != nil {
+ return cmd.err
+ }
+
+ // Pass the list of keys and values.
+ // Skip the first two args for: HMGET key
+ var args []interface{}
+ if cmd.args[0] == "hmget" {
+ args = cmd.args[2:]
+ } else {
+ // Otherwise, it's: MGET field field ...
+ args = cmd.args[1:]
+ }
+
+ return hscan.Scan(dst, args, cmd.val)
+}
+
+func (cmd *SliceCmd) readReply(rd *proto.Reader) error {
+ v, err := rd.ReadArrayReply(sliceParser)
+ if err != nil {
+ return err
+ }
+ cmd.val = v.([]interface{})
+ return nil
+}
+
+//------------------------------------------------------------------------------
+
+type StatusCmd struct {
+ baseCmd
+
+ val string
+}
+
+var _ Cmder = (*StatusCmd)(nil)
+
+func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
+ return &StatusCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *StatusCmd) SetVal(val string) {
+ cmd.val = val
+}
+
+func (cmd *StatusCmd) Val() string {
+ return cmd.val
+}
+
+func (cmd *StatusCmd) Result() (string, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *StatusCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
+ cmd.val, err = rd.ReadString()
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type IntCmd struct {
+ baseCmd
+
+ val int64
+}
+
+var _ Cmder = (*IntCmd)(nil)
+
+func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
+ return &IntCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *IntCmd) SetVal(val int64) {
+ cmd.val = val
+}
+
+func (cmd *IntCmd) Val() int64 {
+ return cmd.val
+}
+
+func (cmd *IntCmd) Result() (int64, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *IntCmd) Uint64() (uint64, error) {
+ return uint64(cmd.val), cmd.err
+}
+
+func (cmd *IntCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
+ cmd.val, err = rd.ReadIntReply()
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type IntSliceCmd struct {
+ baseCmd
+
+ val []int64
+}
+
+var _ Cmder = (*IntSliceCmd)(nil)
+
+func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
+ return &IntSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *IntSliceCmd) SetVal(val []int64) {
+ cmd.val = val
+}
+
+func (cmd *IntSliceCmd) Val() []int64 {
+ return cmd.val
+}
+
+func (cmd *IntSliceCmd) Result() ([]int64, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *IntSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]int64, n)
+ for i := 0; i < len(cmd.val); i++ {
+ num, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ cmd.val[i] = num
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type DurationCmd struct {
+ baseCmd
+
+ val time.Duration
+ precision time.Duration
+}
+
+var _ Cmder = (*DurationCmd)(nil)
+
+func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
+ return &DurationCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ precision: precision,
+ }
+}
+
+func (cmd *DurationCmd) SetVal(val time.Duration) {
+ cmd.val = val
+}
+
+func (cmd *DurationCmd) Val() time.Duration {
+ return cmd.val
+}
+
+func (cmd *DurationCmd) Result() (time.Duration, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *DurationCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
+ n, err := rd.ReadIntReply()
+ if err != nil {
+ return err
+ }
+ switch n {
+ // -2 if the key does not exist
+ // -1 if the key exists but has no associated expire
+ case -2, -1:
+ cmd.val = time.Duration(n)
+ default:
+ cmd.val = time.Duration(n) * cmd.precision
+ }
+ return nil
+}
+
+//------------------------------------------------------------------------------
+
+type TimeCmd struct {
+ baseCmd
+
+ val time.Time
+}
+
+var _ Cmder = (*TimeCmd)(nil)
+
+func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
+ return &TimeCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *TimeCmd) SetVal(val time.Time) {
+ cmd.val = val
+}
+
+func (cmd *TimeCmd) Val() time.Time {
+ return cmd.val
+}
+
+func (cmd *TimeCmd) Result() (time.Time, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *TimeCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 2 {
+ return nil, fmt.Errorf("got %d elements, expected 2", n)
+ }
+
+ sec, err := rd.ReadInt()
+ if err != nil {
+ return nil, err
+ }
+
+ microsec, err := rd.ReadInt()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val = time.Unix(sec, microsec*1000)
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type BoolCmd struct {
+ baseCmd
+
+ val bool
+}
+
+var _ Cmder = (*BoolCmd)(nil)
+
+func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
+ return &BoolCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *BoolCmd) SetVal(val bool) {
+ cmd.val = val
+}
+
+func (cmd *BoolCmd) Val() bool {
+ return cmd.val
+}
+
+func (cmd *BoolCmd) Result() (bool, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *BoolCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *BoolCmd) readReply(rd *proto.Reader) error {
+ v, err := rd.ReadReply(nil)
+ // `SET key value NX` returns nil when key already exists. But
+ // `SETNX key value` returns bool (0/1). So convert nil to bool.
+ if err == Nil {
+ cmd.val = false
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ switch v := v.(type) {
+ case int64:
+ cmd.val = v == 1
+ return nil
+ case string:
+ cmd.val = v == "OK"
+ return nil
+ default:
+ return fmt.Errorf("got %T, wanted int64 or string", v)
+ }
+}
+
+//------------------------------------------------------------------------------
+
+type StringCmd struct {
+ baseCmd
+
+ val string
+}
+
+var _ Cmder = (*StringCmd)(nil)
+
+func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
+ return &StringCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *StringCmd) SetVal(val string) {
+ cmd.val = val
+}
+
+func (cmd *StringCmd) Val() string {
+ return cmd.val
+}
+
+func (cmd *StringCmd) Result() (string, error) {
+ return cmd.Val(), cmd.err
+}
+
+func (cmd *StringCmd) Bytes() ([]byte, error) {
+ return util.StringToBytes(cmd.val), cmd.err
+}
+
+func (cmd *StringCmd) Bool() (bool, error) {
+ if cmd.err != nil {
+ return false, cmd.err
+ }
+ return strconv.ParseBool(cmd.val)
+}
+
+func (cmd *StringCmd) Int() (int, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return strconv.Atoi(cmd.Val())
+}
+
+func (cmd *StringCmd) Int64() (int64, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return strconv.ParseInt(cmd.Val(), 10, 64)
+}
+
+func (cmd *StringCmd) Uint64() (uint64, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return strconv.ParseUint(cmd.Val(), 10, 64)
+}
+
+func (cmd *StringCmd) Float32() (float32, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ f, err := strconv.ParseFloat(cmd.Val(), 32)
+ if err != nil {
+ return 0, err
+ }
+ return float32(f), nil
+}
+
+func (cmd *StringCmd) Float64() (float64, error) {
+ if cmd.err != nil {
+ return 0, cmd.err
+ }
+ return strconv.ParseFloat(cmd.Val(), 64)
+}
+
+func (cmd *StringCmd) Time() (time.Time, error) {
+ if cmd.err != nil {
+ return time.Time{}, cmd.err
+ }
+ return time.Parse(time.RFC3339Nano, cmd.Val())
+}
+
+func (cmd *StringCmd) Scan(val interface{}) error {
+ if cmd.err != nil {
+ return cmd.err
+ }
+ return proto.Scan([]byte(cmd.val), val)
+}
+
+func (cmd *StringCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
+ cmd.val, err = rd.ReadString()
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type FloatCmd struct {
+ baseCmd
+
+ val float64
+}
+
+var _ Cmder = (*FloatCmd)(nil)
+
+func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
+ return &FloatCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *FloatCmd) SetVal(val float64) {
+ cmd.val = val
+}
+
+func (cmd *FloatCmd) Val() float64 {
+ return cmd.val
+}
+
+func (cmd *FloatCmd) Result() (float64, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *FloatCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
+ cmd.val, err = rd.ReadFloatReply()
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type FloatSliceCmd struct {
+ baseCmd
+
+ val []float64
+}
+
+var _ Cmder = (*FloatSliceCmd)(nil)
+
+func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd {
+ return &FloatSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *FloatSliceCmd) SetVal(val []float64) {
+ cmd.val = val
+}
+
+func (cmd *FloatSliceCmd) Val() []float64 {
+ return cmd.val
+}
+
+func (cmd *FloatSliceCmd) Result() ([]float64, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *FloatSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]float64, n)
+ for i := 0; i < len(cmd.val); i++ {
+ switch num, err := rd.ReadFloatReply(); {
+ case err == Nil:
+ cmd.val[i] = 0
+ case err != nil:
+ return nil, err
+ default:
+ cmd.val[i] = num
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type StringSliceCmd struct {
+ baseCmd
+
+ val []string
+}
+
+var _ Cmder = (*StringSliceCmd)(nil)
+
+func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
+ return &StringSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *StringSliceCmd) SetVal(val []string) {
+ cmd.val = val
+}
+
+func (cmd *StringSliceCmd) Val() []string {
+ return cmd.val
+}
+
+func (cmd *StringSliceCmd) Result() ([]string, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *StringSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
+ return proto.ScanSlice(cmd.Val(), container)
+}
+
+func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]string, n)
+ for i := 0; i < len(cmd.val); i++ {
+ switch s, err := rd.ReadString(); {
+ case err == Nil:
+ cmd.val[i] = ""
+ case err != nil:
+ return nil, err
+ default:
+ cmd.val[i] = s
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type BoolSliceCmd struct {
+ baseCmd
+
+ val []bool
+}
+
+var _ Cmder = (*BoolSliceCmd)(nil)
+
+func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
+ return &BoolSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *BoolSliceCmd) SetVal(val []bool) {
+ cmd.val = val
+}
+
+func (cmd *BoolSliceCmd) Val() []bool {
+ return cmd.val
+}
+
+func (cmd *BoolSliceCmd) Result() ([]bool, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *BoolSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]bool, n)
+ for i := 0; i < len(cmd.val); i++ {
+ n, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ cmd.val[i] = n == 1
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type StringStringMapCmd struct {
+ baseCmd
+
+ val map[string]string
+}
+
+var _ Cmder = (*StringStringMapCmd)(nil)
+
+func NewStringStringMapCmd(ctx context.Context, args ...interface{}) *StringStringMapCmd {
+ return &StringStringMapCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *StringStringMapCmd) SetVal(val map[string]string) {
+ cmd.val = val
+}
+
+func (cmd *StringStringMapCmd) Val() map[string]string {
+ return cmd.val
+}
+
+func (cmd *StringStringMapCmd) Result() (map[string]string, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *StringStringMapCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+// Scan scans the results from the map into a destination struct. The map keys
+// are matched in the Redis struct fields by the `redis:"field"` tag.
+func (cmd *StringStringMapCmd) Scan(dest interface{}) error {
+ if cmd.err != nil {
+ return cmd.err
+ }
+
+ strct, err := hscan.Struct(dest)
+ if err != nil {
+ return err
+ }
+
+ for k, v := range cmd.val {
+ if err := strct.Scan(k, v); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make(map[string]string, n/2)
+ for i := int64(0); i < n; i += 2 {
+ key, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ value, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val[key] = value
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type StringIntMapCmd struct {
+ baseCmd
+
+ val map[string]int64
+}
+
+var _ Cmder = (*StringIntMapCmd)(nil)
+
+func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd {
+ return &StringIntMapCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *StringIntMapCmd) SetVal(val map[string]int64) {
+ cmd.val = val
+}
+
+func (cmd *StringIntMapCmd) Val() map[string]int64 {
+ return cmd.val
+}
+
+func (cmd *StringIntMapCmd) Result() (map[string]int64, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *StringIntMapCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *StringIntMapCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make(map[string]int64, n/2)
+ for i := int64(0); i < n; i += 2 {
+ key, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ n, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val[key] = n
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type StringStructMapCmd struct {
+ baseCmd
+
+ val map[string]struct{}
+}
+
+var _ Cmder = (*StringStructMapCmd)(nil)
+
+func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
+ return &StringStructMapCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) {
+ cmd.val = val
+}
+
+func (cmd *StringStructMapCmd) Val() map[string]struct{} {
+ return cmd.val
+}
+
+func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *StringStructMapCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make(map[string]struct{}, n)
+ for i := int64(0); i < n; i++ {
+ key, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ cmd.val[key] = struct{}{}
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type XMessage struct {
+ ID string
+ Values map[string]interface{}
+}
+
+type XMessageSliceCmd struct {
+ baseCmd
+
+ val []XMessage
+}
+
+var _ Cmder = (*XMessageSliceCmd)(nil)
+
+func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
+ return &XMessageSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XMessageSliceCmd) SetVal(val []XMessage) {
+ cmd.val = val
+}
+
+func (cmd *XMessageSliceCmd) Val() []XMessage {
+ return cmd.val
+}
+
+func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XMessageSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) error {
+ var err error
+ cmd.val, err = readXMessageSlice(rd)
+ return err
+}
+
+func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+
+ msgs := make([]XMessage, n)
+ for i := 0; i < n; i++ {
+ var err error
+ msgs[i], err = readXMessage(rd)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return msgs, nil
+}
+
+func readXMessage(rd *proto.Reader) (XMessage, error) {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return XMessage{}, err
+ }
+ if n != 2 {
+ return XMessage{}, fmt.Errorf("got %d, wanted 2", n)
+ }
+
+ id, err := rd.ReadString()
+ if err != nil {
+ return XMessage{}, err
+ }
+
+ var values map[string]interface{}
+
+ v, err := rd.ReadArrayReply(stringInterfaceMapParser)
+ if err != nil {
+ if err != proto.Nil {
+ return XMessage{}, err
+ }
+ } else {
+ values = v.(map[string]interface{})
+ }
+
+ return XMessage{
+ ID: id,
+ Values: values,
+ }, nil
+}
+
+// stringInterfaceMapParser implements proto.MultiBulkParse.
+func stringInterfaceMapParser(rd *proto.Reader, n int64) (interface{}, error) {
+ m := make(map[string]interface{}, n/2)
+ for i := int64(0); i < n; i += 2 {
+ key, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ value, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ m[key] = value
+ }
+ return m, nil
+}
+
+//------------------------------------------------------------------------------
+
+type XStream struct {
+ Stream string
+ Messages []XMessage
+}
+
+type XStreamSliceCmd struct {
+ baseCmd
+
+ val []XStream
+}
+
+var _ Cmder = (*XStreamSliceCmd)(nil)
+
+func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
+ return &XStreamSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XStreamSliceCmd) SetVal(val []XStream) {
+ cmd.val = val
+}
+
+func (cmd *XStreamSliceCmd) Val() []XStream {
+ return cmd.val
+}
+
+func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XStreamSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]XStream, n)
+ for i := 0; i < len(cmd.val); i++ {
+ i := i
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 2 {
+ return nil, fmt.Errorf("got %d, wanted 2", n)
+ }
+
+ stream, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, err := readXMessageSlice(rd)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val[i] = XStream{
+ Stream: stream,
+ Messages: msgs,
+ }
+ return nil, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type XPending struct {
+ Count int64
+ Lower string
+ Higher string
+ Consumers map[string]int64
+}
+
+type XPendingCmd struct {
+ baseCmd
+ val *XPending
+}
+
+var _ Cmder = (*XPendingCmd)(nil)
+
+func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
+ return &XPendingCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XPendingCmd) SetVal(val *XPending) {
+ cmd.val = val
+}
+
+func (cmd *XPendingCmd) Val() *XPending {
+ return cmd.val
+}
+
+func (cmd *XPendingCmd) Result() (*XPending, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XPendingCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 4 {
+ return nil, fmt.Errorf("got %d, wanted 4", n)
+ }
+
+ count, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ lower, err := rd.ReadString()
+ if err != nil && err != Nil {
+ return nil, err
+ }
+
+ higher, err := rd.ReadString()
+ if err != nil && err != Nil {
+ return nil, err
+ }
+
+ cmd.val = &XPending{
+ Count: count,
+ Lower: lower,
+ Higher: higher,
+ }
+ _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ for i := int64(0); i < n; i++ {
+ _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 2 {
+ return nil, fmt.Errorf("got %d, wanted 2", n)
+ }
+
+ consumerName, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ consumerPending, err := rd.ReadInt()
+ if err != nil {
+ return nil, err
+ }
+
+ if cmd.val.Consumers == nil {
+ cmd.val.Consumers = make(map[string]int64)
+ }
+ cmd.val.Consumers[consumerName] = consumerPending
+
+ return nil, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+ return nil, nil
+ })
+ if err != nil && err != Nil {
+ return nil, err
+ }
+
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type XPendingExt struct {
+ ID string
+ Consumer string
+ Idle time.Duration
+ RetryCount int64
+}
+
+type XPendingExtCmd struct {
+ baseCmd
+ val []XPendingExt
+}
+
+var _ Cmder = (*XPendingExtCmd)(nil)
+
+func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
+ return &XPendingExtCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) {
+ cmd.val = val
+}
+
+func (cmd *XPendingExtCmd) Val() []XPendingExt {
+ return cmd.val
+}
+
+func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XPendingExtCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]XPendingExt, 0, n)
+ for i := int64(0); i < n; i++ {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 4 {
+ return nil, fmt.Errorf("got %d, wanted 4", n)
+ }
+
+ id, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ consumer, err := rd.ReadString()
+ if err != nil && err != Nil {
+ return nil, err
+ }
+
+ idle, err := rd.ReadIntReply()
+ if err != nil && err != Nil {
+ return nil, err
+ }
+
+ retryCount, err := rd.ReadIntReply()
+ if err != nil && err != Nil {
+ return nil, err
+ }
+
+ cmd.val = append(cmd.val, XPendingExt{
+ ID: id,
+ Consumer: consumer,
+ Idle: time.Duration(idle) * time.Millisecond,
+ RetryCount: retryCount,
+ })
+ return nil, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type XAutoClaimCmd struct {
+ baseCmd
+
+ start string
+ val []XMessage
+}
+
+var _ Cmder = (*XAutoClaimCmd)(nil)
+
+func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoClaimCmd {
+ return &XAutoClaimCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) {
+ cmd.val = val
+ cmd.start = start
+}
+
+func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) {
+ return cmd.val, cmd.start
+}
+
+func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string, err error) {
+ return cmd.val, cmd.start, cmd.err
+}
+
+func (cmd *XAutoClaimCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 2 {
+ return nil, fmt.Errorf("got %d, wanted 2", n)
+ }
+ var err error
+
+ cmd.start, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val, err = readXMessageSlice(rd)
+ if err != nil {
+ return nil, err
+ }
+
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type XAutoClaimJustIDCmd struct {
+ baseCmd
+
+ start string
+ val []string
+}
+
+var _ Cmder = (*XAutoClaimJustIDCmd)(nil)
+
+func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *XAutoClaimJustIDCmd {
+ return &XAutoClaimJustIDCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) {
+ cmd.val = val
+ cmd.start = start
+}
+
+func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) {
+ return cmd.val, cmd.start
+}
+
+func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, err error) {
+ return cmd.val, cmd.start, cmd.err
+}
+
+func (cmd *XAutoClaimJustIDCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 2 {
+ return nil, fmt.Errorf("got %d, wanted 2", n)
+ }
+ var err error
+
+ cmd.start, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ nn, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val = make([]string, nn)
+ for i := 0; i < nn; i++ {
+ cmd.val[i], err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type XInfoConsumersCmd struct {
+ baseCmd
+ val []XInfoConsumer
+}
+
+type XInfoConsumer struct {
+ Name string
+ Pending int64
+ Idle int64
+}
+
+var _ Cmder = (*XInfoConsumersCmd)(nil)
+
+func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd {
+ return &XInfoConsumersCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: []interface{}{"xinfo", "consumers", stream, group},
+ },
+ }
+}
+
+func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) {
+ cmd.val = val
+}
+
+func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer {
+ return cmd.val
+}
+
+func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XInfoConsumersCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return err
+ }
+
+ cmd.val = make([]XInfoConsumer, n)
+
+ for i := 0; i < n; i++ {
+ cmd.val[i], err = readXConsumerInfo(rd)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func readXConsumerInfo(rd *proto.Reader) (XInfoConsumer, error) {
+ var consumer XInfoConsumer
+
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return consumer, err
+ }
+ if n != 6 {
+ return consumer, fmt.Errorf("redis: got %d elements in XINFO CONSUMERS reply, wanted 6", n)
+ }
+
+ for i := 0; i < 3; i++ {
+ key, err := rd.ReadString()
+ if err != nil {
+ return consumer, err
+ }
+
+ val, err := rd.ReadString()
+ if err != nil {
+ return consumer, err
+ }
+
+ switch key {
+ case "name":
+ consumer.Name = val
+ case "pending":
+ consumer.Pending, err = strconv.ParseInt(val, 0, 64)
+ if err != nil {
+ return consumer, err
+ }
+ case "idle":
+ consumer.Idle, err = strconv.ParseInt(val, 0, 64)
+ if err != nil {
+ return consumer, err
+ }
+ default:
+ return consumer, fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key)
+ }
+ }
+
+ return consumer, nil
+}
+
+//------------------------------------------------------------------------------
+
+type XInfoGroupsCmd struct {
+ baseCmd
+ val []XInfoGroup
+}
+
+type XInfoGroup struct {
+ Name string
+ Consumers int64
+ Pending int64
+ LastDeliveredID string
+}
+
+var _ Cmder = (*XInfoGroupsCmd)(nil)
+
+func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
+ return &XInfoGroupsCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: []interface{}{"xinfo", "groups", stream},
+ },
+ }
+}
+
+func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) {
+ cmd.val = val
+}
+
+func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
+ return cmd.val
+}
+
+func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XInfoGroupsCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return err
+ }
+
+ cmd.val = make([]XInfoGroup, n)
+
+ for i := 0; i < n; i++ {
+ cmd.val[i], err = readXGroupInfo(rd)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func readXGroupInfo(rd *proto.Reader) (XInfoGroup, error) {
+ var group XInfoGroup
+
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return group, err
+ }
+ if n != 8 {
+ return group, fmt.Errorf("redis: got %d elements in XINFO GROUPS reply, wanted 8", n)
+ }
+
+ for i := 0; i < 4; i++ {
+ key, err := rd.ReadString()
+ if err != nil {
+ return group, err
+ }
+
+ val, err := rd.ReadString()
+ if err != nil {
+ return group, err
+ }
+
+ switch key {
+ case "name":
+ group.Name = val
+ case "consumers":
+ group.Consumers, err = strconv.ParseInt(val, 0, 64)
+ if err != nil {
+ return group, err
+ }
+ case "pending":
+ group.Pending, err = strconv.ParseInt(val, 0, 64)
+ if err != nil {
+ return group, err
+ }
+ case "last-delivered-id":
+ group.LastDeliveredID = val
+ default:
+ return group, fmt.Errorf("redis: unexpected content %s in XINFO GROUPS reply", key)
+ }
+ }
+
+ return group, nil
+}
+
+//------------------------------------------------------------------------------
+
+type XInfoStreamCmd struct {
+ baseCmd
+ val *XInfoStream
+}
+
+type XInfoStream struct {
+ Length int64
+ RadixTreeKeys int64
+ RadixTreeNodes int64
+ Groups int64
+ LastGeneratedID string
+ FirstEntry XMessage
+ LastEntry XMessage
+}
+
+var _ Cmder = (*XInfoStreamCmd)(nil)
+
+func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
+ return &XInfoStreamCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: []interface{}{"xinfo", "stream", stream},
+ },
+ }
+}
+
+func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) {
+ cmd.val = val
+}
+
+func (cmd *XInfoStreamCmd) Val() *XInfoStream {
+ return cmd.val
+}
+
+func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XInfoStreamCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
+ v, err := rd.ReadReply(xStreamInfoParser)
+ if err != nil {
+ return err
+ }
+ cmd.val = v.(*XInfoStream)
+ return nil
+}
+
+func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 14 {
+ return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+
+ "wanted 14", n)
+ }
+ var info XInfoStream
+ for i := 0; i < 7; i++ {
+ key, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ switch key {
+ case "length":
+ info.Length, err = rd.ReadIntReply()
+ case "radix-tree-keys":
+ info.RadixTreeKeys, err = rd.ReadIntReply()
+ case "radix-tree-nodes":
+ info.RadixTreeNodes, err = rd.ReadIntReply()
+ case "groups":
+ info.Groups, err = rd.ReadIntReply()
+ case "last-generated-id":
+ info.LastGeneratedID, err = rd.ReadString()
+ case "first-entry":
+ info.FirstEntry, err = readXMessage(rd)
+ if err == Nil {
+ err = nil
+ }
+ case "last-entry":
+ info.LastEntry, err = readXMessage(rd)
+ if err == Nil {
+ err = nil
+ }
+ default:
+ return nil, fmt.Errorf("redis: unexpected content %s "+
+ "in XINFO STREAM reply", key)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &info, nil
+}
+
+//------------------------------------------------------------------------------
+
+type XInfoStreamFullCmd struct {
+ baseCmd
+ val *XInfoStreamFull
+}
+
+type XInfoStreamFull struct {
+ Length int64
+ RadixTreeKeys int64
+ RadixTreeNodes int64
+ LastGeneratedID string
+ Entries []XMessage
+ Groups []XInfoStreamGroup
+}
+
+type XInfoStreamGroup struct {
+ Name string
+ LastDeliveredID string
+ PelCount int64
+ Pending []XInfoStreamGroupPending
+ Consumers []XInfoStreamConsumer
+}
+
+type XInfoStreamGroupPending struct {
+ ID string
+ Consumer string
+ DeliveryTime time.Time
+ DeliveryCount int64
+}
+
+type XInfoStreamConsumer struct {
+ Name string
+ SeenTime time.Time
+ PelCount int64
+ Pending []XInfoStreamConsumerPending
+}
+
+type XInfoStreamConsumerPending struct {
+ ID string
+ DeliveryTime time.Time
+ DeliveryCount int64
+}
+
+var _ Cmder = (*XInfoStreamFullCmd)(nil)
+
+func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd {
+ return &XInfoStreamFullCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) {
+ cmd.val = val
+}
+
+func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull {
+ return cmd.val
+}
+
+func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *XInfoStreamFullCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return err
+ }
+ if n != 12 {
+ return fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
+ "wanted 12", n)
+ }
+
+ cmd.val = &XInfoStreamFull{}
+
+ for i := 0; i < 6; i++ {
+ key, err := rd.ReadString()
+ if err != nil {
+ return err
+ }
+
+ switch key {
+ case "length":
+ cmd.val.Length, err = rd.ReadIntReply()
+ case "radix-tree-keys":
+ cmd.val.RadixTreeKeys, err = rd.ReadIntReply()
+ case "radix-tree-nodes":
+ cmd.val.RadixTreeNodes, err = rd.ReadIntReply()
+ case "last-generated-id":
+ cmd.val.LastGeneratedID, err = rd.ReadString()
+ case "entries":
+ cmd.val.Entries, err = readXMessageSlice(rd)
+ case "groups":
+ cmd.val.Groups, err = readStreamGroups(rd)
+ default:
+ return fmt.Errorf("redis: unexpected content %s "+
+ "in XINFO STREAM reply", key)
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ groups := make([]XInfoStreamGroup, 0, n)
+ for i := 0; i < n; i++ {
+ nn, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if nn != 10 {
+ return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
+ "wanted 10", nn)
+ }
+
+ group := XInfoStreamGroup{}
+
+ for f := 0; f < 5; f++ {
+ key, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ switch key {
+ case "name":
+ group.Name, err = rd.ReadString()
+ case "last-delivered-id":
+ group.LastDeliveredID, err = rd.ReadString()
+ case "pel-count":
+ group.PelCount, err = rd.ReadIntReply()
+ case "pending":
+ group.Pending, err = readXInfoStreamGroupPending(rd)
+ case "consumers":
+ group.Consumers, err = readXInfoStreamConsumers(rd)
+ default:
+ return nil, fmt.Errorf("redis: unexpected content %s "+
+ "in XINFO STREAM reply", key)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ groups = append(groups, group)
+ }
+
+ return groups, nil
+}
+
+func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+
+ pending := make([]XInfoStreamGroupPending, 0, n)
+
+ for i := 0; i < n; i++ {
+ nn, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if nn != 4 {
+ return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
+ "wanted 4", nn)
+ }
+
+ p := XInfoStreamGroupPending{}
+
+ p.ID, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ p.Consumer, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ delivery, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
+
+ p.DeliveryCount, err = rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ pending = append(pending, p)
+ }
+
+ return pending, nil
+}
+
+func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+
+ consumers := make([]XInfoStreamConsumer, 0, n)
+
+ for i := 0; i < n; i++ {
+ nn, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if nn != 8 {
+ return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM FULL reply,"+
+ "wanted 8", nn)
+ }
+
+ c := XInfoStreamConsumer{}
+
+ for f := 0; f < 4; f++ {
+ cKey, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ switch cKey {
+ case "name":
+ c.Name, err = rd.ReadString()
+ case "seen-time":
+ seen, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ c.SeenTime = time.Unix(seen/1000, seen%1000*int64(time.Millisecond))
+ case "pel-count":
+ c.PelCount, err = rd.ReadIntReply()
+ case "pending":
+ pendingNumber, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+
+ c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber)
+
+ for pn := 0; pn < pendingNumber; pn++ {
+ nn, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if nn != 3 {
+ return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+
+ "wanted 3", nn)
+ }
+
+ p := XInfoStreamConsumerPending{}
+
+ p.ID, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ delivery, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
+
+ p.DeliveryCount, err = rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ c.Pending = append(c.Pending, p)
+ }
+ default:
+ return nil, fmt.Errorf("redis: unexpected content %s "+
+ "in XINFO STREAM reply", cKey)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ consumers = append(consumers, c)
+ }
+
+ return consumers, nil
+}
+
+//------------------------------------------------------------------------------
+
+type ZSliceCmd struct {
+ baseCmd
+
+ val []Z
+}
+
+var _ Cmder = (*ZSliceCmd)(nil)
+
+func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
+ return &ZSliceCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *ZSliceCmd) SetVal(val []Z) {
+ cmd.val = val
+}
+
+func (cmd *ZSliceCmd) Val() []Z {
+ return cmd.val
+}
+
+func (cmd *ZSliceCmd) Result() ([]Z, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *ZSliceCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]Z, n/2)
+ for i := 0; i < len(cmd.val); i++ {
+ member, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ score, err := rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val[i] = Z{
+ Member: member,
+ Score: score,
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type ZWithKeyCmd struct {
+ baseCmd
+
+ val *ZWithKey
+}
+
+var _ Cmder = (*ZWithKeyCmd)(nil)
+
+func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
+ return &ZWithKeyCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) {
+ cmd.val = val
+}
+
+func (cmd *ZWithKeyCmd) Val() *ZWithKey {
+ return cmd.val
+}
+
+func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *ZWithKeyCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ if n != 3 {
+ return nil, fmt.Errorf("got %d elements, expected 3", n)
+ }
+
+ cmd.val = &ZWithKey{}
+ var err error
+
+ cmd.val.Key, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val.Member, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val.Score, err = rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type ScanCmd struct {
+ baseCmd
+
+ page []string
+ cursor uint64
+
+ process cmdable
+}
+
+var _ Cmder = (*ScanCmd)(nil)
+
+func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
+ return &ScanCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ process: process,
+ }
+}
+
+func (cmd *ScanCmd) SetVal(page []string, cursor uint64) {
+ cmd.page = page
+ cmd.cursor = cursor
+}
+
+func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
+ return cmd.page, cmd.cursor
+}
+
+func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
+ return cmd.page, cmd.cursor, cmd.err
+}
+
+func (cmd *ScanCmd) String() string {
+ return cmdString(cmd, cmd.page)
+}
+
+func (cmd *ScanCmd) readReply(rd *proto.Reader) (err error) {
+ cmd.page, cmd.cursor, err = rd.ReadScanReply()
+ return err
+}
+
+// Iterator creates a new ScanIterator.
+func (cmd *ScanCmd) Iterator() *ScanIterator {
+ return &ScanIterator{
+ cmd: cmd,
+ }
+}
+
+//------------------------------------------------------------------------------
+
+type ClusterNode struct {
+ ID string
+ Addr string
+}
+
+type ClusterSlot struct {
+ Start int
+ End int
+ Nodes []ClusterNode
+}
+
+type ClusterSlotsCmd struct {
+ baseCmd
+
+ val []ClusterSlot
+}
+
+var _ Cmder = (*ClusterSlotsCmd)(nil)
+
+func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
+ return &ClusterSlotsCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) {
+ cmd.val = val
+}
+
+func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
+ return cmd.val
+}
+
+func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *ClusterSlotsCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]ClusterSlot, n)
+ for i := 0; i < len(cmd.val); i++ {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if n < 2 {
+ err := fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
+ return nil, err
+ }
+
+ start, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ end, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ nodes := make([]ClusterNode, n-2)
+ for j := 0; j < len(nodes); j++ {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if n != 2 && n != 3 {
+ err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3", n)
+ return nil, err
+ }
+
+ ip, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ port, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ nodes[j].Addr = net.JoinHostPort(ip, port)
+
+ if n == 3 {
+ id, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ nodes[j].ID = id
+ }
+ }
+
+ cmd.val[i] = ClusterSlot{
+ Start: int(start),
+ End: int(end),
+ Nodes: nodes,
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+// GeoLocation is used with GeoAdd to add geospatial location.
+type GeoLocation struct {
+ Name string
+ Longitude, Latitude, Dist float64
+ GeoHash int64
+}
+
+// GeoRadiusQuery is used with GeoRadius to query geospatial index.
+type GeoRadiusQuery struct {
+ Radius float64
+ // Can be m, km, ft, or mi. Default is km.
+ Unit string
+ WithCoord bool
+ WithDist bool
+ WithGeoHash bool
+ Count int
+ // Can be ASC or DESC. Default is no sort order.
+ Sort string
+ Store string
+ StoreDist string
+}
+
+type GeoLocationCmd struct {
+ baseCmd
+
+ q *GeoRadiusQuery
+ locations []GeoLocation
+}
+
+var _ Cmder = (*GeoLocationCmd)(nil)
+
+func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
+ return &GeoLocationCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: geoLocationArgs(q, args...),
+ },
+ q: q,
+ }
+}
+
+func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
+ args = append(args, q.Radius)
+ if q.Unit != "" {
+ args = append(args, q.Unit)
+ } else {
+ args = append(args, "km")
+ }
+ if q.WithCoord {
+ args = append(args, "withcoord")
+ }
+ if q.WithDist {
+ args = append(args, "withdist")
+ }
+ if q.WithGeoHash {
+ args = append(args, "withhash")
+ }
+ if q.Count > 0 {
+ args = append(args, "count", q.Count)
+ }
+ if q.Sort != "" {
+ args = append(args, q.Sort)
+ }
+ if q.Store != "" {
+ args = append(args, "store")
+ args = append(args, q.Store)
+ }
+ if q.StoreDist != "" {
+ args = append(args, "storedist")
+ args = append(args, q.StoreDist)
+ }
+ return args
+}
+
+func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) {
+ cmd.locations = locations
+}
+
+func (cmd *GeoLocationCmd) Val() []GeoLocation {
+ return cmd.locations
+}
+
+func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
+ return cmd.locations, cmd.err
+}
+
+func (cmd *GeoLocationCmd) String() string {
+ return cmdString(cmd, cmd.locations)
+}
+
+func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
+ v, err := rd.ReadArrayReply(newGeoLocationSliceParser(cmd.q))
+ if err != nil {
+ return err
+ }
+ cmd.locations = v.([]GeoLocation)
+ return nil
+}
+
+func newGeoLocationSliceParser(q *GeoRadiusQuery) proto.MultiBulkParse {
+ return func(rd *proto.Reader, n int64) (interface{}, error) {
+ locs := make([]GeoLocation, 0, n)
+ for i := int64(0); i < n; i++ {
+ v, err := rd.ReadReply(newGeoLocationParser(q))
+ if err != nil {
+ return nil, err
+ }
+ switch vv := v.(type) {
+ case string:
+ locs = append(locs, GeoLocation{
+ Name: vv,
+ })
+ case *GeoLocation:
+ // TODO: avoid copying
+ locs = append(locs, *vv)
+ default:
+ return nil, fmt.Errorf("got %T, expected string or *GeoLocation", v)
+ }
+ }
+ return locs, nil
+ }
+}
+
+func newGeoLocationParser(q *GeoRadiusQuery) proto.MultiBulkParse {
+ return func(rd *proto.Reader, n int64) (interface{}, error) {
+ var loc GeoLocation
+ var err error
+
+ loc.Name, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ if q.WithDist {
+ loc.Dist, err = rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if q.WithGeoHash {
+ loc.GeoHash, err = rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if q.WithCoord {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if n != 2 {
+ return nil, fmt.Errorf("got %d coordinates, expected 2", n)
+ }
+
+ loc.Longitude, err = rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+ loc.Latitude, err = rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return &loc, nil
+ }
+}
+
+//------------------------------------------------------------------------------
+
+// GeoSearchQuery is used for GEOSearch/GEOSearchStore command query.
+type GeoSearchQuery struct {
+ Member string
+
+ // Latitude and Longitude when using FromLonLat option.
+ Longitude float64
+ Latitude float64
+
+ // Distance and unit when using ByRadius option.
+ // Can use m, km, ft, or mi. Default is km.
+ Radius float64
+ RadiusUnit string
+
+ // Height, width and unit when using ByBox option.
+ // Can be m, km, ft, or mi. Default is km.
+ BoxWidth float64
+ BoxHeight float64
+ BoxUnit string
+
+ // Can be ASC or DESC. Default is no sort order.
+ Sort string
+ Count int
+ CountAny bool
+}
+
+type GeoSearchLocationQuery struct {
+ GeoSearchQuery
+
+ WithCoord bool
+ WithDist bool
+ WithHash bool
+}
+
+type GeoSearchStoreQuery struct {
+ GeoSearchQuery
+
+ // When using the StoreDist option, the command stores the items in a
+ // sorted set populated with their distance from the center of the circle or box,
+ // as a floating-point number, in the same unit specified for that shape.
+ StoreDist bool
+}
+
+func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}) []interface{} {
+ args = geoSearchArgs(&q.GeoSearchQuery, args)
+
+ if q.WithCoord {
+ args = append(args, "withcoord")
+ }
+ if q.WithDist {
+ args = append(args, "withdist")
+ }
+ if q.WithHash {
+ args = append(args, "withhash")
+ }
+
+ return args
+}
+
+func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} {
+ if q.Member != "" {
+ args = append(args, "frommember", q.Member)
+ } else {
+ args = append(args, "fromlonlat", q.Longitude, q.Latitude)
+ }
+
+ if q.Radius > 0 {
+ if q.RadiusUnit == "" {
+ q.RadiusUnit = "km"
+ }
+ args = append(args, "byradius", q.Radius, q.RadiusUnit)
+ } else {
+ if q.BoxUnit == "" {
+ q.BoxUnit = "km"
+ }
+ args = append(args, "bybox", q.BoxWidth, q.BoxHeight, q.BoxUnit)
+ }
+
+ if q.Sort != "" {
+ args = append(args, q.Sort)
+ }
+
+ if q.Count > 0 {
+ args = append(args, "count", q.Count)
+ if q.CountAny {
+ args = append(args, "any")
+ }
+ }
+
+ return args
+}
+
+type GeoSearchLocationCmd struct {
+ baseCmd
+
+ opt *GeoSearchLocationQuery
+ val []GeoLocation
+}
+
+var _ Cmder = (*GeoSearchLocationCmd)(nil)
+
+func NewGeoSearchLocationCmd(
+ ctx context.Context, opt *GeoSearchLocationQuery, args ...interface{},
+) *GeoSearchLocationCmd {
+ return &GeoSearchLocationCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ opt: opt,
+ }
+}
+
+func (cmd *GeoSearchLocationCmd) SetVal(val []GeoLocation) {
+ cmd.val = val
+}
+
+func (cmd *GeoSearchLocationCmd) Val() []GeoLocation {
+ return cmd.val
+}
+
+func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) {
+ return cmd.val, cmd.err
+}
+
+func (cmd *GeoSearchLocationCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return err
+ }
+
+ cmd.val = make([]GeoLocation, n)
+ for i := 0; i < n; i++ {
+ _, err = rd.ReadArrayLen()
+ if err != nil {
+ return err
+ }
+
+ var loc GeoLocation
+
+ loc.Name, err = rd.ReadString()
+ if err != nil {
+ return err
+ }
+ if cmd.opt.WithDist {
+ loc.Dist, err = rd.ReadFloatReply()
+ if err != nil {
+ return err
+ }
+ }
+ if cmd.opt.WithHash {
+ loc.GeoHash, err = rd.ReadIntReply()
+ if err != nil {
+ return err
+ }
+ }
+ if cmd.opt.WithCoord {
+ nn, err := rd.ReadArrayLen()
+ if err != nil {
+ return err
+ }
+ if nn != 2 {
+ return fmt.Errorf("got %d coordinates, expected 2", nn)
+ }
+
+ loc.Longitude, err = rd.ReadFloatReply()
+ if err != nil {
+ return err
+ }
+ loc.Latitude, err = rd.ReadFloatReply()
+ if err != nil {
+ return err
+ }
+ }
+
+ cmd.val[i] = loc
+ }
+
+ return nil
+}
+
+//------------------------------------------------------------------------------
+
+type GeoPos struct {
+ Longitude, Latitude float64
+}
+
+type GeoPosCmd struct {
+ baseCmd
+
+ val []*GeoPos
+}
+
+var _ Cmder = (*GeoPosCmd)(nil)
+
+func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
+ return &GeoPosCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *GeoPosCmd) SetVal(val []*GeoPos) {
+ cmd.val = val
+}
+
+func (cmd *GeoPosCmd) Val() []*GeoPos {
+ return cmd.val
+}
+
+func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *GeoPosCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]*GeoPos, n)
+ for i := 0; i < len(cmd.val); i++ {
+ i := i
+ _, err := rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ longitude, err := rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+
+ latitude, err := rd.ReadFloatReply()
+ if err != nil {
+ return nil, err
+ }
+
+ cmd.val[i] = &GeoPos{
+ Longitude: longitude,
+ Latitude: latitude,
+ }
+ return nil, nil
+ })
+ if err != nil {
+ if err == Nil {
+ cmd.val[i] = nil
+ continue
+ }
+ return nil, err
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
+
+//------------------------------------------------------------------------------
+
+type CommandInfo struct {
+ Name string
+ Arity int8
+ Flags []string
+ ACLFlags []string
+ FirstKeyPos int8
+ LastKeyPos int8
+ StepCount int8
+ ReadOnly bool
+}
+
+type CommandsInfoCmd struct {
+ baseCmd
+
+ val map[string]*CommandInfo
+}
+
+var _ Cmder = (*CommandsInfoCmd)(nil)
+
+func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
+ return &CommandsInfoCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) {
+ cmd.val = val
+}
+
+func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
+ return cmd.val
+}
+
+func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *CommandsInfoCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make(map[string]*CommandInfo, n)
+ for i := int64(0); i < n; i++ {
+ v, err := rd.ReadReply(commandInfoParser)
+ if err != nil {
+ return nil, err
+ }
+ vv := v.(*CommandInfo)
+ cmd.val[vv.Name] = vv
+ }
+ return nil, nil
+ })
+ return err
+}
+
+func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
+ const numArgRedis5 = 6
+ const numArgRedis6 = 7
+
+ switch n {
+ case numArgRedis5, numArgRedis6:
+ // continue
+ default:
+ return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 7", n)
+ }
+
+ var cmd CommandInfo
+ var err error
+
+ cmd.Name, err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+
+ arity, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ cmd.Arity = int8(arity)
+
+ _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.Flags = make([]string, n)
+ for i := 0; i < len(cmd.Flags); i++ {
+ switch s, err := rd.ReadString(); {
+ case err == Nil:
+ cmd.Flags[i] = ""
+ case err != nil:
+ return nil, err
+ default:
+ cmd.Flags[i] = s
+ }
+ }
+ return nil, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ firstKeyPos, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ cmd.FirstKeyPos = int8(firstKeyPos)
+
+ lastKeyPos, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ cmd.LastKeyPos = int8(lastKeyPos)
+
+ stepCount, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ cmd.StepCount = int8(stepCount)
+
+ for _, flag := range cmd.Flags {
+ if flag == "readonly" {
+ cmd.ReadOnly = true
+ break
+ }
+ }
+
+ if n == numArgRedis5 {
+ return &cmd, nil
+ }
+
+ _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.ACLFlags = make([]string, n)
+ for i := 0; i < len(cmd.ACLFlags); i++ {
+ switch s, err := rd.ReadString(); {
+ case err == Nil:
+ cmd.ACLFlags[i] = ""
+ case err != nil:
+ return nil, err
+ default:
+ cmd.ACLFlags[i] = s
+ }
+ }
+ return nil, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return &cmd, nil
+}
+
+//------------------------------------------------------------------------------
+
+type cmdsInfoCache struct {
+ fn func(ctx context.Context) (map[string]*CommandInfo, error)
+
+ once internal.Once
+ cmds map[string]*CommandInfo
+}
+
+func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
+ return &cmdsInfoCache{
+ fn: fn,
+ }
+}
+
+func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
+ err := c.once.Do(func() error {
+ cmds, err := c.fn(ctx)
+ if err != nil {
+ return err
+ }
+
+ // Extensions have cmd names in upper case. Convert them to lower case.
+ for k, v := range cmds {
+ lower := internal.ToLower(k)
+ if lower != k {
+ cmds[lower] = v
+ }
+ }
+
+ c.cmds = cmds
+ return nil
+ })
+ return c.cmds, err
+}
+
+//------------------------------------------------------------------------------
+
+type SlowLog struct {
+ ID int64
+ Time time.Time
+ Duration time.Duration
+ Args []string
+ // These are also optional fields emitted only by Redis 4.0 or greater:
+ // https://redis.io/commands/slowlog#output-format
+ ClientAddr string
+ ClientName string
+}
+
+type SlowLogCmd struct {
+ baseCmd
+
+ val []SlowLog
+}
+
+var _ Cmder = (*SlowLogCmd)(nil)
+
+func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
+ return &SlowLogCmd{
+ baseCmd: baseCmd{
+ ctx: ctx,
+ args: args,
+ },
+ }
+}
+
+func (cmd *SlowLogCmd) SetVal(val []SlowLog) {
+ cmd.val = val
+}
+
+func (cmd *SlowLogCmd) Val() []SlowLog {
+ return cmd.val
+}
+
+func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
+ return cmd.Val(), cmd.Err()
+}
+
+func (cmd *SlowLogCmd) String() string {
+ return cmdString(cmd, cmd.val)
+}
+
+func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
+ _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
+ cmd.val = make([]SlowLog, n)
+ for i := 0; i < len(cmd.val); i++ {
+ n, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if n < 4 {
+ err := fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", n)
+ return nil, err
+ }
+
+ id, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+
+ createdAt, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ createdAtTime := time.Unix(createdAt, 0)
+
+ costs, err := rd.ReadIntReply()
+ if err != nil {
+ return nil, err
+ }
+ costsDuration := time.Duration(costs) * time.Microsecond
+
+ cmdLen, err := rd.ReadArrayLen()
+ if err != nil {
+ return nil, err
+ }
+ if cmdLen < 1 {
+ err := fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
+ return nil, err
+ }
+
+ cmdString := make([]string, cmdLen)
+ for i := 0; i < cmdLen; i++ {
+ cmdString[i], err = rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ var address, name string
+ for i := 4; i < n; i++ {
+ str, err := rd.ReadString()
+ if err != nil {
+ return nil, err
+ }
+ if i == 4 {
+ address = str
+ } else if i == 5 {
+ name = str
+ }
+ }
+
+ cmd.val[i] = SlowLog{
+ ID: id,
+ Time: createdAtTime,
+ Duration: costsDuration,
+ Args: cmdString,
+ ClientAddr: address,
+ ClientName: name,
+ }
+ }
+ return nil, nil
+ })
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/commands.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/commands.go
new file mode 100644
index 000000000000..bbfe089df166
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/commands.go
@@ -0,0 +1,3475 @@
+package redis
+
+import (
+ "context"
+ "errors"
+ "io"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+)
+
+// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
+// otherwise you will receive an error: (error) ERR syntax error.
+// For example:
+//
+// rdb.Set(ctx, key, value, redis.KeepTTL)
+const KeepTTL = -1
+
+func usePrecise(dur time.Duration) bool {
+ return dur < time.Second || dur%time.Second != 0
+}
+
+func formatMs(ctx context.Context, dur time.Duration) int64 {
+ if dur > 0 && dur < time.Millisecond {
+ internal.Logger.Printf(
+ ctx,
+ "specified duration is %s, but minimal supported value is %s - truncating to 1ms",
+ dur, time.Millisecond,
+ )
+ return 1
+ }
+ return int64(dur / time.Millisecond)
+}
+
+func formatSec(ctx context.Context, dur time.Duration) int64 {
+ if dur > 0 && dur < time.Second {
+ internal.Logger.Printf(
+ ctx,
+ "specified duration is %s, but minimal supported value is %s - truncating to 1s",
+ dur, time.Second,
+ )
+ return 1
+ }
+ return int64(dur / time.Second)
+}
+
+func appendArgs(dst, src []interface{}) []interface{} {
+ if len(src) == 1 {
+ return appendArg(dst, src[0])
+ }
+
+ dst = append(dst, src...)
+ return dst
+}
+
+func appendArg(dst []interface{}, arg interface{}) []interface{} {
+ switch arg := arg.(type) {
+ case []string:
+ for _, s := range arg {
+ dst = append(dst, s)
+ }
+ return dst
+ case []interface{}:
+ dst = append(dst, arg...)
+ return dst
+ case map[string]interface{}:
+ for k, v := range arg {
+ dst = append(dst, k, v)
+ }
+ return dst
+ case map[string]string:
+ for k, v := range arg {
+ dst = append(dst, k, v)
+ }
+ return dst
+ default:
+ return append(dst, arg)
+ }
+}
+
+type Cmdable interface {
+ Pipeline() Pipeliner
+ Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
+
+ TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
+ TxPipeline() Pipeliner
+
+ Command(ctx context.Context) *CommandsInfoCmd
+ ClientGetName(ctx context.Context) *StringCmd
+ Echo(ctx context.Context, message interface{}) *StringCmd
+ Ping(ctx context.Context) *StatusCmd
+ Quit(ctx context.Context) *StatusCmd
+ Del(ctx context.Context, keys ...string) *IntCmd
+ Unlink(ctx context.Context, keys ...string) *IntCmd
+ Dump(ctx context.Context, key string) *StringCmd
+ Exists(ctx context.Context, keys ...string) *IntCmd
+ Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
+ ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
+ ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
+ ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
+ ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
+ ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
+ Keys(ctx context.Context, pattern string) *StringSliceCmd
+ Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd
+ Move(ctx context.Context, key string, db int) *BoolCmd
+ ObjectRefCount(ctx context.Context, key string) *IntCmd
+ ObjectEncoding(ctx context.Context, key string) *StringCmd
+ ObjectIdleTime(ctx context.Context, key string) *DurationCmd
+ Persist(ctx context.Context, key string) *BoolCmd
+ PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
+ PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
+ PTTL(ctx context.Context, key string) *DurationCmd
+ RandomKey(ctx context.Context) *StringCmd
+ Rename(ctx context.Context, key, newkey string) *StatusCmd
+ RenameNX(ctx context.Context, key, newkey string) *BoolCmd
+ Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
+ RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
+ Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd
+ SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd
+ SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd
+ Touch(ctx context.Context, keys ...string) *IntCmd
+ TTL(ctx context.Context, key string) *DurationCmd
+ Type(ctx context.Context, key string) *StatusCmd
+ Append(ctx context.Context, key, value string) *IntCmd
+ Decr(ctx context.Context, key string) *IntCmd
+ DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
+ Get(ctx context.Context, key string) *StringCmd
+ GetRange(ctx context.Context, key string, start, end int64) *StringCmd
+ GetSet(ctx context.Context, key string, value interface{}) *StringCmd
+ GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd
+ GetDel(ctx context.Context, key string) *StringCmd
+ Incr(ctx context.Context, key string) *IntCmd
+ IncrBy(ctx context.Context, key string, value int64) *IntCmd
+ IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
+ MGet(ctx context.Context, keys ...string) *SliceCmd
+ MSet(ctx context.Context, values ...interface{}) *StatusCmd
+ MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
+ Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
+ SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd
+ // TODO: rename to SetEx
+ SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
+ SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
+ SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
+ SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
+ StrLen(ctx context.Context, key string) *IntCmd
+ Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *IntCmd
+
+ GetBit(ctx context.Context, key string, offset int64) *IntCmd
+ SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
+ BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
+ BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
+ BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
+ BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
+ BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
+ BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
+ BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd
+
+ Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd
+ ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd
+ SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
+ HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
+ ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
+
+ HDel(ctx context.Context, key string, fields ...string) *IntCmd
+ HExists(ctx context.Context, key, field string) *BoolCmd
+ HGet(ctx context.Context, key, field string) *StringCmd
+ HGetAll(ctx context.Context, key string) *StringStringMapCmd
+ HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
+ HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
+ HKeys(ctx context.Context, key string) *StringSliceCmd
+ HLen(ctx context.Context, key string) *IntCmd
+ HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
+ HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
+ HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
+ HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
+ HVals(ctx context.Context, key string) *StringSliceCmd
+ HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd
+
+ BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
+ BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
+ BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd
+ LIndex(ctx context.Context, key string, index int64) *StringCmd
+ LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd
+ LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd
+ LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd
+ LLen(ctx context.Context, key string) *IntCmd
+ LPop(ctx context.Context, key string) *StringCmd
+ LPopCount(ctx context.Context, key string, count int) *StringSliceCmd
+ LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd
+ LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd
+ LPush(ctx context.Context, key string, values ...interface{}) *IntCmd
+ LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
+ LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
+ LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
+ LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd
+ LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd
+ RPop(ctx context.Context, key string) *StringCmd
+ RPopCount(ctx context.Context, key string, count int) *StringSliceCmd
+ RPopLPush(ctx context.Context, source, destination string) *StringCmd
+ RPush(ctx context.Context, key string, values ...interface{}) *IntCmd
+ RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
+ LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd
+ BLMove(ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration) *StringCmd
+
+ SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
+ SCard(ctx context.Context, key string) *IntCmd
+ SDiff(ctx context.Context, keys ...string) *StringSliceCmd
+ SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
+ SInter(ctx context.Context, keys ...string) *StringSliceCmd
+ SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd
+ SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd
+ SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd
+ SMembers(ctx context.Context, key string) *StringSliceCmd
+ SMembersMap(ctx context.Context, key string) *StringStructMapCmd
+ SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd
+ SPop(ctx context.Context, key string) *StringCmd
+ SPopN(ctx context.Context, key string, count int64) *StringSliceCmd
+ SRandMember(ctx context.Context, key string) *StringCmd
+ SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd
+ SRem(ctx context.Context, key string, members ...interface{}) *IntCmd
+ SUnion(ctx context.Context, keys ...string) *StringSliceCmd
+ SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
+
+ XAdd(ctx context.Context, a *XAddArgs) *StringCmd
+ XDel(ctx context.Context, stream string, ids ...string) *IntCmd
+ XLen(ctx context.Context, stream string) *IntCmd
+ XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
+ XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
+ XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
+ XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
+ XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
+ XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
+ XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
+ XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
+ XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
+ XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
+ XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
+ XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
+ XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
+ XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
+ XPending(ctx context.Context, stream, group string) *XPendingCmd
+ XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
+ XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
+ XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
+ XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd
+ XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd
+
+ // TODO: XTrim and XTrimApprox remove in v9.
+ XTrim(ctx context.Context, key string, maxLen int64) *IntCmd
+ XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd
+ XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd
+ XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd
+ XTrimMinID(ctx context.Context, key string, minID string) *IntCmd
+ XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd
+ XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
+ XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
+ XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd
+ XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd
+
+ BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
+ BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
+
+ // TODO: remove
+ // ZAddCh
+ // ZIncr
+ // ZAddNXCh
+ // ZAddXXCh
+ // ZIncrNX
+ // ZIncrXX
+ // in v9.
+ // use ZAddArgs and ZAddArgsIncr.
+
+ ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd
+ ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd
+ ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd
+ ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd
+ ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd
+ ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd
+ ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd
+ ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd
+ ZIncr(ctx context.Context, key string, member *Z) *FloatCmd
+ ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd
+ ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd
+ ZCard(ctx context.Context, key string) *IntCmd
+ ZCount(ctx context.Context, key, min, max string) *IntCmd
+ ZLexCount(ctx context.Context, key, min, max string) *IntCmd
+ ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
+ ZInter(ctx context.Context, store *ZStore) *StringSliceCmd
+ ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
+ ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
+ ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
+ ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
+ ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
+ ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
+ ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
+ ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
+ ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
+ ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
+ ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd
+ ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd
+ ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd
+ ZRank(ctx context.Context, key, member string) *IntCmd
+ ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
+ ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
+ ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
+ ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
+ ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
+ ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
+ ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
+ ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
+ ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
+ ZRevRank(ctx context.Context, key, member string) *IntCmd
+ ZScore(ctx context.Context, key, member string) *FloatCmd
+ ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
+ ZUnion(ctx context.Context, store ZStore) *StringSliceCmd
+ ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd
+ ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd
+ ZDiff(ctx context.Context, keys ...string) *StringSliceCmd
+ ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd
+ ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
+
+ PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd
+ PFCount(ctx context.Context, keys ...string) *IntCmd
+ PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd
+
+ BgRewriteAOF(ctx context.Context) *StatusCmd
+ BgSave(ctx context.Context) *StatusCmd
+ ClientKill(ctx context.Context, ipPort string) *StatusCmd
+ ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd
+ ClientList(ctx context.Context) *StringCmd
+ ClientPause(ctx context.Context, dur time.Duration) *BoolCmd
+ ClientID(ctx context.Context) *IntCmd
+ ConfigGet(ctx context.Context, parameter string) *SliceCmd
+ ConfigResetStat(ctx context.Context) *StatusCmd
+ ConfigSet(ctx context.Context, parameter, value string) *StatusCmd
+ ConfigRewrite(ctx context.Context) *StatusCmd
+ DBSize(ctx context.Context) *IntCmd
+ FlushAll(ctx context.Context) *StatusCmd
+ FlushAllAsync(ctx context.Context) *StatusCmd
+ FlushDB(ctx context.Context) *StatusCmd
+ FlushDBAsync(ctx context.Context) *StatusCmd
+ Info(ctx context.Context, section ...string) *StringCmd
+ LastSave(ctx context.Context) *IntCmd
+ Save(ctx context.Context) *StatusCmd
+ Shutdown(ctx context.Context) *StatusCmd
+ ShutdownSave(ctx context.Context) *StatusCmd
+ ShutdownNoSave(ctx context.Context) *StatusCmd
+ SlaveOf(ctx context.Context, host, port string) *StatusCmd
+ Time(ctx context.Context) *TimeCmd
+ DebugObject(ctx context.Context, key string) *StringCmd
+ ReadOnly(ctx context.Context) *StatusCmd
+ ReadWrite(ctx context.Context) *StatusCmd
+ MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd
+
+ Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
+ EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
+ ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
+ ScriptFlush(ctx context.Context) *StatusCmd
+ ScriptKill(ctx context.Context) *StatusCmd
+ ScriptLoad(ctx context.Context, script string) *StringCmd
+
+ Publish(ctx context.Context, channel string, message interface{}) *IntCmd
+ PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd
+ PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd
+ PubSubNumPat(ctx context.Context) *IntCmd
+
+ ClusterSlots(ctx context.Context) *ClusterSlotsCmd
+ ClusterNodes(ctx context.Context) *StringCmd
+ ClusterMeet(ctx context.Context, host, port string) *StatusCmd
+ ClusterForget(ctx context.Context, nodeID string) *StatusCmd
+ ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
+ ClusterResetSoft(ctx context.Context) *StatusCmd
+ ClusterResetHard(ctx context.Context) *StatusCmd
+ ClusterInfo(ctx context.Context) *StringCmd
+ ClusterKeySlot(ctx context.Context, key string) *IntCmd
+ ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
+ ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
+ ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
+ ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
+ ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
+ ClusterSaveConfig(ctx context.Context) *StatusCmd
+ ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
+ ClusterFailover(ctx context.Context) *StatusCmd
+ ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
+ ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
+
+ GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd
+ GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd
+ GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd
+ GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd
+ GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd
+ GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd
+ GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd
+ GeoSearchLocation(ctx context.Context, key string, q *GeoSearchLocationQuery) *GeoSearchLocationCmd
+ GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd
+ GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd
+ GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd
+}
+
+type StatefulCmdable interface {
+ Cmdable
+ Auth(ctx context.Context, password string) *StatusCmd
+ AuthACL(ctx context.Context, username, password string) *StatusCmd
+ Select(ctx context.Context, index int) *StatusCmd
+ SwapDB(ctx context.Context, index1, index2 int) *StatusCmd
+ ClientSetName(ctx context.Context, name string) *BoolCmd
+}
+
+var (
+ _ Cmdable = (*Client)(nil)
+ _ Cmdable = (*Tx)(nil)
+ _ Cmdable = (*Ring)(nil)
+ _ Cmdable = (*ClusterClient)(nil)
+)
+
+type cmdable func(ctx context.Context, cmd Cmder) error
+
+type statefulCmdable func(ctx context.Context, cmd Cmder) error
+
+//------------------------------------------------------------------------------
+
+func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "auth", password)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// AuthACL Perform an AUTH command, using the given user and pass.
+// Should be used to authenticate the current connection with one of the connections defined in the ACL list
+// when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
+func (c statefulCmdable) AuthACL(ctx context.Context, username, password string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "auth", username, password)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd {
+ cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond))
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "select", index)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "swapdb", index1, index2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ClientSetName assigns a name to the connection.
+func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "client", "setname", name)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
+ cmd := NewCommandsInfoCmd(ctx, "command")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ClientGetName returns the name of the connection.
+func (c cmdable) ClientGetName(ctx context.Context) *StringCmd {
+ cmd := NewStringCmd(ctx, "client", "getname")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd {
+ cmd := NewStringCmd(ctx, "echo", message)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Ping(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "ping")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Quit(_ context.Context) *StatusCmd {
+ panic("not implemented")
+}
+
+func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "del"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "unlink"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "dump", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "exists"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
+ return c.expire(ctx, key, expiration, "")
+}
+
+func (c cmdable) ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
+ return c.expire(ctx, key, expiration, "NX")
+}
+
+func (c cmdable) ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
+ return c.expire(ctx, key, expiration, "XX")
+}
+
+func (c cmdable) ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
+ return c.expire(ctx, key, expiration, "GT")
+}
+
+func (c cmdable) ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
+ return c.expire(ctx, key, expiration, "LT")
+}
+
+func (c cmdable) expire(
+ ctx context.Context, key string, expiration time.Duration, mode string,
+) *BoolCmd {
+ args := make([]interface{}, 3, 4)
+ args[0] = "expire"
+ args[1] = key
+ args[2] = formatSec(ctx, expiration)
+ if mode != "" {
+ args = append(args, mode)
+ }
+
+ cmd := NewBoolCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix())
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "keys", pattern)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd {
+ cmd := NewStatusCmd(
+ ctx,
+ "migrate",
+ host,
+ port,
+ key,
+ db,
+ formatMs(ctx, timeout),
+ )
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "move", key, db)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "object", "refcount", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "object", "encoding", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd {
+ cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "persist", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration))
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
+ cmd := NewBoolCmd(
+ ctx,
+ "pexpireat",
+ key,
+ tm.UnixNano()/int64(time.Millisecond),
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
+ cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
+ cmd := NewStringCmd(ctx, "randomkey")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "rename", key, newkey)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "renamenx", key, newkey)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
+ cmd := NewStatusCmd(
+ ctx,
+ "restore",
+ key,
+ formatMs(ctx, ttl),
+ value,
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
+ cmd := NewStatusCmd(
+ ctx,
+ "restore",
+ key,
+ formatMs(ctx, ttl),
+ value,
+ "replace",
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type Sort struct {
+ By string
+ Offset, Count int64
+ Get []string
+ Order string
+ Alpha bool
+}
+
+func (sort *Sort) args(key string) []interface{} {
+ args := []interface{}{"sort", key}
+ if sort.By != "" {
+ args = append(args, "by", sort.By)
+ }
+ if sort.Offset != 0 || sort.Count != 0 {
+ args = append(args, "limit", sort.Offset, sort.Count)
+ }
+ for _, get := range sort.Get {
+ args = append(args, "get", get)
+ }
+ if sort.Order != "" {
+ args = append(args, sort.Order)
+ }
+ if sort.Alpha {
+ args = append(args, "alpha")
+ }
+ return args
+}
+
+func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, sort.args(key)...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd {
+ args := sort.args(key)
+ if store != "" {
+ args = append(args, "store", store)
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd {
+ cmd := NewSliceCmd(ctx, sort.args(key)...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
+ args := make([]interface{}, len(keys)+1)
+ args[0] = "touch"
+ for i, key := range keys {
+ args[i+1] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
+ cmd := NewDurationCmd(ctx, time.Second, "ttl", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "type", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
+ cmd := NewIntCmd(ctx, "append", key, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "decr", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
+ cmd := NewIntCmd(ctx, "decrby", key, decrement)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// Get Redis `GET key` command. It returns redis.Nil error when key does not exist.
+func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "get", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
+ cmd := NewStringCmd(ctx, "getrange", key, start, end)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
+ cmd := NewStringCmd(ctx, "getset", key, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist).
+// Requires Redis >= 6.2.0.
+func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd {
+ args := make([]interface{}, 0, 4)
+ args = append(args, "getex", key)
+ if expiration > 0 {
+ if usePrecise(expiration) {
+ args = append(args, "px", formatMs(ctx, expiration))
+ } else {
+ args = append(args, "ex", formatSec(ctx, expiration))
+ }
+ } else if expiration == 0 {
+ args = append(args, "persist")
+ }
+
+ cmd := NewStringCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// GetDel redis-server version >= 6.2.0.
+func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "getdel", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "incr", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
+ cmd := NewIntCmd(ctx, "incrby", key, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
+ cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "mget"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// MSet is like Set but accepts multiple values:
+// - MSet("key1", "value1", "key2", "value2")
+// - MSet([]string{"key1", "value1", "key2", "value2"})
+// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
+func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
+ args := make([]interface{}, 1, 1+len(values))
+ args[0] = "mset"
+ args = appendArgs(args, values)
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// MSetNX is like SetNX but accepts multiple values:
+// - MSetNX("key1", "value1", "key2", "value2")
+// - MSetNX([]string{"key1", "value1", "key2", "value2"})
+// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
+func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
+ args := make([]interface{}, 1, 1+len(values))
+ args[0] = "msetnx"
+ args = appendArgs(args, values)
+ cmd := NewBoolCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// Set Redis `SET key value [expiration]` command.
+// Use expiration for `SETEX`-like behavior.
+//
+// Zero expiration means the key has no expiration time.
+// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
+// otherwise you will receive an error: (error) ERR syntax error.
+func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
+ args := make([]interface{}, 3, 5)
+ args[0] = "set"
+ args[1] = key
+ args[2] = value
+ if expiration > 0 {
+ if usePrecise(expiration) {
+ args = append(args, "px", formatMs(ctx, expiration))
+ } else {
+ args = append(args, "ex", formatSec(ctx, expiration))
+ }
+ } else if expiration == KeepTTL {
+ args = append(args, "keepttl")
+ }
+
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SetArgs provides arguments for the SetArgs function.
+type SetArgs struct {
+ // Mode can be `NX` or `XX` or empty.
+ Mode string
+
+ // Zero `TTL` or `Expiration` means that the key has no expiration time.
+ TTL time.Duration
+ ExpireAt time.Time
+
+ // When Get is true, the command returns the old value stored at key, or nil when key did not exist.
+ Get bool
+
+ // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
+ // otherwise you will receive an error: (error) ERR syntax error.
+ KeepTTL bool
+}
+
+// SetArgs supports all the options that the SET command supports.
+// It is the alternative to the Set function when you want
+// to have more control over the options.
+func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd {
+ args := []interface{}{"set", key, value}
+
+ if a.KeepTTL {
+ args = append(args, "keepttl")
+ }
+
+ if !a.ExpireAt.IsZero() {
+ args = append(args, "exat", a.ExpireAt.Unix())
+ }
+ if a.TTL > 0 {
+ if usePrecise(a.TTL) {
+ args = append(args, "px", formatMs(ctx, a.TTL))
+ } else {
+ args = append(args, "ex", formatSec(ctx, a.TTL))
+ }
+ }
+
+ if a.Mode != "" {
+ args = append(args, a.Mode)
+ }
+
+ if a.Get {
+ args = append(args, "get")
+ }
+
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SetEX Redis `SETEX key expiration value` command.
+func (c cmdable) SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SetNX Redis `SET key value [expiration] NX` command.
+//
+// Zero expiration means the key has no expiration time.
+// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
+// otherwise you will receive an error: (error) ERR syntax error.
+func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
+ var cmd *BoolCmd
+ switch expiration {
+ case 0:
+ // Use old `SETNX` to support old Redis versions.
+ cmd = NewBoolCmd(ctx, "setnx", key, value)
+ case KeepTTL:
+ cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
+ default:
+ if usePrecise(expiration) {
+ cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
+ } else {
+ cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
+ }
+ }
+
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SetXX Redis `SET key value [expiration] XX` command.
+//
+// Zero expiration means the key has no expiration time.
+// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
+// otherwise you will receive an error: (error) ERR syntax error.
+func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
+ var cmd *BoolCmd
+ switch expiration {
+ case 0:
+ cmd = NewBoolCmd(ctx, "set", key, value, "xx")
+ case KeepTTL:
+ cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
+ default:
+ if usePrecise(expiration) {
+ cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
+ } else {
+ cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
+ }
+ }
+
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
+ cmd := NewIntCmd(ctx, "setrange", key, offset, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "strlen", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Copy(ctx context.Context, sourceKey, destKey string, db int, replace bool) *IntCmd {
+ args := []interface{}{"copy", sourceKey, destKey, "DB", db}
+ if replace {
+ args = append(args, "REPLACE")
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
+ cmd := NewIntCmd(ctx, "getbit", key, offset)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
+ cmd := NewIntCmd(
+ ctx,
+ "setbit",
+ key,
+ offset,
+ value,
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type BitCount struct {
+ Start, End int64
+}
+
+func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
+ args := []interface{}{"bitcount", key}
+ if bitCount != nil {
+ args = append(
+ args,
+ bitCount.Start,
+ bitCount.End,
+ )
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
+ args := make([]interface{}, 3+len(keys))
+ args[0] = "bitop"
+ args[1] = op
+ args[2] = destKey
+ for i, key := range keys {
+ args[3+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
+ return c.bitOp(ctx, "and", destKey, keys...)
+}
+
+func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
+ return c.bitOp(ctx, "or", destKey, keys...)
+}
+
+func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
+ return c.bitOp(ctx, "xor", destKey, keys...)
+}
+
+func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
+ return c.bitOp(ctx, "not", destKey, key)
+}
+
+func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
+ args := make([]interface{}, 3+len(pos))
+ args[0] = "bitpos"
+ args[1] = key
+ args[2] = bit
+ switch len(pos) {
+ case 0:
+ case 1:
+ args[3] = pos[0]
+ case 2:
+ args[3] = pos[0]
+ args[4] = pos[1]
+ default:
+ panic("too many arguments")
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd {
+ a := make([]interface{}, 0, 2+len(args))
+ a = append(a, "bitfield")
+ a = append(a, key)
+ a = append(a, args...)
+ cmd := NewIntSliceCmd(ctx, a...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {
+ args := []interface{}{"scan", cursor}
+ if match != "" {
+ args = append(args, "match", match)
+ }
+ if count > 0 {
+ args = append(args, "count", count)
+ }
+ cmd := NewScanCmd(ctx, c, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd {
+ args := []interface{}{"scan", cursor}
+ if match != "" {
+ args = append(args, "match", match)
+ }
+ if count > 0 {
+ args = append(args, "count", count)
+ }
+ if keyType != "" {
+ args = append(args, "type", keyType)
+ }
+ cmd := NewScanCmd(ctx, c, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
+ args := []interface{}{"sscan", key, cursor}
+ if match != "" {
+ args = append(args, "match", match)
+ }
+ if count > 0 {
+ args = append(args, "count", count)
+ }
+ cmd := NewScanCmd(ctx, c, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
+ args := []interface{}{"hscan", key, cursor}
+ if match != "" {
+ args = append(args, "match", match)
+ }
+ if count > 0 {
+ args = append(args, "count", count)
+ }
+ cmd := NewScanCmd(ctx, c, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
+ args := []interface{}{"zscan", key, cursor}
+ if match != "" {
+ args = append(args, "match", match)
+ }
+ if count > 0 {
+ args = append(args, "count", count)
+ }
+ cmd := NewScanCmd(ctx, c, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
+ args := make([]interface{}, 2+len(fields))
+ args[0] = "hdel"
+ args[1] = key
+ for i, field := range fields {
+ args[2+i] = field
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "hexists", key, field)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
+ cmd := NewStringCmd(ctx, "hget", key, field)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HGetAll(ctx context.Context, key string) *StringStringMapCmd {
+ cmd := NewStringStringMapCmd(ctx, "hgetall", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
+ cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
+ cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "hkeys", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "hlen", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// HMGet returns the values for the specified fields in the hash stored at key.
+// It returns an interface{} to distinguish between empty string and nil value.
+func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
+ args := make([]interface{}, 2+len(fields))
+ args[0] = "hmget"
+ args[1] = key
+ for i, field := range fields {
+ args[2+i] = field
+ }
+ cmd := NewSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// HSet accepts values in following formats:
+// - HSet("myhash", "key1", "value1", "key2", "value2")
+// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
+// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
+//
+// Note that it requires Redis v4 for multiple field/value pairs support.
+func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(values))
+ args[0] = "hset"
+ args[1] = key
+ args = appendArgs(args, values)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// HMSet is a deprecated version of HSet left for compatibility with Redis 3.
+func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
+ args := make([]interface{}, 2, 2+len(values))
+ args[0] = "hmset"
+ args[1] = key
+ args = appendArgs(args, values)
+ cmd := NewBoolCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "hvals", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// HRandField redis-server version >= 6.2.0.
+func (c cmdable) HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd {
+ args := make([]interface{}, 0, 4)
+
+ // Although count=0 is meaningless, redis accepts count=0.
+ args = append(args, "hrandfield", key, count)
+ if withValues {
+ args = append(args, "withvalues")
+ }
+
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
+ args := make([]interface{}, 1+len(keys)+1)
+ args[0] = "blpop"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ args[len(args)-1] = formatSec(ctx, timeout)
+ cmd := NewStringSliceCmd(ctx, args...)
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
+ args := make([]interface{}, 1+len(keys)+1)
+ args[0] = "brpop"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ args[len(keys)+1] = formatSec(ctx, timeout)
+ cmd := NewStringSliceCmd(ctx, args...)
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd {
+ cmd := NewStringCmd(
+ ctx,
+ "brpoplpush",
+ source,
+ destination,
+ formatSec(ctx, timeout),
+ )
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd {
+ cmd := NewStringCmd(ctx, "lindex", key, index)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd {
+ cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
+ cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
+ cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LLen(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "llen", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LPop(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "lpop", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "lpop", key, count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type LPosArgs struct {
+ Rank, MaxLen int64
+}
+
+func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd {
+ args := []interface{}{"lpos", key, value}
+ if a.Rank != 0 {
+ args = append(args, "rank", a.Rank)
+ }
+ if a.MaxLen != 0 {
+ args = append(args, "maxlen", a.MaxLen)
+ }
+
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd {
+ args := []interface{}{"lpos", key, value, "count", count}
+ if a.Rank != 0 {
+ args = append(args, "rank", a.Rank)
+ }
+ if a.MaxLen != 0 {
+ args = append(args, "maxlen", a.MaxLen)
+ }
+ cmd := NewIntSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(values))
+ args[0] = "lpush"
+ args[1] = key
+ args = appendArgs(args, values)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(values))
+ args[0] = "lpushx"
+ args[1] = key
+ args = appendArgs(args, values)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
+ cmd := NewStringSliceCmd(
+ ctx,
+ "lrange",
+ key,
+ start,
+ stop,
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd {
+ cmd := NewIntCmd(ctx, "lrem", key, count, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "lset", key, index, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd {
+ cmd := NewStatusCmd(
+ ctx,
+ "ltrim",
+ key,
+ start,
+ stop,
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RPop(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "rpop", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "rpop", key, count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd {
+ cmd := NewStringCmd(ctx, "rpoplpush", source, destination)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(values))
+ args[0] = "rpush"
+ args[1] = key
+ args = appendArgs(args, values)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(values))
+ args[0] = "rpushx"
+ args[1] = key
+ args = appendArgs(args, values)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd {
+ cmd := NewStringCmd(ctx, "lmove", source, destination, srcpos, destpos)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) BLMove(
+ ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration,
+) *StringCmd {
+ cmd := NewStringCmd(ctx, "blmove", source, destination, srcpos, destpos, formatSec(ctx, timeout))
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(members))
+ args[0] = "sadd"
+ args[1] = key
+ args = appendArgs(args, members)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "scard", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "sdiff"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
+ args := make([]interface{}, 2+len(keys))
+ args[0] = "sdiffstore"
+ args[1] = destination
+ for i, key := range keys {
+ args[2+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "sinter"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
+ args := make([]interface{}, 2+len(keys))
+ args[0] = "sinterstore"
+ args[1] = destination
+ for i, key := range keys {
+ args[2+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "sismember", key, member)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SMIsMember Redis `SMISMEMBER key member [member ...]` command.
+func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd {
+ args := make([]interface{}, 2, 2+len(members))
+ args[0] = "smismember"
+ args[1] = key
+ args = appendArgs(args, members)
+ cmd := NewBoolSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SMembers Redis `SMEMBERS key` command output as a slice.
+func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "smembers", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SMembersMap Redis `SMEMBERS key` command output as a map.
+func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
+ cmd := NewStringStructMapCmd(ctx, "smembers", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "smove", source, destination, member)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SPop Redis `SPOP key` command.
+func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "spop", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SPopN Redis `SPOP key count` command.
+func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "spop", key, count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SRandMember Redis `SRANDMEMBER key` command.
+func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "srandmember", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// SRandMemberN Redis `SRANDMEMBER key count` command.
+func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(members))
+ args[0] = "srem"
+ args[1] = key
+ args = appendArgs(args, members)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "sunion"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
+ args := make([]interface{}, 2+len(keys))
+ args[0] = "sunionstore"
+ args[1] = destination
+ for i, key := range keys {
+ args[2+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+// XAddArgs accepts values in the following formats:
+// - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
+// - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
+// - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
+//
+// Note that map will not preserve the order of key-value pairs.
+// MaxLen/MaxLenApprox and MinID are in conflict, only one of them can be used.
+type XAddArgs struct {
+ Stream string
+ NoMkStream bool
+ MaxLen int64 // MAXLEN N
+
+ // Deprecated: use MaxLen+Approx, remove in v9.
+ MaxLenApprox int64 // MAXLEN ~ N
+
+ MinID string
+ // Approx causes MaxLen and MinID to use "~" matcher (instead of "=").
+ Approx bool
+ Limit int64
+ ID string
+ Values interface{}
+}
+
+// XAdd a.Limit has a bug, please confirm it and use it.
+// issue: https://github.com/redis/redis/issues/9046
+func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
+ args := make([]interface{}, 0, 11)
+ args = append(args, "xadd", a.Stream)
+ if a.NoMkStream {
+ args = append(args, "nomkstream")
+ }
+ switch {
+ case a.MaxLen > 0:
+ if a.Approx {
+ args = append(args, "maxlen", "~", a.MaxLen)
+ } else {
+ args = append(args, "maxlen", a.MaxLen)
+ }
+ case a.MaxLenApprox > 0:
+ // TODO remove in v9.
+ args = append(args, "maxlen", "~", a.MaxLenApprox)
+ case a.MinID != "":
+ if a.Approx {
+ args = append(args, "minid", "~", a.MinID)
+ } else {
+ args = append(args, "minid", a.MinID)
+ }
+ }
+ if a.Limit > 0 {
+ args = append(args, "limit", a.Limit)
+ }
+ if a.ID != "" {
+ args = append(args, a.ID)
+ } else {
+ args = append(args, "*")
+ }
+ args = appendArg(args, a.Values)
+
+ cmd := NewStringCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
+ args := []interface{}{"xdel", stream}
+ for _, id := range ids {
+ args = append(args, id)
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
+ cmd := NewIntCmd(ctx, "xlen", stream)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
+ cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
+ cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
+ cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
+ cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type XReadArgs struct {
+ Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
+ Count int64
+ Block time.Duration
+}
+
+func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
+ args := make([]interface{}, 0, 6+len(a.Streams))
+ args = append(args, "xread")
+
+ keyPos := int8(1)
+ if a.Count > 0 {
+ args = append(args, "count")
+ args = append(args, a.Count)
+ keyPos += 2
+ }
+ if a.Block >= 0 {
+ args = append(args, "block")
+ args = append(args, int64(a.Block/time.Millisecond))
+ keyPos += 2
+ }
+ args = append(args, "streams")
+ keyPos++
+ for _, s := range a.Streams {
+ args = append(args, s)
+ }
+
+ cmd := NewXStreamSliceCmd(ctx, args...)
+ if a.Block >= 0 {
+ cmd.setReadTimeout(a.Block)
+ }
+ cmd.SetFirstKeyPos(keyPos)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
+ return c.XRead(ctx, &XReadArgs{
+ Streams: streams,
+ Block: -1,
+ })
+}
+
+func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
+ cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
+ cmd := NewIntCmd(ctx, "xgroup", "createconsumer", stream, group, consumer)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
+ cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type XReadGroupArgs struct {
+ Group string
+ Consumer string
+ Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
+ Count int64
+ Block time.Duration
+ NoAck bool
+}
+
+func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
+ args := make([]interface{}, 0, 10+len(a.Streams))
+ args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
+
+ keyPos := int8(4)
+ if a.Count > 0 {
+ args = append(args, "count", a.Count)
+ keyPos += 2
+ }
+ if a.Block >= 0 {
+ args = append(args, "block", int64(a.Block/time.Millisecond))
+ keyPos += 2
+ }
+ if a.NoAck {
+ args = append(args, "noack")
+ keyPos++
+ }
+ args = append(args, "streams")
+ keyPos++
+ for _, s := range a.Streams {
+ args = append(args, s)
+ }
+
+ cmd := NewXStreamSliceCmd(ctx, args...)
+ if a.Block >= 0 {
+ cmd.setReadTimeout(a.Block)
+ }
+ cmd.SetFirstKeyPos(keyPos)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
+ args := []interface{}{"xack", stream, group}
+ for _, id := range ids {
+ args = append(args, id)
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
+ cmd := NewXPendingCmd(ctx, "xpending", stream, group)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type XPendingExtArgs struct {
+ Stream string
+ Group string
+ Idle time.Duration
+ Start string
+ End string
+ Count int64
+ Consumer string
+}
+
+func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
+ args := make([]interface{}, 0, 9)
+ args = append(args, "xpending", a.Stream, a.Group)
+ if a.Idle != 0 {
+ args = append(args, "idle", formatMs(ctx, a.Idle))
+ }
+ args = append(args, a.Start, a.End, a.Count)
+ if a.Consumer != "" {
+ args = append(args, a.Consumer)
+ }
+ cmd := NewXPendingExtCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+type XAutoClaimArgs struct {
+ Stream string
+ Group string
+ MinIdle time.Duration
+ Start string
+ Count int64
+ Consumer string
+}
+
+func (c cmdable) XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd {
+ args := xAutoClaimArgs(ctx, a)
+ cmd := NewXAutoClaimCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd {
+ args := xAutoClaimArgs(ctx, a)
+ args = append(args, "justid")
+ cmd := NewXAutoClaimJustIDCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func xAutoClaimArgs(ctx context.Context, a *XAutoClaimArgs) []interface{} {
+ args := make([]interface{}, 0, 8)
+ args = append(args, "xautoclaim", a.Stream, a.Group, a.Consumer, formatMs(ctx, a.MinIdle), a.Start)
+ if a.Count > 0 {
+ args = append(args, "count", a.Count)
+ }
+ return args
+}
+
+type XClaimArgs struct {
+ Stream string
+ Group string
+ Consumer string
+ MinIdle time.Duration
+ Messages []string
+}
+
+func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
+ args := xClaimArgs(a)
+ cmd := NewXMessageSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
+ args := xClaimArgs(a)
+ args = append(args, "justid")
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func xClaimArgs(a *XClaimArgs) []interface{} {
+ args := make([]interface{}, 0, 5+len(a.Messages))
+ args = append(args,
+ "xclaim",
+ a.Stream,
+ a.Group, a.Consumer,
+ int64(a.MinIdle/time.Millisecond))
+ for _, id := range a.Messages {
+ args = append(args, id)
+ }
+ return args
+}
+
+// xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default).
+// example:
+// XTRIM key MAXLEN/MINID threshold LIMIT limit.
+// XTRIM key MAXLEN/MINID ~ threshold LIMIT limit.
+// The redis-server version is lower than 6.2, please set limit to 0.
+func (c cmdable) xTrim(
+ ctx context.Context, key, strategy string,
+ approx bool, threshold interface{}, limit int64,
+) *IntCmd {
+ args := make([]interface{}, 0, 7)
+ args = append(args, "xtrim", key, strategy)
+ if approx {
+ args = append(args, "~")
+ }
+ args = append(args, threshold)
+ if limit > 0 {
+ args = append(args, "limit", limit)
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// Deprecated: use XTrimMaxLen, remove in v9.
+func (c cmdable) XTrim(ctx context.Context, key string, maxLen int64) *IntCmd {
+ return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
+}
+
+// Deprecated: use XTrimMaxLenApprox, remove in v9.
+func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd {
+ return c.xTrim(ctx, key, "maxlen", true, maxLen, 0)
+}
+
+// XTrimMaxLen No `~` rules are used, `limit` cannot be used.
+// cmd: XTRIM key MAXLEN maxLen
+func (c cmdable) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd {
+ return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
+}
+
+// XTrimMaxLenApprox LIMIT has a bug, please confirm it and use it.
+// issue: https://github.com/redis/redis/issues/9046
+// cmd: XTRIM key MAXLEN ~ maxLen LIMIT limit
+func (c cmdable) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd {
+ return c.xTrim(ctx, key, "maxlen", true, maxLen, limit)
+}
+
+// XTrimMinID No `~` rules are used, `limit` cannot be used.
+// cmd: XTRIM key MINID minID
+func (c cmdable) XTrimMinID(ctx context.Context, key string, minID string) *IntCmd {
+ return c.xTrim(ctx, key, "minid", false, minID, 0)
+}
+
+// XTrimMinIDApprox LIMIT has a bug, please confirm it and use it.
+// issue: https://github.com/redis/redis/issues/9046
+// cmd: XTRIM key MINID ~ minID LIMIT limit
+func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd {
+ return c.xTrim(ctx, key, "minid", true, minID, limit)
+}
+
+func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd {
+ cmd := NewXInfoConsumersCmd(ctx, key, group)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
+ cmd := NewXInfoGroupsCmd(ctx, key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
+ cmd := NewXInfoStreamCmd(ctx, key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// XInfoStreamFull XINFO STREAM FULL [COUNT count]
+// redis-server >= 6.0.
+func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd {
+ args := make([]interface{}, 0, 6)
+ args = append(args, "xinfo", "stream", key, "full")
+ if count > 0 {
+ args = append(args, "count", count)
+ }
+ cmd := NewXInfoStreamFullCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+// Z represents sorted set member.
+type Z struct {
+ Score float64
+ Member interface{}
+}
+
+// ZWithKey represents sorted set member including the name of the key where it was popped.
+type ZWithKey struct {
+ Z
+ Key string
+}
+
+// ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore.
+type ZStore struct {
+ Keys []string
+ Weights []float64
+ // Can be SUM, MIN or MAX.
+ Aggregate string
+}
+
+func (z ZStore) len() (n int) {
+ n = len(z.Keys)
+ if len(z.Weights) > 0 {
+ n += 1 + len(z.Weights)
+ }
+ if z.Aggregate != "" {
+ n += 2
+ }
+ return n
+}
+
+func (z ZStore) appendArgs(args []interface{}) []interface{} {
+ for _, key := range z.Keys {
+ args = append(args, key)
+ }
+ if len(z.Weights) > 0 {
+ args = append(args, "weights")
+ for _, weights := range z.Weights {
+ args = append(args, weights)
+ }
+ }
+ if z.Aggregate != "" {
+ args = append(args, "aggregate", z.Aggregate)
+ }
+ return args
+}
+
+// BZPopMax Redis `BZPOPMAX key [key ...] timeout` command.
+func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
+ args := make([]interface{}, 1+len(keys)+1)
+ args[0] = "bzpopmax"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ args[len(args)-1] = formatSec(ctx, timeout)
+ cmd := NewZWithKeyCmd(ctx, args...)
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// BZPopMin Redis `BZPOPMIN key [key ...] timeout` command.
+func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
+ args := make([]interface{}, 1+len(keys)+1)
+ args[0] = "bzpopmin"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ args[len(args)-1] = formatSec(ctx, timeout)
+ cmd := NewZWithKeyCmd(ctx, args...)
+ cmd.setReadTimeout(timeout)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
+type ZAddArgs struct {
+ NX bool
+ XX bool
+ LT bool
+ GT bool
+ Ch bool
+ Members []Z
+}
+
+func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} {
+ a := make([]interface{}, 0, 6+2*len(args.Members))
+ a = append(a, "zadd", key)
+
+ // The GT, LT and NX options are mutually exclusive.
+ if args.NX {
+ a = append(a, "nx")
+ } else {
+ if args.XX {
+ a = append(a, "xx")
+ }
+ if args.GT {
+ a = append(a, "gt")
+ } else if args.LT {
+ a = append(a, "lt")
+ }
+ }
+ if args.Ch {
+ a = append(a, "ch")
+ }
+ if incr {
+ a = append(a, "incr")
+ }
+ for _, m := range args.Members {
+ a = append(a, m.Score)
+ a = append(a, m.Member)
+ }
+ return a
+}
+
+func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd {
+ cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd {
+ cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// TODO: Compatible with v8 api, will be removed in v9.
+func (c cmdable) zAdd(ctx context.Context, key string, args ZAddArgs, members ...*Z) *IntCmd {
+ args.Members = make([]Z, len(members))
+ for i, m := range members {
+ args.Members[i] = *m
+ }
+ cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZAdd Redis `ZADD key score member [score member ...]` command.
+func (c cmdable) ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd {
+ return c.zAdd(ctx, key, ZAddArgs{}, members...)
+}
+
+// ZAddNX Redis `ZADD key NX score member [score member ...]` command.
+func (c cmdable) ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd {
+ return c.zAdd(ctx, key, ZAddArgs{
+ NX: true,
+ }, members...)
+}
+
+// ZAddXX Redis `ZADD key XX score member [score member ...]` command.
+func (c cmdable) ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd {
+ return c.zAdd(ctx, key, ZAddArgs{
+ XX: true,
+ }, members...)
+}
+
+// ZAddCh Redis `ZADD key CH score member [score member ...]` command.
+// Deprecated: Use
+// client.ZAddArgs(ctx, ZAddArgs{
+// Ch: true,
+// Members: []Z,
+// })
+// remove in v9.
+func (c cmdable) ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd {
+ return c.zAdd(ctx, key, ZAddArgs{
+ Ch: true,
+ }, members...)
+}
+
+// ZAddNXCh Redis `ZADD key NX CH score member [score member ...]` command.
+// Deprecated: Use
+// client.ZAddArgs(ctx, ZAddArgs{
+// NX: true,
+// Ch: true,
+// Members: []Z,
+// })
+// remove in v9.
+func (c cmdable) ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
+ return c.zAdd(ctx, key, ZAddArgs{
+ NX: true,
+ Ch: true,
+ }, members...)
+}
+
+// ZAddXXCh Redis `ZADD key XX CH score member [score member ...]` command.
+// Deprecated: Use
+// client.ZAddArgs(ctx, ZAddArgs{
+// XX: true,
+// Ch: true,
+// Members: []Z,
+// })
+// remove in v9.
+func (c cmdable) ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
+ return c.zAdd(ctx, key, ZAddArgs{
+ XX: true,
+ Ch: true,
+ }, members...)
+}
+
+// ZIncr Redis `ZADD key INCR score member` command.
+// Deprecated: Use
+// client.ZAddArgsIncr(ctx, ZAddArgs{
+// Members: []Z,
+// })
+// remove in v9.
+func (c cmdable) ZIncr(ctx context.Context, key string, member *Z) *FloatCmd {
+ return c.ZAddArgsIncr(ctx, key, ZAddArgs{
+ Members: []Z{*member},
+ })
+}
+
+// ZIncrNX Redis `ZADD key NX INCR score member` command.
+// Deprecated: Use
+// client.ZAddArgsIncr(ctx, ZAddArgs{
+// NX: true,
+// Members: []Z,
+// })
+// remove in v9.
+func (c cmdable) ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd {
+ return c.ZAddArgsIncr(ctx, key, ZAddArgs{
+ NX: true,
+ Members: []Z{*member},
+ })
+}
+
+// ZIncrXX Redis `ZADD key XX INCR score member` command.
+// Deprecated: Use
+// client.ZAddArgsIncr(ctx, ZAddArgs{
+// XX: true,
+// Members: []Z,
+// })
+// remove in v9.
+func (c cmdable) ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd {
+ return c.ZAddArgsIncr(ctx, key, ZAddArgs{
+ XX: true,
+ Members: []Z{*member},
+ })
+}
+
+func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zcard", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zcount", key, min, max)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
+ cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
+ args := make([]interface{}, 0, 3+store.len())
+ args = append(args, "zinterstore", destination, len(store.Keys))
+ args = store.appendArgs(args)
+ cmd := NewIntCmd(ctx, args...)
+ cmd.SetFirstKeyPos(3)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd {
+ args := make([]interface{}, 0, 2+store.len())
+ args = append(args, "zinter", len(store.Keys))
+ args = store.appendArgs(args)
+ cmd := NewStringSliceCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd {
+ args := make([]interface{}, 0, 3+store.len())
+ args = append(args, "zinter", len(store.Keys))
+ args = store.appendArgs(args)
+ args = append(args, "withscores")
+ cmd := NewZSliceCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
+ args := make([]interface{}, 2+len(members))
+ args[0] = "zmscore"
+ args[1] = key
+ for i, member := range members {
+ args[2+i] = member
+ }
+ cmd := NewFloatSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
+ args := []interface{}{
+ "zpopmax",
+ key,
+ }
+
+ switch len(count) {
+ case 0:
+ break
+ case 1:
+ args = append(args, count[0])
+ default:
+ panic("too many arguments")
+ }
+
+ cmd := NewZSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
+ args := []interface{}{
+ "zpopmin",
+ key,
+ }
+
+ switch len(count) {
+ case 0:
+ break
+ case 1:
+ args = append(args, count[0])
+ default:
+ panic("too many arguments")
+ }
+
+ cmd := NewZSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZRangeArgs is all the options of the ZRange command.
+// In version> 6.2.0, you can replace the(cmd):
+// ZREVRANGE,
+// ZRANGEBYSCORE,
+// ZREVRANGEBYSCORE,
+// ZRANGEBYLEX,
+// ZREVRANGEBYLEX.
+// Please pay attention to your redis-server version.
+//
+// Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher.
+type ZRangeArgs struct {
+ Key string
+
+ // When the ByScore option is provided, the open interval(exclusive) can be set.
+ // By default, the score intervals specified by and are closed (inclusive).
+ // It is similar to the deprecated(6.2.0+) ZRangeByScore command.
+ // For example:
+ // ZRangeArgs{
+ // Key: "example-key",
+ // Start: "(3",
+ // Stop: 8,
+ // ByScore: true,
+ // }
+ // cmd: "ZRange example-key (3 8 ByScore" (3 < score <= 8).
+ //
+ // For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command.
+ // You can set the and options as follows:
+ // ZRangeArgs{
+ // Key: "example-key",
+ // Start: "[abc",
+ // Stop: "(def",
+ // ByLex: true,
+ // }
+ // cmd: "ZRange example-key [abc (def ByLex"
+ //
+ // For normal cases (ByScore==false && ByLex==false), and should be set to the index range (int).
+ // You can read the documentation for more information: https://redis.io/commands/zrange
+ Start interface{}
+ Stop interface{}
+
+ // The ByScore and ByLex options are mutually exclusive.
+ ByScore bool
+ ByLex bool
+
+ Rev bool
+
+ // limit offset count.
+ Offset int64
+ Count int64
+}
+
+func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} {
+ // For Rev+ByScore/ByLex, we need to adjust the position of and .
+ if z.Rev && (z.ByScore || z.ByLex) {
+ args = append(args, z.Key, z.Stop, z.Start)
+ } else {
+ args = append(args, z.Key, z.Start, z.Stop)
+ }
+
+ if z.ByScore {
+ args = append(args, "byscore")
+ } else if z.ByLex {
+ args = append(args, "bylex")
+ }
+ if z.Rev {
+ args = append(args, "rev")
+ }
+ if z.Offset != 0 || z.Count != 0 {
+ args = append(args, "limit", z.Offset, z.Count)
+ }
+ return args
+}
+
+func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd {
+ args := make([]interface{}, 0, 9)
+ args = append(args, "zrange")
+ args = z.appendArgs(args)
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd {
+ args := make([]interface{}, 0, 10)
+ args = append(args, "zrange")
+ args = z.appendArgs(args)
+ args = append(args, "withscores")
+ cmd := NewZSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
+ return c.ZRangeArgs(ctx, ZRangeArgs{
+ Key: key,
+ Start: start,
+ Stop: stop,
+ })
+}
+
+func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
+ return c.ZRangeArgsWithScores(ctx, ZRangeArgs{
+ Key: key,
+ Start: start,
+ Stop: stop,
+ })
+}
+
+type ZRangeBy struct {
+ Min, Max string
+ Offset, Count int64
+}
+
+func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
+ args := []interface{}{zcmd, key, opt.Min, opt.Max}
+ if withScores {
+ args = append(args, "withscores")
+ }
+ if opt.Offset != 0 || opt.Count != 0 {
+ args = append(
+ args,
+ "limit",
+ opt.Offset,
+ opt.Count,
+ )
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
+ return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
+}
+
+func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
+ return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
+}
+
+func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
+ args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
+ if opt.Offset != 0 || opt.Count != 0 {
+ args = append(
+ args,
+ "limit",
+ opt.Offset,
+ opt.Count,
+ )
+ }
+ cmd := NewZSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd {
+ args := make([]interface{}, 0, 10)
+ args = append(args, "zrangestore", dst)
+ args = z.appendArgs(args)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zrank", key, member)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(members))
+ args[0] = "zrem"
+ args[1] = key
+ args = appendArgs(args, members)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
+ cmd := NewIntCmd(
+ ctx,
+ "zremrangebyrank",
+ key,
+ start,
+ stop,
+ )
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
+ cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
+ args := []interface{}{zcmd, key, opt.Max, opt.Min}
+ if opt.Offset != 0 || opt.Count != 0 {
+ args = append(
+ args,
+ "limit",
+ opt.Offset,
+ opt.Count,
+ )
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
+ return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
+}
+
+func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
+ return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
+}
+
+func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
+ args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
+ if opt.Offset != 0 || opt.Count != 0 {
+ args = append(
+ args,
+ "limit",
+ opt.Offset,
+ opt.Count,
+ )
+ }
+ cmd := NewZSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
+ cmd := NewIntCmd(ctx, "zrevrank", key, member)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
+ cmd := NewFloatCmd(ctx, "zscore", key, member)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd {
+ args := make([]interface{}, 0, 2+store.len())
+ args = append(args, "zunion", len(store.Keys))
+ args = store.appendArgs(args)
+ cmd := NewStringSliceCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd {
+ args := make([]interface{}, 0, 3+store.len())
+ args = append(args, "zunion", len(store.Keys))
+ args = store.appendArgs(args)
+ args = append(args, "withscores")
+ cmd := NewZSliceCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
+ args := make([]interface{}, 0, 3+store.len())
+ args = append(args, "zunionstore", dest, len(store.Keys))
+ args = store.appendArgs(args)
+ cmd := NewIntCmd(ctx, args...)
+ cmd.SetFirstKeyPos(3)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZRandMember redis-server version >= 6.2.0.
+func (c cmdable) ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd {
+ args := make([]interface{}, 0, 4)
+
+ // Although count=0 is meaningless, redis accepts count=0.
+ args = append(args, "zrandmember", key, count)
+ if withScores {
+ args = append(args, "withscores")
+ }
+
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZDiff redis-server version >= 6.2.0.
+func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd {
+ args := make([]interface{}, 2+len(keys))
+ args[0] = "zdiff"
+ args[1] = len(keys)
+ for i, key := range keys {
+ args[i+2] = key
+ }
+
+ cmd := NewStringSliceCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZDiffWithScores redis-server version >= 6.2.0.
+func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd {
+ args := make([]interface{}, 3+len(keys))
+ args[0] = "zdiff"
+ args[1] = len(keys)
+ for i, key := range keys {
+ args[i+2] = key
+ }
+ args[len(keys)+2] = "withscores"
+
+ cmd := NewZSliceCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ZDiffStore redis-server version >=6.2.0.
+func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
+ args := make([]interface{}, 0, 3+len(keys))
+ args = append(args, "zdiffstore", destination, len(keys))
+ for _, key := range keys {
+ args = append(args, key)
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd {
+ args := make([]interface{}, 2, 2+len(els))
+ args[0] = "pfadd"
+ args[1] = key
+ args = appendArgs(args, els)
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "pfcount"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd {
+ args := make([]interface{}, 2+len(keys))
+ args[0] = "pfmerge"
+ args[1] = dest
+ for i, key := range keys {
+ args[2+i] = key
+ }
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "bgrewriteaof")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) BgSave(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "bgsave")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "client", "kill", ipPort)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// ClientKillByFilter is new style syntax, while the ClientKill is old
+//
+// CLIENT KILL [value] ... [value]
+func (c cmdable) ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd {
+ args := make([]interface{}, 2+len(keys))
+ args[0] = "client"
+ args[1] = "kill"
+ for i, key := range keys {
+ args[2+i] = key
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClientList(ctx context.Context) *StringCmd {
+ cmd := NewStringCmd(ctx, "client", "list")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClientPause(ctx context.Context, dur time.Duration) *BoolCmd {
+ cmd := NewBoolCmd(ctx, "client", "pause", formatMs(ctx, dur))
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClientID(ctx context.Context) *IntCmd {
+ cmd := NewIntCmd(ctx, "client", "id")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClientUnblock(ctx context.Context, id int64) *IntCmd {
+ cmd := NewIntCmd(ctx, "client", "unblock", id)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClientUnblockWithError(ctx context.Context, id int64) *IntCmd {
+ cmd := NewIntCmd(ctx, "client", "unblock", id, "error")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ConfigGet(ctx context.Context, parameter string) *SliceCmd {
+ cmd := NewSliceCmd(ctx, "config", "get", parameter)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ConfigResetStat(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "config", "resetstat")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ConfigSet(ctx context.Context, parameter, value string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "config", "set", parameter, value)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ConfigRewrite(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "config", "rewrite")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) DBSize(ctx context.Context) *IntCmd {
+ cmd := NewIntCmd(ctx, "dbsize")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) FlushAll(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "flushall")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) FlushAllAsync(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "flushall", "async")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) FlushDB(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "flushdb")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) FlushDBAsync(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "flushdb", "async")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Info(ctx context.Context, section ...string) *StringCmd {
+ args := []interface{}{"info"}
+ if len(section) > 0 {
+ args = append(args, section[0])
+ }
+ cmd := NewStringCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) LastSave(ctx context.Context) *IntCmd {
+ cmd := NewIntCmd(ctx, "lastsave")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Save(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "save")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) shutdown(ctx context.Context, modifier string) *StatusCmd {
+ var args []interface{}
+ if modifier == "" {
+ args = []interface{}{"shutdown"}
+ } else {
+ args = []interface{}{"shutdown", modifier}
+ }
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ if err := cmd.Err(); err != nil {
+ if err == io.EOF {
+ // Server quit as expected.
+ cmd.err = nil
+ }
+ } else {
+ // Server did not quit. String reply contains the reason.
+ cmd.err = errors.New(cmd.val)
+ cmd.val = ""
+ }
+ return cmd
+}
+
+func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
+ return c.shutdown(ctx, "")
+}
+
+func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
+ return c.shutdown(ctx, "save")
+}
+
+func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
+ return c.shutdown(ctx, "nosave")
+}
+
+func (c cmdable) SlaveOf(ctx context.Context, host, port string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "slaveof", host, port)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) SlowLogGet(ctx context.Context, num int64) *SlowLogCmd {
+ cmd := NewSlowLogCmd(context.Background(), "slowlog", "get", num)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) Sync(_ context.Context) {
+ panic("not implemented")
+}
+
+func (c cmdable) Time(ctx context.Context) *TimeCmd {
+ cmd := NewTimeCmd(ctx, "time")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) DebugObject(ctx context.Context, key string) *StringCmd {
+ cmd := NewStringCmd(ctx, "debug", "object", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "readonly")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "readwrite")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd {
+ args := []interface{}{"memory", "usage", key}
+ if len(samples) > 0 {
+ if len(samples) != 1 {
+ panic("MemoryUsage expects single sample count")
+ }
+ args = append(args, "SAMPLES", samples[0])
+ }
+ cmd := NewIntCmd(ctx, args...)
+ cmd.SetFirstKeyPos(2)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
+ cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
+ cmdArgs[0] = "eval"
+ cmdArgs[1] = script
+ cmdArgs[2] = len(keys)
+ for i, key := range keys {
+ cmdArgs[3+i] = key
+ }
+ cmdArgs = appendArgs(cmdArgs, args)
+ cmd := NewCmd(ctx, cmdArgs...)
+ cmd.SetFirstKeyPos(3)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
+ cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
+ cmdArgs[0] = "evalsha"
+ cmdArgs[1] = sha1
+ cmdArgs[2] = len(keys)
+ for i, key := range keys {
+ cmdArgs[3+i] = key
+ }
+ cmdArgs = appendArgs(cmdArgs, args)
+ cmd := NewCmd(ctx, cmdArgs...)
+ cmd.SetFirstKeyPos(3)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
+ args := make([]interface{}, 2+len(hashes))
+ args[0] = "script"
+ args[1] = "exists"
+ for i, hash := range hashes {
+ args[2+i] = hash
+ }
+ cmd := NewBoolSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ScriptFlush(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "script", "flush")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ScriptKill(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "script", "kill")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
+ cmd := NewStringCmd(ctx, "script", "load", script)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+// Publish posts the message to the channel.
+func (c cmdable) Publish(ctx context.Context, channel string, message interface{}) *IntCmd {
+ cmd := NewIntCmd(ctx, "publish", channel, message)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd {
+ args := []interface{}{"pubsub", "channels"}
+ if pattern != "*" {
+ args = append(args, pattern)
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd {
+ args := make([]interface{}, 2+len(channels))
+ args[0] = "pubsub"
+ args[1] = "numsub"
+ for i, channel := range channels {
+ args[2+i] = channel
+ }
+ cmd := NewStringIntMapCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) PubSubNumPat(ctx context.Context) *IntCmd {
+ cmd := NewIntCmd(ctx, "pubsub", "numpat")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
+ cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
+ cmd := NewStringCmd(ctx, "cluster", "nodes")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
+ cmd := NewStringCmd(ctx, "cluster", "info")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
+ cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
+ cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
+ cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
+ args := make([]interface{}, 2+len(slots))
+ args[0] = "cluster"
+ args[1] = "delslots"
+ for i, slot := range slots {
+ args[2+i] = slot
+ }
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
+ size := max - min + 1
+ slots := make([]int, size)
+ for i := 0; i < size; i++ {
+ slots[i] = min + i
+ }
+ return c.ClusterDelSlots(ctx, slots...)
+}
+
+func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "cluster", "failover")
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
+ args := make([]interface{}, 2+len(slots))
+ args[0] = "cluster"
+ args[1] = "addslots"
+ for i, num := range slots {
+ args[2+i] = num
+ }
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
+ size := max - min + 1
+ slots := make([]int, size)
+ for i := 0; i < size; i++ {
+ slots[i] = min + i
+ }
+ return c.ClusterAddSlots(ctx, slots...)
+}
+
+//------------------------------------------------------------------------------
+
+func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd {
+ args := make([]interface{}, 2+3*len(geoLocation))
+ args[0] = "geoadd"
+ args[1] = key
+ for i, eachLoc := range geoLocation {
+ args[2+3*i] = eachLoc.Longitude
+ args[2+3*i+1] = eachLoc.Latitude
+ args[2+3*i+2] = eachLoc.Name
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// GeoRadius is a read-only GEORADIUS_RO command.
+func (c cmdable) GeoRadius(
+ ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
+) *GeoLocationCmd {
+ cmd := NewGeoLocationCmd(ctx, query, "georadius_ro", key, longitude, latitude)
+ if query.Store != "" || query.StoreDist != "" {
+ cmd.SetErr(errors.New("GeoRadius does not support Store or StoreDist"))
+ return cmd
+ }
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// GeoRadiusStore is a writing GEORADIUS command.
+func (c cmdable) GeoRadiusStore(
+ ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
+) *IntCmd {
+ args := geoLocationArgs(query, "georadius", key, longitude, latitude)
+ cmd := NewIntCmd(ctx, args...)
+ if query.Store == "" && query.StoreDist == "" {
+ cmd.SetErr(errors.New("GeoRadiusStore requires Store or StoreDist"))
+ return cmd
+ }
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// GeoRadiusByMember is a read-only GEORADIUSBYMEMBER_RO command.
+func (c cmdable) GeoRadiusByMember(
+ ctx context.Context, key, member string, query *GeoRadiusQuery,
+) *GeoLocationCmd {
+ cmd := NewGeoLocationCmd(ctx, query, "georadiusbymember_ro", key, member)
+ if query.Store != "" || query.StoreDist != "" {
+ cmd.SetErr(errors.New("GeoRadiusByMember does not support Store or StoreDist"))
+ return cmd
+ }
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+// GeoRadiusByMemberStore is a writing GEORADIUSBYMEMBER command.
+func (c cmdable) GeoRadiusByMemberStore(
+ ctx context.Context, key, member string, query *GeoRadiusQuery,
+) *IntCmd {
+ args := geoLocationArgs(query, "georadiusbymember", key, member)
+ cmd := NewIntCmd(ctx, args...)
+ if query.Store == "" && query.StoreDist == "" {
+ cmd.SetErr(errors.New("GeoRadiusByMemberStore requires Store or StoreDist"))
+ return cmd
+ }
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd {
+ args := make([]interface{}, 0, 13)
+ args = append(args, "geosearch", key)
+ args = geoSearchArgs(q, args)
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GeoSearchLocation(
+ ctx context.Context, key string, q *GeoSearchLocationQuery,
+) *GeoSearchLocationCmd {
+ args := make([]interface{}, 0, 16)
+ args = append(args, "geosearch", key)
+ args = geoSearchLocationArgs(q, args)
+ cmd := NewGeoSearchLocationCmd(ctx, q, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd {
+ args := make([]interface{}, 0, 15)
+ args = append(args, "geosearchstore", store, key)
+ args = geoSearchArgs(&q.GeoSearchQuery, args)
+ if q.StoreDist {
+ args = append(args, "storedist")
+ }
+ cmd := NewIntCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GeoDist(
+ ctx context.Context, key string, member1, member2, unit string,
+) *FloatCmd {
+ if unit == "" {
+ unit = "km"
+ }
+ cmd := NewFloatCmd(ctx, "geodist", key, member1, member2, unit)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd {
+ args := make([]interface{}, 2+len(members))
+ args[0] = "geohash"
+ args[1] = key
+ for i, member := range members {
+ args[2+i] = member
+ }
+ cmd := NewStringSliceCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
+
+func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd {
+ args := make([]interface{}, 2+len(members))
+ args[0] = "geopos"
+ args[1] = key
+ for i, member := range members {
+ args[2+i] = member
+ }
+ cmd := NewGeoPosCmd(ctx, args...)
+ _ = c(ctx, cmd)
+ return cmd
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/doc.go
new file mode 100644
index 000000000000..55262533a63d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/doc.go
@@ -0,0 +1,4 @@
+/*
+Package redis implements a Redis client.
+*/
+package redis
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/error.go
new file mode 100644
index 000000000000..521594bbd0c9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/error.go
@@ -0,0 +1,144 @@
+package redis
+
+import (
+ "context"
+ "io"
+ "net"
+ "strings"
+
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/proto"
+)
+
+// ErrClosed performs any operation on the closed client will return this error.
+var ErrClosed = pool.ErrClosed
+
+type Error interface {
+ error
+
+ // RedisError is a no-op function but
+ // serves to distinguish types that are Redis
+ // errors from ordinary errors: a type is a
+ // Redis error if it has a RedisError method.
+ RedisError()
+}
+
+var _ Error = proto.RedisError("")
+
+func shouldRetry(err error, retryTimeout bool) bool {
+ switch err {
+ case io.EOF, io.ErrUnexpectedEOF:
+ return true
+ case nil, context.Canceled, context.DeadlineExceeded:
+ return false
+ }
+
+ if v, ok := err.(timeoutError); ok {
+ if v.Timeout() {
+ return retryTimeout
+ }
+ return true
+ }
+
+ s := err.Error()
+ if s == "ERR max number of clients reached" {
+ return true
+ }
+ if strings.HasPrefix(s, "LOADING ") {
+ return true
+ }
+ if strings.HasPrefix(s, "READONLY ") {
+ return true
+ }
+ if strings.HasPrefix(s, "CLUSTERDOWN ") {
+ return true
+ }
+ if strings.HasPrefix(s, "TRYAGAIN ") {
+ return true
+ }
+
+ return false
+}
+
+func isRedisError(err error) bool {
+ _, ok := err.(proto.RedisError)
+ return ok
+}
+
+func isBadConn(err error, allowTimeout bool, addr string) bool {
+ switch err {
+ case nil:
+ return false
+ case context.Canceled, context.DeadlineExceeded:
+ return true
+ }
+
+ if isRedisError(err) {
+ switch {
+ case isReadOnlyError(err):
+ // Close connections in read only state in case domain addr is used
+ // and domain resolves to a different Redis Server. See #790.
+ return true
+ case isMovedSameConnAddr(err, addr):
+ // Close connections when we are asked to move to the same addr
+ // of the connection. Force a DNS resolution when all connections
+ // of the pool are recycled
+ return true
+ default:
+ return false
+ }
+ }
+
+ if allowTimeout {
+ if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
+ return !netErr.Temporary()
+ }
+ }
+
+ return true
+}
+
+func isMovedError(err error) (moved bool, ask bool, addr string) {
+ if !isRedisError(err) {
+ return
+ }
+
+ s := err.Error()
+ switch {
+ case strings.HasPrefix(s, "MOVED "):
+ moved = true
+ case strings.HasPrefix(s, "ASK "):
+ ask = true
+ default:
+ return
+ }
+
+ ind := strings.LastIndex(s, " ")
+ if ind == -1 {
+ return false, false, ""
+ }
+ addr = s[ind+1:]
+ return
+}
+
+func isLoadingError(err error) bool {
+ return strings.HasPrefix(err.Error(), "LOADING ")
+}
+
+func isReadOnlyError(err error) bool {
+ return strings.HasPrefix(err.Error(), "READONLY ")
+}
+
+func isMovedSameConnAddr(err error, addr string) bool {
+ redisError := err.Error()
+ if !strings.HasPrefix(redisError, "MOVED ") {
+ return false
+ }
+ return strings.HasSuffix(redisError, " "+addr)
+}
+
+//------------------------------------------------------------------------------
+
+type timeoutError interface {
+ Timeout() bool
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/arg.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/arg.go
new file mode 100644
index 000000000000..b97fa0d68517
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/arg.go
@@ -0,0 +1,56 @@
+package internal
+
+import (
+ "fmt"
+ "strconv"
+ "time"
+)
+
+func AppendArg(b []byte, v interface{}) []byte {
+ switch v := v.(type) {
+ case nil:
+ return append(b, ""...)
+ case string:
+ return appendUTF8String(b, Bytes(v))
+ case []byte:
+ return appendUTF8String(b, v)
+ case int:
+ return strconv.AppendInt(b, int64(v), 10)
+ case int8:
+ return strconv.AppendInt(b, int64(v), 10)
+ case int16:
+ return strconv.AppendInt(b, int64(v), 10)
+ case int32:
+ return strconv.AppendInt(b, int64(v), 10)
+ case int64:
+ return strconv.AppendInt(b, v, 10)
+ case uint:
+ return strconv.AppendUint(b, uint64(v), 10)
+ case uint8:
+ return strconv.AppendUint(b, uint64(v), 10)
+ case uint16:
+ return strconv.AppendUint(b, uint64(v), 10)
+ case uint32:
+ return strconv.AppendUint(b, uint64(v), 10)
+ case uint64:
+ return strconv.AppendUint(b, v, 10)
+ case float32:
+ return strconv.AppendFloat(b, float64(v), 'f', -1, 64)
+ case float64:
+ return strconv.AppendFloat(b, v, 'f', -1, 64)
+ case bool:
+ if v {
+ return append(b, "true"...)
+ }
+ return append(b, "false"...)
+ case time.Time:
+ return v.AppendFormat(b, time.RFC3339Nano)
+ default:
+ return append(b, fmt.Sprint(v)...)
+ }
+}
+
+func appendUTF8String(dst []byte, src []byte) []byte {
+ dst = append(dst, src...)
+ return dst
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go
new file mode 100644
index 000000000000..b3a4f211e336
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go
@@ -0,0 +1,78 @@
+package hashtag
+
+import (
+ "strings"
+
+ "github.com/go-redis/redis/v8/internal/rand"
+)
+
+const slotNumber = 16384
+
+// CRC16 implementation according to CCITT standards.
+// Copyright 2001-2010 Georges Menie (www.menie.org)
+// Copyright 2013 The Go Authors. All rights reserved.
+// http://redis.io/topics/cluster-spec#appendix-a-crc16-reference-implementation-in-ansi-c
+var crc16tab = [256]uint16{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
+}
+
+func Key(key string) string {
+ if s := strings.IndexByte(key, '{'); s > -1 {
+ if e := strings.IndexByte(key[s+1:], '}'); e > 0 {
+ return key[s+1 : s+e+1]
+ }
+ }
+ return key
+}
+
+func RandomSlot() int {
+ return rand.Intn(slotNumber)
+}
+
+// Slot returns a consistent slot number between 0 and 16383
+// for any given string key.
+func Slot(key string) int {
+ if key == "" {
+ return RandomSlot()
+ }
+ key = Key(key)
+ return int(crc16sum(key)) % slotNumber
+}
+
+func crc16sum(key string) (crc uint16) {
+ for i := 0; i < len(key); i++ {
+ crc = (crc << 8) ^ crc16tab[(byte(crc>>8)^key[i])&0x00ff]
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go
new file mode 100644
index 000000000000..852c8bd525a7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go
@@ -0,0 +1,201 @@
+package hscan
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+// decoderFunc represents decoding functions for default built-in types.
+type decoderFunc func(reflect.Value, string) error
+
+var (
+ // List of built-in decoders indexed by their numeric constant values (eg: reflect.Bool = 1).
+ decoders = []decoderFunc{
+ reflect.Bool: decodeBool,
+ reflect.Int: decodeInt,
+ reflect.Int8: decodeInt8,
+ reflect.Int16: decodeInt16,
+ reflect.Int32: decodeInt32,
+ reflect.Int64: decodeInt64,
+ reflect.Uint: decodeUint,
+ reflect.Uint8: decodeUint8,
+ reflect.Uint16: decodeUint16,
+ reflect.Uint32: decodeUint32,
+ reflect.Uint64: decodeUint64,
+ reflect.Float32: decodeFloat32,
+ reflect.Float64: decodeFloat64,
+ reflect.Complex64: decodeUnsupported,
+ reflect.Complex128: decodeUnsupported,
+ reflect.Array: decodeUnsupported,
+ reflect.Chan: decodeUnsupported,
+ reflect.Func: decodeUnsupported,
+ reflect.Interface: decodeUnsupported,
+ reflect.Map: decodeUnsupported,
+ reflect.Ptr: decodeUnsupported,
+ reflect.Slice: decodeSlice,
+ reflect.String: decodeString,
+ reflect.Struct: decodeUnsupported,
+ reflect.UnsafePointer: decodeUnsupported,
+ }
+
+ // Global map of struct field specs that is populated once for every new
+ // struct type that is scanned. This caches the field types and the corresponding
+ // decoder functions to avoid iterating through struct fields on subsequent scans.
+ globalStructMap = newStructMap()
+)
+
+func Struct(dst interface{}) (StructValue, error) {
+ v := reflect.ValueOf(dst)
+
+ // The destination to scan into should be a struct pointer.
+ if v.Kind() != reflect.Ptr || v.IsNil() {
+ return StructValue{}, fmt.Errorf("redis.Scan(non-pointer %T)", dst)
+ }
+
+ v = v.Elem()
+ if v.Kind() != reflect.Struct {
+ return StructValue{}, fmt.Errorf("redis.Scan(non-struct %T)", dst)
+ }
+
+ return StructValue{
+ spec: globalStructMap.get(v.Type()),
+ value: v,
+ }, nil
+}
+
+// Scan scans the results from a key-value Redis map result set to a destination struct.
+// The Redis keys are matched to the struct's field with the `redis` tag.
+func Scan(dst interface{}, keys []interface{}, vals []interface{}) error {
+ if len(keys) != len(vals) {
+ return errors.New("args should have the same number of keys and vals")
+ }
+
+ strct, err := Struct(dst)
+ if err != nil {
+ return err
+ }
+
+ // Iterate through the (key, value) sequence.
+ for i := 0; i < len(vals); i++ {
+ key, ok := keys[i].(string)
+ if !ok {
+ continue
+ }
+
+ val, ok := vals[i].(string)
+ if !ok {
+ continue
+ }
+
+ if err := strct.Scan(key, val); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func decodeBool(f reflect.Value, s string) error {
+ b, err := strconv.ParseBool(s)
+ if err != nil {
+ return err
+ }
+ f.SetBool(b)
+ return nil
+}
+
+func decodeInt8(f reflect.Value, s string) error {
+ return decodeNumber(f, s, 8)
+}
+
+func decodeInt16(f reflect.Value, s string) error {
+ return decodeNumber(f, s, 16)
+}
+
+func decodeInt32(f reflect.Value, s string) error {
+ return decodeNumber(f, s, 32)
+}
+
+func decodeInt64(f reflect.Value, s string) error {
+ return decodeNumber(f, s, 64)
+}
+
+func decodeInt(f reflect.Value, s string) error {
+ return decodeNumber(f, s, 0)
+}
+
+func decodeNumber(f reflect.Value, s string, bitSize int) error {
+ v, err := strconv.ParseInt(s, 10, bitSize)
+ if err != nil {
+ return err
+ }
+ f.SetInt(v)
+ return nil
+}
+
+func decodeUint8(f reflect.Value, s string) error {
+ return decodeUnsignedNumber(f, s, 8)
+}
+
+func decodeUint16(f reflect.Value, s string) error {
+ return decodeUnsignedNumber(f, s, 16)
+}
+
+func decodeUint32(f reflect.Value, s string) error {
+ return decodeUnsignedNumber(f, s, 32)
+}
+
+func decodeUint64(f reflect.Value, s string) error {
+ return decodeUnsignedNumber(f, s, 64)
+}
+
+func decodeUint(f reflect.Value, s string) error {
+ return decodeUnsignedNumber(f, s, 0)
+}
+
+func decodeUnsignedNumber(f reflect.Value, s string, bitSize int) error {
+ v, err := strconv.ParseUint(s, 10, bitSize)
+ if err != nil {
+ return err
+ }
+ f.SetUint(v)
+ return nil
+}
+
+func decodeFloat32(f reflect.Value, s string) error {
+ v, err := strconv.ParseFloat(s, 32)
+ if err != nil {
+ return err
+ }
+ f.SetFloat(v)
+ return nil
+}
+
+// although the default is float64, but we better define it.
+func decodeFloat64(f reflect.Value, s string) error {
+ v, err := strconv.ParseFloat(s, 64)
+ if err != nil {
+ return err
+ }
+ f.SetFloat(v)
+ return nil
+}
+
+func decodeString(f reflect.Value, s string) error {
+ f.SetString(s)
+ return nil
+}
+
+func decodeSlice(f reflect.Value, s string) error {
+ // []byte slice ([]uint8).
+ if f.Type().Elem().Kind() == reflect.Uint8 {
+ f.SetBytes([]byte(s))
+ }
+ return nil
+}
+
+func decodeUnsupported(v reflect.Value, s string) error {
+ return fmt.Errorf("redis.Scan(unsupported %s)", v.Type())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go
new file mode 100644
index 000000000000..6839412ba259
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go
@@ -0,0 +1,93 @@
+package hscan
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+)
+
+// structMap contains the map of struct fields for target structs
+// indexed by the struct type.
+type structMap struct {
+ m sync.Map
+}
+
+func newStructMap() *structMap {
+ return new(structMap)
+}
+
+func (s *structMap) get(t reflect.Type) *structSpec {
+ if v, ok := s.m.Load(t); ok {
+ return v.(*structSpec)
+ }
+
+ spec := newStructSpec(t, "redis")
+ s.m.Store(t, spec)
+ return spec
+}
+
+//------------------------------------------------------------------------------
+
+// structSpec contains the list of all fields in a target struct.
+type structSpec struct {
+ m map[string]*structField
+}
+
+func (s *structSpec) set(tag string, sf *structField) {
+ s.m[tag] = sf
+}
+
+func newStructSpec(t reflect.Type, fieldTag string) *structSpec {
+ numField := t.NumField()
+ out := &structSpec{
+ m: make(map[string]*structField, numField),
+ }
+
+ for i := 0; i < numField; i++ {
+ f := t.Field(i)
+
+ tag := f.Tag.Get(fieldTag)
+ if tag == "" || tag == "-" {
+ continue
+ }
+
+ tag = strings.Split(tag, ",")[0]
+ if tag == "" {
+ continue
+ }
+
+ // Use the built-in decoder.
+ out.set(tag, &structField{index: i, fn: decoders[f.Type.Kind()]})
+ }
+
+ return out
+}
+
+//------------------------------------------------------------------------------
+
+// structField represents a single field in a target struct.
+type structField struct {
+ index int
+ fn decoderFunc
+}
+
+//------------------------------------------------------------------------------
+
+type StructValue struct {
+ spec *structSpec
+ value reflect.Value
+}
+
+func (s StructValue) Scan(key string, value string) error {
+ field, ok := s.spec.m[key]
+ if !ok {
+ return nil
+ }
+ if err := field.fn(s.value.Field(field.index), value); err != nil {
+ t := s.value.Type()
+ return fmt.Errorf("cannot scan redis.result %s into struct field %s.%s of type %s, error-%s",
+ value, t.Name(), t.Field(field.index).Name, t.Field(field.index).Type, err.Error())
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/internal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/internal.go
new file mode 100644
index 000000000000..4a59c599be77
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/internal.go
@@ -0,0 +1,29 @@
+package internal
+
+import (
+ "time"
+
+ "github.com/go-redis/redis/v8/internal/rand"
+)
+
+func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration {
+ if retry < 0 {
+ panic("not reached")
+ }
+ if minBackoff == 0 {
+ return 0
+ }
+
+ d := minBackoff << uint(retry)
+ if d < minBackoff {
+ return maxBackoff
+ }
+
+ d = minBackoff + time.Duration(rand.Int63n(int64(d)))
+
+ if d > maxBackoff || d < minBackoff {
+ d = maxBackoff
+ }
+
+ return d
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/log.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/log.go
new file mode 100644
index 000000000000..c8b9213de48c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/log.go
@@ -0,0 +1,26 @@
+package internal
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "os"
+)
+
+type Logging interface {
+ Printf(ctx context.Context, format string, v ...interface{})
+}
+
+type logger struct {
+ log *log.Logger
+}
+
+func (l *logger) Printf(ctx context.Context, format string, v ...interface{}) {
+ _ = l.log.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Logger calls Output to print to the stderr.
+// Arguments are handled in the manner of fmt.Print.
+var Logger Logging = &logger{
+ log: log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile),
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/once.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/once.go
new file mode 100644
index 000000000000..64f46272aedc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/once.go
@@ -0,0 +1,60 @@
+/*
+Copyright 2014 The Camlistore Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package internal
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// A Once will perform a successful action exactly once.
+//
+// Unlike a sync.Once, this Once's func returns an error
+// and is re-armed on failure.
+type Once struct {
+ m sync.Mutex
+ done uint32
+}
+
+// Do calls the function f if and only if Do has not been invoked
+// without error for this instance of Once. In other words, given
+// var once Once
+// if once.Do(f) is called multiple times, only the first call will
+// invoke f, even if f has a different value in each invocation unless
+// f returns an error. A new instance of Once is required for each
+// function to execute.
+//
+// Do is intended for initialization that must be run exactly once. Since f
+// is niladic, it may be necessary to use a function literal to capture the
+// arguments to a function to be invoked by Do:
+// err := config.once.Do(func() error { return config.init(filename) })
+func (o *Once) Do(f func() error) error {
+ if atomic.LoadUint32(&o.done) == 1 {
+ return nil
+ }
+ // Slow-path.
+ o.m.Lock()
+ defer o.m.Unlock()
+ var err error
+ if o.done == 0 {
+ err = f()
+ if err == nil {
+ atomic.StoreUint32(&o.done, 1)
+ }
+ }
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go
new file mode 100644
index 000000000000..566165986512
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go
@@ -0,0 +1,121 @@
+package pool
+
+import (
+ "bufio"
+ "context"
+ "net"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal/proto"
+)
+
+var noDeadline = time.Time{}
+
+type Conn struct {
+ usedAt int64 // atomic
+ netConn net.Conn
+
+ rd *proto.Reader
+ bw *bufio.Writer
+ wr *proto.Writer
+
+ Inited bool
+ pooled bool
+ createdAt time.Time
+}
+
+func NewConn(netConn net.Conn) *Conn {
+ cn := &Conn{
+ netConn: netConn,
+ createdAt: time.Now(),
+ }
+ cn.rd = proto.NewReader(netConn)
+ cn.bw = bufio.NewWriter(netConn)
+ cn.wr = proto.NewWriter(cn.bw)
+ cn.SetUsedAt(time.Now())
+ return cn
+}
+
+func (cn *Conn) UsedAt() time.Time {
+ unix := atomic.LoadInt64(&cn.usedAt)
+ return time.Unix(unix, 0)
+}
+
+func (cn *Conn) SetUsedAt(tm time.Time) {
+ atomic.StoreInt64(&cn.usedAt, tm.Unix())
+}
+
+func (cn *Conn) SetNetConn(netConn net.Conn) {
+ cn.netConn = netConn
+ cn.rd.Reset(netConn)
+ cn.bw.Reset(netConn)
+}
+
+func (cn *Conn) Write(b []byte) (int, error) {
+ return cn.netConn.Write(b)
+}
+
+func (cn *Conn) RemoteAddr() net.Addr {
+ if cn.netConn != nil {
+ return cn.netConn.RemoteAddr()
+ }
+ return nil
+}
+
+func (cn *Conn) WithReader(ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error) error {
+ if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil {
+ return err
+ }
+ return fn(cn.rd)
+}
+
+func (cn *Conn) WithWriter(
+ ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error,
+) error {
+ if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil {
+ return err
+ }
+
+ if cn.bw.Buffered() > 0 {
+ cn.bw.Reset(cn.netConn)
+ }
+
+ if err := fn(cn.wr); err != nil {
+ return err
+ }
+
+ return cn.bw.Flush()
+}
+
+func (cn *Conn) Close() error {
+ return cn.netConn.Close()
+}
+
+func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) time.Time {
+ tm := time.Now()
+ cn.SetUsedAt(tm)
+
+ if timeout > 0 {
+ tm = tm.Add(timeout)
+ }
+
+ if ctx != nil {
+ deadline, ok := ctx.Deadline()
+ if ok {
+ if timeout == 0 {
+ return deadline
+ }
+ if deadline.Before(tm) {
+ return deadline
+ }
+ return tm
+ }
+ }
+
+ if timeout > 0 {
+ return tm
+ }
+
+ return noDeadline
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go
new file mode 100644
index 000000000000..44a4e779dfae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go
@@ -0,0 +1,557 @@
+package pool
+
+import (
+ "context"
+ "errors"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+)
+
+var (
+ // ErrClosed performs any operation on the closed client will return this error.
+ ErrClosed = errors.New("redis: client is closed")
+
+ // ErrPoolTimeout timed out waiting to get a connection from the connection pool.
+ ErrPoolTimeout = errors.New("redis: connection pool timeout")
+)
+
+var timers = sync.Pool{
+ New: func() interface{} {
+ t := time.NewTimer(time.Hour)
+ t.Stop()
+ return t
+ },
+}
+
+// Stats contains pool state information and accumulated stats.
+type Stats struct {
+ Hits uint32 // number of times free connection was found in the pool
+ Misses uint32 // number of times free connection was NOT found in the pool
+ Timeouts uint32 // number of times a wait timeout occurred
+
+ TotalConns uint32 // number of total connections in the pool
+ IdleConns uint32 // number of idle connections in the pool
+ StaleConns uint32 // number of stale connections removed from the pool
+}
+
+type Pooler interface {
+ NewConn(context.Context) (*Conn, error)
+ CloseConn(*Conn) error
+
+ Get(context.Context) (*Conn, error)
+ Put(context.Context, *Conn)
+ Remove(context.Context, *Conn, error)
+
+ Len() int
+ IdleLen() int
+ Stats() *Stats
+
+ Close() error
+}
+
+type Options struct {
+ Dialer func(context.Context) (net.Conn, error)
+ OnClose func(*Conn) error
+
+ PoolFIFO bool
+ PoolSize int
+ MinIdleConns int
+ MaxConnAge time.Duration
+ PoolTimeout time.Duration
+ IdleTimeout time.Duration
+ IdleCheckFrequency time.Duration
+}
+
+type lastDialErrorWrap struct {
+ err error
+}
+
+type ConnPool struct {
+ opt *Options
+
+ dialErrorsNum uint32 // atomic
+
+ lastDialError atomic.Value
+
+ queue chan struct{}
+
+ connsMu sync.Mutex
+ conns []*Conn
+ idleConns []*Conn
+ poolSize int
+ idleConnsLen int
+
+ stats Stats
+
+ _closed uint32 // atomic
+ closedCh chan struct{}
+}
+
+var _ Pooler = (*ConnPool)(nil)
+
+func NewConnPool(opt *Options) *ConnPool {
+ p := &ConnPool{
+ opt: opt,
+
+ queue: make(chan struct{}, opt.PoolSize),
+ conns: make([]*Conn, 0, opt.PoolSize),
+ idleConns: make([]*Conn, 0, opt.PoolSize),
+ closedCh: make(chan struct{}),
+ }
+
+ p.connsMu.Lock()
+ p.checkMinIdleConns()
+ p.connsMu.Unlock()
+
+ if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
+ go p.reaper(opt.IdleCheckFrequency)
+ }
+
+ return p
+}
+
+func (p *ConnPool) checkMinIdleConns() {
+ if p.opt.MinIdleConns == 0 {
+ return
+ }
+ for p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns {
+ p.poolSize++
+ p.idleConnsLen++
+
+ go func() {
+ err := p.addIdleConn()
+ if err != nil && err != ErrClosed {
+ p.connsMu.Lock()
+ p.poolSize--
+ p.idleConnsLen--
+ p.connsMu.Unlock()
+ }
+ }()
+ }
+}
+
+func (p *ConnPool) addIdleConn() error {
+ cn, err := p.dialConn(context.TODO(), true)
+ if err != nil {
+ return err
+ }
+
+ p.connsMu.Lock()
+ defer p.connsMu.Unlock()
+
+ // It is not allowed to add new connections to the closed connection pool.
+ if p.closed() {
+ _ = cn.Close()
+ return ErrClosed
+ }
+
+ p.conns = append(p.conns, cn)
+ p.idleConns = append(p.idleConns, cn)
+ return nil
+}
+
+func (p *ConnPool) NewConn(ctx context.Context) (*Conn, error) {
+ return p.newConn(ctx, false)
+}
+
+func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, error) {
+ cn, err := p.dialConn(ctx, pooled)
+ if err != nil {
+ return nil, err
+ }
+
+ p.connsMu.Lock()
+ defer p.connsMu.Unlock()
+
+ // It is not allowed to add new connections to the closed connection pool.
+ if p.closed() {
+ _ = cn.Close()
+ return nil, ErrClosed
+ }
+
+ p.conns = append(p.conns, cn)
+ if pooled {
+ // If pool is full remove the cn on next Put.
+ if p.poolSize >= p.opt.PoolSize {
+ cn.pooled = false
+ } else {
+ p.poolSize++
+ }
+ }
+
+ return cn, nil
+}
+
+func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, error) {
+ if p.closed() {
+ return nil, ErrClosed
+ }
+
+ if atomic.LoadUint32(&p.dialErrorsNum) >= uint32(p.opt.PoolSize) {
+ return nil, p.getLastDialError()
+ }
+
+ netConn, err := p.opt.Dialer(ctx)
+ if err != nil {
+ p.setLastDialError(err)
+ if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.opt.PoolSize) {
+ go p.tryDial()
+ }
+ return nil, err
+ }
+
+ cn := NewConn(netConn)
+ cn.pooled = pooled
+ return cn, nil
+}
+
+func (p *ConnPool) tryDial() {
+ for {
+ if p.closed() {
+ return
+ }
+
+ conn, err := p.opt.Dialer(context.Background())
+ if err != nil {
+ p.setLastDialError(err)
+ time.Sleep(time.Second)
+ continue
+ }
+
+ atomic.StoreUint32(&p.dialErrorsNum, 0)
+ _ = conn.Close()
+ return
+ }
+}
+
+func (p *ConnPool) setLastDialError(err error) {
+ p.lastDialError.Store(&lastDialErrorWrap{err: err})
+}
+
+func (p *ConnPool) getLastDialError() error {
+ err, _ := p.lastDialError.Load().(*lastDialErrorWrap)
+ if err != nil {
+ return err.err
+ }
+ return nil
+}
+
+// Get returns existed connection from the pool or creates a new one.
+func (p *ConnPool) Get(ctx context.Context) (*Conn, error) {
+ if p.closed() {
+ return nil, ErrClosed
+ }
+
+ if err := p.waitTurn(ctx); err != nil {
+ return nil, err
+ }
+
+ for {
+ p.connsMu.Lock()
+ cn, err := p.popIdle()
+ p.connsMu.Unlock()
+
+ if err != nil {
+ return nil, err
+ }
+
+ if cn == nil {
+ break
+ }
+
+ if p.isStaleConn(cn) {
+ _ = p.CloseConn(cn)
+ continue
+ }
+
+ atomic.AddUint32(&p.stats.Hits, 1)
+ return cn, nil
+ }
+
+ atomic.AddUint32(&p.stats.Misses, 1)
+
+ newcn, err := p.newConn(ctx, true)
+ if err != nil {
+ p.freeTurn()
+ return nil, err
+ }
+
+ return newcn, nil
+}
+
+func (p *ConnPool) getTurn() {
+ p.queue <- struct{}{}
+}
+
+func (p *ConnPool) waitTurn(ctx context.Context) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ }
+
+ select {
+ case p.queue <- struct{}{}:
+ return nil
+ default:
+ }
+
+ timer := timers.Get().(*time.Timer)
+ timer.Reset(p.opt.PoolTimeout)
+
+ select {
+ case <-ctx.Done():
+ if !timer.Stop() {
+ <-timer.C
+ }
+ timers.Put(timer)
+ return ctx.Err()
+ case p.queue <- struct{}{}:
+ if !timer.Stop() {
+ <-timer.C
+ }
+ timers.Put(timer)
+ return nil
+ case <-timer.C:
+ timers.Put(timer)
+ atomic.AddUint32(&p.stats.Timeouts, 1)
+ return ErrPoolTimeout
+ }
+}
+
+func (p *ConnPool) freeTurn() {
+ <-p.queue
+}
+
+func (p *ConnPool) popIdle() (*Conn, error) {
+ if p.closed() {
+ return nil, ErrClosed
+ }
+ n := len(p.idleConns)
+ if n == 0 {
+ return nil, nil
+ }
+
+ var cn *Conn
+ if p.opt.PoolFIFO {
+ cn = p.idleConns[0]
+ copy(p.idleConns, p.idleConns[1:])
+ p.idleConns = p.idleConns[:n-1]
+ } else {
+ idx := n - 1
+ cn = p.idleConns[idx]
+ p.idleConns = p.idleConns[:idx]
+ }
+ p.idleConnsLen--
+ p.checkMinIdleConns()
+ return cn, nil
+}
+
+func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
+ if cn.rd.Buffered() > 0 {
+ internal.Logger.Printf(ctx, "Conn has unread data")
+ p.Remove(ctx, cn, BadConnError{})
+ return
+ }
+
+ if !cn.pooled {
+ p.Remove(ctx, cn, nil)
+ return
+ }
+
+ p.connsMu.Lock()
+ p.idleConns = append(p.idleConns, cn)
+ p.idleConnsLen++
+ p.connsMu.Unlock()
+ p.freeTurn()
+}
+
+func (p *ConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
+ p.removeConnWithLock(cn)
+ p.freeTurn()
+ _ = p.closeConn(cn)
+}
+
+func (p *ConnPool) CloseConn(cn *Conn) error {
+ p.removeConnWithLock(cn)
+ return p.closeConn(cn)
+}
+
+func (p *ConnPool) removeConnWithLock(cn *Conn) {
+ p.connsMu.Lock()
+ p.removeConn(cn)
+ p.connsMu.Unlock()
+}
+
+func (p *ConnPool) removeConn(cn *Conn) {
+ for i, c := range p.conns {
+ if c == cn {
+ p.conns = append(p.conns[:i], p.conns[i+1:]...)
+ if cn.pooled {
+ p.poolSize--
+ p.checkMinIdleConns()
+ }
+ return
+ }
+ }
+}
+
+func (p *ConnPool) closeConn(cn *Conn) error {
+ if p.opt.OnClose != nil {
+ _ = p.opt.OnClose(cn)
+ }
+ return cn.Close()
+}
+
+// Len returns total number of connections.
+func (p *ConnPool) Len() int {
+ p.connsMu.Lock()
+ n := len(p.conns)
+ p.connsMu.Unlock()
+ return n
+}
+
+// IdleLen returns number of idle connections.
+func (p *ConnPool) IdleLen() int {
+ p.connsMu.Lock()
+ n := p.idleConnsLen
+ p.connsMu.Unlock()
+ return n
+}
+
+func (p *ConnPool) Stats() *Stats {
+ idleLen := p.IdleLen()
+ return &Stats{
+ Hits: atomic.LoadUint32(&p.stats.Hits),
+ Misses: atomic.LoadUint32(&p.stats.Misses),
+ Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
+
+ TotalConns: uint32(p.Len()),
+ IdleConns: uint32(idleLen),
+ StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
+ }
+}
+
+func (p *ConnPool) closed() bool {
+ return atomic.LoadUint32(&p._closed) == 1
+}
+
+func (p *ConnPool) Filter(fn func(*Conn) bool) error {
+ p.connsMu.Lock()
+ defer p.connsMu.Unlock()
+
+ var firstErr error
+ for _, cn := range p.conns {
+ if fn(cn) {
+ if err := p.closeConn(cn); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+ }
+ return firstErr
+}
+
+func (p *ConnPool) Close() error {
+ if !atomic.CompareAndSwapUint32(&p._closed, 0, 1) {
+ return ErrClosed
+ }
+ close(p.closedCh)
+
+ var firstErr error
+ p.connsMu.Lock()
+ for _, cn := range p.conns {
+ if err := p.closeConn(cn); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+ p.conns = nil
+ p.poolSize = 0
+ p.idleConns = nil
+ p.idleConnsLen = 0
+ p.connsMu.Unlock()
+
+ return firstErr
+}
+
+func (p *ConnPool) reaper(frequency time.Duration) {
+ ticker := time.NewTicker(frequency)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ticker.C:
+ // It is possible that ticker and closedCh arrive together,
+ // and select pseudo-randomly pick ticker case, we double
+ // check here to prevent being executed after closed.
+ if p.closed() {
+ return
+ }
+ _, err := p.ReapStaleConns()
+ if err != nil {
+ internal.Logger.Printf(context.Background(), "ReapStaleConns failed: %s", err)
+ continue
+ }
+ case <-p.closedCh:
+ return
+ }
+ }
+}
+
+func (p *ConnPool) ReapStaleConns() (int, error) {
+ var n int
+ for {
+ p.getTurn()
+
+ p.connsMu.Lock()
+ cn := p.reapStaleConn()
+ p.connsMu.Unlock()
+
+ p.freeTurn()
+
+ if cn != nil {
+ _ = p.closeConn(cn)
+ n++
+ } else {
+ break
+ }
+ }
+ atomic.AddUint32(&p.stats.StaleConns, uint32(n))
+ return n, nil
+}
+
+func (p *ConnPool) reapStaleConn() *Conn {
+ if len(p.idleConns) == 0 {
+ return nil
+ }
+
+ cn := p.idleConns[0]
+ if !p.isStaleConn(cn) {
+ return nil
+ }
+
+ p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
+ p.idleConnsLen--
+ p.removeConn(cn)
+
+ return cn
+}
+
+func (p *ConnPool) isStaleConn(cn *Conn) bool {
+ if p.opt.IdleTimeout == 0 && p.opt.MaxConnAge == 0 {
+ return false
+ }
+
+ now := time.Now()
+ if p.opt.IdleTimeout > 0 && now.Sub(cn.UsedAt()) >= p.opt.IdleTimeout {
+ return true
+ }
+ if p.opt.MaxConnAge > 0 && now.Sub(cn.createdAt) >= p.opt.MaxConnAge {
+ return true
+ }
+
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go
new file mode 100644
index 000000000000..5a3fde191bbb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go
@@ -0,0 +1,58 @@
+package pool
+
+import "context"
+
+type SingleConnPool struct {
+ pool Pooler
+ cn *Conn
+ stickyErr error
+}
+
+var _ Pooler = (*SingleConnPool)(nil)
+
+func NewSingleConnPool(pool Pooler, cn *Conn) *SingleConnPool {
+ return &SingleConnPool{
+ pool: pool,
+ cn: cn,
+ }
+}
+
+func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) {
+ return p.pool.NewConn(ctx)
+}
+
+func (p *SingleConnPool) CloseConn(cn *Conn) error {
+ return p.pool.CloseConn(cn)
+}
+
+func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) {
+ if p.stickyErr != nil {
+ return nil, p.stickyErr
+ }
+ return p.cn, nil
+}
+
+func (p *SingleConnPool) Put(ctx context.Context, cn *Conn) {}
+
+func (p *SingleConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
+ p.cn = nil
+ p.stickyErr = reason
+}
+
+func (p *SingleConnPool) Close() error {
+ p.cn = nil
+ p.stickyErr = ErrClosed
+ return nil
+}
+
+func (p *SingleConnPool) Len() int {
+ return 0
+}
+
+func (p *SingleConnPool) IdleLen() int {
+ return 0
+}
+
+func (p *SingleConnPool) Stats() *Stats {
+ return &Stats{}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go
new file mode 100644
index 000000000000..3adb99bc820f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go
@@ -0,0 +1,201 @@
+package pool
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync/atomic"
+)
+
+const (
+ stateDefault = 0
+ stateInited = 1
+ stateClosed = 2
+)
+
+type BadConnError struct {
+ wrapped error
+}
+
+var _ error = (*BadConnError)(nil)
+
+func (e BadConnError) Error() string {
+ s := "redis: Conn is in a bad state"
+ if e.wrapped != nil {
+ s += ": " + e.wrapped.Error()
+ }
+ return s
+}
+
+func (e BadConnError) Unwrap() error {
+ return e.wrapped
+}
+
+//------------------------------------------------------------------------------
+
+type StickyConnPool struct {
+ pool Pooler
+ shared int32 // atomic
+
+ state uint32 // atomic
+ ch chan *Conn
+
+ _badConnError atomic.Value
+}
+
+var _ Pooler = (*StickyConnPool)(nil)
+
+func NewStickyConnPool(pool Pooler) *StickyConnPool {
+ p, ok := pool.(*StickyConnPool)
+ if !ok {
+ p = &StickyConnPool{
+ pool: pool,
+ ch: make(chan *Conn, 1),
+ }
+ }
+ atomic.AddInt32(&p.shared, 1)
+ return p
+}
+
+func (p *StickyConnPool) NewConn(ctx context.Context) (*Conn, error) {
+ return p.pool.NewConn(ctx)
+}
+
+func (p *StickyConnPool) CloseConn(cn *Conn) error {
+ return p.pool.CloseConn(cn)
+}
+
+func (p *StickyConnPool) Get(ctx context.Context) (*Conn, error) {
+ // In worst case this races with Close which is not a very common operation.
+ for i := 0; i < 1000; i++ {
+ switch atomic.LoadUint32(&p.state) {
+ case stateDefault:
+ cn, err := p.pool.Get(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) {
+ return cn, nil
+ }
+ p.pool.Remove(ctx, cn, ErrClosed)
+ case stateInited:
+ if err := p.badConnError(); err != nil {
+ return nil, err
+ }
+ cn, ok := <-p.ch
+ if !ok {
+ return nil, ErrClosed
+ }
+ return cn, nil
+ case stateClosed:
+ return nil, ErrClosed
+ default:
+ panic("not reached")
+ }
+ }
+ return nil, fmt.Errorf("redis: StickyConnPool.Get: infinite loop")
+}
+
+func (p *StickyConnPool) Put(ctx context.Context, cn *Conn) {
+ defer func() {
+ if recover() != nil {
+ p.freeConn(ctx, cn)
+ }
+ }()
+ p.ch <- cn
+}
+
+func (p *StickyConnPool) freeConn(ctx context.Context, cn *Conn) {
+ if err := p.badConnError(); err != nil {
+ p.pool.Remove(ctx, cn, err)
+ } else {
+ p.pool.Put(ctx, cn)
+ }
+}
+
+func (p *StickyConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
+ defer func() {
+ if recover() != nil {
+ p.pool.Remove(ctx, cn, ErrClosed)
+ }
+ }()
+ p._badConnError.Store(BadConnError{wrapped: reason})
+ p.ch <- cn
+}
+
+func (p *StickyConnPool) Close() error {
+ if shared := atomic.AddInt32(&p.shared, -1); shared > 0 {
+ return nil
+ }
+
+ for i := 0; i < 1000; i++ {
+ state := atomic.LoadUint32(&p.state)
+ if state == stateClosed {
+ return ErrClosed
+ }
+ if atomic.CompareAndSwapUint32(&p.state, state, stateClosed) {
+ close(p.ch)
+ cn, ok := <-p.ch
+ if ok {
+ p.freeConn(context.TODO(), cn)
+ }
+ return nil
+ }
+ }
+
+ return errors.New("redis: StickyConnPool.Close: infinite loop")
+}
+
+func (p *StickyConnPool) Reset(ctx context.Context) error {
+ if p.badConnError() == nil {
+ return nil
+ }
+
+ select {
+ case cn, ok := <-p.ch:
+ if !ok {
+ return ErrClosed
+ }
+ p.pool.Remove(ctx, cn, ErrClosed)
+ p._badConnError.Store(BadConnError{wrapped: nil})
+ default:
+ return errors.New("redis: StickyConnPool does not have a Conn")
+ }
+
+ if !atomic.CompareAndSwapUint32(&p.state, stateInited, stateDefault) {
+ state := atomic.LoadUint32(&p.state)
+ return fmt.Errorf("redis: invalid StickyConnPool state: %d", state)
+ }
+
+ return nil
+}
+
+func (p *StickyConnPool) badConnError() error {
+ if v := p._badConnError.Load(); v != nil {
+ if err := v.(BadConnError); err.wrapped != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *StickyConnPool) Len() int {
+ switch atomic.LoadUint32(&p.state) {
+ case stateDefault:
+ return 0
+ case stateInited:
+ return 1
+ case stateClosed:
+ return 0
+ default:
+ panic("not reached")
+ }
+}
+
+func (p *StickyConnPool) IdleLen() int {
+ return len(p.ch)
+}
+
+func (p *StickyConnPool) Stats() *Stats {
+ return &Stats{}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go
new file mode 100644
index 000000000000..0e6ca779b189
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go
@@ -0,0 +1,332 @@
+package proto
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+
+ "github.com/go-redis/redis/v8/internal/util"
+)
+
+// redis resp protocol data type.
+const (
+ ErrorReply = '-'
+ StatusReply = '+'
+ IntReply = ':'
+ StringReply = '$'
+ ArrayReply = '*'
+)
+
+//------------------------------------------------------------------------------
+
+const Nil = RedisError("redis: nil") // nolint:errname
+
+type RedisError string
+
+func (e RedisError) Error() string { return string(e) }
+
+func (RedisError) RedisError() {}
+
+//------------------------------------------------------------------------------
+
+type MultiBulkParse func(*Reader, int64) (interface{}, error)
+
+type Reader struct {
+ rd *bufio.Reader
+ _buf []byte
+}
+
+func NewReader(rd io.Reader) *Reader {
+ return &Reader{
+ rd: bufio.NewReader(rd),
+ _buf: make([]byte, 64),
+ }
+}
+
+func (r *Reader) Buffered() int {
+ return r.rd.Buffered()
+}
+
+func (r *Reader) Peek(n int) ([]byte, error) {
+ return r.rd.Peek(n)
+}
+
+func (r *Reader) Reset(rd io.Reader) {
+ r.rd.Reset(rd)
+}
+
+func (r *Reader) ReadLine() ([]byte, error) {
+ line, err := r.readLine()
+ if err != nil {
+ return nil, err
+ }
+ if isNilReply(line) {
+ return nil, Nil
+ }
+ return line, nil
+}
+
+// readLine that returns an error if:
+// - there is a pending read error;
+// - or line does not end with \r\n.
+func (r *Reader) readLine() ([]byte, error) {
+ b, err := r.rd.ReadSlice('\n')
+ if err != nil {
+ if err != bufio.ErrBufferFull {
+ return nil, err
+ }
+
+ full := make([]byte, len(b))
+ copy(full, b)
+
+ b, err = r.rd.ReadBytes('\n')
+ if err != nil {
+ return nil, err
+ }
+
+ full = append(full, b...) //nolint:makezero
+ b = full
+ }
+ if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' {
+ return nil, fmt.Errorf("redis: invalid reply: %q", b)
+ }
+ return b[:len(b)-2], nil
+}
+
+func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return nil, err
+ }
+
+ switch line[0] {
+ case ErrorReply:
+ return nil, ParseErrorReply(line)
+ case StatusReply:
+ return string(line[1:]), nil
+ case IntReply:
+ return util.ParseInt(line[1:], 10, 64)
+ case StringReply:
+ return r.readStringReply(line)
+ case ArrayReply:
+ n, err := parseArrayLen(line)
+ if err != nil {
+ return nil, err
+ }
+ if m == nil {
+ err := fmt.Errorf("redis: got %.100q, but multi bulk parser is nil", line)
+ return nil, err
+ }
+ return m(r, n)
+ }
+ return nil, fmt.Errorf("redis: can't parse %.100q", line)
+}
+
+func (r *Reader) ReadIntReply() (int64, error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return 0, err
+ }
+ switch line[0] {
+ case ErrorReply:
+ return 0, ParseErrorReply(line)
+ case IntReply:
+ return util.ParseInt(line[1:], 10, 64)
+ default:
+ return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
+ }
+}
+
+func (r *Reader) ReadString() (string, error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return "", err
+ }
+ switch line[0] {
+ case ErrorReply:
+ return "", ParseErrorReply(line)
+ case StringReply:
+ return r.readStringReply(line)
+ case StatusReply:
+ return string(line[1:]), nil
+ case IntReply:
+ return string(line[1:]), nil
+ default:
+ return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
+ }
+}
+
+func (r *Reader) readStringReply(line []byte) (string, error) {
+ if isNilReply(line) {
+ return "", Nil
+ }
+
+ replyLen, err := util.Atoi(line[1:])
+ if err != nil {
+ return "", err
+ }
+
+ b := make([]byte, replyLen+2)
+ _, err = io.ReadFull(r.rd, b)
+ if err != nil {
+ return "", err
+ }
+
+ return util.BytesToString(b[:replyLen]), nil
+}
+
+func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return nil, err
+ }
+ switch line[0] {
+ case ErrorReply:
+ return nil, ParseErrorReply(line)
+ case ArrayReply:
+ n, err := parseArrayLen(line)
+ if err != nil {
+ return nil, err
+ }
+ return m(r, n)
+ default:
+ return nil, fmt.Errorf("redis: can't parse array reply: %.100q", line)
+ }
+}
+
+func (r *Reader) ReadArrayLen() (int, error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return 0, err
+ }
+ switch line[0] {
+ case ErrorReply:
+ return 0, ParseErrorReply(line)
+ case ArrayReply:
+ n, err := parseArrayLen(line)
+ if err != nil {
+ return 0, err
+ }
+ return int(n), nil
+ default:
+ return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line)
+ }
+}
+
+func (r *Reader) ReadScanReply() ([]string, uint64, error) {
+ n, err := r.ReadArrayLen()
+ if err != nil {
+ return nil, 0, err
+ }
+ if n != 2 {
+ return nil, 0, fmt.Errorf("redis: got %d elements in scan reply, expected 2", n)
+ }
+
+ cursor, err := r.ReadUint()
+ if err != nil {
+ return nil, 0, err
+ }
+
+ n, err = r.ReadArrayLen()
+ if err != nil {
+ return nil, 0, err
+ }
+
+ keys := make([]string, n)
+
+ for i := 0; i < n; i++ {
+ key, err := r.ReadString()
+ if err != nil {
+ return nil, 0, err
+ }
+ keys[i] = key
+ }
+
+ return keys, cursor, err
+}
+
+func (r *Reader) ReadInt() (int64, error) {
+ b, err := r.readTmpBytesReply()
+ if err != nil {
+ return 0, err
+ }
+ return util.ParseInt(b, 10, 64)
+}
+
+func (r *Reader) ReadUint() (uint64, error) {
+ b, err := r.readTmpBytesReply()
+ if err != nil {
+ return 0, err
+ }
+ return util.ParseUint(b, 10, 64)
+}
+
+func (r *Reader) ReadFloatReply() (float64, error) {
+ b, err := r.readTmpBytesReply()
+ if err != nil {
+ return 0, err
+ }
+ return util.ParseFloat(b, 64)
+}
+
+func (r *Reader) readTmpBytesReply() ([]byte, error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return nil, err
+ }
+ switch line[0] {
+ case ErrorReply:
+ return nil, ParseErrorReply(line)
+ case StringReply:
+ return r._readTmpBytesReply(line)
+ case StatusReply:
+ return line[1:], nil
+ default:
+ return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
+ }
+}
+
+func (r *Reader) _readTmpBytesReply(line []byte) ([]byte, error) {
+ if isNilReply(line) {
+ return nil, Nil
+ }
+
+ replyLen, err := util.Atoi(line[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ buf := r.buf(replyLen + 2)
+ _, err = io.ReadFull(r.rd, buf)
+ if err != nil {
+ return nil, err
+ }
+
+ return buf[:replyLen], nil
+}
+
+func (r *Reader) buf(n int) []byte {
+ if n <= cap(r._buf) {
+ return r._buf[:n]
+ }
+ d := n - cap(r._buf)
+ r._buf = append(r._buf, make([]byte, d)...)
+ return r._buf
+}
+
+func isNilReply(b []byte) bool {
+ return len(b) == 3 &&
+ (b[0] == StringReply || b[0] == ArrayReply) &&
+ b[1] == '-' && b[2] == '1'
+}
+
+func ParseErrorReply(line []byte) error {
+ return RedisError(string(line[1:]))
+}
+
+func parseArrayLen(line []byte) (int64, error) {
+ if isNilReply(line) {
+ return 0, Nil
+ }
+ return util.ParseInt(line[1:], 10, 64)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go
new file mode 100644
index 000000000000..0e994765feed
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go
@@ -0,0 +1,180 @@
+package proto
+
+import (
+ "encoding"
+ "fmt"
+ "reflect"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal/util"
+)
+
+// Scan parses bytes `b` to `v` with appropriate type.
+//nolint:gocyclo
+func Scan(b []byte, v interface{}) error {
+ switch v := v.(type) {
+ case nil:
+ return fmt.Errorf("redis: Scan(nil)")
+ case *string:
+ *v = util.BytesToString(b)
+ return nil
+ case *[]byte:
+ *v = b
+ return nil
+ case *int:
+ var err error
+ *v, err = util.Atoi(b)
+ return err
+ case *int8:
+ n, err := util.ParseInt(b, 10, 8)
+ if err != nil {
+ return err
+ }
+ *v = int8(n)
+ return nil
+ case *int16:
+ n, err := util.ParseInt(b, 10, 16)
+ if err != nil {
+ return err
+ }
+ *v = int16(n)
+ return nil
+ case *int32:
+ n, err := util.ParseInt(b, 10, 32)
+ if err != nil {
+ return err
+ }
+ *v = int32(n)
+ return nil
+ case *int64:
+ n, err := util.ParseInt(b, 10, 64)
+ if err != nil {
+ return err
+ }
+ *v = n
+ return nil
+ case *uint:
+ n, err := util.ParseUint(b, 10, 64)
+ if err != nil {
+ return err
+ }
+ *v = uint(n)
+ return nil
+ case *uint8:
+ n, err := util.ParseUint(b, 10, 8)
+ if err != nil {
+ return err
+ }
+ *v = uint8(n)
+ return nil
+ case *uint16:
+ n, err := util.ParseUint(b, 10, 16)
+ if err != nil {
+ return err
+ }
+ *v = uint16(n)
+ return nil
+ case *uint32:
+ n, err := util.ParseUint(b, 10, 32)
+ if err != nil {
+ return err
+ }
+ *v = uint32(n)
+ return nil
+ case *uint64:
+ n, err := util.ParseUint(b, 10, 64)
+ if err != nil {
+ return err
+ }
+ *v = n
+ return nil
+ case *float32:
+ n, err := util.ParseFloat(b, 32)
+ if err != nil {
+ return err
+ }
+ *v = float32(n)
+ return err
+ case *float64:
+ var err error
+ *v, err = util.ParseFloat(b, 64)
+ return err
+ case *bool:
+ *v = len(b) == 1 && b[0] == '1'
+ return nil
+ case *time.Time:
+ var err error
+ *v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
+ return err
+ case *time.Duration:
+ n, err := util.ParseInt(b, 10, 64)
+ if err != nil {
+ return err
+ }
+ *v = time.Duration(n)
+ return nil
+ case encoding.BinaryUnmarshaler:
+ return v.UnmarshalBinary(b)
+ default:
+ return fmt.Errorf(
+ "redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
+ }
+}
+
+func ScanSlice(data []string, slice interface{}) error {
+ v := reflect.ValueOf(slice)
+ if !v.IsValid() {
+ return fmt.Errorf("redis: ScanSlice(nil)")
+ }
+ if v.Kind() != reflect.Ptr {
+ return fmt.Errorf("redis: ScanSlice(non-pointer %T)", slice)
+ }
+ v = v.Elem()
+ if v.Kind() != reflect.Slice {
+ return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
+ }
+
+ next := makeSliceNextElemFunc(v)
+ for i, s := range data {
+ elem := next()
+ if err := Scan([]byte(s), elem.Addr().Interface()); err != nil {
+ err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %w", i, s, err)
+ return err
+ }
+ }
+
+ return nil
+}
+
+func makeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
+ elemType := v.Type().Elem()
+
+ if elemType.Kind() == reflect.Ptr {
+ elemType = elemType.Elem()
+ return func() reflect.Value {
+ if v.Len() < v.Cap() {
+ v.Set(v.Slice(0, v.Len()+1))
+ elem := v.Index(v.Len() - 1)
+ if elem.IsNil() {
+ elem.Set(reflect.New(elemType))
+ }
+ return elem.Elem()
+ }
+
+ elem := reflect.New(elemType)
+ v.Set(reflect.Append(v, elem))
+ return elem.Elem()
+ }
+ }
+
+ zero := reflect.Zero(elemType)
+ return func() reflect.Value {
+ if v.Len() < v.Cap() {
+ v.Set(v.Slice(0, v.Len()+1))
+ return v.Index(v.Len() - 1)
+ }
+
+ v.Set(reflect.Append(v, zero))
+ return v.Index(v.Len() - 1)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/writer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/writer.go
new file mode 100644
index 000000000000..c4260981ed14
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/proto/writer.go
@@ -0,0 +1,155 @@
+package proto
+
+import (
+ "encoding"
+ "fmt"
+ "io"
+ "strconv"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal/util"
+)
+
+type writer interface {
+ io.Writer
+ io.ByteWriter
+ // io.StringWriter
+ WriteString(s string) (n int, err error)
+}
+
+type Writer struct {
+ writer
+
+ lenBuf []byte
+ numBuf []byte
+}
+
+func NewWriter(wr writer) *Writer {
+ return &Writer{
+ writer: wr,
+
+ lenBuf: make([]byte, 64),
+ numBuf: make([]byte, 64),
+ }
+}
+
+func (w *Writer) WriteArgs(args []interface{}) error {
+ if err := w.WriteByte(ArrayReply); err != nil {
+ return err
+ }
+
+ if err := w.writeLen(len(args)); err != nil {
+ return err
+ }
+
+ for _, arg := range args {
+ if err := w.WriteArg(arg); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (w *Writer) writeLen(n int) error {
+ w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10)
+ w.lenBuf = append(w.lenBuf, '\r', '\n')
+ _, err := w.Write(w.lenBuf)
+ return err
+}
+
+func (w *Writer) WriteArg(v interface{}) error {
+ switch v := v.(type) {
+ case nil:
+ return w.string("")
+ case string:
+ return w.string(v)
+ case []byte:
+ return w.bytes(v)
+ case int:
+ return w.int(int64(v))
+ case int8:
+ return w.int(int64(v))
+ case int16:
+ return w.int(int64(v))
+ case int32:
+ return w.int(int64(v))
+ case int64:
+ return w.int(v)
+ case uint:
+ return w.uint(uint64(v))
+ case uint8:
+ return w.uint(uint64(v))
+ case uint16:
+ return w.uint(uint64(v))
+ case uint32:
+ return w.uint(uint64(v))
+ case uint64:
+ return w.uint(v)
+ case float32:
+ return w.float(float64(v))
+ case float64:
+ return w.float(v)
+ case bool:
+ if v {
+ return w.int(1)
+ }
+ return w.int(0)
+ case time.Time:
+ w.numBuf = v.AppendFormat(w.numBuf[:0], time.RFC3339Nano)
+ return w.bytes(w.numBuf)
+ case time.Duration:
+ return w.int(v.Nanoseconds())
+ case encoding.BinaryMarshaler:
+ b, err := v.MarshalBinary()
+ if err != nil {
+ return err
+ }
+ return w.bytes(b)
+ default:
+ return fmt.Errorf(
+ "redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
+ }
+}
+
+func (w *Writer) bytes(b []byte) error {
+ if err := w.WriteByte(StringReply); err != nil {
+ return err
+ }
+
+ if err := w.writeLen(len(b)); err != nil {
+ return err
+ }
+
+ if _, err := w.Write(b); err != nil {
+ return err
+ }
+
+ return w.crlf()
+}
+
+func (w *Writer) string(s string) error {
+ return w.bytes(util.StringToBytes(s))
+}
+
+func (w *Writer) uint(n uint64) error {
+ w.numBuf = strconv.AppendUint(w.numBuf[:0], n, 10)
+ return w.bytes(w.numBuf)
+}
+
+func (w *Writer) int(n int64) error {
+ w.numBuf = strconv.AppendInt(w.numBuf[:0], n, 10)
+ return w.bytes(w.numBuf)
+}
+
+func (w *Writer) float(f float64) error {
+ w.numBuf = strconv.AppendFloat(w.numBuf[:0], f, 'f', -1, 64)
+ return w.bytes(w.numBuf)
+}
+
+func (w *Writer) crlf() error {
+ if err := w.WriteByte('\r'); err != nil {
+ return err
+ }
+ return w.WriteByte('\n')
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go
new file mode 100644
index 000000000000..2edccba94fe8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go
@@ -0,0 +1,50 @@
+package rand
+
+import (
+ "math/rand"
+ "sync"
+)
+
+// Int returns a non-negative pseudo-random int.
+func Int() int { return pseudo.Int() }
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
+func Intn(n int) int { return pseudo.Intn(n) }
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
+func Int63n(n int64) int64 { return pseudo.Int63n(n) }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func Perm(n int) []int { return pseudo.Perm(n) }
+
+// Seed uses the provided seed value to initialize the default Source to a
+// deterministic state. If Seed is not called, the generator behaves as if
+// seeded by Seed(1).
+func Seed(n int64) { pseudo.Seed(n) }
+
+var pseudo = rand.New(&source{src: rand.NewSource(1)})
+
+type source struct {
+ src rand.Source
+ mu sync.Mutex
+}
+
+func (s *source) Int63() int64 {
+ s.mu.Lock()
+ n := s.src.Int63()
+ s.mu.Unlock()
+ return n
+}
+
+func (s *source) Seed(seed int64) {
+ s.mu.Lock()
+ s.src.Seed(seed)
+ s.mu.Unlock()
+}
+
+// Shuffle pseudo-randomizes the order of elements.
+// n is the number of elements.
+// swap swaps the elements with indexes i and j.
+func Shuffle(n int, swap func(i, j int)) { pseudo.Shuffle(n, swap) }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/safe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/safe.go
new file mode 100644
index 000000000000..fd2f43409472
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/safe.go
@@ -0,0 +1,12 @@
+//go:build appengine
+// +build appengine
+
+package internal
+
+func String(b []byte) string {
+ return string(b)
+}
+
+func Bytes(s string) []byte {
+ return []byte(s)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/unsafe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/unsafe.go
new file mode 100644
index 000000000000..9f2e418f7901
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/unsafe.go
@@ -0,0 +1,21 @@
+//go:build !appengine
+// +build !appengine
+
+package internal
+
+import "unsafe"
+
+// String converts byte slice to string.
+func String(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+// Bytes converts string to byte slice.
+func Bytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(
+ &struct {
+ string
+ Cap int
+ }{s, len(s)},
+ ))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util.go
new file mode 100644
index 000000000000..e34a7f032620
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util.go
@@ -0,0 +1,46 @@
+package internal
+
+import (
+ "context"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal/util"
+)
+
+func Sleep(ctx context.Context, dur time.Duration) error {
+ t := time.NewTimer(dur)
+ defer t.Stop()
+
+ select {
+ case <-t.C:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
+
+func ToLower(s string) string {
+ if isLower(s) {
+ return s
+ }
+
+ b := make([]byte, len(s))
+ for i := range b {
+ c := s[i]
+ if c >= 'A' && c <= 'Z' {
+ c += 'a' - 'A'
+ }
+ b[i] = c
+ }
+ return util.BytesToString(b)
+}
+
+func isLower(s string) bool {
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c >= 'A' && c <= 'Z' {
+ return false
+ }
+ }
+ return true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/safe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/safe.go
new file mode 100644
index 000000000000..21307110bd54
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/safe.go
@@ -0,0 +1,12 @@
+//go:build appengine
+// +build appengine
+
+package util
+
+func BytesToString(b []byte) string {
+ return string(b)
+}
+
+func StringToBytes(s string) []byte {
+ return []byte(s)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/strconv.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/strconv.go
new file mode 100644
index 000000000000..db5033802a95
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/strconv.go
@@ -0,0 +1,19 @@
+package util
+
+import "strconv"
+
+func Atoi(b []byte) (int, error) {
+ return strconv.Atoi(BytesToString(b))
+}
+
+func ParseInt(b []byte, base int, bitSize int) (int64, error) {
+ return strconv.ParseInt(BytesToString(b), base, bitSize)
+}
+
+func ParseUint(b []byte, base int, bitSize int) (uint64, error) {
+ return strconv.ParseUint(BytesToString(b), base, bitSize)
+}
+
+func ParseFloat(b []byte, bitSize int) (float64, error) {
+ return strconv.ParseFloat(BytesToString(b), bitSize)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go
new file mode 100644
index 000000000000..daa8d7692ae0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go
@@ -0,0 +1,23 @@
+//go:build !appengine
+// +build !appengine
+
+package util
+
+import (
+ "unsafe"
+)
+
+// BytesToString converts byte slice to string.
+func BytesToString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+// StringToBytes converts string to byte slice.
+func StringToBytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(
+ &struct {
+ string
+ Cap int
+ }{s, len(s)},
+ ))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/iterator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/iterator.go
new file mode 100644
index 000000000000..2f8bc2beda08
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/iterator.go
@@ -0,0 +1,77 @@
+package redis
+
+import (
+ "context"
+ "sync"
+)
+
+// ScanIterator is used to incrementally iterate over a collection of elements.
+// It's safe for concurrent use by multiple goroutines.
+type ScanIterator struct {
+ mu sync.Mutex // protects Scanner and pos
+ cmd *ScanCmd
+ pos int
+}
+
+// Err returns the last iterator error, if any.
+func (it *ScanIterator) Err() error {
+ it.mu.Lock()
+ err := it.cmd.Err()
+ it.mu.Unlock()
+ return err
+}
+
+// Next advances the cursor and returns true if more values can be read.
+func (it *ScanIterator) Next(ctx context.Context) bool {
+ it.mu.Lock()
+ defer it.mu.Unlock()
+
+ // Instantly return on errors.
+ if it.cmd.Err() != nil {
+ return false
+ }
+
+ // Advance cursor, check if we are still within range.
+ if it.pos < len(it.cmd.page) {
+ it.pos++
+ return true
+ }
+
+ for {
+ // Return if there is no more data to fetch.
+ if it.cmd.cursor == 0 {
+ return false
+ }
+
+ // Fetch next page.
+ switch it.cmd.args[0] {
+ case "scan", "qscan":
+ it.cmd.args[1] = it.cmd.cursor
+ default:
+ it.cmd.args[2] = it.cmd.cursor
+ }
+
+ err := it.cmd.process(ctx, it.cmd)
+ if err != nil {
+ return false
+ }
+
+ it.pos = 1
+
+ // Redis can occasionally return empty page.
+ if len(it.cmd.page) > 0 {
+ return true
+ }
+ }
+}
+
+// Val returns the key/field at the current cursor position.
+func (it *ScanIterator) Val() string {
+ var v string
+ it.mu.Lock()
+ if it.cmd.Err() == nil && it.pos > 0 && it.pos <= len(it.cmd.page) {
+ v = it.cmd.page[it.pos-1]
+ }
+ it.mu.Unlock()
+ return v
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/options.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/options.go
new file mode 100644
index 000000000000..a4abe32c3a04
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/options.go
@@ -0,0 +1,429 @@
+package redis
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "net"
+ "net/url"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal/pool"
+)
+
+// Limiter is the interface of a rate limiter or a circuit breaker.
+type Limiter interface {
+ // Allow returns nil if operation is allowed or an error otherwise.
+ // If operation is allowed client must ReportResult of the operation
+ // whether it is a success or a failure.
+ Allow() error
+ // ReportResult reports the result of the previously allowed operation.
+ // nil indicates a success, non-nil error usually indicates a failure.
+ ReportResult(result error)
+}
+
+// Options keeps the settings to setup redis connection.
+type Options struct {
+ // The network type, either tcp or unix.
+ // Default is tcp.
+ Network string
+ // host:port address.
+ Addr string
+
+ // Dialer creates new network connection and has priority over
+ // Network and Addr options.
+ Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ // Hook that is called when new connection is established.
+ OnConnect func(ctx context.Context, cn *Conn) error
+
+ // Use the specified Username to authenticate the current connection
+ // with one of the connections defined in the ACL list when connecting
+ // to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
+ Username string
+ // Optional password. Must match the password specified in the
+ // requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower),
+ // or the User Password when connecting to a Redis 6.0 instance, or greater,
+ // that is using the Redis ACL system.
+ Password string
+
+ // Database to be selected after connecting to the server.
+ DB int
+
+ // Maximum number of retries before giving up.
+ // Default is 3 retries; -1 (not 0) disables retries.
+ MaxRetries int
+ // Minimum backoff between each retry.
+ // Default is 8 milliseconds; -1 disables backoff.
+ MinRetryBackoff time.Duration
+ // Maximum backoff between each retry.
+ // Default is 512 milliseconds; -1 disables backoff.
+ MaxRetryBackoff time.Duration
+
+ // Dial timeout for establishing new connections.
+ // Default is 5 seconds.
+ DialTimeout time.Duration
+ // Timeout for socket reads. If reached, commands will fail
+ // with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
+ // Default is 3 seconds.
+ ReadTimeout time.Duration
+ // Timeout for socket writes. If reached, commands will fail
+ // with a timeout instead of blocking.
+ // Default is ReadTimeout.
+ WriteTimeout time.Duration
+
+ // Type of connection pool.
+ // true for FIFO pool, false for LIFO pool.
+ // Note that fifo has higher overhead compared to lifo.
+ PoolFIFO bool
+ // Maximum number of socket connections.
+ // Default is 10 connections per every available CPU as reported by runtime.GOMAXPROCS.
+ PoolSize int
+ // Minimum number of idle connections which is useful when establishing
+ // new connection is slow.
+ MinIdleConns int
+ // Connection age at which client retires (closes) the connection.
+ // Default is to not close aged connections.
+ MaxConnAge time.Duration
+ // Amount of time client waits for connection if all connections
+ // are busy before returning an error.
+ // Default is ReadTimeout + 1 second.
+ PoolTimeout time.Duration
+ // Amount of time after which client closes idle connections.
+ // Should be less than server's timeout.
+ // Default is 5 minutes. -1 disables idle timeout check.
+ IdleTimeout time.Duration
+ // Frequency of idle checks made by idle connections reaper.
+ // Default is 1 minute. -1 disables idle connections reaper,
+ // but idle connections are still discarded by the client
+ // if IdleTimeout is set.
+ IdleCheckFrequency time.Duration
+
+ // Enables read only queries on slave nodes.
+ readOnly bool
+
+ // TLS Config to use. When set TLS will be negotiated.
+ TLSConfig *tls.Config
+
+ // Limiter interface used to implemented circuit breaker or rate limiter.
+ Limiter Limiter
+}
+
+func (opt *Options) init() {
+ if opt.Addr == "" {
+ opt.Addr = "localhost:6379"
+ }
+ if opt.Network == "" {
+ if strings.HasPrefix(opt.Addr, "/") {
+ opt.Network = "unix"
+ } else {
+ opt.Network = "tcp"
+ }
+ }
+ if opt.DialTimeout == 0 {
+ opt.DialTimeout = 5 * time.Second
+ }
+ if opt.Dialer == nil {
+ opt.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
+ netDialer := &net.Dialer{
+ Timeout: opt.DialTimeout,
+ KeepAlive: 5 * time.Minute,
+ }
+ if opt.TLSConfig == nil {
+ return netDialer.DialContext(ctx, network, addr)
+ }
+ return tls.DialWithDialer(netDialer, network, addr, opt.TLSConfig)
+ }
+ }
+ if opt.PoolSize == 0 {
+ opt.PoolSize = 10 * runtime.GOMAXPROCS(0)
+ }
+ switch opt.ReadTimeout {
+ case -1:
+ opt.ReadTimeout = 0
+ case 0:
+ opt.ReadTimeout = 3 * time.Second
+ }
+ switch opt.WriteTimeout {
+ case -1:
+ opt.WriteTimeout = 0
+ case 0:
+ opt.WriteTimeout = opt.ReadTimeout
+ }
+ if opt.PoolTimeout == 0 {
+ opt.PoolTimeout = opt.ReadTimeout + time.Second
+ }
+ if opt.IdleTimeout == 0 {
+ opt.IdleTimeout = 5 * time.Minute
+ }
+ if opt.IdleCheckFrequency == 0 {
+ opt.IdleCheckFrequency = time.Minute
+ }
+
+ if opt.MaxRetries == -1 {
+ opt.MaxRetries = 0
+ } else if opt.MaxRetries == 0 {
+ opt.MaxRetries = 3
+ }
+ switch opt.MinRetryBackoff {
+ case -1:
+ opt.MinRetryBackoff = 0
+ case 0:
+ opt.MinRetryBackoff = 8 * time.Millisecond
+ }
+ switch opt.MaxRetryBackoff {
+ case -1:
+ opt.MaxRetryBackoff = 0
+ case 0:
+ opt.MaxRetryBackoff = 512 * time.Millisecond
+ }
+}
+
+func (opt *Options) clone() *Options {
+ clone := *opt
+ return &clone
+}
+
+// ParseURL parses an URL into Options that can be used to connect to Redis.
+// Scheme is required.
+// There are two connection types: by tcp socket and by unix socket.
+// Tcp connection:
+// redis://:@:/
+// Unix connection:
+// unix://:@?db=
+// Most Option fields can be set using query parameters, with the following restrictions:
+// - field names are mapped using snake-case conversion: to set MaxRetries, use max_retries
+// - only scalar type fields are supported (bool, int, time.Duration)
+// - for time.Duration fields, values must be a valid input for time.ParseDuration();
+// additionally a plain integer as value (i.e. without unit) is intepreted as seconds
+// - to disable a duration field, use value less than or equal to 0; to use the default
+// value, leave the value blank or remove the parameter
+// - only the last value is interpreted if a parameter is given multiple times
+// - fields "network", "addr", "username" and "password" can only be set using other
+// URL attributes (scheme, host, userinfo, resp.), query paremeters using these
+// names will be treated as unknown parameters
+// - unknown parameter names will result in an error
+// Examples:
+// redis://user:password@localhost:6789/3?dial_timeout=3&db=1&read_timeout=6s&max_retries=2
+// is equivalent to:
+// &Options{
+// Network: "tcp",
+// Addr: "localhost:6789",
+// DB: 1, // path "/3" was overridden by "&db=1"
+// DialTimeout: 3 * time.Second, // no time unit = seconds
+// ReadTimeout: 6 * time.Second,
+// MaxRetries: 2,
+// }
+func ParseURL(redisURL string) (*Options, error) {
+ u, err := url.Parse(redisURL)
+ if err != nil {
+ return nil, err
+ }
+
+ switch u.Scheme {
+ case "redis", "rediss":
+ return setupTCPConn(u)
+ case "unix":
+ return setupUnixConn(u)
+ default:
+ return nil, fmt.Errorf("redis: invalid URL scheme: %s", u.Scheme)
+ }
+}
+
+func setupTCPConn(u *url.URL) (*Options, error) {
+ o := &Options{Network: "tcp"}
+
+ o.Username, o.Password = getUserPassword(u)
+
+ h, p, err := net.SplitHostPort(u.Host)
+ if err != nil {
+ h = u.Host
+ }
+ if h == "" {
+ h = "localhost"
+ }
+ if p == "" {
+ p = "6379"
+ }
+ o.Addr = net.JoinHostPort(h, p)
+
+ f := strings.FieldsFunc(u.Path, func(r rune) bool {
+ return r == '/'
+ })
+ switch len(f) {
+ case 0:
+ o.DB = 0
+ case 1:
+ if o.DB, err = strconv.Atoi(f[0]); err != nil {
+ return nil, fmt.Errorf("redis: invalid database number: %q", f[0])
+ }
+ default:
+ return nil, fmt.Errorf("redis: invalid URL path: %s", u.Path)
+ }
+
+ if u.Scheme == "rediss" {
+ o.TLSConfig = &tls.Config{ServerName: h}
+ }
+
+ return setupConnParams(u, o)
+}
+
+func setupUnixConn(u *url.URL) (*Options, error) {
+ o := &Options{
+ Network: "unix",
+ }
+
+ if strings.TrimSpace(u.Path) == "" { // path is required with unix connection
+ return nil, errors.New("redis: empty unix socket path")
+ }
+ o.Addr = u.Path
+ o.Username, o.Password = getUserPassword(u)
+ return setupConnParams(u, o)
+}
+
+type queryOptions struct {
+ q url.Values
+ err error
+}
+
+func (o *queryOptions) string(name string) string {
+ vs := o.q[name]
+ if len(vs) == 0 {
+ return ""
+ }
+ delete(o.q, name) // enable detection of unknown parameters
+ return vs[len(vs)-1]
+}
+
+func (o *queryOptions) int(name string) int {
+ s := o.string(name)
+ if s == "" {
+ return 0
+ }
+ i, err := strconv.Atoi(s)
+ if err == nil {
+ return i
+ }
+ if o.err == nil {
+ o.err = fmt.Errorf("redis: invalid %s number: %s", name, err)
+ }
+ return 0
+}
+
+func (o *queryOptions) duration(name string) time.Duration {
+ s := o.string(name)
+ if s == "" {
+ return 0
+ }
+ // try plain number first
+ if i, err := strconv.Atoi(s); err == nil {
+ if i <= 0 {
+ // disable timeouts
+ return -1
+ }
+ return time.Duration(i) * time.Second
+ }
+ dur, err := time.ParseDuration(s)
+ if err == nil {
+ return dur
+ }
+ if o.err == nil {
+ o.err = fmt.Errorf("redis: invalid %s duration: %w", name, err)
+ }
+ return 0
+}
+
+func (o *queryOptions) bool(name string) bool {
+ switch s := o.string(name); s {
+ case "true", "1":
+ return true
+ case "false", "0", "":
+ return false
+ default:
+ if o.err == nil {
+ o.err = fmt.Errorf("redis: invalid %s boolean: expected true/false/1/0 or an empty string, got %q", name, s)
+ }
+ return false
+ }
+}
+
+func (o *queryOptions) remaining() []string {
+ if len(o.q) == 0 {
+ return nil
+ }
+ keys := make([]string, 0, len(o.q))
+ for k := range o.q {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+// setupConnParams converts query parameters in u to option value in o.
+func setupConnParams(u *url.URL, o *Options) (*Options, error) {
+ q := queryOptions{q: u.Query()}
+
+ // compat: a future major release may use q.int("db")
+ if tmp := q.string("db"); tmp != "" {
+ db, err := strconv.Atoi(tmp)
+ if err != nil {
+ return nil, fmt.Errorf("redis: invalid database number: %w", err)
+ }
+ o.DB = db
+ }
+
+ o.MaxRetries = q.int("max_retries")
+ o.MinRetryBackoff = q.duration("min_retry_backoff")
+ o.MaxRetryBackoff = q.duration("max_retry_backoff")
+ o.DialTimeout = q.duration("dial_timeout")
+ o.ReadTimeout = q.duration("read_timeout")
+ o.WriteTimeout = q.duration("write_timeout")
+ o.PoolFIFO = q.bool("pool_fifo")
+ o.PoolSize = q.int("pool_size")
+ o.MinIdleConns = q.int("min_idle_conns")
+ o.MaxConnAge = q.duration("max_conn_age")
+ o.PoolTimeout = q.duration("pool_timeout")
+ o.IdleTimeout = q.duration("idle_timeout")
+ o.IdleCheckFrequency = q.duration("idle_check_frequency")
+ if q.err != nil {
+ return nil, q.err
+ }
+
+ // any parameters left?
+ if r := q.remaining(); len(r) > 0 {
+ return nil, fmt.Errorf("redis: unexpected option: %s", strings.Join(r, ", "))
+ }
+
+ return o, nil
+}
+
+func getUserPassword(u *url.URL) (string, string) {
+ var user, password string
+ if u.User != nil {
+ user = u.User.Username()
+ if p, ok := u.User.Password(); ok {
+ password = p
+ }
+ }
+ return user, password
+}
+
+func newConnPool(opt *Options) *pool.ConnPool {
+ return pool.NewConnPool(&pool.Options{
+ Dialer: func(ctx context.Context) (net.Conn, error) {
+ return opt.Dialer(ctx, opt.Network, opt.Addr)
+ },
+ PoolFIFO: opt.PoolFIFO,
+ PoolSize: opt.PoolSize,
+ MinIdleConns: opt.MinIdleConns,
+ MaxConnAge: opt.MaxConnAge,
+ PoolTimeout: opt.PoolTimeout,
+ IdleTimeout: opt.IdleTimeout,
+ IdleCheckFrequency: opt.IdleCheckFrequency,
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/package.json b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/package.json
new file mode 100644
index 000000000000..e4ea4bb074c4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "redis",
+ "version": "8.11.5",
+ "main": "index.js",
+ "repository": "git@github.com:go-redis/redis.git",
+ "author": "Vladimir Mihailenco ",
+ "license": "BSD-2-clause"
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/pipeline.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/pipeline.go
new file mode 100644
index 000000000000..31bab971e63f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/pipeline.go
@@ -0,0 +1,147 @@
+package redis
+
+import (
+ "context"
+ "sync"
+
+ "github.com/go-redis/redis/v8/internal/pool"
+)
+
+type pipelineExecer func(context.Context, []Cmder) error
+
+// Pipeliner is an mechanism to realise Redis Pipeline technique.
+//
+// Pipelining is a technique to extremely speed up processing by packing
+// operations to batches, send them at once to Redis and read a replies in a
+// singe step.
+// See https://redis.io/topics/pipelining
+//
+// Pay attention, that Pipeline is not a transaction, so you can get unexpected
+// results in case of big pipelines and small read/write timeouts.
+// Redis client has retransmission logic in case of timeouts, pipeline
+// can be retransmitted and commands can be executed more then once.
+// To avoid this: it is good idea to use reasonable bigger read/write timeouts
+// depends of your batch size and/or use TxPipeline.
+type Pipeliner interface {
+ StatefulCmdable
+ Len() int
+ Do(ctx context.Context, args ...interface{}) *Cmd
+ Process(ctx context.Context, cmd Cmder) error
+ Close() error
+ Discard() error
+ Exec(ctx context.Context) ([]Cmder, error)
+}
+
+var _ Pipeliner = (*Pipeline)(nil)
+
+// Pipeline implements pipelining as described in
+// http://redis.io/topics/pipelining. It's safe for concurrent use
+// by multiple goroutines.
+type Pipeline struct {
+ cmdable
+ statefulCmdable
+
+ ctx context.Context
+ exec pipelineExecer
+
+ mu sync.Mutex
+ cmds []Cmder
+ closed bool
+}
+
+func (c *Pipeline) init() {
+ c.cmdable = c.Process
+ c.statefulCmdable = c.Process
+}
+
+// Len returns the number of queued commands.
+func (c *Pipeline) Len() int {
+ c.mu.Lock()
+ ln := len(c.cmds)
+ c.mu.Unlock()
+ return ln
+}
+
+// Do queues the custom command for later execution.
+func (c *Pipeline) Do(ctx context.Context, args ...interface{}) *Cmd {
+ cmd := NewCmd(ctx, args...)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Process queues the cmd for later execution.
+func (c *Pipeline) Process(ctx context.Context, cmd Cmder) error {
+ c.mu.Lock()
+ c.cmds = append(c.cmds, cmd)
+ c.mu.Unlock()
+ return nil
+}
+
+// Close closes the pipeline, releasing any open resources.
+func (c *Pipeline) Close() error {
+ c.mu.Lock()
+ _ = c.discard()
+ c.closed = true
+ c.mu.Unlock()
+ return nil
+}
+
+// Discard resets the pipeline and discards queued commands.
+func (c *Pipeline) Discard() error {
+ c.mu.Lock()
+ err := c.discard()
+ c.mu.Unlock()
+ return err
+}
+
+func (c *Pipeline) discard() error {
+ if c.closed {
+ return pool.ErrClosed
+ }
+ c.cmds = c.cmds[:0]
+ return nil
+}
+
+// Exec executes all previously queued commands using one
+// client-server roundtrip.
+//
+// Exec always returns list of commands and error of the first failed
+// command if any.
+func (c *Pipeline) Exec(ctx context.Context) ([]Cmder, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.closed {
+ return nil, pool.ErrClosed
+ }
+
+ if len(c.cmds) == 0 {
+ return nil, nil
+ }
+
+ cmds := c.cmds
+ c.cmds = nil
+
+ return cmds, c.exec(ctx, cmds)
+}
+
+func (c *Pipeline) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ if err := fn(c); err != nil {
+ return nil, err
+ }
+ cmds, err := c.Exec(ctx)
+ _ = c.Close()
+ return cmds, err
+}
+
+func (c *Pipeline) Pipeline() Pipeliner {
+ return c
+}
+
+func (c *Pipeline) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.Pipelined(ctx, fn)
+}
+
+func (c *Pipeline) TxPipeline() Pipeliner {
+ return c
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/pubsub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/pubsub.go
new file mode 100644
index 000000000000..efc2354af0c5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/pubsub.go
@@ -0,0 +1,668 @@
+package redis
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/proto"
+)
+
+// PubSub implements Pub/Sub commands as described in
+// http://redis.io/topics/pubsub. Message receiving is NOT safe
+// for concurrent use by multiple goroutines.
+//
+// PubSub automatically reconnects to Redis Server and resubscribes
+// to the channels in case of network errors.
+type PubSub struct {
+ opt *Options
+
+ newConn func(ctx context.Context, channels []string) (*pool.Conn, error)
+ closeConn func(*pool.Conn) error
+
+ mu sync.Mutex
+ cn *pool.Conn
+ channels map[string]struct{}
+ patterns map[string]struct{}
+
+ closed bool
+ exit chan struct{}
+
+ cmd *Cmd
+
+ chOnce sync.Once
+ msgCh *channel
+ allCh *channel
+}
+
+func (c *PubSub) init() {
+ c.exit = make(chan struct{})
+}
+
+func (c *PubSub) String() string {
+ channels := mapKeys(c.channels)
+ channels = append(channels, mapKeys(c.patterns)...)
+ return fmt.Sprintf("PubSub(%s)", strings.Join(channels, ", "))
+}
+
+func (c *PubSub) connWithLock(ctx context.Context) (*pool.Conn, error) {
+ c.mu.Lock()
+ cn, err := c.conn(ctx, nil)
+ c.mu.Unlock()
+ return cn, err
+}
+
+func (c *PubSub) conn(ctx context.Context, newChannels []string) (*pool.Conn, error) {
+ if c.closed {
+ return nil, pool.ErrClosed
+ }
+ if c.cn != nil {
+ return c.cn, nil
+ }
+
+ channels := mapKeys(c.channels)
+ channels = append(channels, newChannels...)
+
+ cn, err := c.newConn(ctx, channels)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := c.resubscribe(ctx, cn); err != nil {
+ _ = c.closeConn(cn)
+ return nil, err
+ }
+
+ c.cn = cn
+ return cn, nil
+}
+
+func (c *PubSub) writeCmd(ctx context.Context, cn *pool.Conn, cmd Cmder) error {
+ return cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
+ return writeCmd(wr, cmd)
+ })
+}
+
+func (c *PubSub) resubscribe(ctx context.Context, cn *pool.Conn) error {
+ var firstErr error
+
+ if len(c.channels) > 0 {
+ firstErr = c._subscribe(ctx, cn, "subscribe", mapKeys(c.channels))
+ }
+
+ if len(c.patterns) > 0 {
+ err := c._subscribe(ctx, cn, "psubscribe", mapKeys(c.patterns))
+ if err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+
+ return firstErr
+}
+
+func mapKeys(m map[string]struct{}) []string {
+ s := make([]string, len(m))
+ i := 0
+ for k := range m {
+ s[i] = k
+ i++
+ }
+ return s
+}
+
+func (c *PubSub) _subscribe(
+ ctx context.Context, cn *pool.Conn, redisCmd string, channels []string,
+) error {
+ args := make([]interface{}, 0, 1+len(channels))
+ args = append(args, redisCmd)
+ for _, channel := range channels {
+ args = append(args, channel)
+ }
+ cmd := NewSliceCmd(ctx, args...)
+ return c.writeCmd(ctx, cn, cmd)
+}
+
+func (c *PubSub) releaseConnWithLock(
+ ctx context.Context,
+ cn *pool.Conn,
+ err error,
+ allowTimeout bool,
+) {
+ c.mu.Lock()
+ c.releaseConn(ctx, cn, err, allowTimeout)
+ c.mu.Unlock()
+}
+
+func (c *PubSub) releaseConn(ctx context.Context, cn *pool.Conn, err error, allowTimeout bool) {
+ if c.cn != cn {
+ return
+ }
+ if isBadConn(err, allowTimeout, c.opt.Addr) {
+ c.reconnect(ctx, err)
+ }
+}
+
+func (c *PubSub) reconnect(ctx context.Context, reason error) {
+ _ = c.closeTheCn(reason)
+ _, _ = c.conn(ctx, nil)
+}
+
+func (c *PubSub) closeTheCn(reason error) error {
+ if c.cn == nil {
+ return nil
+ }
+ if !c.closed {
+ internal.Logger.Printf(c.getContext(), "redis: discarding bad PubSub connection: %s", reason)
+ }
+ err := c.closeConn(c.cn)
+ c.cn = nil
+ return err
+}
+
+func (c *PubSub) Close() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.closed {
+ return pool.ErrClosed
+ }
+ c.closed = true
+ close(c.exit)
+
+ return c.closeTheCn(pool.ErrClosed)
+}
+
+// Subscribe the client to the specified channels. It returns
+// empty subscription if there are no channels.
+func (c *PubSub) Subscribe(ctx context.Context, channels ...string) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ err := c.subscribe(ctx, "subscribe", channels...)
+ if c.channels == nil {
+ c.channels = make(map[string]struct{})
+ }
+ for _, s := range channels {
+ c.channels[s] = struct{}{}
+ }
+ return err
+}
+
+// PSubscribe the client to the given patterns. It returns
+// empty subscription if there are no patterns.
+func (c *PubSub) PSubscribe(ctx context.Context, patterns ...string) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ err := c.subscribe(ctx, "psubscribe", patterns...)
+ if c.patterns == nil {
+ c.patterns = make(map[string]struct{})
+ }
+ for _, s := range patterns {
+ c.patterns[s] = struct{}{}
+ }
+ return err
+}
+
+// Unsubscribe the client from the given channels, or from all of
+// them if none is given.
+func (c *PubSub) Unsubscribe(ctx context.Context, channels ...string) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ for _, channel := range channels {
+ delete(c.channels, channel)
+ }
+ err := c.subscribe(ctx, "unsubscribe", channels...)
+ return err
+}
+
+// PUnsubscribe the client from the given patterns, or from all of
+// them if none is given.
+func (c *PubSub) PUnsubscribe(ctx context.Context, patterns ...string) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ for _, pattern := range patterns {
+ delete(c.patterns, pattern)
+ }
+ err := c.subscribe(ctx, "punsubscribe", patterns...)
+ return err
+}
+
+func (c *PubSub) subscribe(ctx context.Context, redisCmd string, channels ...string) error {
+ cn, err := c.conn(ctx, channels)
+ if err != nil {
+ return err
+ }
+
+ err = c._subscribe(ctx, cn, redisCmd, channels)
+ c.releaseConn(ctx, cn, err, false)
+ return err
+}
+
+func (c *PubSub) Ping(ctx context.Context, payload ...string) error {
+ args := []interface{}{"ping"}
+ if len(payload) == 1 {
+ args = append(args, payload[0])
+ }
+ cmd := NewCmd(ctx, args...)
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ cn, err := c.conn(ctx, nil)
+ if err != nil {
+ return err
+ }
+
+ err = c.writeCmd(ctx, cn, cmd)
+ c.releaseConn(ctx, cn, err, false)
+ return err
+}
+
+// Subscription received after a successful subscription to channel.
+type Subscription struct {
+ // Can be "subscribe", "unsubscribe", "psubscribe" or "punsubscribe".
+ Kind string
+ // Channel name we have subscribed to.
+ Channel string
+ // Number of channels we are currently subscribed to.
+ Count int
+}
+
+func (m *Subscription) String() string {
+ return fmt.Sprintf("%s: %s", m.Kind, m.Channel)
+}
+
+// Message received as result of a PUBLISH command issued by another client.
+type Message struct {
+ Channel string
+ Pattern string
+ Payload string
+ PayloadSlice []string
+}
+
+func (m *Message) String() string {
+ return fmt.Sprintf("Message<%s: %s>", m.Channel, m.Payload)
+}
+
+// Pong received as result of a PING command issued by another client.
+type Pong struct {
+ Payload string
+}
+
+func (p *Pong) String() string {
+ if p.Payload != "" {
+ return fmt.Sprintf("Pong<%s>", p.Payload)
+ }
+ return "Pong"
+}
+
+func (c *PubSub) newMessage(reply interface{}) (interface{}, error) {
+ switch reply := reply.(type) {
+ case string:
+ return &Pong{
+ Payload: reply,
+ }, nil
+ case []interface{}:
+ switch kind := reply[0].(string); kind {
+ case "subscribe", "unsubscribe", "psubscribe", "punsubscribe":
+ // Can be nil in case of "unsubscribe".
+ channel, _ := reply[1].(string)
+ return &Subscription{
+ Kind: kind,
+ Channel: channel,
+ Count: int(reply[2].(int64)),
+ }, nil
+ case "message":
+ switch payload := reply[2].(type) {
+ case string:
+ return &Message{
+ Channel: reply[1].(string),
+ Payload: payload,
+ }, nil
+ case []interface{}:
+ ss := make([]string, len(payload))
+ for i, s := range payload {
+ ss[i] = s.(string)
+ }
+ return &Message{
+ Channel: reply[1].(string),
+ PayloadSlice: ss,
+ }, nil
+ default:
+ return nil, fmt.Errorf("redis: unsupported pubsub message payload: %T", payload)
+ }
+ case "pmessage":
+ return &Message{
+ Pattern: reply[1].(string),
+ Channel: reply[2].(string),
+ Payload: reply[3].(string),
+ }, nil
+ case "pong":
+ return &Pong{
+ Payload: reply[1].(string),
+ }, nil
+ default:
+ return nil, fmt.Errorf("redis: unsupported pubsub message: %q", kind)
+ }
+ default:
+ return nil, fmt.Errorf("redis: unsupported pubsub message: %#v", reply)
+ }
+}
+
+// ReceiveTimeout acts like Receive but returns an error if message
+// is not received in time. This is low-level API and in most cases
+// Channel should be used instead.
+func (c *PubSub) ReceiveTimeout(ctx context.Context, timeout time.Duration) (interface{}, error) {
+ if c.cmd == nil {
+ c.cmd = NewCmd(ctx)
+ }
+
+ // Don't hold the lock to allow subscriptions and pings.
+
+ cn, err := c.connWithLock(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ err = cn.WithReader(ctx, timeout, func(rd *proto.Reader) error {
+ return c.cmd.readReply(rd)
+ })
+
+ c.releaseConnWithLock(ctx, cn, err, timeout > 0)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return c.newMessage(c.cmd.Val())
+}
+
+// Receive returns a message as a Subscription, Message, Pong or error.
+// See PubSub example for details. This is low-level API and in most cases
+// Channel should be used instead.
+func (c *PubSub) Receive(ctx context.Context) (interface{}, error) {
+ return c.ReceiveTimeout(ctx, 0)
+}
+
+// ReceiveMessage returns a Message or error ignoring Subscription and Pong
+// messages. This is low-level API and in most cases Channel should be used
+// instead.
+func (c *PubSub) ReceiveMessage(ctx context.Context) (*Message, error) {
+ for {
+ msg, err := c.Receive(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ switch msg := msg.(type) {
+ case *Subscription:
+ // Ignore.
+ case *Pong:
+ // Ignore.
+ case *Message:
+ return msg, nil
+ default:
+ err := fmt.Errorf("redis: unknown message: %T", msg)
+ return nil, err
+ }
+ }
+}
+
+func (c *PubSub) getContext() context.Context {
+ if c.cmd != nil {
+ return c.cmd.ctx
+ }
+ return context.Background()
+}
+
+//------------------------------------------------------------------------------
+
+// Channel returns a Go channel for concurrently receiving messages.
+// The channel is closed together with the PubSub. If the Go channel
+// is blocked full for 30 seconds the message is dropped.
+// Receive* APIs can not be used after channel is created.
+//
+// go-redis periodically sends ping messages to test connection health
+// and re-subscribes if ping can not not received for 30 seconds.
+func (c *PubSub) Channel(opts ...ChannelOption) <-chan *Message {
+ c.chOnce.Do(func() {
+ c.msgCh = newChannel(c, opts...)
+ c.msgCh.initMsgChan()
+ })
+ if c.msgCh == nil {
+ err := fmt.Errorf("redis: Channel can't be called after ChannelWithSubscriptions")
+ panic(err)
+ }
+ return c.msgCh.msgCh
+}
+
+// ChannelSize is like Channel, but creates a Go channel
+// with specified buffer size.
+//
+// Deprecated: use Channel(WithChannelSize(size)), remove in v9.
+func (c *PubSub) ChannelSize(size int) <-chan *Message {
+ return c.Channel(WithChannelSize(size))
+}
+
+// ChannelWithSubscriptions is like Channel, but message type can be either
+// *Subscription or *Message. Subscription messages can be used to detect
+// reconnections.
+//
+// ChannelWithSubscriptions can not be used together with Channel or ChannelSize.
+func (c *PubSub) ChannelWithSubscriptions(_ context.Context, size int) <-chan interface{} {
+ c.chOnce.Do(func() {
+ c.allCh = newChannel(c, WithChannelSize(size))
+ c.allCh.initAllChan()
+ })
+ if c.allCh == nil {
+ err := fmt.Errorf("redis: ChannelWithSubscriptions can't be called after Channel")
+ panic(err)
+ }
+ return c.allCh.allCh
+}
+
+type ChannelOption func(c *channel)
+
+// WithChannelSize specifies the Go chan size that is used to buffer incoming messages.
+//
+// The default is 100 messages.
+func WithChannelSize(size int) ChannelOption {
+ return func(c *channel) {
+ c.chanSize = size
+ }
+}
+
+// WithChannelHealthCheckInterval specifies the health check interval.
+// PubSub will ping Redis Server if it does not receive any messages within the interval.
+// To disable health check, use zero interval.
+//
+// The default is 3 seconds.
+func WithChannelHealthCheckInterval(d time.Duration) ChannelOption {
+ return func(c *channel) {
+ c.checkInterval = d
+ }
+}
+
+// WithChannelSendTimeout specifies the channel send timeout after which
+// the message is dropped.
+//
+// The default is 60 seconds.
+func WithChannelSendTimeout(d time.Duration) ChannelOption {
+ return func(c *channel) {
+ c.chanSendTimeout = d
+ }
+}
+
+type channel struct {
+ pubSub *PubSub
+
+ msgCh chan *Message
+ allCh chan interface{}
+ ping chan struct{}
+
+ chanSize int
+ chanSendTimeout time.Duration
+ checkInterval time.Duration
+}
+
+func newChannel(pubSub *PubSub, opts ...ChannelOption) *channel {
+ c := &channel{
+ pubSub: pubSub,
+
+ chanSize: 100,
+ chanSendTimeout: time.Minute,
+ checkInterval: 3 * time.Second,
+ }
+ for _, opt := range opts {
+ opt(c)
+ }
+ if c.checkInterval > 0 {
+ c.initHealthCheck()
+ }
+ return c
+}
+
+func (c *channel) initHealthCheck() {
+ ctx := context.TODO()
+ c.ping = make(chan struct{}, 1)
+
+ go func() {
+ timer := time.NewTimer(time.Minute)
+ timer.Stop()
+
+ for {
+ timer.Reset(c.checkInterval)
+ select {
+ case <-c.ping:
+ if !timer.Stop() {
+ <-timer.C
+ }
+ case <-timer.C:
+ if pingErr := c.pubSub.Ping(ctx); pingErr != nil {
+ c.pubSub.mu.Lock()
+ c.pubSub.reconnect(ctx, pingErr)
+ c.pubSub.mu.Unlock()
+ }
+ case <-c.pubSub.exit:
+ return
+ }
+ }
+ }()
+}
+
+// initMsgChan must be in sync with initAllChan.
+func (c *channel) initMsgChan() {
+ ctx := context.TODO()
+ c.msgCh = make(chan *Message, c.chanSize)
+
+ go func() {
+ timer := time.NewTimer(time.Minute)
+ timer.Stop()
+
+ var errCount int
+ for {
+ msg, err := c.pubSub.Receive(ctx)
+ if err != nil {
+ if err == pool.ErrClosed {
+ close(c.msgCh)
+ return
+ }
+ if errCount > 0 {
+ time.Sleep(100 * time.Millisecond)
+ }
+ errCount++
+ continue
+ }
+
+ errCount = 0
+
+ // Any message is as good as a ping.
+ select {
+ case c.ping <- struct{}{}:
+ default:
+ }
+
+ switch msg := msg.(type) {
+ case *Subscription:
+ // Ignore.
+ case *Pong:
+ // Ignore.
+ case *Message:
+ timer.Reset(c.chanSendTimeout)
+ select {
+ case c.msgCh <- msg:
+ if !timer.Stop() {
+ <-timer.C
+ }
+ case <-timer.C:
+ internal.Logger.Printf(
+ ctx, "redis: %s channel is full for %s (message is dropped)",
+ c, c.chanSendTimeout)
+ }
+ default:
+ internal.Logger.Printf(ctx, "redis: unknown message type: %T", msg)
+ }
+ }
+ }()
+}
+
+// initAllChan must be in sync with initMsgChan.
+func (c *channel) initAllChan() {
+ ctx := context.TODO()
+ c.allCh = make(chan interface{}, c.chanSize)
+
+ go func() {
+ timer := time.NewTimer(time.Minute)
+ timer.Stop()
+
+ var errCount int
+ for {
+ msg, err := c.pubSub.Receive(ctx)
+ if err != nil {
+ if err == pool.ErrClosed {
+ close(c.allCh)
+ return
+ }
+ if errCount > 0 {
+ time.Sleep(100 * time.Millisecond)
+ }
+ errCount++
+ continue
+ }
+
+ errCount = 0
+
+ // Any message is as good as a ping.
+ select {
+ case c.ping <- struct{}{}:
+ default:
+ }
+
+ switch msg := msg.(type) {
+ case *Pong:
+ // Ignore.
+ case *Subscription, *Message:
+ timer.Reset(c.chanSendTimeout)
+ select {
+ case c.allCh <- msg:
+ if !timer.Stop() {
+ <-timer.C
+ }
+ case <-timer.C:
+ internal.Logger.Printf(
+ ctx, "redis: %s channel is full for %s (message is dropped)",
+ c, c.chanSendTimeout)
+ }
+ default:
+ internal.Logger.Printf(ctx, "redis: unknown message type: %T", msg)
+ }
+ }
+ }()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/redis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/redis.go
new file mode 100644
index 000000000000..bcf8a2a94bd0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/redis.go
@@ -0,0 +1,773 @@
+package redis
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/proto"
+)
+
+// Nil reply returned by Redis when key does not exist.
+const Nil = proto.Nil
+
+func SetLogger(logger internal.Logging) {
+ internal.Logger = logger
+}
+
+//------------------------------------------------------------------------------
+
+type Hook interface {
+ BeforeProcess(ctx context.Context, cmd Cmder) (context.Context, error)
+ AfterProcess(ctx context.Context, cmd Cmder) error
+
+ BeforeProcessPipeline(ctx context.Context, cmds []Cmder) (context.Context, error)
+ AfterProcessPipeline(ctx context.Context, cmds []Cmder) error
+}
+
+type hooks struct {
+ hooks []Hook
+}
+
+func (hs *hooks) lock() {
+ hs.hooks = hs.hooks[:len(hs.hooks):len(hs.hooks)]
+}
+
+func (hs hooks) clone() hooks {
+ clone := hs
+ clone.lock()
+ return clone
+}
+
+func (hs *hooks) AddHook(hook Hook) {
+ hs.hooks = append(hs.hooks, hook)
+}
+
+func (hs hooks) process(
+ ctx context.Context, cmd Cmder, fn func(context.Context, Cmder) error,
+) error {
+ if len(hs.hooks) == 0 {
+ err := fn(ctx, cmd)
+ cmd.SetErr(err)
+ return err
+ }
+
+ var hookIndex int
+ var retErr error
+
+ for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ {
+ ctx, retErr = hs.hooks[hookIndex].BeforeProcess(ctx, cmd)
+ if retErr != nil {
+ cmd.SetErr(retErr)
+ }
+ }
+
+ if retErr == nil {
+ retErr = fn(ctx, cmd)
+ cmd.SetErr(retErr)
+ }
+
+ for hookIndex--; hookIndex >= 0; hookIndex-- {
+ if err := hs.hooks[hookIndex].AfterProcess(ctx, cmd); err != nil {
+ retErr = err
+ cmd.SetErr(retErr)
+ }
+ }
+
+ return retErr
+}
+
+func (hs hooks) processPipeline(
+ ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error,
+) error {
+ if len(hs.hooks) == 0 {
+ err := fn(ctx, cmds)
+ return err
+ }
+
+ var hookIndex int
+ var retErr error
+
+ for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ {
+ ctx, retErr = hs.hooks[hookIndex].BeforeProcessPipeline(ctx, cmds)
+ if retErr != nil {
+ setCmdsErr(cmds, retErr)
+ }
+ }
+
+ if retErr == nil {
+ retErr = fn(ctx, cmds)
+ }
+
+ for hookIndex--; hookIndex >= 0; hookIndex-- {
+ if err := hs.hooks[hookIndex].AfterProcessPipeline(ctx, cmds); err != nil {
+ retErr = err
+ setCmdsErr(cmds, retErr)
+ }
+ }
+
+ return retErr
+}
+
+func (hs hooks) processTxPipeline(
+ ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error,
+) error {
+ cmds = wrapMultiExec(ctx, cmds)
+ return hs.processPipeline(ctx, cmds, fn)
+}
+
+//------------------------------------------------------------------------------
+
+type baseClient struct {
+ opt *Options
+ connPool pool.Pooler
+
+ onClose func() error // hook called when client is closed
+}
+
+func newBaseClient(opt *Options, connPool pool.Pooler) *baseClient {
+ return &baseClient{
+ opt: opt,
+ connPool: connPool,
+ }
+}
+
+func (c *baseClient) clone() *baseClient {
+ clone := *c
+ return &clone
+}
+
+func (c *baseClient) withTimeout(timeout time.Duration) *baseClient {
+ opt := c.opt.clone()
+ opt.ReadTimeout = timeout
+ opt.WriteTimeout = timeout
+
+ clone := c.clone()
+ clone.opt = opt
+
+ return clone
+}
+
+func (c *baseClient) String() string {
+ return fmt.Sprintf("Redis<%s db:%d>", c.getAddr(), c.opt.DB)
+}
+
+func (c *baseClient) newConn(ctx context.Context) (*pool.Conn, error) {
+ cn, err := c.connPool.NewConn(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ err = c.initConn(ctx, cn)
+ if err != nil {
+ _ = c.connPool.CloseConn(cn)
+ return nil, err
+ }
+
+ return cn, nil
+}
+
+func (c *baseClient) getConn(ctx context.Context) (*pool.Conn, error) {
+ if c.opt.Limiter != nil {
+ err := c.opt.Limiter.Allow()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ cn, err := c._getConn(ctx)
+ if err != nil {
+ if c.opt.Limiter != nil {
+ c.opt.Limiter.ReportResult(err)
+ }
+ return nil, err
+ }
+
+ return cn, nil
+}
+
+func (c *baseClient) _getConn(ctx context.Context) (*pool.Conn, error) {
+ cn, err := c.connPool.Get(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ if cn.Inited {
+ return cn, nil
+ }
+
+ if err := c.initConn(ctx, cn); err != nil {
+ c.connPool.Remove(ctx, cn, err)
+ if err := errors.Unwrap(err); err != nil {
+ return nil, err
+ }
+ return nil, err
+ }
+
+ return cn, nil
+}
+
+func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
+ if cn.Inited {
+ return nil
+ }
+ cn.Inited = true
+
+ if c.opt.Password == "" &&
+ c.opt.DB == 0 &&
+ !c.opt.readOnly &&
+ c.opt.OnConnect == nil {
+ return nil
+ }
+
+ connPool := pool.NewSingleConnPool(c.connPool, cn)
+ conn := newConn(ctx, c.opt, connPool)
+
+ _, err := conn.Pipelined(ctx, func(pipe Pipeliner) error {
+ if c.opt.Password != "" {
+ if c.opt.Username != "" {
+ pipe.AuthACL(ctx, c.opt.Username, c.opt.Password)
+ } else {
+ pipe.Auth(ctx, c.opt.Password)
+ }
+ }
+
+ if c.opt.DB > 0 {
+ pipe.Select(ctx, c.opt.DB)
+ }
+
+ if c.opt.readOnly {
+ pipe.ReadOnly(ctx)
+ }
+
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ if c.opt.OnConnect != nil {
+ return c.opt.OnConnect(ctx, conn)
+ }
+ return nil
+}
+
+func (c *baseClient) releaseConn(ctx context.Context, cn *pool.Conn, err error) {
+ if c.opt.Limiter != nil {
+ c.opt.Limiter.ReportResult(err)
+ }
+
+ if isBadConn(err, false, c.opt.Addr) {
+ c.connPool.Remove(ctx, cn, err)
+ } else {
+ c.connPool.Put(ctx, cn)
+ }
+}
+
+func (c *baseClient) withConn(
+ ctx context.Context, fn func(context.Context, *pool.Conn) error,
+) error {
+ cn, err := c.getConn(ctx)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ c.releaseConn(ctx, cn, err)
+ }()
+
+ done := ctx.Done() //nolint:ifshort
+
+ if done == nil {
+ err = fn(ctx, cn)
+ return err
+ }
+
+ errc := make(chan error, 1)
+ go func() { errc <- fn(ctx, cn) }()
+
+ select {
+ case <-done:
+ _ = cn.Close()
+ // Wait for the goroutine to finish and send something.
+ <-errc
+
+ err = ctx.Err()
+ return err
+ case err = <-errc:
+ return err
+ }
+}
+
+func (c *baseClient) process(ctx context.Context, cmd Cmder) error {
+ var lastErr error
+ for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
+ attempt := attempt
+
+ retry, err := c._process(ctx, cmd, attempt)
+ if err == nil || !retry {
+ return err
+ }
+
+ lastErr = err
+ }
+ return lastErr
+}
+
+func (c *baseClient) _process(ctx context.Context, cmd Cmder, attempt int) (bool, error) {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ return false, err
+ }
+ }
+
+ retryTimeout := uint32(1)
+ err := c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
+ err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
+ return writeCmd(wr, cmd)
+ })
+ if err != nil {
+ return err
+ }
+
+ err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply)
+ if err != nil {
+ if cmd.readTimeout() == nil {
+ atomic.StoreUint32(&retryTimeout, 1)
+ }
+ return err
+ }
+
+ return nil
+ })
+ if err == nil {
+ return false, nil
+ }
+
+ retry := shouldRetry(err, atomic.LoadUint32(&retryTimeout) == 1)
+ return retry, err
+}
+
+func (c *baseClient) retryBackoff(attempt int) time.Duration {
+ return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
+}
+
+func (c *baseClient) cmdTimeout(cmd Cmder) time.Duration {
+ if timeout := cmd.readTimeout(); timeout != nil {
+ t := *timeout
+ if t == 0 {
+ return 0
+ }
+ return t + 10*time.Second
+ }
+ return c.opt.ReadTimeout
+}
+
+// Close closes the client, releasing any open resources.
+//
+// It is rare to Close a Client, as the Client is meant to be
+// long-lived and shared between many goroutines.
+func (c *baseClient) Close() error {
+ var firstErr error
+ if c.onClose != nil {
+ if err := c.onClose(); err != nil {
+ firstErr = err
+ }
+ }
+ if err := c.connPool.Close(); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ return firstErr
+}
+
+func (c *baseClient) getAddr() string {
+ return c.opt.Addr
+}
+
+func (c *baseClient) processPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.generalProcessPipeline(ctx, cmds, c.pipelineProcessCmds)
+}
+
+func (c *baseClient) processTxPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.generalProcessPipeline(ctx, cmds, c.txPipelineProcessCmds)
+}
+
+type pipelineProcessor func(context.Context, *pool.Conn, []Cmder) (bool, error)
+
+func (c *baseClient) generalProcessPipeline(
+ ctx context.Context, cmds []Cmder, p pipelineProcessor,
+) error {
+ err := c._generalProcessPipeline(ctx, cmds, p)
+ if err != nil {
+ setCmdsErr(cmds, err)
+ return err
+ }
+ return cmdsFirstErr(cmds)
+}
+
+func (c *baseClient) _generalProcessPipeline(
+ ctx context.Context, cmds []Cmder, p pipelineProcessor,
+) error {
+ var lastErr error
+ for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ return err
+ }
+ }
+
+ var canRetry bool
+ lastErr = c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
+ var err error
+ canRetry, err = p(ctx, cn, cmds)
+ return err
+ })
+ if lastErr == nil || !canRetry || !shouldRetry(lastErr, true) {
+ return lastErr
+ }
+ }
+ return lastErr
+}
+
+func (c *baseClient) pipelineProcessCmds(
+ ctx context.Context, cn *pool.Conn, cmds []Cmder,
+) (bool, error) {
+ err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
+ return writeCmds(wr, cmds)
+ })
+ if err != nil {
+ return true, err
+ }
+
+ err = cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
+ return pipelineReadCmds(rd, cmds)
+ })
+ return true, err
+}
+
+func pipelineReadCmds(rd *proto.Reader, cmds []Cmder) error {
+ for _, cmd := range cmds {
+ err := cmd.readReply(rd)
+ cmd.SetErr(err)
+ if err != nil && !isRedisError(err) {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *baseClient) txPipelineProcessCmds(
+ ctx context.Context, cn *pool.Conn, cmds []Cmder,
+) (bool, error) {
+ err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
+ return writeCmds(wr, cmds)
+ })
+ if err != nil {
+ return true, err
+ }
+
+ err = cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
+ statusCmd := cmds[0].(*StatusCmd)
+ // Trim multi and exec.
+ cmds = cmds[1 : len(cmds)-1]
+
+ err := txPipelineReadQueued(rd, statusCmd, cmds)
+ if err != nil {
+ return err
+ }
+
+ return pipelineReadCmds(rd, cmds)
+ })
+ return false, err
+}
+
+func wrapMultiExec(ctx context.Context, cmds []Cmder) []Cmder {
+ if len(cmds) == 0 {
+ panic("not reached")
+ }
+ cmdCopy := make([]Cmder, len(cmds)+2)
+ cmdCopy[0] = NewStatusCmd(ctx, "multi")
+ copy(cmdCopy[1:], cmds)
+ cmdCopy[len(cmdCopy)-1] = NewSliceCmd(ctx, "exec")
+ return cmdCopy
+}
+
+func txPipelineReadQueued(rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder) error {
+ // Parse queued replies.
+ if err := statusCmd.readReply(rd); err != nil {
+ return err
+ }
+
+ for range cmds {
+ if err := statusCmd.readReply(rd); err != nil && !isRedisError(err) {
+ return err
+ }
+ }
+
+ // Parse number of replies.
+ line, err := rd.ReadLine()
+ if err != nil {
+ if err == Nil {
+ err = TxFailedErr
+ }
+ return err
+ }
+
+ switch line[0] {
+ case proto.ErrorReply:
+ return proto.ParseErrorReply(line)
+ case proto.ArrayReply:
+ // ok
+ default:
+ err := fmt.Errorf("redis: expected '*', but got line %q", line)
+ return err
+ }
+
+ return nil
+}
+
+//------------------------------------------------------------------------------
+
+// Client is a Redis client representing a pool of zero or more
+// underlying connections. It's safe for concurrent use by multiple
+// goroutines.
+type Client struct {
+ *baseClient
+ cmdable
+ hooks
+ ctx context.Context
+}
+
+// NewClient returns a client to the Redis Server specified by Options.
+func NewClient(opt *Options) *Client {
+ opt.init()
+
+ c := Client{
+ baseClient: newBaseClient(opt, newConnPool(opt)),
+ ctx: context.Background(),
+ }
+ c.cmdable = c.Process
+
+ return &c
+}
+
+func (c *Client) clone() *Client {
+ clone := *c
+ clone.cmdable = clone.Process
+ clone.hooks.lock()
+ return &clone
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ clone := c.clone()
+ clone.baseClient = c.baseClient.withTimeout(timeout)
+ return clone
+}
+
+func (c *Client) Context() context.Context {
+ return c.ctx
+}
+
+func (c *Client) WithContext(ctx context.Context) *Client {
+ if ctx == nil {
+ panic("nil context")
+ }
+ clone := c.clone()
+ clone.ctx = ctx
+ return clone
+}
+
+func (c *Client) Conn(ctx context.Context) *Conn {
+ return newConn(ctx, c.opt, pool.NewStickyConnPool(c.connPool))
+}
+
+// Do creates a Cmd from the args and processes the cmd.
+func (c *Client) Do(ctx context.Context, args ...interface{}) *Cmd {
+ cmd := NewCmd(ctx, args...)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+func (c *Client) Process(ctx context.Context, cmd Cmder) error {
+ return c.hooks.process(ctx, cmd, c.baseClient.process)
+}
+
+func (c *Client) processPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline)
+}
+
+func (c *Client) processTxPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline)
+}
+
+// Options returns read-only Options that were used to create the client.
+func (c *Client) Options() *Options {
+ return c.opt
+}
+
+type PoolStats pool.Stats
+
+// PoolStats returns connection pool stats.
+func (c *Client) PoolStats() *PoolStats {
+ stats := c.connPool.Stats()
+ return (*PoolStats)(stats)
+}
+
+func (c *Client) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.Pipeline().Pipelined(ctx, fn)
+}
+
+func (c *Client) Pipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *Client) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.TxPipeline().Pipelined(ctx, fn)
+}
+
+// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
+func (c *Client) TxPipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processTxPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *Client) pubSub() *PubSub {
+ pubsub := &PubSub{
+ opt: c.opt,
+
+ newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) {
+ return c.newConn(ctx)
+ },
+ closeConn: c.connPool.CloseConn,
+ }
+ pubsub.init()
+ return pubsub
+}
+
+// Subscribe subscribes the client to the specified channels.
+// Channels can be omitted to create empty subscription.
+// Note that this method does not wait on a response from Redis, so the
+// subscription may not be active immediately. To force the connection to wait,
+// you may call the Receive() method on the returned *PubSub like so:
+//
+// sub := client.Subscribe(queryResp)
+// iface, err := sub.Receive()
+// if err != nil {
+// // handle error
+// }
+//
+// // Should be *Subscription, but others are possible if other actions have been
+// // taken on sub since it was created.
+// switch iface.(type) {
+// case *Subscription:
+// // subscribe succeeded
+// case *Message:
+// // received first message
+// case *Pong:
+// // pong received
+// default:
+// // handle error
+// }
+//
+// ch := sub.Channel()
+func (c *Client) Subscribe(ctx context.Context, channels ...string) *PubSub {
+ pubsub := c.pubSub()
+ if len(channels) > 0 {
+ _ = pubsub.Subscribe(ctx, channels...)
+ }
+ return pubsub
+}
+
+// PSubscribe subscribes the client to the given patterns.
+// Patterns can be omitted to create empty subscription.
+func (c *Client) PSubscribe(ctx context.Context, channels ...string) *PubSub {
+ pubsub := c.pubSub()
+ if len(channels) > 0 {
+ _ = pubsub.PSubscribe(ctx, channels...)
+ }
+ return pubsub
+}
+
+//------------------------------------------------------------------------------
+
+type conn struct {
+ baseClient
+ cmdable
+ statefulCmdable
+ hooks // TODO: inherit hooks
+}
+
+// Conn represents a single Redis connection rather than a pool of connections.
+// Prefer running commands from Client unless there is a specific need
+// for a continuous single Redis connection.
+type Conn struct {
+ *conn
+ ctx context.Context
+}
+
+func newConn(ctx context.Context, opt *Options, connPool pool.Pooler) *Conn {
+ c := Conn{
+ conn: &conn{
+ baseClient: baseClient{
+ opt: opt,
+ connPool: connPool,
+ },
+ },
+ ctx: ctx,
+ }
+ c.cmdable = c.Process
+ c.statefulCmdable = c.Process
+ return &c
+}
+
+func (c *Conn) Process(ctx context.Context, cmd Cmder) error {
+ return c.hooks.process(ctx, cmd, c.baseClient.process)
+}
+
+func (c *Conn) processPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline)
+}
+
+func (c *Conn) processTxPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline)
+}
+
+func (c *Conn) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.Pipeline().Pipelined(ctx, fn)
+}
+
+func (c *Conn) Pipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *Conn) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.TxPipeline().Pipelined(ctx, fn)
+}
+
+// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
+func (c *Conn) TxPipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processTxPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/result.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/result.go
new file mode 100644
index 000000000000..24cfd4994026
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/result.go
@@ -0,0 +1,180 @@
+package redis
+
+import "time"
+
+// NewCmdResult returns a Cmd initialised with val and err for testing.
+func NewCmdResult(val interface{}, err error) *Cmd {
+ var cmd Cmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewSliceResult returns a SliceCmd initialised with val and err for testing.
+func NewSliceResult(val []interface{}, err error) *SliceCmd {
+ var cmd SliceCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewStatusResult returns a StatusCmd initialised with val and err for testing.
+func NewStatusResult(val string, err error) *StatusCmd {
+ var cmd StatusCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewIntResult returns an IntCmd initialised with val and err for testing.
+func NewIntResult(val int64, err error) *IntCmd {
+ var cmd IntCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewDurationResult returns a DurationCmd initialised with val and err for testing.
+func NewDurationResult(val time.Duration, err error) *DurationCmd {
+ var cmd DurationCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewBoolResult returns a BoolCmd initialised with val and err for testing.
+func NewBoolResult(val bool, err error) *BoolCmd {
+ var cmd BoolCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewStringResult returns a StringCmd initialised with val and err for testing.
+func NewStringResult(val string, err error) *StringCmd {
+ var cmd StringCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewFloatResult returns a FloatCmd initialised with val and err for testing.
+func NewFloatResult(val float64, err error) *FloatCmd {
+ var cmd FloatCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewStringSliceResult returns a StringSliceCmd initialised with val and err for testing.
+func NewStringSliceResult(val []string, err error) *StringSliceCmd {
+ var cmd StringSliceCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewBoolSliceResult returns a BoolSliceCmd initialised with val and err for testing.
+func NewBoolSliceResult(val []bool, err error) *BoolSliceCmd {
+ var cmd BoolSliceCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewStringStringMapResult returns a StringStringMapCmd initialised with val and err for testing.
+func NewStringStringMapResult(val map[string]string, err error) *StringStringMapCmd {
+ var cmd StringStringMapCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewStringIntMapCmdResult returns a StringIntMapCmd initialised with val and err for testing.
+func NewStringIntMapCmdResult(val map[string]int64, err error) *StringIntMapCmd {
+ var cmd StringIntMapCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewTimeCmdResult returns a TimeCmd initialised with val and err for testing.
+func NewTimeCmdResult(val time.Time, err error) *TimeCmd {
+ var cmd TimeCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewZSliceCmdResult returns a ZSliceCmd initialised with val and err for testing.
+func NewZSliceCmdResult(val []Z, err error) *ZSliceCmd {
+ var cmd ZSliceCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewZWithKeyCmdResult returns a NewZWithKeyCmd initialised with val and err for testing.
+func NewZWithKeyCmdResult(val *ZWithKey, err error) *ZWithKeyCmd {
+ var cmd ZWithKeyCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewScanCmdResult returns a ScanCmd initialised with val and err for testing.
+func NewScanCmdResult(keys []string, cursor uint64, err error) *ScanCmd {
+ var cmd ScanCmd
+ cmd.page = keys
+ cmd.cursor = cursor
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewClusterSlotsCmdResult returns a ClusterSlotsCmd initialised with val and err for testing.
+func NewClusterSlotsCmdResult(val []ClusterSlot, err error) *ClusterSlotsCmd {
+ var cmd ClusterSlotsCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewGeoLocationCmdResult returns a GeoLocationCmd initialised with val and err for testing.
+func NewGeoLocationCmdResult(val []GeoLocation, err error) *GeoLocationCmd {
+ var cmd GeoLocationCmd
+ cmd.locations = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewGeoPosCmdResult returns a GeoPosCmd initialised with val and err for testing.
+func NewGeoPosCmdResult(val []*GeoPos, err error) *GeoPosCmd {
+ var cmd GeoPosCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewCommandsInfoCmdResult returns a CommandsInfoCmd initialised with val and err for testing.
+func NewCommandsInfoCmdResult(val map[string]*CommandInfo, err error) *CommandsInfoCmd {
+ var cmd CommandsInfoCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewXMessageSliceCmdResult returns a XMessageSliceCmd initialised with val and err for testing.
+func NewXMessageSliceCmdResult(val []XMessage, err error) *XMessageSliceCmd {
+ var cmd XMessageSliceCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
+
+// NewXStreamSliceCmdResult returns a XStreamSliceCmd initialised with val and err for testing.
+func NewXStreamSliceCmdResult(val []XStream, err error) *XStreamSliceCmd {
+ var cmd XStreamSliceCmd
+ cmd.val = val
+ cmd.SetErr(err)
+ return &cmd
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/ring.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/ring.go
new file mode 100644
index 000000000000..4df00fc857f5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/ring.go
@@ -0,0 +1,736 @@
+package redis
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "net"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/cespare/xxhash/v2"
+ rendezvous "github.com/dgryski/go-rendezvous" //nolint
+
+ "github.com/go-redis/redis/v8/internal"
+ "github.com/go-redis/redis/v8/internal/hashtag"
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/rand"
+)
+
+var errRingShardsDown = errors.New("redis: all ring shards are down")
+
+//------------------------------------------------------------------------------
+
+type ConsistentHash interface {
+ Get(string) string
+}
+
+type rendezvousWrapper struct {
+ *rendezvous.Rendezvous
+}
+
+func (w rendezvousWrapper) Get(key string) string {
+ return w.Lookup(key)
+}
+
+func newRendezvous(shards []string) ConsistentHash {
+ return rendezvousWrapper{rendezvous.New(shards, xxhash.Sum64String)}
+}
+
+//------------------------------------------------------------------------------
+
+// RingOptions are used to configure a ring client and should be
+// passed to NewRing.
+type RingOptions struct {
+ // Map of name => host:port addresses of ring shards.
+ Addrs map[string]string
+
+ // NewClient creates a shard client with provided name and options.
+ NewClient func(name string, opt *Options) *Client
+
+ // Frequency of PING commands sent to check shards availability.
+ // Shard is considered down after 3 subsequent failed checks.
+ HeartbeatFrequency time.Duration
+
+ // NewConsistentHash returns a consistent hash that is used
+ // to distribute keys across the shards.
+ //
+ // See https://medium.com/@dgryski/consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8
+ // for consistent hashing algorithmic tradeoffs.
+ NewConsistentHash func(shards []string) ConsistentHash
+
+ // Following options are copied from Options struct.
+
+ Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
+ OnConnect func(ctx context.Context, cn *Conn) error
+
+ Username string
+ Password string
+ DB int
+
+ MaxRetries int
+ MinRetryBackoff time.Duration
+ MaxRetryBackoff time.Duration
+
+ DialTimeout time.Duration
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+
+ // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
+ PoolFIFO bool
+
+ PoolSize int
+ MinIdleConns int
+ MaxConnAge time.Duration
+ PoolTimeout time.Duration
+ IdleTimeout time.Duration
+ IdleCheckFrequency time.Duration
+
+ TLSConfig *tls.Config
+ Limiter Limiter
+}
+
+func (opt *RingOptions) init() {
+ if opt.NewClient == nil {
+ opt.NewClient = func(name string, opt *Options) *Client {
+ return NewClient(opt)
+ }
+ }
+
+ if opt.HeartbeatFrequency == 0 {
+ opt.HeartbeatFrequency = 500 * time.Millisecond
+ }
+
+ if opt.NewConsistentHash == nil {
+ opt.NewConsistentHash = newRendezvous
+ }
+
+ if opt.MaxRetries == -1 {
+ opt.MaxRetries = 0
+ } else if opt.MaxRetries == 0 {
+ opt.MaxRetries = 3
+ }
+ switch opt.MinRetryBackoff {
+ case -1:
+ opt.MinRetryBackoff = 0
+ case 0:
+ opt.MinRetryBackoff = 8 * time.Millisecond
+ }
+ switch opt.MaxRetryBackoff {
+ case -1:
+ opt.MaxRetryBackoff = 0
+ case 0:
+ opt.MaxRetryBackoff = 512 * time.Millisecond
+ }
+}
+
+func (opt *RingOptions) clientOptions() *Options {
+ return &Options{
+ Dialer: opt.Dialer,
+ OnConnect: opt.OnConnect,
+
+ Username: opt.Username,
+ Password: opt.Password,
+ DB: opt.DB,
+
+ MaxRetries: -1,
+
+ DialTimeout: opt.DialTimeout,
+ ReadTimeout: opt.ReadTimeout,
+ WriteTimeout: opt.WriteTimeout,
+
+ PoolFIFO: opt.PoolFIFO,
+ PoolSize: opt.PoolSize,
+ MinIdleConns: opt.MinIdleConns,
+ MaxConnAge: opt.MaxConnAge,
+ PoolTimeout: opt.PoolTimeout,
+ IdleTimeout: opt.IdleTimeout,
+ IdleCheckFrequency: opt.IdleCheckFrequency,
+
+ TLSConfig: opt.TLSConfig,
+ Limiter: opt.Limiter,
+ }
+}
+
+//------------------------------------------------------------------------------
+
+type ringShard struct {
+ Client *Client
+ down int32
+}
+
+func newRingShard(opt *RingOptions, name, addr string) *ringShard {
+ clopt := opt.clientOptions()
+ clopt.Addr = addr
+
+ return &ringShard{
+ Client: opt.NewClient(name, clopt),
+ }
+}
+
+func (shard *ringShard) String() string {
+ var state string
+ if shard.IsUp() {
+ state = "up"
+ } else {
+ state = "down"
+ }
+ return fmt.Sprintf("%s is %s", shard.Client, state)
+}
+
+func (shard *ringShard) IsDown() bool {
+ const threshold = 3
+ return atomic.LoadInt32(&shard.down) >= threshold
+}
+
+func (shard *ringShard) IsUp() bool {
+ return !shard.IsDown()
+}
+
+// Vote votes to set shard state and returns true if state was changed.
+func (shard *ringShard) Vote(up bool) bool {
+ if up {
+ changed := shard.IsDown()
+ atomic.StoreInt32(&shard.down, 0)
+ return changed
+ }
+
+ if shard.IsDown() {
+ return false
+ }
+
+ atomic.AddInt32(&shard.down, 1)
+ return shard.IsDown()
+}
+
+//------------------------------------------------------------------------------
+
+type ringShards struct {
+ opt *RingOptions
+
+ mu sync.RWMutex
+ hash ConsistentHash
+ shards map[string]*ringShard // read only
+ list []*ringShard // read only
+ numShard int
+ closed bool
+}
+
+func newRingShards(opt *RingOptions) *ringShards {
+ shards := make(map[string]*ringShard, len(opt.Addrs))
+ list := make([]*ringShard, 0, len(shards))
+
+ for name, addr := range opt.Addrs {
+ shard := newRingShard(opt, name, addr)
+ shards[name] = shard
+
+ list = append(list, shard)
+ }
+
+ c := &ringShards{
+ opt: opt,
+
+ shards: shards,
+ list: list,
+ }
+ c.rebalance()
+
+ return c
+}
+
+func (c *ringShards) List() []*ringShard {
+ var list []*ringShard
+
+ c.mu.RLock()
+ if !c.closed {
+ list = c.list
+ }
+ c.mu.RUnlock()
+
+ return list
+}
+
+func (c *ringShards) Hash(key string) string {
+ key = hashtag.Key(key)
+
+ var hash string
+
+ c.mu.RLock()
+ if c.numShard > 0 {
+ hash = c.hash.Get(key)
+ }
+ c.mu.RUnlock()
+
+ return hash
+}
+
+func (c *ringShards) GetByKey(key string) (*ringShard, error) {
+ key = hashtag.Key(key)
+
+ c.mu.RLock()
+
+ if c.closed {
+ c.mu.RUnlock()
+ return nil, pool.ErrClosed
+ }
+
+ if c.numShard == 0 {
+ c.mu.RUnlock()
+ return nil, errRingShardsDown
+ }
+
+ hash := c.hash.Get(key)
+ if hash == "" {
+ c.mu.RUnlock()
+ return nil, errRingShardsDown
+ }
+
+ shard := c.shards[hash]
+ c.mu.RUnlock()
+
+ return shard, nil
+}
+
+func (c *ringShards) GetByName(shardName string) (*ringShard, error) {
+ if shardName == "" {
+ return c.Random()
+ }
+
+ c.mu.RLock()
+ shard := c.shards[shardName]
+ c.mu.RUnlock()
+ return shard, nil
+}
+
+func (c *ringShards) Random() (*ringShard, error) {
+ return c.GetByKey(strconv.Itoa(rand.Int()))
+}
+
+// heartbeat monitors state of each shard in the ring.
+func (c *ringShards) Heartbeat(frequency time.Duration) {
+ ticker := time.NewTicker(frequency)
+ defer ticker.Stop()
+
+ ctx := context.Background()
+ for range ticker.C {
+ var rebalance bool
+
+ for _, shard := range c.List() {
+ err := shard.Client.Ping(ctx).Err()
+ isUp := err == nil || err == pool.ErrPoolTimeout
+ if shard.Vote(isUp) {
+ internal.Logger.Printf(context.Background(), "ring shard state changed: %s", shard)
+ rebalance = true
+ }
+ }
+
+ if rebalance {
+ c.rebalance()
+ }
+ }
+}
+
+// rebalance removes dead shards from the Ring.
+func (c *ringShards) rebalance() {
+ c.mu.RLock()
+ shards := c.shards
+ c.mu.RUnlock()
+
+ liveShards := make([]string, 0, len(shards))
+
+ for name, shard := range shards {
+ if shard.IsUp() {
+ liveShards = append(liveShards, name)
+ }
+ }
+
+ hash := c.opt.NewConsistentHash(liveShards)
+
+ c.mu.Lock()
+ c.hash = hash
+ c.numShard = len(liveShards)
+ c.mu.Unlock()
+}
+
+func (c *ringShards) Len() int {
+ c.mu.RLock()
+ l := c.numShard
+ c.mu.RUnlock()
+ return l
+}
+
+func (c *ringShards) Close() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.closed {
+ return nil
+ }
+ c.closed = true
+
+ var firstErr error
+ for _, shard := range c.shards {
+ if err := shard.Client.Close(); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+ c.hash = nil
+ c.shards = nil
+ c.list = nil
+
+ return firstErr
+}
+
+//------------------------------------------------------------------------------
+
+type ring struct {
+ opt *RingOptions
+ shards *ringShards
+ cmdsInfoCache *cmdsInfoCache //nolint:structcheck
+}
+
+// Ring is a Redis client that uses consistent hashing to distribute
+// keys across multiple Redis servers (shards). It's safe for
+// concurrent use by multiple goroutines.
+//
+// Ring monitors the state of each shard and removes dead shards from
+// the ring. When a shard comes online it is added back to the ring. This
+// gives you maximum availability and partition tolerance, but no
+// consistency between different shards or even clients. Each client
+// uses shards that are available to the client and does not do any
+// coordination when shard state is changed.
+//
+// Ring should be used when you need multiple Redis servers for caching
+// and can tolerate losing data when one of the servers dies.
+// Otherwise you should use Redis Cluster.
+type Ring struct {
+ *ring
+ cmdable
+ hooks
+ ctx context.Context
+}
+
+func NewRing(opt *RingOptions) *Ring {
+ opt.init()
+
+ ring := Ring{
+ ring: &ring{
+ opt: opt,
+ shards: newRingShards(opt),
+ },
+ ctx: context.Background(),
+ }
+
+ ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo)
+ ring.cmdable = ring.Process
+
+ go ring.shards.Heartbeat(opt.HeartbeatFrequency)
+
+ return &ring
+}
+
+func (c *Ring) Context() context.Context {
+ return c.ctx
+}
+
+func (c *Ring) WithContext(ctx context.Context) *Ring {
+ if ctx == nil {
+ panic("nil context")
+ }
+ clone := *c
+ clone.cmdable = clone.Process
+ clone.hooks.lock()
+ clone.ctx = ctx
+ return &clone
+}
+
+// Do creates a Cmd from the args and processes the cmd.
+func (c *Ring) Do(ctx context.Context, args ...interface{}) *Cmd {
+ cmd := NewCmd(ctx, args...)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+func (c *Ring) Process(ctx context.Context, cmd Cmder) error {
+ return c.hooks.process(ctx, cmd, c.process)
+}
+
+// Options returns read-only Options that were used to create the client.
+func (c *Ring) Options() *RingOptions {
+ return c.opt
+}
+
+func (c *Ring) retryBackoff(attempt int) time.Duration {
+ return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
+}
+
+// PoolStats returns accumulated connection pool stats.
+func (c *Ring) PoolStats() *PoolStats {
+ shards := c.shards.List()
+ var acc PoolStats
+ for _, shard := range shards {
+ s := shard.Client.connPool.Stats()
+ acc.Hits += s.Hits
+ acc.Misses += s.Misses
+ acc.Timeouts += s.Timeouts
+ acc.TotalConns += s.TotalConns
+ acc.IdleConns += s.IdleConns
+ }
+ return &acc
+}
+
+// Len returns the current number of shards in the ring.
+func (c *Ring) Len() int {
+ return c.shards.Len()
+}
+
+// Subscribe subscribes the client to the specified channels.
+func (c *Ring) Subscribe(ctx context.Context, channels ...string) *PubSub {
+ if len(channels) == 0 {
+ panic("at least one channel is required")
+ }
+
+ shard, err := c.shards.GetByKey(channels[0])
+ if err != nil {
+ // TODO: return PubSub with sticky error
+ panic(err)
+ }
+ return shard.Client.Subscribe(ctx, channels...)
+}
+
+// PSubscribe subscribes the client to the given patterns.
+func (c *Ring) PSubscribe(ctx context.Context, channels ...string) *PubSub {
+ if len(channels) == 0 {
+ panic("at least one channel is required")
+ }
+
+ shard, err := c.shards.GetByKey(channels[0])
+ if err != nil {
+ // TODO: return PubSub with sticky error
+ panic(err)
+ }
+ return shard.Client.PSubscribe(ctx, channels...)
+}
+
+// ForEachShard concurrently calls the fn on each live shard in the ring.
+// It returns the first error if any.
+func (c *Ring) ForEachShard(
+ ctx context.Context,
+ fn func(ctx context.Context, client *Client) error,
+) error {
+ shards := c.shards.List()
+ var wg sync.WaitGroup
+ errCh := make(chan error, 1)
+ for _, shard := range shards {
+ if shard.IsDown() {
+ continue
+ }
+
+ wg.Add(1)
+ go func(shard *ringShard) {
+ defer wg.Done()
+ err := fn(ctx, shard.Client)
+ if err != nil {
+ select {
+ case errCh <- err:
+ default:
+ }
+ }
+ }(shard)
+ }
+ wg.Wait()
+
+ select {
+ case err := <-errCh:
+ return err
+ default:
+ return nil
+ }
+}
+
+func (c *Ring) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) {
+ shards := c.shards.List()
+ var firstErr error
+ for _, shard := range shards {
+ cmdsInfo, err := shard.Client.Command(ctx).Result()
+ if err == nil {
+ return cmdsInfo, nil
+ }
+ if firstErr == nil {
+ firstErr = err
+ }
+ }
+ if firstErr == nil {
+ return nil, errRingShardsDown
+ }
+ return nil, firstErr
+}
+
+func (c *Ring) cmdInfo(ctx context.Context, name string) *CommandInfo {
+ cmdsInfo, err := c.cmdsInfoCache.Get(ctx)
+ if err != nil {
+ return nil
+ }
+ info := cmdsInfo[name]
+ if info == nil {
+ internal.Logger.Printf(ctx, "info for cmd=%s not found", name)
+ }
+ return info
+}
+
+func (c *Ring) cmdShard(ctx context.Context, cmd Cmder) (*ringShard, error) {
+ cmdInfo := c.cmdInfo(ctx, cmd.Name())
+ pos := cmdFirstKeyPos(cmd, cmdInfo)
+ if pos == 0 {
+ return c.shards.Random()
+ }
+ firstKey := cmd.stringArg(pos)
+ return c.shards.GetByKey(firstKey)
+}
+
+func (c *Ring) process(ctx context.Context, cmd Cmder) error {
+ var lastErr error
+ for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
+ if attempt > 0 {
+ if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
+ return err
+ }
+ }
+
+ shard, err := c.cmdShard(ctx, cmd)
+ if err != nil {
+ return err
+ }
+
+ lastErr = shard.Client.Process(ctx, cmd)
+ if lastErr == nil || !shouldRetry(lastErr, cmd.readTimeout() == nil) {
+ return lastErr
+ }
+ }
+ return lastErr
+}
+
+func (c *Ring) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.Pipeline().Pipelined(ctx, fn)
+}
+
+func (c *Ring) Pipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *Ring) processPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
+ return c.generalProcessPipeline(ctx, cmds, false)
+ })
+}
+
+func (c *Ring) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.TxPipeline().Pipelined(ctx, fn)
+}
+
+func (c *Ring) TxPipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: c.processTxPipeline,
+ }
+ pipe.init()
+ return &pipe
+}
+
+func (c *Ring) processTxPipeline(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
+ return c.generalProcessPipeline(ctx, cmds, true)
+ })
+}
+
+func (c *Ring) generalProcessPipeline(
+ ctx context.Context, cmds []Cmder, tx bool,
+) error {
+ cmdsMap := make(map[string][]Cmder)
+ for _, cmd := range cmds {
+ cmdInfo := c.cmdInfo(ctx, cmd.Name())
+ hash := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
+ if hash != "" {
+ hash = c.shards.Hash(hash)
+ }
+ cmdsMap[hash] = append(cmdsMap[hash], cmd)
+ }
+
+ var wg sync.WaitGroup
+ for hash, cmds := range cmdsMap {
+ wg.Add(1)
+ go func(hash string, cmds []Cmder) {
+ defer wg.Done()
+
+ _ = c.processShardPipeline(ctx, hash, cmds, tx)
+ }(hash, cmds)
+ }
+
+ wg.Wait()
+ return cmdsFirstErr(cmds)
+}
+
+func (c *Ring) processShardPipeline(
+ ctx context.Context, hash string, cmds []Cmder, tx bool,
+) error {
+ // TODO: retry?
+ shard, err := c.shards.GetByName(hash)
+ if err != nil {
+ setCmdsErr(cmds, err)
+ return err
+ }
+
+ if tx {
+ return shard.Client.processTxPipeline(ctx, cmds)
+ }
+ return shard.Client.processPipeline(ctx, cmds)
+}
+
+func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
+ if len(keys) == 0 {
+ return fmt.Errorf("redis: Watch requires at least one key")
+ }
+
+ var shards []*ringShard
+ for _, key := range keys {
+ if key != "" {
+ shard, err := c.shards.GetByKey(hashtag.Key(key))
+ if err != nil {
+ return err
+ }
+
+ shards = append(shards, shard)
+ }
+ }
+
+ if len(shards) == 0 {
+ return fmt.Errorf("redis: Watch requires at least one shard")
+ }
+
+ if len(shards) > 1 {
+ for _, shard := range shards[1:] {
+ if shard.Client != shards[0].Client {
+ err := fmt.Errorf("redis: Watch requires all keys to be in the same shard")
+ return err
+ }
+ }
+ }
+
+ return shards[0].Client.Watch(ctx, fn, keys...)
+}
+
+// Close closes the ring client, releasing any open resources.
+//
+// It is rare to Close a Ring, as the Ring is meant to be long-lived
+// and shared between many goroutines.
+func (c *Ring) Close() error {
+ return c.shards.Close()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/script.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/script.go
new file mode 100644
index 000000000000..5cab18d617c8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/script.go
@@ -0,0 +1,65 @@
+package redis
+
+import (
+ "context"
+ "crypto/sha1"
+ "encoding/hex"
+ "io"
+ "strings"
+)
+
+type Scripter interface {
+ Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
+ EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
+ ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
+ ScriptLoad(ctx context.Context, script string) *StringCmd
+}
+
+var (
+ _ Scripter = (*Client)(nil)
+ _ Scripter = (*Ring)(nil)
+ _ Scripter = (*ClusterClient)(nil)
+)
+
+type Script struct {
+ src, hash string
+}
+
+func NewScript(src string) *Script {
+ h := sha1.New()
+ _, _ = io.WriteString(h, src)
+ return &Script{
+ src: src,
+ hash: hex.EncodeToString(h.Sum(nil)),
+ }
+}
+
+func (s *Script) Hash() string {
+ return s.hash
+}
+
+func (s *Script) Load(ctx context.Context, c Scripter) *StringCmd {
+ return c.ScriptLoad(ctx, s.src)
+}
+
+func (s *Script) Exists(ctx context.Context, c Scripter) *BoolSliceCmd {
+ return c.ScriptExists(ctx, s.hash)
+}
+
+func (s *Script) Eval(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
+ return c.Eval(ctx, s.src, keys, args...)
+}
+
+func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
+ return c.EvalSha(ctx, s.hash, keys, args...)
+}
+
+// Run optimistically uses EVALSHA to run the script. If script does not exist
+// it is retried using EVAL.
+func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
+ r := s.EvalSha(ctx, c, keys, args...)
+ if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") {
+ return s.Eval(ctx, c, keys, args...)
+ }
+ return r
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/sentinel.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/sentinel.go
new file mode 100644
index 000000000000..ec6221dc83d4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/sentinel.go
@@ -0,0 +1,796 @@
+package redis
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "net"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/go-redis/redis/v8/internal"
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/rand"
+)
+
+//------------------------------------------------------------------------------
+
+// FailoverOptions are used to configure a failover client and should
+// be passed to NewFailoverClient.
+type FailoverOptions struct {
+ // The master name.
+ MasterName string
+ // A seed list of host:port addresses of sentinel nodes.
+ SentinelAddrs []string
+
+ // If specified with SentinelPassword, enables ACL-based authentication (via
+ // AUTH ).
+ SentinelUsername string
+ // Sentinel password from "requirepass " (if enabled) in Sentinel
+ // configuration, or, if SentinelUsername is also supplied, used for ACL-based
+ // authentication.
+ SentinelPassword string
+
+ // Allows routing read-only commands to the closest master or slave node.
+ // This option only works with NewFailoverClusterClient.
+ RouteByLatency bool
+ // Allows routing read-only commands to the random master or slave node.
+ // This option only works with NewFailoverClusterClient.
+ RouteRandomly bool
+
+ // Route all commands to slave read-only nodes.
+ SlaveOnly bool
+
+ // Use slaves disconnected with master when cannot get connected slaves
+ // Now, this option only works in RandomSlaveAddr function.
+ UseDisconnectedSlaves bool
+
+ // Following options are copied from Options struct.
+
+ Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
+ OnConnect func(ctx context.Context, cn *Conn) error
+
+ Username string
+ Password string
+ DB int
+
+ MaxRetries int
+ MinRetryBackoff time.Duration
+ MaxRetryBackoff time.Duration
+
+ DialTimeout time.Duration
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+
+ // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
+ PoolFIFO bool
+
+ PoolSize int
+ MinIdleConns int
+ MaxConnAge time.Duration
+ PoolTimeout time.Duration
+ IdleTimeout time.Duration
+ IdleCheckFrequency time.Duration
+
+ TLSConfig *tls.Config
+}
+
+func (opt *FailoverOptions) clientOptions() *Options {
+ return &Options{
+ Addr: "FailoverClient",
+
+ Dialer: opt.Dialer,
+ OnConnect: opt.OnConnect,
+
+ DB: opt.DB,
+ Username: opt.Username,
+ Password: opt.Password,
+
+ MaxRetries: opt.MaxRetries,
+ MinRetryBackoff: opt.MinRetryBackoff,
+ MaxRetryBackoff: opt.MaxRetryBackoff,
+
+ DialTimeout: opt.DialTimeout,
+ ReadTimeout: opt.ReadTimeout,
+ WriteTimeout: opt.WriteTimeout,
+
+ PoolFIFO: opt.PoolFIFO,
+ PoolSize: opt.PoolSize,
+ PoolTimeout: opt.PoolTimeout,
+ IdleTimeout: opt.IdleTimeout,
+ IdleCheckFrequency: opt.IdleCheckFrequency,
+ MinIdleConns: opt.MinIdleConns,
+ MaxConnAge: opt.MaxConnAge,
+
+ TLSConfig: opt.TLSConfig,
+ }
+}
+
+func (opt *FailoverOptions) sentinelOptions(addr string) *Options {
+ return &Options{
+ Addr: addr,
+
+ Dialer: opt.Dialer,
+ OnConnect: opt.OnConnect,
+
+ DB: 0,
+ Username: opt.SentinelUsername,
+ Password: opt.SentinelPassword,
+
+ MaxRetries: opt.MaxRetries,
+ MinRetryBackoff: opt.MinRetryBackoff,
+ MaxRetryBackoff: opt.MaxRetryBackoff,
+
+ DialTimeout: opt.DialTimeout,
+ ReadTimeout: opt.ReadTimeout,
+ WriteTimeout: opt.WriteTimeout,
+
+ PoolFIFO: opt.PoolFIFO,
+ PoolSize: opt.PoolSize,
+ PoolTimeout: opt.PoolTimeout,
+ IdleTimeout: opt.IdleTimeout,
+ IdleCheckFrequency: opt.IdleCheckFrequency,
+ MinIdleConns: opt.MinIdleConns,
+ MaxConnAge: opt.MaxConnAge,
+
+ TLSConfig: opt.TLSConfig,
+ }
+}
+
+func (opt *FailoverOptions) clusterOptions() *ClusterOptions {
+ return &ClusterOptions{
+ Dialer: opt.Dialer,
+ OnConnect: opt.OnConnect,
+
+ Username: opt.Username,
+ Password: opt.Password,
+
+ MaxRedirects: opt.MaxRetries,
+
+ RouteByLatency: opt.RouteByLatency,
+ RouteRandomly: opt.RouteRandomly,
+
+ MinRetryBackoff: opt.MinRetryBackoff,
+ MaxRetryBackoff: opt.MaxRetryBackoff,
+
+ DialTimeout: opt.DialTimeout,
+ ReadTimeout: opt.ReadTimeout,
+ WriteTimeout: opt.WriteTimeout,
+
+ PoolFIFO: opt.PoolFIFO,
+ PoolSize: opt.PoolSize,
+ PoolTimeout: opt.PoolTimeout,
+ IdleTimeout: opt.IdleTimeout,
+ IdleCheckFrequency: opt.IdleCheckFrequency,
+ MinIdleConns: opt.MinIdleConns,
+ MaxConnAge: opt.MaxConnAge,
+
+ TLSConfig: opt.TLSConfig,
+ }
+}
+
+// NewFailoverClient returns a Redis client that uses Redis Sentinel
+// for automatic failover. It's safe for concurrent use by multiple
+// goroutines.
+func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
+ if failoverOpt.RouteByLatency {
+ panic("to route commands by latency, use NewFailoverClusterClient")
+ }
+ if failoverOpt.RouteRandomly {
+ panic("to route commands randomly, use NewFailoverClusterClient")
+ }
+
+ sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
+ copy(sentinelAddrs, failoverOpt.SentinelAddrs)
+
+ rand.Shuffle(len(sentinelAddrs), func(i, j int) {
+ sentinelAddrs[i], sentinelAddrs[j] = sentinelAddrs[j], sentinelAddrs[i]
+ })
+
+ failover := &sentinelFailover{
+ opt: failoverOpt,
+ sentinelAddrs: sentinelAddrs,
+ }
+
+ opt := failoverOpt.clientOptions()
+ opt.Dialer = masterSlaveDialer(failover)
+ opt.init()
+
+ connPool := newConnPool(opt)
+
+ failover.mu.Lock()
+ failover.onFailover = func(ctx context.Context, addr string) {
+ _ = connPool.Filter(func(cn *pool.Conn) bool {
+ return cn.RemoteAddr().String() != addr
+ })
+ }
+ failover.mu.Unlock()
+
+ c := Client{
+ baseClient: newBaseClient(opt, connPool),
+ ctx: context.Background(),
+ }
+ c.cmdable = c.Process
+ c.onClose = failover.Close
+
+ return &c
+}
+
+func masterSlaveDialer(
+ failover *sentinelFailover,
+) func(ctx context.Context, network, addr string) (net.Conn, error) {
+ return func(ctx context.Context, network, _ string) (net.Conn, error) {
+ var addr string
+ var err error
+
+ if failover.opt.SlaveOnly {
+ addr, err = failover.RandomSlaveAddr(ctx)
+ } else {
+ addr, err = failover.MasterAddr(ctx)
+ if err == nil {
+ failover.trySwitchMaster(ctx, addr)
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+ if failover.opt.Dialer != nil {
+ return failover.opt.Dialer(ctx, network, addr)
+ }
+
+ netDialer := &net.Dialer{
+ Timeout: failover.opt.DialTimeout,
+ KeepAlive: 5 * time.Minute,
+ }
+ if failover.opt.TLSConfig == nil {
+ return netDialer.DialContext(ctx, network, addr)
+ }
+ return tls.DialWithDialer(netDialer, network, addr, failover.opt.TLSConfig)
+ }
+}
+
+//------------------------------------------------------------------------------
+
+// SentinelClient is a client for a Redis Sentinel.
+type SentinelClient struct {
+ *baseClient
+ hooks
+ ctx context.Context
+}
+
+func NewSentinelClient(opt *Options) *SentinelClient {
+ opt.init()
+ c := &SentinelClient{
+ baseClient: &baseClient{
+ opt: opt,
+ connPool: newConnPool(opt),
+ },
+ ctx: context.Background(),
+ }
+ return c
+}
+
+func (c *SentinelClient) Context() context.Context {
+ return c.ctx
+}
+
+func (c *SentinelClient) WithContext(ctx context.Context) *SentinelClient {
+ if ctx == nil {
+ panic("nil context")
+ }
+ clone := *c
+ clone.ctx = ctx
+ return &clone
+}
+
+func (c *SentinelClient) Process(ctx context.Context, cmd Cmder) error {
+ return c.hooks.process(ctx, cmd, c.baseClient.process)
+}
+
+func (c *SentinelClient) pubSub() *PubSub {
+ pubsub := &PubSub{
+ opt: c.opt,
+
+ newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) {
+ return c.newConn(ctx)
+ },
+ closeConn: c.connPool.CloseConn,
+ }
+ pubsub.init()
+ return pubsub
+}
+
+// Ping is used to test if a connection is still alive, or to
+// measure latency.
+func (c *SentinelClient) Ping(ctx context.Context) *StringCmd {
+ cmd := NewStringCmd(ctx, "ping")
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Subscribe subscribes the client to the specified channels.
+// Channels can be omitted to create empty subscription.
+func (c *SentinelClient) Subscribe(ctx context.Context, channels ...string) *PubSub {
+ pubsub := c.pubSub()
+ if len(channels) > 0 {
+ _ = pubsub.Subscribe(ctx, channels...)
+ }
+ return pubsub
+}
+
+// PSubscribe subscribes the client to the given patterns.
+// Patterns can be omitted to create empty subscription.
+func (c *SentinelClient) PSubscribe(ctx context.Context, channels ...string) *PubSub {
+ pubsub := c.pubSub()
+ if len(channels) > 0 {
+ _ = pubsub.PSubscribe(ctx, channels...)
+ }
+ return pubsub
+}
+
+func (c *SentinelClient) GetMasterAddrByName(ctx context.Context, name string) *StringSliceCmd {
+ cmd := NewStringSliceCmd(ctx, "sentinel", "get-master-addr-by-name", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+func (c *SentinelClient) Sentinels(ctx context.Context, name string) *SliceCmd {
+ cmd := NewSliceCmd(ctx, "sentinel", "sentinels", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Failover forces a failover as if the master was not reachable, and without
+// asking for agreement to other Sentinels.
+func (c *SentinelClient) Failover(ctx context.Context, name string) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "sentinel", "failover", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Reset resets all the masters with matching name. The pattern argument is a
+// glob-style pattern. The reset process clears any previous state in a master
+// (including a failover in progress), and removes every slave and sentinel
+// already discovered and associated with the master.
+func (c *SentinelClient) Reset(ctx context.Context, pattern string) *IntCmd {
+ cmd := NewIntCmd(ctx, "sentinel", "reset", pattern)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// FlushConfig forces Sentinel to rewrite its configuration on disk, including
+// the current Sentinel state.
+func (c *SentinelClient) FlushConfig(ctx context.Context) *StatusCmd {
+ cmd := NewStatusCmd(ctx, "sentinel", "flushconfig")
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Master shows the state and info of the specified master.
+func (c *SentinelClient) Master(ctx context.Context, name string) *StringStringMapCmd {
+ cmd := NewStringStringMapCmd(ctx, "sentinel", "master", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Masters shows a list of monitored masters and their state.
+func (c *SentinelClient) Masters(ctx context.Context) *SliceCmd {
+ cmd := NewSliceCmd(ctx, "sentinel", "masters")
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Slaves shows a list of slaves for the specified master and their state.
+func (c *SentinelClient) Slaves(ctx context.Context, name string) *SliceCmd {
+ cmd := NewSliceCmd(ctx, "sentinel", "slaves", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// CkQuorum checks if the current Sentinel configuration is able to reach the
+// quorum needed to failover a master, and the majority needed to authorize the
+// failover. This command should be used in monitoring systems to check if a
+// Sentinel deployment is ok.
+func (c *SentinelClient) CkQuorum(ctx context.Context, name string) *StringCmd {
+ cmd := NewStringCmd(ctx, "sentinel", "ckquorum", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Monitor tells the Sentinel to start monitoring a new master with the specified
+// name, ip, port, and quorum.
+func (c *SentinelClient) Monitor(ctx context.Context, name, ip, port, quorum string) *StringCmd {
+ cmd := NewStringCmd(ctx, "sentinel", "monitor", name, ip, port, quorum)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Set is used in order to change configuration parameters of a specific master.
+func (c *SentinelClient) Set(ctx context.Context, name, option, value string) *StringCmd {
+ cmd := NewStringCmd(ctx, "sentinel", "set", name, option, value)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Remove is used in order to remove the specified master: the master will no
+// longer be monitored, and will totally be removed from the internal state of
+// the Sentinel.
+func (c *SentinelClient) Remove(ctx context.Context, name string) *StringCmd {
+ cmd := NewStringCmd(ctx, "sentinel", "remove", name)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+//------------------------------------------------------------------------------
+
+type sentinelFailover struct {
+ opt *FailoverOptions
+
+ sentinelAddrs []string
+
+ onFailover func(ctx context.Context, addr string)
+ onUpdate func(ctx context.Context)
+
+ mu sync.RWMutex
+ _masterAddr string
+ sentinel *SentinelClient
+ pubsub *PubSub
+}
+
+func (c *sentinelFailover) Close() error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.sentinel != nil {
+ return c.closeSentinel()
+ }
+ return nil
+}
+
+func (c *sentinelFailover) closeSentinel() error {
+ firstErr := c.pubsub.Close()
+ c.pubsub = nil
+
+ err := c.sentinel.Close()
+ if err != nil && firstErr == nil {
+ firstErr = err
+ }
+ c.sentinel = nil
+
+ return firstErr
+}
+
+func (c *sentinelFailover) RandomSlaveAddr(ctx context.Context) (string, error) {
+ if c.opt == nil {
+ return "", errors.New("opt is nil")
+ }
+
+ addresses, err := c.slaveAddrs(ctx, false)
+ if err != nil {
+ return "", err
+ }
+
+ if len(addresses) == 0 && c.opt.UseDisconnectedSlaves {
+ addresses, err = c.slaveAddrs(ctx, true)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ if len(addresses) == 0 {
+ return c.MasterAddr(ctx)
+ }
+ return addresses[rand.Intn(len(addresses))], nil
+}
+
+func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
+ c.mu.RLock()
+ sentinel := c.sentinel
+ c.mu.RUnlock()
+
+ if sentinel != nil {
+ addr := c.getMasterAddr(ctx, sentinel)
+ if addr != "" {
+ return addr, nil
+ }
+ }
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.sentinel != nil {
+ addr := c.getMasterAddr(ctx, c.sentinel)
+ if addr != "" {
+ return addr, nil
+ }
+ _ = c.closeSentinel()
+ }
+
+ for i, sentinelAddr := range c.sentinelAddrs {
+ sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr))
+
+ masterAddr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result()
+ if err != nil {
+ internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName master=%q failed: %s",
+ c.opt.MasterName, err)
+ _ = sentinel.Close()
+ continue
+ }
+
+ // Push working sentinel to the top.
+ c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
+ c.setSentinel(ctx, sentinel)
+
+ addr := net.JoinHostPort(masterAddr[0], masterAddr[1])
+ return addr, nil
+ }
+
+ return "", errors.New("redis: all sentinels specified in configuration are unreachable")
+}
+
+func (c *sentinelFailover) slaveAddrs(ctx context.Context, useDisconnected bool) ([]string, error) {
+ c.mu.RLock()
+ sentinel := c.sentinel
+ c.mu.RUnlock()
+
+ if sentinel != nil {
+ addrs := c.getSlaveAddrs(ctx, sentinel)
+ if len(addrs) > 0 {
+ return addrs, nil
+ }
+ }
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if c.sentinel != nil {
+ addrs := c.getSlaveAddrs(ctx, c.sentinel)
+ if len(addrs) > 0 {
+ return addrs, nil
+ }
+ _ = c.closeSentinel()
+ }
+
+ var sentinelReachable bool
+
+ for i, sentinelAddr := range c.sentinelAddrs {
+ sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr))
+
+ slaves, err := sentinel.Slaves(ctx, c.opt.MasterName).Result()
+ if err != nil {
+ internal.Logger.Printf(ctx, "sentinel: Slaves master=%q failed: %s",
+ c.opt.MasterName, err)
+ _ = sentinel.Close()
+ continue
+ }
+ sentinelReachable = true
+ addrs := parseSlaveAddrs(slaves, useDisconnected)
+ if len(addrs) == 0 {
+ continue
+ }
+ // Push working sentinel to the top.
+ c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
+ c.setSentinel(ctx, sentinel)
+
+ return addrs, nil
+ }
+
+ if sentinelReachable {
+ return []string{}, nil
+ }
+ return []string{}, errors.New("redis: all sentinels specified in configuration are unreachable")
+}
+
+func (c *sentinelFailover) getMasterAddr(ctx context.Context, sentinel *SentinelClient) string {
+ addr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result()
+ if err != nil {
+ internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName name=%q failed: %s",
+ c.opt.MasterName, err)
+ return ""
+ }
+ return net.JoinHostPort(addr[0], addr[1])
+}
+
+func (c *sentinelFailover) getSlaveAddrs(ctx context.Context, sentinel *SentinelClient) []string {
+ addrs, err := sentinel.Slaves(ctx, c.opt.MasterName).Result()
+ if err != nil {
+ internal.Logger.Printf(ctx, "sentinel: Slaves name=%q failed: %s",
+ c.opt.MasterName, err)
+ return []string{}
+ }
+ return parseSlaveAddrs(addrs, false)
+}
+
+func parseSlaveAddrs(addrs []interface{}, keepDisconnected bool) []string {
+ nodes := make([]string, 0, len(addrs))
+ for _, node := range addrs {
+ ip := ""
+ port := ""
+ flags := []string{}
+ lastkey := ""
+ isDown := false
+
+ for _, key := range node.([]interface{}) {
+ switch lastkey {
+ case "ip":
+ ip = key.(string)
+ case "port":
+ port = key.(string)
+ case "flags":
+ flags = strings.Split(key.(string), ",")
+ }
+ lastkey = key.(string)
+ }
+
+ for _, flag := range flags {
+ switch flag {
+ case "s_down", "o_down":
+ isDown = true
+ case "disconnected":
+ if !keepDisconnected {
+ isDown = true
+ }
+ }
+ }
+
+ if !isDown {
+ nodes = append(nodes, net.JoinHostPort(ip, port))
+ }
+ }
+
+ return nodes
+}
+
+func (c *sentinelFailover) trySwitchMaster(ctx context.Context, addr string) {
+ c.mu.RLock()
+ currentAddr := c._masterAddr //nolint:ifshort
+ c.mu.RUnlock()
+
+ if addr == currentAddr {
+ return
+ }
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ if addr == c._masterAddr {
+ return
+ }
+ c._masterAddr = addr
+
+ internal.Logger.Printf(ctx, "sentinel: new master=%q addr=%q",
+ c.opt.MasterName, addr)
+ if c.onFailover != nil {
+ c.onFailover(ctx, addr)
+ }
+}
+
+func (c *sentinelFailover) setSentinel(ctx context.Context, sentinel *SentinelClient) {
+ if c.sentinel != nil {
+ panic("not reached")
+ }
+ c.sentinel = sentinel
+ c.discoverSentinels(ctx)
+
+ c.pubsub = sentinel.Subscribe(ctx, "+switch-master", "+slave-reconf-done")
+ go c.listen(c.pubsub)
+}
+
+func (c *sentinelFailover) discoverSentinels(ctx context.Context) {
+ sentinels, err := c.sentinel.Sentinels(ctx, c.opt.MasterName).Result()
+ if err != nil {
+ internal.Logger.Printf(ctx, "sentinel: Sentinels master=%q failed: %s", c.opt.MasterName, err)
+ return
+ }
+ for _, sentinel := range sentinels {
+ vals := sentinel.([]interface{})
+ var ip, port string
+ for i := 0; i < len(vals); i += 2 {
+ key := vals[i].(string)
+ switch key {
+ case "ip":
+ ip = vals[i+1].(string)
+ case "port":
+ port = vals[i+1].(string)
+ }
+ }
+ if ip != "" && port != "" {
+ sentinelAddr := net.JoinHostPort(ip, port)
+ if !contains(c.sentinelAddrs, sentinelAddr) {
+ internal.Logger.Printf(ctx, "sentinel: discovered new sentinel=%q for master=%q",
+ sentinelAddr, c.opt.MasterName)
+ c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr)
+ }
+ }
+ }
+}
+
+func (c *sentinelFailover) listen(pubsub *PubSub) {
+ ctx := context.TODO()
+
+ if c.onUpdate != nil {
+ c.onUpdate(ctx)
+ }
+
+ ch := pubsub.Channel()
+ for msg := range ch {
+ if msg.Channel == "+switch-master" {
+ parts := strings.Split(msg.Payload, " ")
+ if parts[0] != c.opt.MasterName {
+ internal.Logger.Printf(pubsub.getContext(), "sentinel: ignore addr for master=%q", parts[0])
+ continue
+ }
+ addr := net.JoinHostPort(parts[3], parts[4])
+ c.trySwitchMaster(pubsub.getContext(), addr)
+ }
+
+ if c.onUpdate != nil {
+ c.onUpdate(ctx)
+ }
+ }
+}
+
+func contains(slice []string, str string) bool {
+ for _, s := range slice {
+ if s == str {
+ return true
+ }
+ }
+ return false
+}
+
+//------------------------------------------------------------------------------
+
+// NewFailoverClusterClient returns a client that supports routing read-only commands
+// to a slave node.
+func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient {
+ sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
+ copy(sentinelAddrs, failoverOpt.SentinelAddrs)
+
+ failover := &sentinelFailover{
+ opt: failoverOpt,
+ sentinelAddrs: sentinelAddrs,
+ }
+
+ opt := failoverOpt.clusterOptions()
+ opt.ClusterSlots = func(ctx context.Context) ([]ClusterSlot, error) {
+ masterAddr, err := failover.MasterAddr(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ nodes := []ClusterNode{{
+ Addr: masterAddr,
+ }}
+
+ slaveAddrs, err := failover.slaveAddrs(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, slaveAddr := range slaveAddrs {
+ nodes = append(nodes, ClusterNode{
+ Addr: slaveAddr,
+ })
+ }
+
+ slots := []ClusterSlot{
+ {
+ Start: 0,
+ End: 16383,
+ Nodes: nodes,
+ },
+ }
+ return slots, nil
+ }
+
+ c := NewClusterClient(opt)
+
+ failover.mu.Lock()
+ failover.onUpdate = func(ctx context.Context) {
+ c.ReloadState(ctx)
+ }
+ failover.mu.Unlock()
+
+ return c
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/tx.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/tx.go
new file mode 100644
index 000000000000..8c9d87202aed
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/tx.go
@@ -0,0 +1,149 @@
+package redis
+
+import (
+ "context"
+
+ "github.com/go-redis/redis/v8/internal/pool"
+ "github.com/go-redis/redis/v8/internal/proto"
+)
+
+// TxFailedErr transaction redis failed.
+const TxFailedErr = proto.RedisError("redis: transaction failed")
+
+// Tx implements Redis transactions as described in
+// http://redis.io/topics/transactions. It's NOT safe for concurrent use
+// by multiple goroutines, because Exec resets list of watched keys.
+//
+// If you don't need WATCH, use Pipeline instead.
+type Tx struct {
+ baseClient
+ cmdable
+ statefulCmdable
+ hooks
+ ctx context.Context
+}
+
+func (c *Client) newTx(ctx context.Context) *Tx {
+ tx := Tx{
+ baseClient: baseClient{
+ opt: c.opt,
+ connPool: pool.NewStickyConnPool(c.connPool),
+ },
+ hooks: c.hooks.clone(),
+ ctx: ctx,
+ }
+ tx.init()
+ return &tx
+}
+
+func (c *Tx) init() {
+ c.cmdable = c.Process
+ c.statefulCmdable = c.Process
+}
+
+func (c *Tx) Context() context.Context {
+ return c.ctx
+}
+
+func (c *Tx) WithContext(ctx context.Context) *Tx {
+ if ctx == nil {
+ panic("nil context")
+ }
+ clone := *c
+ clone.init()
+ clone.hooks.lock()
+ clone.ctx = ctx
+ return &clone
+}
+
+func (c *Tx) Process(ctx context.Context, cmd Cmder) error {
+ return c.hooks.process(ctx, cmd, c.baseClient.process)
+}
+
+// Watch prepares a transaction and marks the keys to be watched
+// for conditional execution if there are any keys.
+//
+// The transaction is automatically closed when fn exits.
+func (c *Client) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
+ tx := c.newTx(ctx)
+ defer tx.Close(ctx)
+ if len(keys) > 0 {
+ if err := tx.Watch(ctx, keys...).Err(); err != nil {
+ return err
+ }
+ }
+ return fn(tx)
+}
+
+// Close closes the transaction, releasing any open resources.
+func (c *Tx) Close(ctx context.Context) error {
+ _ = c.Unwatch(ctx).Err()
+ return c.baseClient.Close()
+}
+
+// Watch marks the keys to be watched for conditional execution
+// of a transaction.
+func (c *Tx) Watch(ctx context.Context, keys ...string) *StatusCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "watch"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Unwatch flushes all the previously watched keys for a transaction.
+func (c *Tx) Unwatch(ctx context.Context, keys ...string) *StatusCmd {
+ args := make([]interface{}, 1+len(keys))
+ args[0] = "unwatch"
+ for i, key := range keys {
+ args[1+i] = key
+ }
+ cmd := NewStatusCmd(ctx, args...)
+ _ = c.Process(ctx, cmd)
+ return cmd
+}
+
+// Pipeline creates a pipeline. Usually it is more convenient to use Pipelined.
+func (c *Tx) Pipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: func(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline)
+ },
+ }
+ pipe.init()
+ return &pipe
+}
+
+// Pipelined executes commands queued in the fn outside of the transaction.
+// Use TxPipelined if you need transactional behavior.
+func (c *Tx) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.Pipeline().Pipelined(ctx, fn)
+}
+
+// TxPipelined executes commands queued in the fn in the transaction.
+//
+// When using WATCH, EXEC will execute commands only if the watched keys
+// were not modified, allowing for a check-and-set mechanism.
+//
+// Exec always returns list of commands. If transaction fails
+// TxFailedErr is returned. Otherwise Exec returns an error of the first
+// failed command or nil.
+func (c *Tx) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
+ return c.TxPipeline().Pipelined(ctx, fn)
+}
+
+// TxPipeline creates a pipeline. Usually it is more convenient to use TxPipelined.
+func (c *Tx) TxPipeline() Pipeliner {
+ pipe := Pipeline{
+ ctx: c.ctx,
+ exec: func(ctx context.Context, cmds []Cmder) error {
+ return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline)
+ },
+ }
+ pipe.init()
+ return &pipe
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/universal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/universal.go
new file mode 100644
index 000000000000..c89b3e5d7431
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/universal.go
@@ -0,0 +1,215 @@
+package redis
+
+import (
+ "context"
+ "crypto/tls"
+ "net"
+ "time"
+)
+
+// UniversalOptions information is required by UniversalClient to establish
+// connections.
+type UniversalOptions struct {
+ // Either a single address or a seed list of host:port addresses
+ // of cluster/sentinel nodes.
+ Addrs []string
+
+ // Database to be selected after connecting to the server.
+ // Only single-node and failover clients.
+ DB int
+
+ // Common options.
+
+ Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
+ OnConnect func(ctx context.Context, cn *Conn) error
+
+ Username string
+ Password string
+ SentinelUsername string
+ SentinelPassword string
+
+ MaxRetries int
+ MinRetryBackoff time.Duration
+ MaxRetryBackoff time.Duration
+
+ DialTimeout time.Duration
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+
+ // PoolFIFO uses FIFO mode for each node connection pool GET/PUT (default LIFO).
+ PoolFIFO bool
+
+ PoolSize int
+ MinIdleConns int
+ MaxConnAge time.Duration
+ PoolTimeout time.Duration
+ IdleTimeout time.Duration
+ IdleCheckFrequency time.Duration
+
+ TLSConfig *tls.Config
+
+ // Only cluster clients.
+
+ MaxRedirects int
+ ReadOnly bool
+ RouteByLatency bool
+ RouteRandomly bool
+
+ // The sentinel master name.
+ // Only failover clients.
+
+ MasterName string
+}
+
+// Cluster returns cluster options created from the universal options.
+func (o *UniversalOptions) Cluster() *ClusterOptions {
+ if len(o.Addrs) == 0 {
+ o.Addrs = []string{"127.0.0.1:6379"}
+ }
+
+ return &ClusterOptions{
+ Addrs: o.Addrs,
+ Dialer: o.Dialer,
+ OnConnect: o.OnConnect,
+
+ Username: o.Username,
+ Password: o.Password,
+
+ MaxRedirects: o.MaxRedirects,
+ ReadOnly: o.ReadOnly,
+ RouteByLatency: o.RouteByLatency,
+ RouteRandomly: o.RouteRandomly,
+
+ MaxRetries: o.MaxRetries,
+ MinRetryBackoff: o.MinRetryBackoff,
+ MaxRetryBackoff: o.MaxRetryBackoff,
+
+ DialTimeout: o.DialTimeout,
+ ReadTimeout: o.ReadTimeout,
+ WriteTimeout: o.WriteTimeout,
+ PoolFIFO: o.PoolFIFO,
+ PoolSize: o.PoolSize,
+ MinIdleConns: o.MinIdleConns,
+ MaxConnAge: o.MaxConnAge,
+ PoolTimeout: o.PoolTimeout,
+ IdleTimeout: o.IdleTimeout,
+ IdleCheckFrequency: o.IdleCheckFrequency,
+
+ TLSConfig: o.TLSConfig,
+ }
+}
+
+// Failover returns failover options created from the universal options.
+func (o *UniversalOptions) Failover() *FailoverOptions {
+ if len(o.Addrs) == 0 {
+ o.Addrs = []string{"127.0.0.1:26379"}
+ }
+
+ return &FailoverOptions{
+ SentinelAddrs: o.Addrs,
+ MasterName: o.MasterName,
+
+ Dialer: o.Dialer,
+ OnConnect: o.OnConnect,
+
+ DB: o.DB,
+ Username: o.Username,
+ Password: o.Password,
+ SentinelUsername: o.SentinelUsername,
+ SentinelPassword: o.SentinelPassword,
+
+ MaxRetries: o.MaxRetries,
+ MinRetryBackoff: o.MinRetryBackoff,
+ MaxRetryBackoff: o.MaxRetryBackoff,
+
+ DialTimeout: o.DialTimeout,
+ ReadTimeout: o.ReadTimeout,
+ WriteTimeout: o.WriteTimeout,
+
+ PoolFIFO: o.PoolFIFO,
+ PoolSize: o.PoolSize,
+ MinIdleConns: o.MinIdleConns,
+ MaxConnAge: o.MaxConnAge,
+ PoolTimeout: o.PoolTimeout,
+ IdleTimeout: o.IdleTimeout,
+ IdleCheckFrequency: o.IdleCheckFrequency,
+
+ TLSConfig: o.TLSConfig,
+ }
+}
+
+// Simple returns basic options created from the universal options.
+func (o *UniversalOptions) Simple() *Options {
+ addr := "127.0.0.1:6379"
+ if len(o.Addrs) > 0 {
+ addr = o.Addrs[0]
+ }
+
+ return &Options{
+ Addr: addr,
+ Dialer: o.Dialer,
+ OnConnect: o.OnConnect,
+
+ DB: o.DB,
+ Username: o.Username,
+ Password: o.Password,
+
+ MaxRetries: o.MaxRetries,
+ MinRetryBackoff: o.MinRetryBackoff,
+ MaxRetryBackoff: o.MaxRetryBackoff,
+
+ DialTimeout: o.DialTimeout,
+ ReadTimeout: o.ReadTimeout,
+ WriteTimeout: o.WriteTimeout,
+
+ PoolFIFO: o.PoolFIFO,
+ PoolSize: o.PoolSize,
+ MinIdleConns: o.MinIdleConns,
+ MaxConnAge: o.MaxConnAge,
+ PoolTimeout: o.PoolTimeout,
+ IdleTimeout: o.IdleTimeout,
+ IdleCheckFrequency: o.IdleCheckFrequency,
+
+ TLSConfig: o.TLSConfig,
+ }
+}
+
+// --------------------------------------------------------------------
+
+// UniversalClient is an abstract client which - based on the provided options -
+// represents either a ClusterClient, a FailoverClient, or a single-node Client.
+// This can be useful for testing cluster-specific applications locally or having different
+// clients in different environments.
+type UniversalClient interface {
+ Cmdable
+ Context() context.Context
+ AddHook(Hook)
+ Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error
+ Do(ctx context.Context, args ...interface{}) *Cmd
+ Process(ctx context.Context, cmd Cmder) error
+ Subscribe(ctx context.Context, channels ...string) *PubSub
+ PSubscribe(ctx context.Context, channels ...string) *PubSub
+ Close() error
+ PoolStats() *PoolStats
+}
+
+var (
+ _ UniversalClient = (*Client)(nil)
+ _ UniversalClient = (*ClusterClient)(nil)
+ _ UniversalClient = (*Ring)(nil)
+)
+
+// NewUniversalClient returns a new multi client. The type of the returned client depends
+// on the following conditions:
+//
+// 1. If the MasterName option is specified, a sentinel-backed FailoverClient is returned.
+// 2. if the number of Addrs is two or more, a ClusterClient is returned.
+// 3. Otherwise, a single-node Client is returned.
+func NewUniversalClient(opts *UniversalOptions) UniversalClient {
+ if opts.MasterName != "" {
+ return NewFailoverClient(opts.Failover())
+ } else if len(opts.Addrs) > 1 {
+ return NewClusterClient(opts.Cluster())
+ }
+ return NewClient(opts.Simple())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/version.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/version.go
new file mode 100644
index 000000000000..112c9a2da0e3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-redis/redis/v8/version.go
@@ -0,0 +1,6 @@
+package redis
+
+// Version is the current release version.
+func Version() string {
+ return "8.11.5"
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/.gitignore
new file mode 100644
index 000000000000..2de28da16638
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/.gitignore
@@ -0,0 +1,9 @@
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+Icon?
+ehthumbs.db
+Thumbs.db
+.idea
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/AUTHORS b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/AUTHORS
new file mode 100644
index 000000000000..50afa2c85977
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/AUTHORS
@@ -0,0 +1,117 @@
+# This is the official list of Go-MySQL-Driver authors for copyright purposes.
+
+# If you are submitting a patch, please add your name or the name of the
+# organization which holds the copyright to this list in alphabetical order.
+
+# Names should be added to this file as
+# Name
+# The email address is not required for organizations.
+# Please keep the list sorted.
+
+
+# Individual Persons
+
+Aaron Hopkins
+Achille Roussel
+Alex Snast
+Alexey Palazhchenko
+Andrew Reid
+Animesh Ray
+Arne Hormann
+Ariel Mashraki
+Asta Xie
+Bulat Gaifullin
+Caine Jette
+Carlos Nieto
+Chris Moos
+Craig Wilson
+Daniel Montoya
+Daniel Nichter
+Daniël van Eeden
+Dave Protasowski
+DisposaBoy
+Egor Smolyakov
+Erwan Martin
+Evan Shaw
+Frederick Mayle
+Gustavo Kristic
+Hajime Nakagami
+Hanno Braun
+Henri Yandell
+Hirotaka Yamamoto
+Huyiguang
+ICHINOSE Shogo
+Ilia Cimpoes
+INADA Naoki
+Jacek Szwec
+James Harr
+Jeff Hodges
+Jeffrey Charles
+Jerome Meyer
+Jiajia Zhong
+Jian Zhen
+Joshua Prunier
+Julien Lefevre
+Julien Schmidt
+Justin Li
+Justin Nuß
+Kamil Dziedzic
+Kei Kamikawa
+Kevin Malachowski
+Kieron Woodhouse
+Lennart Rudolph
+Leonardo YongUk Kim
+Linh Tran Tuan
+Lion Yang
+Luca Looz
+Lucas Liu
+Luke Scott
+Maciej Zimnoch
+Michael Woolnough
+Nathanial Murphy
+Nicola Peduzzi
+Olivier Mengué
+oscarzhao
+Paul Bonser
+Peter Schultz
+Rebecca Chin
+Reed Allman
+Richard Wilkes
+Robert Russell
+Runrioter Wung
+Sho Iizuka
+Sho Ikeda
+Shuode Li
+Simon J Mudd
+Soroush Pour
+Stan Putrya
+Stanley Gunawan
+Steven Hartland
+Tan Jinhua <312841925 at qq.com>
+Thomas Wodarek
+Tim Ruffles
+Tom Jenkinson
+Vladimir Kovpak
+Vladyslav Zhelezniak
+Xiangyu Hu
+Xiaobing Jiang
+Xiuming Chen
+Xuehong Chan
+Zhenye Xie
+Zhixin Wen
+
+# Organizations
+
+Barracuda Networks, Inc.
+Counting Ltd.
+DigitalOcean Inc.
+Facebook Inc.
+GitHub Inc.
+Google Inc.
+InfoSum Ltd.
+Keybase Inc.
+Multiplay Ltd.
+Percona LLC
+Pivotal Inc.
+Stripe Inc.
+Zendesk Inc.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
new file mode 100644
index 000000000000..72a738ed502d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
@@ -0,0 +1,232 @@
+## Version 1.6 (2021-04-01)
+
+Changes:
+
+ - Migrate the CI service from travis-ci to GitHub Actions (#1176, #1183, #1190)
+ - `NullTime` is deprecated (#960, #1144)
+ - Reduce allocations when building SET command (#1111)
+ - Performance improvement for time formatting (#1118)
+ - Performance improvement for time parsing (#1098, #1113)
+
+New Features:
+
+ - Implement `driver.Validator` interface (#1106, #1174)
+ - Support returning `uint64` from `Valuer` in `ConvertValue` (#1143)
+ - Add `json.RawMessage` for converter and prepared statement (#1059)
+ - Interpolate `json.RawMessage` as `string` (#1058)
+ - Implements `CheckNamedValue` (#1090)
+
+Bugfixes:
+
+ - Stop rounding times (#1121, #1172)
+ - Put zero filler into the SSL handshake packet (#1066)
+ - Fix checking cancelled connections back into the connection pool (#1095)
+ - Fix remove last 0 byte for mysql_old_password when password is empty (#1133)
+
+
+## Version 1.5 (2020-01-07)
+
+Changes:
+
+ - Dropped support Go 1.9 and lower (#823, #829, #886, #1016, #1017)
+ - Improve buffer handling (#890)
+ - Document potentially insecure TLS configs (#901)
+ - Use a double-buffering scheme to prevent data races (#943)
+ - Pass uint64 values without converting them to string (#838, #955)
+ - Update collations and make utf8mb4 default (#877, #1054)
+ - Make NullTime compatible with sql.NullTime in Go 1.13+ (#995)
+ - Removed CloudSQL support (#993, #1007)
+ - Add Go Module support (#1003)
+
+New Features:
+
+ - Implement support of optional TLS (#900)
+ - Check connection liveness (#934, #964, #997, #1048, #1051, #1052)
+ - Implement Connector Interface (#941, #958, #1020, #1035)
+
+Bugfixes:
+
+ - Mark connections as bad on error during ping (#875)
+ - Mark connections as bad on error during dial (#867)
+ - Fix connection leak caused by rapid context cancellation (#1024)
+ - Mark connections as bad on error during Conn.Prepare (#1030)
+
+
+## Version 1.4.1 (2018-11-14)
+
+Bugfixes:
+
+ - Fix TIME format for binary columns (#818)
+ - Fix handling of empty auth plugin names (#835)
+ - Fix caching_sha2_password with empty password (#826)
+ - Fix canceled context broke mysqlConn (#862)
+ - Fix OldAuthSwitchRequest support (#870)
+ - Fix Auth Response packet for cleartext password (#887)
+
+## Version 1.4 (2018-06-03)
+
+Changes:
+
+ - Documentation fixes (#530, #535, #567)
+ - Refactoring (#575, #579, #580, #581, #603, #615, #704)
+ - Cache column names (#444)
+ - Sort the DSN parameters in DSNs generated from a config (#637)
+ - Allow native password authentication by default (#644)
+ - Use the default port if it is missing in the DSN (#668)
+ - Removed the `strict` mode (#676)
+ - Do not query `max_allowed_packet` by default (#680)
+ - Dropped support Go 1.6 and lower (#696)
+ - Updated `ConvertValue()` to match the database/sql/driver implementation (#760)
+ - Document the usage of `0000-00-00T00:00:00` as the time.Time zero value (#783)
+ - Improved the compatibility of the authentication system (#807)
+
+New Features:
+
+ - Multi-Results support (#537)
+ - `rejectReadOnly` DSN option (#604)
+ - `context.Context` support (#608, #612, #627, #761)
+ - Transaction isolation level support (#619, #744)
+ - Read-Only transactions support (#618, #634)
+ - `NewConfig` function which initializes a config with default values (#679)
+ - Implemented the `ColumnType` interfaces (#667, #724)
+ - Support for custom string types in `ConvertValue` (#623)
+ - Implemented `NamedValueChecker`, improving support for uint64 with high bit set (#690, #709, #710)
+ - `caching_sha2_password` authentication plugin support (#794, #800, #801, #802)
+ - Implemented `driver.SessionResetter` (#779)
+ - `sha256_password` authentication plugin support (#808)
+
+Bugfixes:
+
+ - Use the DSN hostname as TLS default ServerName if `tls=true` (#564, #718)
+ - Fixed LOAD LOCAL DATA INFILE for empty files (#590)
+ - Removed columns definition cache since it sometimes cached invalid data (#592)
+ - Don't mutate registered TLS configs (#600)
+ - Make RegisterTLSConfig concurrency-safe (#613)
+ - Handle missing auth data in the handshake packet correctly (#646)
+ - Do not retry queries when data was written to avoid data corruption (#302, #736)
+ - Cache the connection pointer for error handling before invalidating it (#678)
+ - Fixed imports for appengine/cloudsql (#700)
+ - Fix sending STMT_LONG_DATA for 0 byte data (#734)
+ - Set correct capacity for []bytes read from length-encoded strings (#766)
+ - Make RegisterDial concurrency-safe (#773)
+
+
+## Version 1.3 (2016-12-01)
+
+Changes:
+
+ - Go 1.1 is no longer supported
+ - Use decimals fields in MySQL to format time types (#249)
+ - Buffer optimizations (#269)
+ - TLS ServerName defaults to the host (#283)
+ - Refactoring (#400, #410, #437)
+ - Adjusted documentation for second generation CloudSQL (#485)
+ - Documented DSN system var quoting rules (#502)
+ - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512)
+
+New Features:
+
+ - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
+ - Support for returning table alias on Columns() (#289, #359, #382)
+ - Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490)
+ - Support for uint64 parameters with high bit set (#332, #345)
+ - Cleartext authentication plugin support (#327)
+ - Exported ParseDSN function and the Config struct (#403, #419, #429)
+ - Read / Write timeouts (#401)
+ - Support for JSON field type (#414)
+ - Support for multi-statements and multi-results (#411, #431)
+ - DSN parameter to set the driver-side max_allowed_packet value manually (#489)
+ - Native password authentication plugin support (#494, #524)
+
+Bugfixes:
+
+ - Fixed handling of queries without columns and rows (#255)
+ - Fixed a panic when SetKeepAlive() failed (#298)
+ - Handle ERR packets while reading rows (#321)
+ - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349)
+ - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356)
+ - Actually zero out bytes in handshake response (#378)
+ - Fixed race condition in registering LOAD DATA INFILE handler (#383)
+ - Fixed tests with MySQL 5.7.9+ (#380)
+ - QueryUnescape TLS config names (#397)
+ - Fixed "broken pipe" error by writing to closed socket (#390)
+ - Fixed LOAD LOCAL DATA INFILE buffering (#424)
+ - Fixed parsing of floats into float64 when placeholders are used (#434)
+ - Fixed DSN tests with Go 1.7+ (#459)
+ - Handle ERR packets while waiting for EOF (#473)
+ - Invalidate connection on error while discarding additional results (#513)
+ - Allow terminating packets of length 0 (#516)
+
+
+## Version 1.2 (2014-06-03)
+
+Changes:
+
+ - We switched back to a "rolling release". `go get` installs the current master branch again
+ - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver
+ - Exported errors to allow easy checking from application code
+ - Enabled TCP Keepalives on TCP connections
+ - Optimized INFILE handling (better buffer size calculation, lazy init, ...)
+ - The DSN parser also checks for a missing separating slash
+ - Faster binary date / datetime to string formatting
+ - Also exported the MySQLWarning type
+ - mysqlConn.Close returns the first error encountered instead of ignoring all errors
+ - writePacket() automatically writes the packet size to the header
+ - readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets
+
+New Features:
+
+ - `RegisterDial` allows the usage of a custom dial function to establish the network connection
+ - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter
+ - Logging of critical errors is configurable with `SetLogger`
+ - Google CloudSQL support
+
+Bugfixes:
+
+ - Allow more than 32 parameters in prepared statements
+ - Various old_password fixes
+ - Fixed TestConcurrent test to pass Go's race detection
+ - Fixed appendLengthEncodedInteger for large numbers
+ - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo)
+
+
+## Version 1.1 (2013-11-02)
+
+Changes:
+
+ - Go-MySQL-Driver now requires Go 1.1
+ - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore
+ - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors
+ - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")`
+ - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'.
+ - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries
+ - Optimized the buffer for reading
+ - stmt.Query now caches column metadata
+ - New Logo
+ - Changed the copyright header to include all contributors
+ - Improved the LOAD INFILE documentation
+ - The driver struct is now exported to make the driver directly accessible
+ - Refactored the driver tests
+ - Added more benchmarks and moved all to a separate file
+ - Other small refactoring
+
+New Features:
+
+ - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure
+ - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs
+ - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used
+
+Bugfixes:
+
+ - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification
+ - Convert to DB timezone when inserting `time.Time`
+ - Splitted packets (more than 16MB) are now merged correctly
+ - Fixed false positive `io.EOF` errors when the data was fully read
+ - Avoid panics on reuse of closed connections
+ - Fixed empty string producing false nil values
+ - Fixed sign byte for positive TIME fields
+
+
+## Version 1.0 (2013-05-14)
+
+Initial Release
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/LICENSE
new file mode 100644
index 000000000000..14e2f777f6c3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/README.md
new file mode 100644
index 000000000000..0b13154fccf1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/README.md
@@ -0,0 +1,520 @@
+# Go-MySQL-Driver
+
+A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package
+
+![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin")
+
+---------------------------------------
+ * [Features](#features)
+ * [Requirements](#requirements)
+ * [Installation](#installation)
+ * [Usage](#usage)
+ * [DSN (Data Source Name)](#dsn-data-source-name)
+ * [Password](#password)
+ * [Protocol](#protocol)
+ * [Address](#address)
+ * [Parameters](#parameters)
+ * [Examples](#examples)
+ * [Connection pool and timeouts](#connection-pool-and-timeouts)
+ * [context.Context Support](#contextcontext-support)
+ * [ColumnType Support](#columntype-support)
+ * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support)
+ * [time.Time support](#timetime-support)
+ * [Unicode support](#unicode-support)
+ * [Testing / Development](#testing--development)
+ * [License](#license)
+
+---------------------------------------
+
+## Features
+ * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance")
+ * Native Go implementation. No C-bindings, just pure Go
+ * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc)
+ * Automatic handling of broken connections
+ * Automatic Connection Pooling *(by database/sql package)*
+ * Supports queries larger than 16MB
+ * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support.
+ * Intelligent `LONG DATA` handling in prepared statements
+ * Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support
+ * Optional `time.Time` parsing
+ * Optional placeholder interpolation
+
+## Requirements
+ * Go 1.10 or higher. We aim to support the 3 latest versions of Go.
+ * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)
+
+---------------------------------------
+
+## Installation
+Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell:
+```bash
+$ go get -u github.com/go-sql-driver/mysql
+```
+Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
+
+## Usage
+_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then.
+
+Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`:
+
+```go
+import (
+ "database/sql"
+ "time"
+
+ _ "github.com/go-sql-driver/mysql"
+)
+
+// ...
+
+db, err := sql.Open("mysql", "user:password@/dbname")
+if err != nil {
+ panic(err)
+}
+// See "Important settings" section.
+db.SetConnMaxLifetime(time.Minute * 3)
+db.SetMaxOpenConns(10)
+db.SetMaxIdleConns(10)
+```
+
+[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples").
+
+### Important settings
+
+`db.SetConnMaxLifetime()` is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too.
+
+`db.SetMaxOpenConns()` is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server.
+
+`db.SetMaxIdleConns()` is recommended to be set same to (or greater than) `db.SetMaxOpenConns()`. When it is smaller than `SetMaxOpenConns()`, connections can be opened and closed very frequently than you expect. Idle connections can be closed by the `db.SetConnMaxLifetime()`. If you want to close idle connections more rapidly, you can use `db.SetConnMaxIdleTime()` since Go 1.15.
+
+
+### DSN (Data Source Name)
+
+The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets):
+```
+[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
+```
+
+A DSN in its fullest form:
+```
+username:password@protocol(address)/dbname?param=value
+```
+
+Except for the databasename, all values are optional. So the minimal DSN is:
+```
+/dbname
+```
+
+If you do not want to preselect a database, leave `dbname` empty:
+```
+/
+```
+This has the same effect as an empty DSN string:
+```
+
+```
+
+Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct.
+
+#### Password
+Passwords can consist of any character. Escaping is **not** necessary.
+
+#### Protocol
+See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available.
+In general you should use an Unix domain socket if available and TCP otherwise for best performance.
+
+#### Address
+For TCP and UDP networks, addresses have the form `host[:port]`.
+If `port` is omitted, the default port will be used.
+If `host` is a literal IPv6 address, it must be enclosed in square brackets.
+The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
+
+For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`.
+
+#### Parameters
+*Parameters are case-sensitive!*
+
+Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`.
+
+##### `allowAllFiles`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+`allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files.
+[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)
+
+##### `allowCleartextPasswords`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+`allowCleartextPasswords=true` allows using the [cleartext client side plugin](https://dev.mysql.com/doc/en/cleartext-pluggable-authentication.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.
+
+##### `allowNativePasswords`
+
+```
+Type: bool
+Valid Values: true, false
+Default: true
+```
+`allowNativePasswords=false` disallows the usage of MySQL native password method.
+
+##### `allowOldPasswords`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords).
+
+##### `charset`
+
+```
+Type: string
+Valid Values:
+Default: none
+```
+
+Sets the charset used for client-server interaction (`"SET NAMES "`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`).
+
+Usage of the `charset` parameter is discouraged because it issues additional queries to the server.
+Unless you need the fallback behavior, please use `collation` instead.
+
+##### `checkConnLiveness`
+
+```
+Type: bool
+Valid Values: true, false
+Default: true
+```
+
+On supported platforms connections retrieved from the connection pool are checked for liveness before using them. If the check fails, the respective connection is marked as bad and the query retried with another connection.
+`checkConnLiveness=false` disables this liveness check of connections.
+
+##### `collation`
+
+```
+Type: string
+Valid Values:
+Default: utf8mb4_general_ci
+```
+
+Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail.
+
+A list of valid charsets for a server is retrievable with `SHOW COLLATION`.
+
+The default collation (`utf8mb4_general_ci`) is supported from MySQL 5.5. You should use an older collation (e.g. `utf8_general_ci`) for older MySQL.
+
+Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)).
+
+
+##### `clientFoundRows`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed.
+
+##### `columnsWithAlias`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+When `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example:
+
+```
+SELECT u.id FROM users as u
+```
+
+will return `u.id` instead of just `id` if `columnsWithAlias=true`.
+
+##### `interpolateParams`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`.
+
+*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!*
+
+##### `loc`
+
+```
+Type: string
+Valid Values:
+Default: UTC
+```
+
+Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details.
+
+Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter.
+
+Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`.
+
+##### `maxAllowedPacket`
+```
+Type: decimal number
+Default: 4194304
+```
+
+Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.
+
+##### `multiStatements`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+Allow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded.
+
+When `multiStatements` is used, `?` parameters must only be used in the first statement.
+
+##### `parseTime`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string`
+The date or datetime like `0000-00-00 00:00:00` is converted into zero value of `time.Time`.
+
+
+##### `readTimeout`
+
+```
+Type: duration
+Default: 0
+```
+
+I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
+
+##### `rejectReadOnly`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+
+`rejectReadOnly=true` causes the driver to reject read-only connections. This
+is for a possible race condition during an automatic failover, where the mysql
+client gets connected to a read-only replica after the failover.
+
+Note that this should be a fairly rare case, as an automatic failover normally
+happens when the primary is down, and the race condition shouldn't happen
+unless it comes back up online as soon as the failover is kicked off. On the
+other hand, when this happens, a MySQL application can get stuck on a
+read-only connection until restarted. It is however fairly easy to reproduce,
+for example, using a manual failover on AWS Aurora's MySQL-compatible cluster.
+
+If you are not relying on read-only transactions to reject writes that aren't
+supposed to happen, setting this on some MySQL providers (such as AWS Aurora)
+is safer for failovers.
+
+Note that ERROR 1290 can be returned for a `read-only` server and this option will
+cause a retry for that error. However the same error number is used for some
+other cases. You should ensure your application will never cause an ERROR 1290
+except for `read-only` mode when enabling this option.
+
+
+##### `serverPubKey`
+
+```
+Type: string
+Valid Values:
+Default: none
+```
+
+Server public keys can be registered with [`mysql.RegisterServerPubKey`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterServerPubKey), which can then be used by the assigned name in the DSN.
+Public keys are used to transmit encrypted data, e.g. for authentication.
+If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required.
+
+
+##### `timeout`
+
+```
+Type: duration
+Default: OS default
+```
+
+Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
+
+
+##### `tls`
+
+```
+Type: bool / string
+Valid Values: true, false, skip-verify, preferred,
+Default: false
+```
+
+`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
+
+
+##### `writeTimeout`
+
+```
+Type: duration
+Default: 0
+```
+
+I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
+
+
+##### System Variables
+
+Any other parameters are interpreted as system variables:
+ * `=`: `SET =`
+ * `=`: `SET =`
+ * `=%27%27`: `SET =''`
+
+Rules:
+* The values for string variables must be quoted with `'`.
+* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!
+ (which implies values of string variables must be wrapped with `%27`).
+
+Examples:
+ * `autocommit=1`: `SET autocommit=1`
+ * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'`
+ * [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'`
+
+
+#### Examples
+```
+user@unix(/path/to/socket)/dbname
+```
+
+```
+root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local
+```
+
+```
+user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true
+```
+
+Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html):
+```
+user:password@/dbname?sql_mode=TRADITIONAL
+```
+
+TCP via IPv6:
+```
+user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci
+```
+
+TCP on a remote host, e.g. Amazon RDS:
+```
+id:password@tcp(your-amazonaws-uri.com:3306)/dbname
+```
+
+Google Cloud SQL on App Engine:
+```
+user:password@unix(/cloudsql/project-id:region-name:instance-name)/dbname
+```
+
+TCP using default port (3306) on localhost:
+```
+user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
+```
+
+Use the default protocol (tcp) and host (localhost:3306):
+```
+user:password@/dbname
+```
+
+No Database preselected:
+```
+user:password@/
+```
+
+
+### Connection pool and timeouts
+The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively.
+
+## `ColumnType` Support
+This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported.
+
+## `context.Context` Support
+Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts.
+See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details.
+
+
+### `LOAD DATA LOCAL INFILE` support
+For this feature you need direct access to the package. Therefore you must change the import path (no `_`):
+```go
+import "github.com/go-sql-driver/mysql"
+```
+
+Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
+
+To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
+
+See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details.
+
+
+### `time.Time` support
+The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program.
+
+However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical equivalent in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
+
+**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).
+
+
+### Unicode support
+Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default.
+
+Other collations / charsets can be set using the [`collation`](#collation) DSN parameter.
+
+Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default.
+
+See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support.
+
+## Testing / Development
+To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details.
+
+Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated.
+If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls).
+
+See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/.github/CONTRIBUTING.md) for details.
+
+---------------------------------------
+
+## License
+Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
+
+Mozilla summarizes the license scope as follows:
+> MPL: The copyleft applies to any files containing MPLed code.
+
+
+That means:
+ * You can **use** the **unchanged** source code both in private and commercially.
+ * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0).
+ * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**.
+
+Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license.
+
+You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
+
+![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/auth.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/auth.go
new file mode 100644
index 000000000000..b2f19e8f0b60
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/auth.go
@@ -0,0 +1,425 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "sync"
+)
+
+// server pub keys registry
+var (
+ serverPubKeyLock sync.RWMutex
+ serverPubKeyRegistry map[string]*rsa.PublicKey
+)
+
+// RegisterServerPubKey registers a server RSA public key which can be used to
+// send data in a secure manner to the server without receiving the public key
+// in a potentially insecure way from the server first.
+// Registered keys can afterwards be used adding serverPubKey= to the DSN.
+//
+// Note: The provided rsa.PublicKey instance is exclusively owned by the driver
+// after registering it and may not be modified.
+//
+// data, err := ioutil.ReadFile("mykey.pem")
+// if err != nil {
+// log.Fatal(err)
+// }
+//
+// block, _ := pem.Decode(data)
+// if block == nil || block.Type != "PUBLIC KEY" {
+// log.Fatal("failed to decode PEM block containing public key")
+// }
+//
+// pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+// if err != nil {
+// log.Fatal(err)
+// }
+//
+// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok {
+// mysql.RegisterServerPubKey("mykey", rsaPubKey)
+// } else {
+// log.Fatal("not a RSA public key")
+// }
+//
+func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) {
+ serverPubKeyLock.Lock()
+ if serverPubKeyRegistry == nil {
+ serverPubKeyRegistry = make(map[string]*rsa.PublicKey)
+ }
+
+ serverPubKeyRegistry[name] = pubKey
+ serverPubKeyLock.Unlock()
+}
+
+// DeregisterServerPubKey removes the public key registered with the given name.
+func DeregisterServerPubKey(name string) {
+ serverPubKeyLock.Lock()
+ if serverPubKeyRegistry != nil {
+ delete(serverPubKeyRegistry, name)
+ }
+ serverPubKeyLock.Unlock()
+}
+
+func getServerPubKey(name string) (pubKey *rsa.PublicKey) {
+ serverPubKeyLock.RLock()
+ if v, ok := serverPubKeyRegistry[name]; ok {
+ pubKey = v
+ }
+ serverPubKeyLock.RUnlock()
+ return
+}
+
+// Hash password using pre 4.1 (old password) method
+// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c
+type myRnd struct {
+ seed1, seed2 uint32
+}
+
+const myRndMaxVal = 0x3FFFFFFF
+
+// Pseudo random number generator
+func newMyRnd(seed1, seed2 uint32) *myRnd {
+ return &myRnd{
+ seed1: seed1 % myRndMaxVal,
+ seed2: seed2 % myRndMaxVal,
+ }
+}
+
+// Tested to be equivalent to MariaDB's floating point variant
+// http://play.golang.org/p/QHvhd4qved
+// http://play.golang.org/p/RG0q4ElWDx
+func (r *myRnd) NextByte() byte {
+ r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
+ r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
+
+ return byte(uint64(r.seed1) * 31 / myRndMaxVal)
+}
+
+// Generate binary hash from byte string using insecure pre 4.1 method
+func pwHash(password []byte) (result [2]uint32) {
+ var add uint32 = 7
+ var tmp uint32
+
+ result[0] = 1345345333
+ result[1] = 0x12345671
+
+ for _, c := range password {
+ // skip spaces and tabs in password
+ if c == ' ' || c == '\t' {
+ continue
+ }
+
+ tmp = uint32(c)
+ result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8)
+ result[1] += (result[1] << 8) ^ result[0]
+ add += tmp
+ }
+
+ // Remove sign bit (1<<31)-1)
+ result[0] &= 0x7FFFFFFF
+ result[1] &= 0x7FFFFFFF
+
+ return
+}
+
+// Hash password using insecure pre 4.1 method
+func scrambleOldPassword(scramble []byte, password string) []byte {
+ scramble = scramble[:8]
+
+ hashPw := pwHash([]byte(password))
+ hashSc := pwHash(scramble)
+
+ r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])
+
+ var out [8]byte
+ for i := range out {
+ out[i] = r.NextByte() + 64
+ }
+
+ mask := r.NextByte()
+ for i := range out {
+ out[i] ^= mask
+ }
+
+ return out[:]
+}
+
+// Hash password using 4.1+ method (SHA1)
+func scramblePassword(scramble []byte, password string) []byte {
+ if len(password) == 0 {
+ return nil
+ }
+
+ // stage1Hash = SHA1(password)
+ crypt := sha1.New()
+ crypt.Write([]byte(password))
+ stage1 := crypt.Sum(nil)
+
+ // scrambleHash = SHA1(scramble + SHA1(stage1Hash))
+ // inner Hash
+ crypt.Reset()
+ crypt.Write(stage1)
+ hash := crypt.Sum(nil)
+
+ // outer Hash
+ crypt.Reset()
+ crypt.Write(scramble)
+ crypt.Write(hash)
+ scramble = crypt.Sum(nil)
+
+ // token = scrambleHash XOR stage1Hash
+ for i := range scramble {
+ scramble[i] ^= stage1[i]
+ }
+ return scramble
+}
+
+// Hash password using MySQL 8+ method (SHA256)
+func scrambleSHA256Password(scramble []byte, password string) []byte {
+ if len(password) == 0 {
+ return nil
+ }
+
+ // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble))
+
+ crypt := sha256.New()
+ crypt.Write([]byte(password))
+ message1 := crypt.Sum(nil)
+
+ crypt.Reset()
+ crypt.Write(message1)
+ message1Hash := crypt.Sum(nil)
+
+ crypt.Reset()
+ crypt.Write(message1Hash)
+ crypt.Write(scramble)
+ message2 := crypt.Sum(nil)
+
+ for i := range message1 {
+ message1[i] ^= message2[i]
+ }
+
+ return message1
+}
+
+func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) {
+ plain := make([]byte, len(password)+1)
+ copy(plain, password)
+ for i := range plain {
+ j := i % len(seed)
+ plain[i] ^= seed[j]
+ }
+ sha1 := sha1.New()
+ return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil)
+}
+
+func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error {
+ enc, err := encryptPassword(mc.cfg.Passwd, seed, pub)
+ if err != nil {
+ return err
+ }
+ return mc.writeAuthSwitchPacket(enc)
+}
+
+func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
+ switch plugin {
+ case "caching_sha2_password":
+ authResp := scrambleSHA256Password(authData, mc.cfg.Passwd)
+ return authResp, nil
+
+ case "mysql_old_password":
+ if !mc.cfg.AllowOldPasswords {
+ return nil, ErrOldPassword
+ }
+ if len(mc.cfg.Passwd) == 0 {
+ return nil, nil
+ }
+ // Note: there are edge cases where this should work but doesn't;
+ // this is currently "wontfix":
+ // https://github.com/go-sql-driver/mysql/issues/184
+ authResp := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0)
+ return authResp, nil
+
+ case "mysql_clear_password":
+ if !mc.cfg.AllowCleartextPasswords {
+ return nil, ErrCleartextPassword
+ }
+ // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
+ // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
+ return append([]byte(mc.cfg.Passwd), 0), nil
+
+ case "mysql_native_password":
+ if !mc.cfg.AllowNativePasswords {
+ return nil, ErrNativePassword
+ }
+ // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
+ // Native password authentication only need and will need 20-byte challenge.
+ authResp := scramblePassword(authData[:20], mc.cfg.Passwd)
+ return authResp, nil
+
+ case "sha256_password":
+ if len(mc.cfg.Passwd) == 0 {
+ return []byte{0}, nil
+ }
+ if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
+ // write cleartext auth packet
+ return append([]byte(mc.cfg.Passwd), 0), nil
+ }
+
+ pubKey := mc.cfg.pubKey
+ if pubKey == nil {
+ // request public key from server
+ return []byte{1}, nil
+ }
+
+ // encrypted password
+ enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
+ return enc, err
+
+ default:
+ errLog.Print("unknown auth plugin:", plugin)
+ return nil, ErrUnknownPlugin
+ }
+}
+
+func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
+ // Read Result Packet
+ authData, newPlugin, err := mc.readAuthResult()
+ if err != nil {
+ return err
+ }
+
+ // handle auth plugin switch, if requested
+ if newPlugin != "" {
+ // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is
+ // sent and we have to keep using the cipher sent in the init packet.
+ if authData == nil {
+ authData = oldAuthData
+ } else {
+ // copy data from read buffer to owned slice
+ copy(oldAuthData, authData)
+ }
+
+ plugin = newPlugin
+
+ authResp, err := mc.auth(authData, plugin)
+ if err != nil {
+ return err
+ }
+ if err = mc.writeAuthSwitchPacket(authResp); err != nil {
+ return err
+ }
+
+ // Read Result Packet
+ authData, newPlugin, err = mc.readAuthResult()
+ if err != nil {
+ return err
+ }
+
+ // Do not allow to change the auth plugin more than once
+ if newPlugin != "" {
+ return ErrMalformPkt
+ }
+ }
+
+ switch plugin {
+
+ // https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/
+ case "caching_sha2_password":
+ switch len(authData) {
+ case 0:
+ return nil // auth successful
+ case 1:
+ switch authData[0] {
+ case cachingSha2PasswordFastAuthSuccess:
+ if err = mc.readResultOK(); err == nil {
+ return nil // auth successful
+ }
+
+ case cachingSha2PasswordPerformFullAuthentication:
+ if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
+ // write cleartext auth packet
+ err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0))
+ if err != nil {
+ return err
+ }
+ } else {
+ pubKey := mc.cfg.pubKey
+ if pubKey == nil {
+ // request public key from server
+ data, err := mc.buf.takeSmallBuffer(4 + 1)
+ if err != nil {
+ return err
+ }
+ data[4] = cachingSha2PasswordRequestPublicKey
+ mc.writePacket(data)
+
+ // parse public key
+ if data, err = mc.readPacket(); err != nil {
+ return err
+ }
+
+ block, rest := pem.Decode(data[1:])
+ if block == nil {
+ return fmt.Errorf("No Pem data found, data: %s", rest)
+ }
+ pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ return err
+ }
+ pubKey = pkix.(*rsa.PublicKey)
+ }
+
+ // send encrypted password
+ err = mc.sendEncryptedPassword(oldAuthData, pubKey)
+ if err != nil {
+ return err
+ }
+ }
+ return mc.readResultOK()
+
+ default:
+ return ErrMalformPkt
+ }
+ default:
+ return ErrMalformPkt
+ }
+
+ case "sha256_password":
+ switch len(authData) {
+ case 0:
+ return nil // auth successful
+ default:
+ block, _ := pem.Decode(authData)
+ pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ return err
+ }
+
+ // send encrypted password
+ err = mc.sendEncryptedPassword(oldAuthData, pub.(*rsa.PublicKey))
+ if err != nil {
+ return err
+ }
+ return mc.readResultOK()
+ }
+
+ default:
+ return nil // auth successful
+ }
+
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/buffer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/buffer.go
new file mode 100644
index 000000000000..0774c5c8c24b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/buffer.go
@@ -0,0 +1,182 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "io"
+ "net"
+ "time"
+)
+
+const defaultBufSize = 4096
+const maxCachedBufSize = 256 * 1024
+
+// A buffer which is used for both reading and writing.
+// This is possible since communication on each connection is synchronous.
+// In other words, we can't write and read simultaneously on the same connection.
+// The buffer is similar to bufio.Reader / Writer but zero-copy-ish
+// Also highly optimized for this particular use case.
+// This buffer is backed by two byte slices in a double-buffering scheme
+type buffer struct {
+ buf []byte // buf is a byte buffer who's length and capacity are equal.
+ nc net.Conn
+ idx int
+ length int
+ timeout time.Duration
+ dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer
+ flipcnt uint // flipccnt is the current buffer counter for double-buffering
+}
+
+// newBuffer allocates and returns a new buffer.
+func newBuffer(nc net.Conn) buffer {
+ fg := make([]byte, defaultBufSize)
+ return buffer{
+ buf: fg,
+ nc: nc,
+ dbuf: [2][]byte{fg, nil},
+ }
+}
+
+// flip replaces the active buffer with the background buffer
+// this is a delayed flip that simply increases the buffer counter;
+// the actual flip will be performed the next time we call `buffer.fill`
+func (b *buffer) flip() {
+ b.flipcnt += 1
+}
+
+// fill reads into the buffer until at least _need_ bytes are in it
+func (b *buffer) fill(need int) error {
+ n := b.length
+ // fill data into its double-buffering target: if we've called
+ // flip on this buffer, we'll be copying to the background buffer,
+ // and then filling it with network data; otherwise we'll just move
+ // the contents of the current buffer to the front before filling it
+ dest := b.dbuf[b.flipcnt&1]
+
+ // grow buffer if necessary to fit the whole packet.
+ if need > len(dest) {
+ // Round up to the next multiple of the default size
+ dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
+
+ // if the allocated buffer is not too large, move it to backing storage
+ // to prevent extra allocations on applications that perform large reads
+ if len(dest) <= maxCachedBufSize {
+ b.dbuf[b.flipcnt&1] = dest
+ }
+ }
+
+ // if we're filling the fg buffer, move the existing data to the start of it.
+ // if we're filling the bg buffer, copy over the data
+ if n > 0 {
+ copy(dest[:n], b.buf[b.idx:])
+ }
+
+ b.buf = dest
+ b.idx = 0
+
+ for {
+ if b.timeout > 0 {
+ if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
+ return err
+ }
+ }
+
+ nn, err := b.nc.Read(b.buf[n:])
+ n += nn
+
+ switch err {
+ case nil:
+ if n < need {
+ continue
+ }
+ b.length = n
+ return nil
+
+ case io.EOF:
+ if n >= need {
+ b.length = n
+ return nil
+ }
+ return io.ErrUnexpectedEOF
+
+ default:
+ return err
+ }
+ }
+}
+
+// returns next N bytes from buffer.
+// The returned slice is only guaranteed to be valid until the next read
+func (b *buffer) readNext(need int) ([]byte, error) {
+ if b.length < need {
+ // refill
+ if err := b.fill(need); err != nil {
+ return nil, err
+ }
+ }
+
+ offset := b.idx
+ b.idx += need
+ b.length -= need
+ return b.buf[offset:b.idx], nil
+}
+
+// takeBuffer returns a buffer with the requested size.
+// If possible, a slice from the existing buffer is returned.
+// Otherwise a bigger buffer is made.
+// Only one buffer (total) can be used at a time.
+func (b *buffer) takeBuffer(length int) ([]byte, error) {
+ if b.length > 0 {
+ return nil, ErrBusyBuffer
+ }
+
+ // test (cheap) general case first
+ if length <= cap(b.buf) {
+ return b.buf[:length], nil
+ }
+
+ if length < maxPacketSize {
+ b.buf = make([]byte, length)
+ return b.buf, nil
+ }
+
+ // buffer is larger than we want to store.
+ return make([]byte, length), nil
+}
+
+// takeSmallBuffer is shortcut which can be used if length is
+// known to be smaller than defaultBufSize.
+// Only one buffer (total) can be used at a time.
+func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
+ if b.length > 0 {
+ return nil, ErrBusyBuffer
+ }
+ return b.buf[:length], nil
+}
+
+// takeCompleteBuffer returns the complete existing buffer.
+// This can be used if the necessary buffer size is unknown.
+// cap and len of the returned buffer will be equal.
+// Only one buffer (total) can be used at a time.
+func (b *buffer) takeCompleteBuffer() ([]byte, error) {
+ if b.length > 0 {
+ return nil, ErrBusyBuffer
+ }
+ return b.buf, nil
+}
+
+// store stores buf, an updated buffer, if its suitable to do so.
+func (b *buffer) store(buf []byte) error {
+ if b.length > 0 {
+ return ErrBusyBuffer
+ } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
+ b.buf = buf[:cap(buf)]
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/collations.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/collations.go
new file mode 100644
index 000000000000..326a9f7fa8a2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/collations.go
@@ -0,0 +1,265 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+const defaultCollation = "utf8mb4_general_ci"
+const binaryCollation = "binary"
+
+// A list of available collations mapped to the internal ID.
+// To update this map use the following MySQL query:
+// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS WHERE ID<256 ORDER BY ID
+//
+// Handshake packet have only 1 byte for collation_id. So we can't use collations with ID > 255.
+//
+// ucs2, utf16, and utf32 can't be used for connection charset.
+// https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset
+// They are commented out to reduce this map.
+var collations = map[string]byte{
+ "big5_chinese_ci": 1,
+ "latin2_czech_cs": 2,
+ "dec8_swedish_ci": 3,
+ "cp850_general_ci": 4,
+ "latin1_german1_ci": 5,
+ "hp8_english_ci": 6,
+ "koi8r_general_ci": 7,
+ "latin1_swedish_ci": 8,
+ "latin2_general_ci": 9,
+ "swe7_swedish_ci": 10,
+ "ascii_general_ci": 11,
+ "ujis_japanese_ci": 12,
+ "sjis_japanese_ci": 13,
+ "cp1251_bulgarian_ci": 14,
+ "latin1_danish_ci": 15,
+ "hebrew_general_ci": 16,
+ "tis620_thai_ci": 18,
+ "euckr_korean_ci": 19,
+ "latin7_estonian_cs": 20,
+ "latin2_hungarian_ci": 21,
+ "koi8u_general_ci": 22,
+ "cp1251_ukrainian_ci": 23,
+ "gb2312_chinese_ci": 24,
+ "greek_general_ci": 25,
+ "cp1250_general_ci": 26,
+ "latin2_croatian_ci": 27,
+ "gbk_chinese_ci": 28,
+ "cp1257_lithuanian_ci": 29,
+ "latin5_turkish_ci": 30,
+ "latin1_german2_ci": 31,
+ "armscii8_general_ci": 32,
+ "utf8_general_ci": 33,
+ "cp1250_czech_cs": 34,
+ //"ucs2_general_ci": 35,
+ "cp866_general_ci": 36,
+ "keybcs2_general_ci": 37,
+ "macce_general_ci": 38,
+ "macroman_general_ci": 39,
+ "cp852_general_ci": 40,
+ "latin7_general_ci": 41,
+ "latin7_general_cs": 42,
+ "macce_bin": 43,
+ "cp1250_croatian_ci": 44,
+ "utf8mb4_general_ci": 45,
+ "utf8mb4_bin": 46,
+ "latin1_bin": 47,
+ "latin1_general_ci": 48,
+ "latin1_general_cs": 49,
+ "cp1251_bin": 50,
+ "cp1251_general_ci": 51,
+ "cp1251_general_cs": 52,
+ "macroman_bin": 53,
+ //"utf16_general_ci": 54,
+ //"utf16_bin": 55,
+ //"utf16le_general_ci": 56,
+ "cp1256_general_ci": 57,
+ "cp1257_bin": 58,
+ "cp1257_general_ci": 59,
+ //"utf32_general_ci": 60,
+ //"utf32_bin": 61,
+ //"utf16le_bin": 62,
+ "binary": 63,
+ "armscii8_bin": 64,
+ "ascii_bin": 65,
+ "cp1250_bin": 66,
+ "cp1256_bin": 67,
+ "cp866_bin": 68,
+ "dec8_bin": 69,
+ "greek_bin": 70,
+ "hebrew_bin": 71,
+ "hp8_bin": 72,
+ "keybcs2_bin": 73,
+ "koi8r_bin": 74,
+ "koi8u_bin": 75,
+ "utf8_tolower_ci": 76,
+ "latin2_bin": 77,
+ "latin5_bin": 78,
+ "latin7_bin": 79,
+ "cp850_bin": 80,
+ "cp852_bin": 81,
+ "swe7_bin": 82,
+ "utf8_bin": 83,
+ "big5_bin": 84,
+ "euckr_bin": 85,
+ "gb2312_bin": 86,
+ "gbk_bin": 87,
+ "sjis_bin": 88,
+ "tis620_bin": 89,
+ //"ucs2_bin": 90,
+ "ujis_bin": 91,
+ "geostd8_general_ci": 92,
+ "geostd8_bin": 93,
+ "latin1_spanish_ci": 94,
+ "cp932_japanese_ci": 95,
+ "cp932_bin": 96,
+ "eucjpms_japanese_ci": 97,
+ "eucjpms_bin": 98,
+ "cp1250_polish_ci": 99,
+ //"utf16_unicode_ci": 101,
+ //"utf16_icelandic_ci": 102,
+ //"utf16_latvian_ci": 103,
+ //"utf16_romanian_ci": 104,
+ //"utf16_slovenian_ci": 105,
+ //"utf16_polish_ci": 106,
+ //"utf16_estonian_ci": 107,
+ //"utf16_spanish_ci": 108,
+ //"utf16_swedish_ci": 109,
+ //"utf16_turkish_ci": 110,
+ //"utf16_czech_ci": 111,
+ //"utf16_danish_ci": 112,
+ //"utf16_lithuanian_ci": 113,
+ //"utf16_slovak_ci": 114,
+ //"utf16_spanish2_ci": 115,
+ //"utf16_roman_ci": 116,
+ //"utf16_persian_ci": 117,
+ //"utf16_esperanto_ci": 118,
+ //"utf16_hungarian_ci": 119,
+ //"utf16_sinhala_ci": 120,
+ //"utf16_german2_ci": 121,
+ //"utf16_croatian_ci": 122,
+ //"utf16_unicode_520_ci": 123,
+ //"utf16_vietnamese_ci": 124,
+ //"ucs2_unicode_ci": 128,
+ //"ucs2_icelandic_ci": 129,
+ //"ucs2_latvian_ci": 130,
+ //"ucs2_romanian_ci": 131,
+ //"ucs2_slovenian_ci": 132,
+ //"ucs2_polish_ci": 133,
+ //"ucs2_estonian_ci": 134,
+ //"ucs2_spanish_ci": 135,
+ //"ucs2_swedish_ci": 136,
+ //"ucs2_turkish_ci": 137,
+ //"ucs2_czech_ci": 138,
+ //"ucs2_danish_ci": 139,
+ //"ucs2_lithuanian_ci": 140,
+ //"ucs2_slovak_ci": 141,
+ //"ucs2_spanish2_ci": 142,
+ //"ucs2_roman_ci": 143,
+ //"ucs2_persian_ci": 144,
+ //"ucs2_esperanto_ci": 145,
+ //"ucs2_hungarian_ci": 146,
+ //"ucs2_sinhala_ci": 147,
+ //"ucs2_german2_ci": 148,
+ //"ucs2_croatian_ci": 149,
+ //"ucs2_unicode_520_ci": 150,
+ //"ucs2_vietnamese_ci": 151,
+ //"ucs2_general_mysql500_ci": 159,
+ //"utf32_unicode_ci": 160,
+ //"utf32_icelandic_ci": 161,
+ //"utf32_latvian_ci": 162,
+ //"utf32_romanian_ci": 163,
+ //"utf32_slovenian_ci": 164,
+ //"utf32_polish_ci": 165,
+ //"utf32_estonian_ci": 166,
+ //"utf32_spanish_ci": 167,
+ //"utf32_swedish_ci": 168,
+ //"utf32_turkish_ci": 169,
+ //"utf32_czech_ci": 170,
+ //"utf32_danish_ci": 171,
+ //"utf32_lithuanian_ci": 172,
+ //"utf32_slovak_ci": 173,
+ //"utf32_spanish2_ci": 174,
+ //"utf32_roman_ci": 175,
+ //"utf32_persian_ci": 176,
+ //"utf32_esperanto_ci": 177,
+ //"utf32_hungarian_ci": 178,
+ //"utf32_sinhala_ci": 179,
+ //"utf32_german2_ci": 180,
+ //"utf32_croatian_ci": 181,
+ //"utf32_unicode_520_ci": 182,
+ //"utf32_vietnamese_ci": 183,
+ "utf8_unicode_ci": 192,
+ "utf8_icelandic_ci": 193,
+ "utf8_latvian_ci": 194,
+ "utf8_romanian_ci": 195,
+ "utf8_slovenian_ci": 196,
+ "utf8_polish_ci": 197,
+ "utf8_estonian_ci": 198,
+ "utf8_spanish_ci": 199,
+ "utf8_swedish_ci": 200,
+ "utf8_turkish_ci": 201,
+ "utf8_czech_ci": 202,
+ "utf8_danish_ci": 203,
+ "utf8_lithuanian_ci": 204,
+ "utf8_slovak_ci": 205,
+ "utf8_spanish2_ci": 206,
+ "utf8_roman_ci": 207,
+ "utf8_persian_ci": 208,
+ "utf8_esperanto_ci": 209,
+ "utf8_hungarian_ci": 210,
+ "utf8_sinhala_ci": 211,
+ "utf8_german2_ci": 212,
+ "utf8_croatian_ci": 213,
+ "utf8_unicode_520_ci": 214,
+ "utf8_vietnamese_ci": 215,
+ "utf8_general_mysql500_ci": 223,
+ "utf8mb4_unicode_ci": 224,
+ "utf8mb4_icelandic_ci": 225,
+ "utf8mb4_latvian_ci": 226,
+ "utf8mb4_romanian_ci": 227,
+ "utf8mb4_slovenian_ci": 228,
+ "utf8mb4_polish_ci": 229,
+ "utf8mb4_estonian_ci": 230,
+ "utf8mb4_spanish_ci": 231,
+ "utf8mb4_swedish_ci": 232,
+ "utf8mb4_turkish_ci": 233,
+ "utf8mb4_czech_ci": 234,
+ "utf8mb4_danish_ci": 235,
+ "utf8mb4_lithuanian_ci": 236,
+ "utf8mb4_slovak_ci": 237,
+ "utf8mb4_spanish2_ci": 238,
+ "utf8mb4_roman_ci": 239,
+ "utf8mb4_persian_ci": 240,
+ "utf8mb4_esperanto_ci": 241,
+ "utf8mb4_hungarian_ci": 242,
+ "utf8mb4_sinhala_ci": 243,
+ "utf8mb4_german2_ci": 244,
+ "utf8mb4_croatian_ci": 245,
+ "utf8mb4_unicode_520_ci": 246,
+ "utf8mb4_vietnamese_ci": 247,
+ "gb18030_chinese_ci": 248,
+ "gb18030_bin": 249,
+ "gb18030_unicode_520_ci": 250,
+ "utf8mb4_0900_ai_ci": 255,
+}
+
+// A denylist of collations which is unsafe to interpolate parameters.
+// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes.
+var unsafeCollations = map[string]bool{
+ "big5_chinese_ci": true,
+ "sjis_japanese_ci": true,
+ "gbk_chinese_ci": true,
+ "big5_bin": true,
+ "gb2312_bin": true,
+ "gbk_bin": true,
+ "sjis_bin": true,
+ "cp932_japanese_ci": true,
+ "cp932_bin": true,
+ "gb18030_chinese_ci": true,
+ "gb18030_bin": true,
+ "gb18030_unicode_520_ci": true,
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/conncheck.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/conncheck.go
new file mode 100644
index 000000000000..024eb28589ed
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/conncheck.go
@@ -0,0 +1,54 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos
+
+package mysql
+
+import (
+ "errors"
+ "io"
+ "net"
+ "syscall"
+)
+
+var errUnexpectedRead = errors.New("unexpected read from socket")
+
+func connCheck(conn net.Conn) error {
+ var sysErr error
+
+ sysConn, ok := conn.(syscall.Conn)
+ if !ok {
+ return nil
+ }
+ rawConn, err := sysConn.SyscallConn()
+ if err != nil {
+ return err
+ }
+
+ err = rawConn.Read(func(fd uintptr) bool {
+ var buf [1]byte
+ n, err := syscall.Read(int(fd), buf[:])
+ switch {
+ case n == 0 && err == nil:
+ sysErr = io.EOF
+ case n > 0:
+ sysErr = errUnexpectedRead
+ case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK:
+ sysErr = nil
+ default:
+ sysErr = err
+ }
+ return true
+ })
+ if err != nil {
+ return err
+ }
+
+ return sysErr
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go
new file mode 100644
index 000000000000..ea7fb607ac42
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go
@@ -0,0 +1,17 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos
+
+package mysql
+
+import "net"
+
+func connCheck(conn net.Conn) error {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/connection.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/connection.go
new file mode 100644
index 000000000000..835f89729ad3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/connection.go
@@ -0,0 +1,650 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "context"
+ "database/sql"
+ "database/sql/driver"
+ "encoding/json"
+ "io"
+ "net"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type mysqlConn struct {
+ buf buffer
+ netConn net.Conn
+ rawConn net.Conn // underlying connection when netConn is TLS connection.
+ affectedRows uint64
+ insertId uint64
+ cfg *Config
+ maxAllowedPacket int
+ maxWriteSize int
+ writeTimeout time.Duration
+ flags clientFlag
+ status statusFlag
+ sequence uint8
+ parseTime bool
+ reset bool // set when the Go SQL package calls ResetSession
+
+ // for context support (Go 1.8+)
+ watching bool
+ watcher chan<- context.Context
+ closech chan struct{}
+ finished chan<- struct{}
+ canceled atomicError // set non-nil if conn is canceled
+ closed atomicBool // set when conn is closed, before closech is closed
+}
+
+// Handles parameters set in DSN after the connection is established
+func (mc *mysqlConn) handleParams() (err error) {
+ var cmdSet strings.Builder
+ for param, val := range mc.cfg.Params {
+ switch param {
+ // Charset: character_set_connection, character_set_client, character_set_results
+ case "charset":
+ charsets := strings.Split(val, ",")
+ for i := range charsets {
+ // ignore errors here - a charset may not exist
+ err = mc.exec("SET NAMES " + charsets[i])
+ if err == nil {
+ break
+ }
+ }
+ if err != nil {
+ return
+ }
+
+ // Other system vars accumulated in a single SET command
+ default:
+ if cmdSet.Len() == 0 {
+ // Heuristic: 29 chars for each other key=value to reduce reallocations
+ cmdSet.Grow(4 + len(param) + 1 + len(val) + 30*(len(mc.cfg.Params)-1))
+ cmdSet.WriteString("SET ")
+ } else {
+ cmdSet.WriteByte(',')
+ }
+ cmdSet.WriteString(param)
+ cmdSet.WriteByte('=')
+ cmdSet.WriteString(val)
+ }
+ }
+
+ if cmdSet.Len() > 0 {
+ err = mc.exec(cmdSet.String())
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+func (mc *mysqlConn) markBadConn(err error) error {
+ if mc == nil {
+ return err
+ }
+ if err != errBadConnNoWrite {
+ return err
+ }
+ return driver.ErrBadConn
+}
+
+func (mc *mysqlConn) Begin() (driver.Tx, error) {
+ return mc.begin(false)
+}
+
+func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
+ if mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return nil, driver.ErrBadConn
+ }
+ var q string
+ if readOnly {
+ q = "START TRANSACTION READ ONLY"
+ } else {
+ q = "START TRANSACTION"
+ }
+ err := mc.exec(q)
+ if err == nil {
+ return &mysqlTx{mc}, err
+ }
+ return nil, mc.markBadConn(err)
+}
+
+func (mc *mysqlConn) Close() (err error) {
+ // Makes Close idempotent
+ if !mc.closed.IsSet() {
+ err = mc.writeCommandPacket(comQuit)
+ }
+
+ mc.cleanup()
+
+ return
+}
+
+// Closes the network connection and unsets internal variables. Do not call this
+// function after successfully authentication, call Close instead. This function
+// is called before auth or on auth failure because MySQL will have already
+// closed the network connection.
+func (mc *mysqlConn) cleanup() {
+ if !mc.closed.TrySet(true) {
+ return
+ }
+
+ // Makes cleanup idempotent
+ close(mc.closech)
+ if mc.netConn == nil {
+ return
+ }
+ if err := mc.netConn.Close(); err != nil {
+ errLog.Print(err)
+ }
+}
+
+func (mc *mysqlConn) error() error {
+ if mc.closed.IsSet() {
+ if err := mc.canceled.Value(); err != nil {
+ return err
+ }
+ return ErrInvalidConn
+ }
+ return nil
+}
+
+func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
+ if mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return nil, driver.ErrBadConn
+ }
+ // Send command
+ err := mc.writeCommandPacketStr(comStmtPrepare, query)
+ if err != nil {
+ // STMT_PREPARE is safe to retry. So we can return ErrBadConn here.
+ errLog.Print(err)
+ return nil, driver.ErrBadConn
+ }
+
+ stmt := &mysqlStmt{
+ mc: mc,
+ }
+
+ // Read Result
+ columnCount, err := stmt.readPrepareResultPacket()
+ if err == nil {
+ if stmt.paramCount > 0 {
+ if err = mc.readUntilEOF(); err != nil {
+ return nil, err
+ }
+ }
+
+ if columnCount > 0 {
+ err = mc.readUntilEOF()
+ }
+ }
+
+ return stmt, err
+}
+
+func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {
+ // Number of ? should be same to len(args)
+ if strings.Count(query, "?") != len(args) {
+ return "", driver.ErrSkip
+ }
+
+ buf, err := mc.buf.takeCompleteBuffer()
+ if err != nil {
+ // can not take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return "", ErrInvalidConn
+ }
+ buf = buf[:0]
+ argPos := 0
+
+ for i := 0; i < len(query); i++ {
+ q := strings.IndexByte(query[i:], '?')
+ if q == -1 {
+ buf = append(buf, query[i:]...)
+ break
+ }
+ buf = append(buf, query[i:i+q]...)
+ i += q
+
+ arg := args[argPos]
+ argPos++
+
+ if arg == nil {
+ buf = append(buf, "NULL"...)
+ continue
+ }
+
+ switch v := arg.(type) {
+ case int64:
+ buf = strconv.AppendInt(buf, v, 10)
+ case uint64:
+ // Handle uint64 explicitly because our custom ConvertValue emits unsigned values
+ buf = strconv.AppendUint(buf, v, 10)
+ case float64:
+ buf = strconv.AppendFloat(buf, v, 'g', -1, 64)
+ case bool:
+ if v {
+ buf = append(buf, '1')
+ } else {
+ buf = append(buf, '0')
+ }
+ case time.Time:
+ if v.IsZero() {
+ buf = append(buf, "'0000-00-00'"...)
+ } else {
+ buf = append(buf, '\'')
+ buf, err = appendDateTime(buf, v.In(mc.cfg.Loc))
+ if err != nil {
+ return "", err
+ }
+ buf = append(buf, '\'')
+ }
+ case json.RawMessage:
+ buf = append(buf, '\'')
+ if mc.status&statusNoBackslashEscapes == 0 {
+ buf = escapeBytesBackslash(buf, v)
+ } else {
+ buf = escapeBytesQuotes(buf, v)
+ }
+ buf = append(buf, '\'')
+ case []byte:
+ if v == nil {
+ buf = append(buf, "NULL"...)
+ } else {
+ buf = append(buf, "_binary'"...)
+ if mc.status&statusNoBackslashEscapes == 0 {
+ buf = escapeBytesBackslash(buf, v)
+ } else {
+ buf = escapeBytesQuotes(buf, v)
+ }
+ buf = append(buf, '\'')
+ }
+ case string:
+ buf = append(buf, '\'')
+ if mc.status&statusNoBackslashEscapes == 0 {
+ buf = escapeStringBackslash(buf, v)
+ } else {
+ buf = escapeStringQuotes(buf, v)
+ }
+ buf = append(buf, '\'')
+ default:
+ return "", driver.ErrSkip
+ }
+
+ if len(buf)+4 > mc.maxAllowedPacket {
+ return "", driver.ErrSkip
+ }
+ }
+ if argPos != len(args) {
+ return "", driver.ErrSkip
+ }
+ return string(buf), nil
+}
+
+func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+ if mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return nil, driver.ErrBadConn
+ }
+ if len(args) != 0 {
+ if !mc.cfg.InterpolateParams {
+ return nil, driver.ErrSkip
+ }
+ // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement
+ prepared, err := mc.interpolateParams(query, args)
+ if err != nil {
+ return nil, err
+ }
+ query = prepared
+ }
+ mc.affectedRows = 0
+ mc.insertId = 0
+
+ err := mc.exec(query)
+ if err == nil {
+ return &mysqlResult{
+ affectedRows: int64(mc.affectedRows),
+ insertId: int64(mc.insertId),
+ }, err
+ }
+ return nil, mc.markBadConn(err)
+}
+
+// Internal function to execute commands
+func (mc *mysqlConn) exec(query string) error {
+ // Send command
+ if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
+ return mc.markBadConn(err)
+ }
+
+ // Read Result
+ resLen, err := mc.readResultSetHeaderPacket()
+ if err != nil {
+ return err
+ }
+
+ if resLen > 0 {
+ // columns
+ if err := mc.readUntilEOF(); err != nil {
+ return err
+ }
+
+ // rows
+ if err := mc.readUntilEOF(); err != nil {
+ return err
+ }
+ }
+
+ return mc.discardResults()
+}
+
+func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
+ return mc.query(query, args)
+}
+
+func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
+ if mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return nil, driver.ErrBadConn
+ }
+ if len(args) != 0 {
+ if !mc.cfg.InterpolateParams {
+ return nil, driver.ErrSkip
+ }
+ // try client-side prepare to reduce roundtrip
+ prepared, err := mc.interpolateParams(query, args)
+ if err != nil {
+ return nil, err
+ }
+ query = prepared
+ }
+ // Send command
+ err := mc.writeCommandPacketStr(comQuery, query)
+ if err == nil {
+ // Read Result
+ var resLen int
+ resLen, err = mc.readResultSetHeaderPacket()
+ if err == nil {
+ rows := new(textRows)
+ rows.mc = mc
+
+ if resLen == 0 {
+ rows.rs.done = true
+
+ switch err := rows.NextResultSet(); err {
+ case nil, io.EOF:
+ return rows, nil
+ default:
+ return nil, err
+ }
+ }
+
+ // Columns
+ rows.rs.columns, err = mc.readColumns(resLen)
+ return rows, err
+ }
+ }
+ return nil, mc.markBadConn(err)
+}
+
+// Gets the value of the given MySQL System Variable
+// The returned byte slice is only valid until the next read
+func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
+ // Send command
+ if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
+ return nil, err
+ }
+
+ // Read Result
+ resLen, err := mc.readResultSetHeaderPacket()
+ if err == nil {
+ rows := new(textRows)
+ rows.mc = mc
+ rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
+
+ if resLen > 0 {
+ // Columns
+ if err := mc.readUntilEOF(); err != nil {
+ return nil, err
+ }
+ }
+
+ dest := make([]driver.Value, resLen)
+ if err = rows.readRow(dest); err == nil {
+ return dest[0].([]byte), mc.readUntilEOF()
+ }
+ }
+ return nil, err
+}
+
+// finish is called when the query has canceled.
+func (mc *mysqlConn) cancel(err error) {
+ mc.canceled.Set(err)
+ mc.cleanup()
+}
+
+// finish is called when the query has succeeded.
+func (mc *mysqlConn) finish() {
+ if !mc.watching || mc.finished == nil {
+ return
+ }
+ select {
+ case mc.finished <- struct{}{}:
+ mc.watching = false
+ case <-mc.closech:
+ }
+}
+
+// Ping implements driver.Pinger interface
+func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
+ if mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return driver.ErrBadConn
+ }
+
+ if err = mc.watchCancel(ctx); err != nil {
+ return
+ }
+ defer mc.finish()
+
+ if err = mc.writeCommandPacket(comPing); err != nil {
+ return mc.markBadConn(err)
+ }
+
+ return mc.readResultOK()
+}
+
+// BeginTx implements driver.ConnBeginTx interface
+func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
+ if mc.closed.IsSet() {
+ return nil, driver.ErrBadConn
+ }
+
+ if err := mc.watchCancel(ctx); err != nil {
+ return nil, err
+ }
+ defer mc.finish()
+
+ if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
+ level, err := mapIsolationLevel(opts.Isolation)
+ if err != nil {
+ return nil, err
+ }
+ err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return mc.begin(opts.ReadOnly)
+}
+
+func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
+ dargs, err := namedValueToValue(args)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := mc.watchCancel(ctx); err != nil {
+ return nil, err
+ }
+
+ rows, err := mc.query(query, dargs)
+ if err != nil {
+ mc.finish()
+ return nil, err
+ }
+ rows.finish = mc.finish
+ return rows, err
+}
+
+func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
+ dargs, err := namedValueToValue(args)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := mc.watchCancel(ctx); err != nil {
+ return nil, err
+ }
+ defer mc.finish()
+
+ return mc.Exec(query, dargs)
+}
+
+func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
+ if err := mc.watchCancel(ctx); err != nil {
+ return nil, err
+ }
+
+ stmt, err := mc.Prepare(query)
+ mc.finish()
+ if err != nil {
+ return nil, err
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ stmt.Close()
+ return nil, ctx.Err()
+ }
+ return stmt, nil
+}
+
+func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
+ dargs, err := namedValueToValue(args)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := stmt.mc.watchCancel(ctx); err != nil {
+ return nil, err
+ }
+
+ rows, err := stmt.query(dargs)
+ if err != nil {
+ stmt.mc.finish()
+ return nil, err
+ }
+ rows.finish = stmt.mc.finish
+ return rows, err
+}
+
+func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
+ dargs, err := namedValueToValue(args)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := stmt.mc.watchCancel(ctx); err != nil {
+ return nil, err
+ }
+ defer stmt.mc.finish()
+
+ return stmt.Exec(dargs)
+}
+
+func (mc *mysqlConn) watchCancel(ctx context.Context) error {
+ if mc.watching {
+ // Reach here if canceled,
+ // so the connection is already invalid
+ mc.cleanup()
+ return nil
+ }
+ // When ctx is already cancelled, don't watch it.
+ if err := ctx.Err(); err != nil {
+ return err
+ }
+ // When ctx is not cancellable, don't watch it.
+ if ctx.Done() == nil {
+ return nil
+ }
+ // When watcher is not alive, can't watch it.
+ if mc.watcher == nil {
+ return nil
+ }
+
+ mc.watching = true
+ mc.watcher <- ctx
+ return nil
+}
+
+func (mc *mysqlConn) startWatcher() {
+ watcher := make(chan context.Context, 1)
+ mc.watcher = watcher
+ finished := make(chan struct{})
+ mc.finished = finished
+ go func() {
+ for {
+ var ctx context.Context
+ select {
+ case ctx = <-watcher:
+ case <-mc.closech:
+ return
+ }
+
+ select {
+ case <-ctx.Done():
+ mc.cancel(ctx.Err())
+ case <-finished:
+ case <-mc.closech:
+ return
+ }
+ }
+ }()
+}
+
+func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
+ nv.Value, err = converter{}.ConvertValue(nv.Value)
+ return
+}
+
+// ResetSession implements driver.SessionResetter.
+// (From Go 1.10)
+func (mc *mysqlConn) ResetSession(ctx context.Context) error {
+ if mc.closed.IsSet() {
+ return driver.ErrBadConn
+ }
+ mc.reset = true
+ return nil
+}
+
+// IsValid implements driver.Validator interface
+// (From Go 1.15)
+func (mc *mysqlConn) IsValid() bool {
+ return !mc.closed.IsSet()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/connector.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/connector.go
new file mode 100644
index 000000000000..d567b4e4fc0f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/connector.go
@@ -0,0 +1,146 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "context"
+ "database/sql/driver"
+ "net"
+)
+
+type connector struct {
+ cfg *Config // immutable private copy.
+}
+
+// Connect implements driver.Connector interface.
+// Connect returns a connection to the database.
+func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
+ var err error
+
+ // New mysqlConn
+ mc := &mysqlConn{
+ maxAllowedPacket: maxPacketSize,
+ maxWriteSize: maxPacketSize - 1,
+ closech: make(chan struct{}),
+ cfg: c.cfg,
+ }
+ mc.parseTime = mc.cfg.ParseTime
+
+ // Connect to Server
+ dialsLock.RLock()
+ dial, ok := dials[mc.cfg.Net]
+ dialsLock.RUnlock()
+ if ok {
+ dctx := ctx
+ if mc.cfg.Timeout > 0 {
+ var cancel context.CancelFunc
+ dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout)
+ defer cancel()
+ }
+ mc.netConn, err = dial(dctx, mc.cfg.Addr)
+ } else {
+ nd := net.Dialer{Timeout: mc.cfg.Timeout}
+ mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ // Enable TCP Keepalives on TCP connections
+ if tc, ok := mc.netConn.(*net.TCPConn); ok {
+ if err := tc.SetKeepAlive(true); err != nil {
+ // Don't send COM_QUIT before handshake.
+ mc.netConn.Close()
+ mc.netConn = nil
+ return nil, err
+ }
+ }
+
+ // Call startWatcher for context support (From Go 1.8)
+ mc.startWatcher()
+ if err := mc.watchCancel(ctx); err != nil {
+ mc.cleanup()
+ return nil, err
+ }
+ defer mc.finish()
+
+ mc.buf = newBuffer(mc.netConn)
+
+ // Set I/O timeouts
+ mc.buf.timeout = mc.cfg.ReadTimeout
+ mc.writeTimeout = mc.cfg.WriteTimeout
+
+ // Reading Handshake Initialization Packet
+ authData, plugin, err := mc.readHandshakePacket()
+ if err != nil {
+ mc.cleanup()
+ return nil, err
+ }
+
+ if plugin == "" {
+ plugin = defaultAuthPlugin
+ }
+
+ // Send Client Authentication Packet
+ authResp, err := mc.auth(authData, plugin)
+ if err != nil {
+ // try the default auth plugin, if using the requested plugin failed
+ errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
+ plugin = defaultAuthPlugin
+ authResp, err = mc.auth(authData, plugin)
+ if err != nil {
+ mc.cleanup()
+ return nil, err
+ }
+ }
+ if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {
+ mc.cleanup()
+ return nil, err
+ }
+
+ // Handle response to auth packet, switch methods if possible
+ if err = mc.handleAuthResult(authData, plugin); err != nil {
+ // Authentication failed and MySQL has already closed the connection
+ // (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
+ // Do not send COM_QUIT, just cleanup and return the error.
+ mc.cleanup()
+ return nil, err
+ }
+
+ if mc.cfg.MaxAllowedPacket > 0 {
+ mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
+ } else {
+ // Get max allowed packet size
+ maxap, err := mc.getSystemVar("max_allowed_packet")
+ if err != nil {
+ mc.Close()
+ return nil, err
+ }
+ mc.maxAllowedPacket = stringToInt(maxap) - 1
+ }
+ if mc.maxAllowedPacket < maxPacketSize {
+ mc.maxWriteSize = mc.maxAllowedPacket
+ }
+
+ // Handle DSN Params
+ err = mc.handleParams()
+ if err != nil {
+ mc.Close()
+ return nil, err
+ }
+
+ return mc, nil
+}
+
+// Driver implements driver.Connector interface.
+// Driver returns &MySQLDriver{}.
+func (c *connector) Driver() driver.Driver {
+ return &MySQLDriver{}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/const.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/const.go
new file mode 100644
index 000000000000..b1e6b85efcae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/const.go
@@ -0,0 +1,174 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+const (
+ defaultAuthPlugin = "mysql_native_password"
+ defaultMaxAllowedPacket = 4 << 20 // 4 MiB
+ minProtocolVersion = 10
+ maxPacketSize = 1<<24 - 1
+ timeFormat = "2006-01-02 15:04:05.999999"
+)
+
+// MySQL constants documentation:
+// http://dev.mysql.com/doc/internals/en/client-server-protocol.html
+
+const (
+ iOK byte = 0x00
+ iAuthMoreData byte = 0x01
+ iLocalInFile byte = 0xfb
+ iEOF byte = 0xfe
+ iERR byte = 0xff
+)
+
+// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags
+type clientFlag uint32
+
+const (
+ clientLongPassword clientFlag = 1 << iota
+ clientFoundRows
+ clientLongFlag
+ clientConnectWithDB
+ clientNoSchema
+ clientCompress
+ clientODBC
+ clientLocalFiles
+ clientIgnoreSpace
+ clientProtocol41
+ clientInteractive
+ clientSSL
+ clientIgnoreSIGPIPE
+ clientTransactions
+ clientReserved
+ clientSecureConn
+ clientMultiStatements
+ clientMultiResults
+ clientPSMultiResults
+ clientPluginAuth
+ clientConnectAttrs
+ clientPluginAuthLenEncClientData
+ clientCanHandleExpiredPasswords
+ clientSessionTrack
+ clientDeprecateEOF
+)
+
+const (
+ comQuit byte = iota + 1
+ comInitDB
+ comQuery
+ comFieldList
+ comCreateDB
+ comDropDB
+ comRefresh
+ comShutdown
+ comStatistics
+ comProcessInfo
+ comConnect
+ comProcessKill
+ comDebug
+ comPing
+ comTime
+ comDelayedInsert
+ comChangeUser
+ comBinlogDump
+ comTableDump
+ comConnectOut
+ comRegisterSlave
+ comStmtPrepare
+ comStmtExecute
+ comStmtSendLongData
+ comStmtClose
+ comStmtReset
+ comSetOption
+ comStmtFetch
+)
+
+// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType
+type fieldType byte
+
+const (
+ fieldTypeDecimal fieldType = iota
+ fieldTypeTiny
+ fieldTypeShort
+ fieldTypeLong
+ fieldTypeFloat
+ fieldTypeDouble
+ fieldTypeNULL
+ fieldTypeTimestamp
+ fieldTypeLongLong
+ fieldTypeInt24
+ fieldTypeDate
+ fieldTypeTime
+ fieldTypeDateTime
+ fieldTypeYear
+ fieldTypeNewDate
+ fieldTypeVarChar
+ fieldTypeBit
+)
+const (
+ fieldTypeJSON fieldType = iota + 0xf5
+ fieldTypeNewDecimal
+ fieldTypeEnum
+ fieldTypeSet
+ fieldTypeTinyBLOB
+ fieldTypeMediumBLOB
+ fieldTypeLongBLOB
+ fieldTypeBLOB
+ fieldTypeVarString
+ fieldTypeString
+ fieldTypeGeometry
+)
+
+type fieldFlag uint16
+
+const (
+ flagNotNULL fieldFlag = 1 << iota
+ flagPriKey
+ flagUniqueKey
+ flagMultipleKey
+ flagBLOB
+ flagUnsigned
+ flagZeroFill
+ flagBinary
+ flagEnum
+ flagAutoIncrement
+ flagTimestamp
+ flagSet
+ flagUnknown1
+ flagUnknown2
+ flagUnknown3
+ flagUnknown4
+)
+
+// http://dev.mysql.com/doc/internals/en/status-flags.html
+type statusFlag uint16
+
+const (
+ statusInTrans statusFlag = 1 << iota
+ statusInAutocommit
+ statusReserved // Not in documentation
+ statusMoreResultsExists
+ statusNoGoodIndexUsed
+ statusNoIndexUsed
+ statusCursorExists
+ statusLastRowSent
+ statusDbDropped
+ statusNoBackslashEscapes
+ statusMetadataChanged
+ statusQueryWasSlow
+ statusPsOutParams
+ statusInTransReadonly
+ statusSessionStateChanged
+)
+
+const (
+ cachingSha2PasswordRequestPublicKey = 2
+ cachingSha2PasswordFastAuthSuccess = 3
+ cachingSha2PasswordPerformFullAuthentication = 4
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/driver.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/driver.go
new file mode 100644
index 000000000000..c1bdf1199b61
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/driver.go
@@ -0,0 +1,107 @@
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Package mysql provides a MySQL driver for Go's database/sql package.
+//
+// The driver should be used via the database/sql package:
+//
+// import "database/sql"
+// import _ "github.com/go-sql-driver/mysql"
+//
+// db, err := sql.Open("mysql", "user:password@/dbname")
+//
+// See https://github.com/go-sql-driver/mysql#usage for details
+package mysql
+
+import (
+ "context"
+ "database/sql"
+ "database/sql/driver"
+ "net"
+ "sync"
+)
+
+// MySQLDriver is exported to make the driver directly accessible.
+// In general the driver is used via the database/sql package.
+type MySQLDriver struct{}
+
+// DialFunc is a function which can be used to establish the network connection.
+// Custom dial functions must be registered with RegisterDial
+//
+// Deprecated: users should register a DialContextFunc instead
+type DialFunc func(addr string) (net.Conn, error)
+
+// DialContextFunc is a function which can be used to establish the network connection.
+// Custom dial functions must be registered with RegisterDialContext
+type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error)
+
+var (
+ dialsLock sync.RWMutex
+ dials map[string]DialContextFunc
+)
+
+// RegisterDialContext registers a custom dial function. It can then be used by the
+// network address mynet(addr), where mynet is the registered new network.
+// The current context for the connection and its address is passed to the dial function.
+func RegisterDialContext(net string, dial DialContextFunc) {
+ dialsLock.Lock()
+ defer dialsLock.Unlock()
+ if dials == nil {
+ dials = make(map[string]DialContextFunc)
+ }
+ dials[net] = dial
+}
+
+// RegisterDial registers a custom dial function. It can then be used by the
+// network address mynet(addr), where mynet is the registered new network.
+// addr is passed as a parameter to the dial function.
+//
+// Deprecated: users should call RegisterDialContext instead
+func RegisterDial(network string, dial DialFunc) {
+ RegisterDialContext(network, func(_ context.Context, addr string) (net.Conn, error) {
+ return dial(addr)
+ })
+}
+
+// Open new Connection.
+// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
+// the DSN string is formatted
+func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
+ cfg, err := ParseDSN(dsn)
+ if err != nil {
+ return nil, err
+ }
+ c := &connector{
+ cfg: cfg,
+ }
+ return c.Connect(context.Background())
+}
+
+func init() {
+ sql.Register("mysql", &MySQLDriver{})
+}
+
+// NewConnector returns new driver.Connector.
+func NewConnector(cfg *Config) (driver.Connector, error) {
+ cfg = cfg.Clone()
+ // normalize the contents of cfg so calls to NewConnector have the same
+ // behavior as MySQLDriver.OpenConnector
+ if err := cfg.normalize(); err != nil {
+ return nil, err
+ }
+ return &connector{cfg: cfg}, nil
+}
+
+// OpenConnector implements driver.DriverContext.
+func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) {
+ cfg, err := ParseDSN(dsn)
+ if err != nil {
+ return nil, err
+ }
+ return &connector{
+ cfg: cfg,
+ }, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/dsn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/dsn.go
new file mode 100644
index 000000000000..93f3548cb8c8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/dsn.go
@@ -0,0 +1,560 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "bytes"
+ "crypto/rsa"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "math/big"
+ "net"
+ "net/url"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var (
+ errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?")
+ errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)")
+ errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name")
+ errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations")
+)
+
+// Config is a configuration parsed from a DSN string.
+// If a new Config is created instead of being parsed from a DSN string,
+// the NewConfig function should be used, which sets default values.
+type Config struct {
+ User string // Username
+ Passwd string // Password (requires User)
+ Net string // Network type
+ Addr string // Network address (requires Net)
+ DBName string // Database name
+ Params map[string]string // Connection parameters
+ Collation string // Connection collation
+ Loc *time.Location // Location for time.Time values
+ MaxAllowedPacket int // Max packet size allowed
+ ServerPubKey string // Server public key name
+ pubKey *rsa.PublicKey // Server public key
+ TLSConfig string // TLS configuration name
+ tls *tls.Config // TLS configuration
+ Timeout time.Duration // Dial timeout
+ ReadTimeout time.Duration // I/O read timeout
+ WriteTimeout time.Duration // I/O write timeout
+
+ AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
+ AllowCleartextPasswords bool // Allows the cleartext client side plugin
+ AllowNativePasswords bool // Allows the native password authentication method
+ AllowOldPasswords bool // Allows the old insecure password method
+ CheckConnLiveness bool // Check connections for liveness before using them
+ ClientFoundRows bool // Return number of matching rows instead of rows changed
+ ColumnsWithAlias bool // Prepend table alias to column names
+ InterpolateParams bool // Interpolate placeholders into query string
+ MultiStatements bool // Allow multiple statements in one query
+ ParseTime bool // Parse time values to time.Time
+ RejectReadOnly bool // Reject read-only connections
+}
+
+// NewConfig creates a new Config and sets default values.
+func NewConfig() *Config {
+ return &Config{
+ Collation: defaultCollation,
+ Loc: time.UTC,
+ MaxAllowedPacket: defaultMaxAllowedPacket,
+ AllowNativePasswords: true,
+ CheckConnLiveness: true,
+ }
+}
+
+func (cfg *Config) Clone() *Config {
+ cp := *cfg
+ if cp.tls != nil {
+ cp.tls = cfg.tls.Clone()
+ }
+ if len(cp.Params) > 0 {
+ cp.Params = make(map[string]string, len(cfg.Params))
+ for k, v := range cfg.Params {
+ cp.Params[k] = v
+ }
+ }
+ if cfg.pubKey != nil {
+ cp.pubKey = &rsa.PublicKey{
+ N: new(big.Int).Set(cfg.pubKey.N),
+ E: cfg.pubKey.E,
+ }
+ }
+ return &cp
+}
+
+func (cfg *Config) normalize() error {
+ if cfg.InterpolateParams && unsafeCollations[cfg.Collation] {
+ return errInvalidDSNUnsafeCollation
+ }
+
+ // Set default network if empty
+ if cfg.Net == "" {
+ cfg.Net = "tcp"
+ }
+
+ // Set default address if empty
+ if cfg.Addr == "" {
+ switch cfg.Net {
+ case "tcp":
+ cfg.Addr = "127.0.0.1:3306"
+ case "unix":
+ cfg.Addr = "/tmp/mysql.sock"
+ default:
+ return errors.New("default addr for network '" + cfg.Net + "' unknown")
+ }
+ } else if cfg.Net == "tcp" {
+ cfg.Addr = ensureHavePort(cfg.Addr)
+ }
+
+ switch cfg.TLSConfig {
+ case "false", "":
+ // don't set anything
+ case "true":
+ cfg.tls = &tls.Config{}
+ case "skip-verify", "preferred":
+ cfg.tls = &tls.Config{InsecureSkipVerify: true}
+ default:
+ cfg.tls = getTLSConfigClone(cfg.TLSConfig)
+ if cfg.tls == nil {
+ return errors.New("invalid value / unknown config name: " + cfg.TLSConfig)
+ }
+ }
+
+ if cfg.tls != nil && cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify {
+ host, _, err := net.SplitHostPort(cfg.Addr)
+ if err == nil {
+ cfg.tls.ServerName = host
+ }
+ }
+
+ if cfg.ServerPubKey != "" {
+ cfg.pubKey = getServerPubKey(cfg.ServerPubKey)
+ if cfg.pubKey == nil {
+ return errors.New("invalid value / unknown server pub key name: " + cfg.ServerPubKey)
+ }
+ }
+
+ return nil
+}
+
+func writeDSNParam(buf *bytes.Buffer, hasParam *bool, name, value string) {
+ buf.Grow(1 + len(name) + 1 + len(value))
+ if !*hasParam {
+ *hasParam = true
+ buf.WriteByte('?')
+ } else {
+ buf.WriteByte('&')
+ }
+ buf.WriteString(name)
+ buf.WriteByte('=')
+ buf.WriteString(value)
+}
+
+// FormatDSN formats the given Config into a DSN string which can be passed to
+// the driver.
+func (cfg *Config) FormatDSN() string {
+ var buf bytes.Buffer
+
+ // [username[:password]@]
+ if len(cfg.User) > 0 {
+ buf.WriteString(cfg.User)
+ if len(cfg.Passwd) > 0 {
+ buf.WriteByte(':')
+ buf.WriteString(cfg.Passwd)
+ }
+ buf.WriteByte('@')
+ }
+
+ // [protocol[(address)]]
+ if len(cfg.Net) > 0 {
+ buf.WriteString(cfg.Net)
+ if len(cfg.Addr) > 0 {
+ buf.WriteByte('(')
+ buf.WriteString(cfg.Addr)
+ buf.WriteByte(')')
+ }
+ }
+
+ // /dbname
+ buf.WriteByte('/')
+ buf.WriteString(cfg.DBName)
+
+ // [?param1=value1&...¶mN=valueN]
+ hasParam := false
+
+ if cfg.AllowAllFiles {
+ hasParam = true
+ buf.WriteString("?allowAllFiles=true")
+ }
+
+ if cfg.AllowCleartextPasswords {
+ writeDSNParam(&buf, &hasParam, "allowCleartextPasswords", "true")
+ }
+
+ if !cfg.AllowNativePasswords {
+ writeDSNParam(&buf, &hasParam, "allowNativePasswords", "false")
+ }
+
+ if cfg.AllowOldPasswords {
+ writeDSNParam(&buf, &hasParam, "allowOldPasswords", "true")
+ }
+
+ if !cfg.CheckConnLiveness {
+ writeDSNParam(&buf, &hasParam, "checkConnLiveness", "false")
+ }
+
+ if cfg.ClientFoundRows {
+ writeDSNParam(&buf, &hasParam, "clientFoundRows", "true")
+ }
+
+ if col := cfg.Collation; col != defaultCollation && len(col) > 0 {
+ writeDSNParam(&buf, &hasParam, "collation", col)
+ }
+
+ if cfg.ColumnsWithAlias {
+ writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true")
+ }
+
+ if cfg.InterpolateParams {
+ writeDSNParam(&buf, &hasParam, "interpolateParams", "true")
+ }
+
+ if cfg.Loc != time.UTC && cfg.Loc != nil {
+ writeDSNParam(&buf, &hasParam, "loc", url.QueryEscape(cfg.Loc.String()))
+ }
+
+ if cfg.MultiStatements {
+ writeDSNParam(&buf, &hasParam, "multiStatements", "true")
+ }
+
+ if cfg.ParseTime {
+ writeDSNParam(&buf, &hasParam, "parseTime", "true")
+ }
+
+ if cfg.ReadTimeout > 0 {
+ writeDSNParam(&buf, &hasParam, "readTimeout", cfg.ReadTimeout.String())
+ }
+
+ if cfg.RejectReadOnly {
+ writeDSNParam(&buf, &hasParam, "rejectReadOnly", "true")
+ }
+
+ if len(cfg.ServerPubKey) > 0 {
+ writeDSNParam(&buf, &hasParam, "serverPubKey", url.QueryEscape(cfg.ServerPubKey))
+ }
+
+ if cfg.Timeout > 0 {
+ writeDSNParam(&buf, &hasParam, "timeout", cfg.Timeout.String())
+ }
+
+ if len(cfg.TLSConfig) > 0 {
+ writeDSNParam(&buf, &hasParam, "tls", url.QueryEscape(cfg.TLSConfig))
+ }
+
+ if cfg.WriteTimeout > 0 {
+ writeDSNParam(&buf, &hasParam, "writeTimeout", cfg.WriteTimeout.String())
+ }
+
+ if cfg.MaxAllowedPacket != defaultMaxAllowedPacket {
+ writeDSNParam(&buf, &hasParam, "maxAllowedPacket", strconv.Itoa(cfg.MaxAllowedPacket))
+ }
+
+ // other params
+ if cfg.Params != nil {
+ var params []string
+ for param := range cfg.Params {
+ params = append(params, param)
+ }
+ sort.Strings(params)
+ for _, param := range params {
+ writeDSNParam(&buf, &hasParam, param, url.QueryEscape(cfg.Params[param]))
+ }
+ }
+
+ return buf.String()
+}
+
+// ParseDSN parses the DSN string to a Config
+func ParseDSN(dsn string) (cfg *Config, err error) {
+ // New config with some default values
+ cfg = NewConfig()
+
+ // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN]
+ // Find the last '/' (since the password or the net addr might contain a '/')
+ foundSlash := false
+ for i := len(dsn) - 1; i >= 0; i-- {
+ if dsn[i] == '/' {
+ foundSlash = true
+ var j, k int
+
+ // left part is empty if i <= 0
+ if i > 0 {
+ // [username[:password]@][protocol[(address)]]
+ // Find the last '@' in dsn[:i]
+ for j = i; j >= 0; j-- {
+ if dsn[j] == '@' {
+ // username[:password]
+ // Find the first ':' in dsn[:j]
+ for k = 0; k < j; k++ {
+ if dsn[k] == ':' {
+ cfg.Passwd = dsn[k+1 : j]
+ break
+ }
+ }
+ cfg.User = dsn[:k]
+
+ break
+ }
+ }
+
+ // [protocol[(address)]]
+ // Find the first '(' in dsn[j+1:i]
+ for k = j + 1; k < i; k++ {
+ if dsn[k] == '(' {
+ // dsn[i-1] must be == ')' if an address is specified
+ if dsn[i-1] != ')' {
+ if strings.ContainsRune(dsn[k+1:i], ')') {
+ return nil, errInvalidDSNUnescaped
+ }
+ return nil, errInvalidDSNAddr
+ }
+ cfg.Addr = dsn[k+1 : i-1]
+ break
+ }
+ }
+ cfg.Net = dsn[j+1 : k]
+ }
+
+ // dbname[?param1=value1&...¶mN=valueN]
+ // Find the first '?' in dsn[i+1:]
+ for j = i + 1; j < len(dsn); j++ {
+ if dsn[j] == '?' {
+ if err = parseDSNParams(cfg, dsn[j+1:]); err != nil {
+ return
+ }
+ break
+ }
+ }
+ cfg.DBName = dsn[i+1 : j]
+
+ break
+ }
+ }
+
+ if !foundSlash && len(dsn) > 0 {
+ return nil, errInvalidDSNNoSlash
+ }
+
+ if err = cfg.normalize(); err != nil {
+ return nil, err
+ }
+ return
+}
+
+// parseDSNParams parses the DSN "query string"
+// Values must be url.QueryEscape'ed
+func parseDSNParams(cfg *Config, params string) (err error) {
+ for _, v := range strings.Split(params, "&") {
+ param := strings.SplitN(v, "=", 2)
+ if len(param) != 2 {
+ continue
+ }
+
+ // cfg params
+ switch value := param[1]; param[0] {
+ // Disable INFILE allowlist / enable all files
+ case "allowAllFiles":
+ var isBool bool
+ cfg.AllowAllFiles, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Use cleartext authentication mode (MySQL 5.5.10+)
+ case "allowCleartextPasswords":
+ var isBool bool
+ cfg.AllowCleartextPasswords, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Use native password authentication
+ case "allowNativePasswords":
+ var isBool bool
+ cfg.AllowNativePasswords, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Use old authentication mode (pre MySQL 4.1)
+ case "allowOldPasswords":
+ var isBool bool
+ cfg.AllowOldPasswords, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Check connections for Liveness before using them
+ case "checkConnLiveness":
+ var isBool bool
+ cfg.CheckConnLiveness, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Switch "rowsAffected" mode
+ case "clientFoundRows":
+ var isBool bool
+ cfg.ClientFoundRows, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Collation
+ case "collation":
+ cfg.Collation = value
+ break
+
+ case "columnsWithAlias":
+ var isBool bool
+ cfg.ColumnsWithAlias, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Compression
+ case "compress":
+ return errors.New("compression not implemented yet")
+
+ // Enable client side placeholder substitution
+ case "interpolateParams":
+ var isBool bool
+ cfg.InterpolateParams, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Time Location
+ case "loc":
+ if value, err = url.QueryUnescape(value); err != nil {
+ return
+ }
+ cfg.Loc, err = time.LoadLocation(value)
+ if err != nil {
+ return
+ }
+
+ // multiple statements in one query
+ case "multiStatements":
+ var isBool bool
+ cfg.MultiStatements, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // time.Time parsing
+ case "parseTime":
+ var isBool bool
+ cfg.ParseTime, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // I/O read Timeout
+ case "readTimeout":
+ cfg.ReadTimeout, err = time.ParseDuration(value)
+ if err != nil {
+ return
+ }
+
+ // Reject read-only connections
+ case "rejectReadOnly":
+ var isBool bool
+ cfg.RejectReadOnly, isBool = readBool(value)
+ if !isBool {
+ return errors.New("invalid bool value: " + value)
+ }
+
+ // Server public key
+ case "serverPubKey":
+ name, err := url.QueryUnescape(value)
+ if err != nil {
+ return fmt.Errorf("invalid value for server pub key name: %v", err)
+ }
+ cfg.ServerPubKey = name
+
+ // Strict mode
+ case "strict":
+ panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode")
+
+ // Dial Timeout
+ case "timeout":
+ cfg.Timeout, err = time.ParseDuration(value)
+ if err != nil {
+ return
+ }
+
+ // TLS-Encryption
+ case "tls":
+ boolValue, isBool := readBool(value)
+ if isBool {
+ if boolValue {
+ cfg.TLSConfig = "true"
+ } else {
+ cfg.TLSConfig = "false"
+ }
+ } else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" {
+ cfg.TLSConfig = vl
+ } else {
+ name, err := url.QueryUnescape(value)
+ if err != nil {
+ return fmt.Errorf("invalid value for TLS config name: %v", err)
+ }
+ cfg.TLSConfig = name
+ }
+
+ // I/O write Timeout
+ case "writeTimeout":
+ cfg.WriteTimeout, err = time.ParseDuration(value)
+ if err != nil {
+ return
+ }
+ case "maxAllowedPacket":
+ cfg.MaxAllowedPacket, err = strconv.Atoi(value)
+ if err != nil {
+ return
+ }
+ default:
+ // lazy init
+ if cfg.Params == nil {
+ cfg.Params = make(map[string]string)
+ }
+
+ if cfg.Params[param[0]], err = url.QueryUnescape(value); err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
+
+func ensureHavePort(addr string) string {
+ if _, _, err := net.SplitHostPort(addr); err != nil {
+ return net.JoinHostPort(addr, "3306")
+ }
+ return addr
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/errors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/errors.go
new file mode 100644
index 000000000000..760782ff2fb5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/errors.go
@@ -0,0 +1,65 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "os"
+)
+
+// Various errors the driver might return. Can change between driver versions.
+var (
+ ErrInvalidConn = errors.New("invalid connection")
+ ErrMalformPkt = errors.New("malformed packet")
+ ErrNoTLS = errors.New("TLS requested but server does not support TLS")
+ ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN")
+ ErrNativePassword = errors.New("this user requires mysql native password authentication.")
+ ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
+ ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
+ ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
+ ErrPktSync = errors.New("commands out of sync. You can't run this command now")
+ ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
+ ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
+ ErrBusyBuffer = errors.New("busy buffer")
+
+ // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
+ // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn
+ // to trigger a resend.
+ // See https://github.com/go-sql-driver/mysql/pull/302
+ errBadConnNoWrite = errors.New("bad connection")
+)
+
+var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile))
+
+// Logger is used to log critical error messages.
+type Logger interface {
+ Print(v ...interface{})
+}
+
+// SetLogger is used to set the logger for critical errors.
+// The initial logger is os.Stderr.
+func SetLogger(logger Logger) error {
+ if logger == nil {
+ return errors.New("logger is nil")
+ }
+ errLog = logger
+ return nil
+}
+
+// MySQLError is an error type which represents a single MySQL error
+type MySQLError struct {
+ Number uint16
+ Message string
+}
+
+func (me *MySQLError) Error() string {
+ return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/fields.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/fields.go
new file mode 100644
index 000000000000..ed6c7a37d83e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/fields.go
@@ -0,0 +1,194 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "database/sql"
+ "reflect"
+)
+
+func (mf *mysqlField) typeDatabaseName() string {
+ switch mf.fieldType {
+ case fieldTypeBit:
+ return "BIT"
+ case fieldTypeBLOB:
+ if mf.charSet != collations[binaryCollation] {
+ return "TEXT"
+ }
+ return "BLOB"
+ case fieldTypeDate:
+ return "DATE"
+ case fieldTypeDateTime:
+ return "DATETIME"
+ case fieldTypeDecimal:
+ return "DECIMAL"
+ case fieldTypeDouble:
+ return "DOUBLE"
+ case fieldTypeEnum:
+ return "ENUM"
+ case fieldTypeFloat:
+ return "FLOAT"
+ case fieldTypeGeometry:
+ return "GEOMETRY"
+ case fieldTypeInt24:
+ return "MEDIUMINT"
+ case fieldTypeJSON:
+ return "JSON"
+ case fieldTypeLong:
+ return "INT"
+ case fieldTypeLongBLOB:
+ if mf.charSet != collations[binaryCollation] {
+ return "LONGTEXT"
+ }
+ return "LONGBLOB"
+ case fieldTypeLongLong:
+ return "BIGINT"
+ case fieldTypeMediumBLOB:
+ if mf.charSet != collations[binaryCollation] {
+ return "MEDIUMTEXT"
+ }
+ return "MEDIUMBLOB"
+ case fieldTypeNewDate:
+ return "DATE"
+ case fieldTypeNewDecimal:
+ return "DECIMAL"
+ case fieldTypeNULL:
+ return "NULL"
+ case fieldTypeSet:
+ return "SET"
+ case fieldTypeShort:
+ return "SMALLINT"
+ case fieldTypeString:
+ if mf.charSet == collations[binaryCollation] {
+ return "BINARY"
+ }
+ return "CHAR"
+ case fieldTypeTime:
+ return "TIME"
+ case fieldTypeTimestamp:
+ return "TIMESTAMP"
+ case fieldTypeTiny:
+ return "TINYINT"
+ case fieldTypeTinyBLOB:
+ if mf.charSet != collations[binaryCollation] {
+ return "TINYTEXT"
+ }
+ return "TINYBLOB"
+ case fieldTypeVarChar:
+ if mf.charSet == collations[binaryCollation] {
+ return "VARBINARY"
+ }
+ return "VARCHAR"
+ case fieldTypeVarString:
+ if mf.charSet == collations[binaryCollation] {
+ return "VARBINARY"
+ }
+ return "VARCHAR"
+ case fieldTypeYear:
+ return "YEAR"
+ default:
+ return ""
+ }
+}
+
+var (
+ scanTypeFloat32 = reflect.TypeOf(float32(0))
+ scanTypeFloat64 = reflect.TypeOf(float64(0))
+ scanTypeInt8 = reflect.TypeOf(int8(0))
+ scanTypeInt16 = reflect.TypeOf(int16(0))
+ scanTypeInt32 = reflect.TypeOf(int32(0))
+ scanTypeInt64 = reflect.TypeOf(int64(0))
+ scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
+ scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
+ scanTypeNullTime = reflect.TypeOf(nullTime{})
+ scanTypeUint8 = reflect.TypeOf(uint8(0))
+ scanTypeUint16 = reflect.TypeOf(uint16(0))
+ scanTypeUint32 = reflect.TypeOf(uint32(0))
+ scanTypeUint64 = reflect.TypeOf(uint64(0))
+ scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{})
+ scanTypeUnknown = reflect.TypeOf(new(interface{}))
+)
+
+type mysqlField struct {
+ tableName string
+ name string
+ length uint32
+ flags fieldFlag
+ fieldType fieldType
+ decimals byte
+ charSet uint8
+}
+
+func (mf *mysqlField) scanType() reflect.Type {
+ switch mf.fieldType {
+ case fieldTypeTiny:
+ if mf.flags&flagNotNULL != 0 {
+ if mf.flags&flagUnsigned != 0 {
+ return scanTypeUint8
+ }
+ return scanTypeInt8
+ }
+ return scanTypeNullInt
+
+ case fieldTypeShort, fieldTypeYear:
+ if mf.flags&flagNotNULL != 0 {
+ if mf.flags&flagUnsigned != 0 {
+ return scanTypeUint16
+ }
+ return scanTypeInt16
+ }
+ return scanTypeNullInt
+
+ case fieldTypeInt24, fieldTypeLong:
+ if mf.flags&flagNotNULL != 0 {
+ if mf.flags&flagUnsigned != 0 {
+ return scanTypeUint32
+ }
+ return scanTypeInt32
+ }
+ return scanTypeNullInt
+
+ case fieldTypeLongLong:
+ if mf.flags&flagNotNULL != 0 {
+ if mf.flags&flagUnsigned != 0 {
+ return scanTypeUint64
+ }
+ return scanTypeInt64
+ }
+ return scanTypeNullInt
+
+ case fieldTypeFloat:
+ if mf.flags&flagNotNULL != 0 {
+ return scanTypeFloat32
+ }
+ return scanTypeNullFloat
+
+ case fieldTypeDouble:
+ if mf.flags&flagNotNULL != 0 {
+ return scanTypeFloat64
+ }
+ return scanTypeNullFloat
+
+ case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
+ fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
+ fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
+ fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON,
+ fieldTypeTime:
+ return scanTypeRawBytes
+
+ case fieldTypeDate, fieldTypeNewDate,
+ fieldTypeTimestamp, fieldTypeDateTime:
+ // NullTime is always returned for more consistent behavior as it can
+ // handle both cases of parseTime regardless if the field is nullable.
+ return scanTypeNullTime
+
+ default:
+ return scanTypeUnknown
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/fuzz.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/fuzz.go
new file mode 100644
index 000000000000..fa75adf6a09a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/fuzz.go
@@ -0,0 +1,24 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package.
+//
+// Copyright 2020 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build gofuzz
+
+package mysql
+
+import (
+ "database/sql"
+)
+
+func Fuzz(data []byte) int {
+ db, err := sql.Open("mysql", string(data))
+ if err != nil {
+ return 0
+ }
+ db.Close()
+ return 1
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/infile.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/infile.go
new file mode 100644
index 000000000000..60effdfc2250
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/infile.go
@@ -0,0 +1,182 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "sync"
+)
+
+var (
+ fileRegister map[string]bool
+ fileRegisterLock sync.RWMutex
+ readerRegister map[string]func() io.Reader
+ readerRegisterLock sync.RWMutex
+)
+
+// RegisterLocalFile adds the given file to the file allowlist,
+// so that it can be used by "LOAD DATA LOCAL INFILE ".
+// Alternatively you can allow the use of all local files with
+// the DSN parameter 'allowAllFiles=true'
+//
+// filePath := "/home/gopher/data.csv"
+// mysql.RegisterLocalFile(filePath)
+// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo")
+// if err != nil {
+// ...
+//
+func RegisterLocalFile(filePath string) {
+ fileRegisterLock.Lock()
+ // lazy map init
+ if fileRegister == nil {
+ fileRegister = make(map[string]bool)
+ }
+
+ fileRegister[strings.Trim(filePath, `"`)] = true
+ fileRegisterLock.Unlock()
+}
+
+// DeregisterLocalFile removes the given filepath from the allowlist.
+func DeregisterLocalFile(filePath string) {
+ fileRegisterLock.Lock()
+ delete(fileRegister, strings.Trim(filePath, `"`))
+ fileRegisterLock.Unlock()
+}
+
+// RegisterReaderHandler registers a handler function which is used
+// to receive a io.Reader.
+// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::".
+// If the handler returns a io.ReadCloser Close() is called when the
+// request is finished.
+//
+// mysql.RegisterReaderHandler("data", func() io.Reader {
+// var csvReader io.Reader // Some Reader that returns CSV data
+// ... // Open Reader here
+// return csvReader
+// })
+// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo")
+// if err != nil {
+// ...
+//
+func RegisterReaderHandler(name string, handler func() io.Reader) {
+ readerRegisterLock.Lock()
+ // lazy map init
+ if readerRegister == nil {
+ readerRegister = make(map[string]func() io.Reader)
+ }
+
+ readerRegister[name] = handler
+ readerRegisterLock.Unlock()
+}
+
+// DeregisterReaderHandler removes the ReaderHandler function with
+// the given name from the registry.
+func DeregisterReaderHandler(name string) {
+ readerRegisterLock.Lock()
+ delete(readerRegister, name)
+ readerRegisterLock.Unlock()
+}
+
+func deferredClose(err *error, closer io.Closer) {
+ closeErr := closer.Close()
+ if *err == nil {
+ *err = closeErr
+ }
+}
+
+func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
+ var rdr io.Reader
+ var data []byte
+ packetSize := 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP
+ if mc.maxWriteSize < packetSize {
+ packetSize = mc.maxWriteSize
+ }
+
+ if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader
+ // The server might return an an absolute path. See issue #355.
+ name = name[idx+8:]
+
+ readerRegisterLock.RLock()
+ handler, inMap := readerRegister[name]
+ readerRegisterLock.RUnlock()
+
+ if inMap {
+ rdr = handler()
+ if rdr != nil {
+ if cl, ok := rdr.(io.Closer); ok {
+ defer deferredClose(&err, cl)
+ }
+ } else {
+ err = fmt.Errorf("Reader '%s' is ", name)
+ }
+ } else {
+ err = fmt.Errorf("Reader '%s' is not registered", name)
+ }
+ } else { // File
+ name = strings.Trim(name, `"`)
+ fileRegisterLock.RLock()
+ fr := fileRegister[name]
+ fileRegisterLock.RUnlock()
+ if mc.cfg.AllowAllFiles || fr {
+ var file *os.File
+ var fi os.FileInfo
+
+ if file, err = os.Open(name); err == nil {
+ defer deferredClose(&err, file)
+
+ // get file size
+ if fi, err = file.Stat(); err == nil {
+ rdr = file
+ if fileSize := int(fi.Size()); fileSize < packetSize {
+ packetSize = fileSize
+ }
+ }
+ }
+ } else {
+ err = fmt.Errorf("local file '%s' is not registered", name)
+ }
+ }
+
+ // send content packets
+ // if packetSize == 0, the Reader contains no data
+ if err == nil && packetSize > 0 {
+ data := make([]byte, 4+packetSize)
+ var n int
+ for err == nil {
+ n, err = rdr.Read(data[4:])
+ if n > 0 {
+ if ioErr := mc.writePacket(data[:4+n]); ioErr != nil {
+ return ioErr
+ }
+ }
+ }
+ if err == io.EOF {
+ err = nil
+ }
+ }
+
+ // send empty packet (termination)
+ if data == nil {
+ data = make([]byte, 4)
+ }
+ if ioErr := mc.writePacket(data[:4]); ioErr != nil {
+ return ioErr
+ }
+
+ // read OK packet
+ if err == nil {
+ return mc.readResultOK()
+ }
+
+ mc.readPacket()
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime.go
new file mode 100644
index 000000000000..651723a96189
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime.go
@@ -0,0 +1,50 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "time"
+)
+
+// Scan implements the Scanner interface.
+// The value type must be time.Time or string / []byte (formatted time-string),
+// otherwise Scan fails.
+func (nt *NullTime) Scan(value interface{}) (err error) {
+ if value == nil {
+ nt.Time, nt.Valid = time.Time{}, false
+ return
+ }
+
+ switch v := value.(type) {
+ case time.Time:
+ nt.Time, nt.Valid = v, true
+ return
+ case []byte:
+ nt.Time, err = parseDateTime(v, time.UTC)
+ nt.Valid = (err == nil)
+ return
+ case string:
+ nt.Time, err = parseDateTime([]byte(v), time.UTC)
+ nt.Valid = (err == nil)
+ return
+ }
+
+ nt.Valid = false
+ return fmt.Errorf("Can't convert %T to time.Time", value)
+}
+
+// Value implements the driver Valuer interface.
+func (nt NullTime) Value() (driver.Value, error) {
+ if !nt.Valid {
+ return nil, nil
+ }
+ return nt.Time, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime_go113.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
new file mode 100644
index 000000000000..453b4b3944e3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
@@ -0,0 +1,40 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build go1.13
+
+package mysql
+
+import (
+ "database/sql"
+)
+
+// NullTime represents a time.Time that may be NULL.
+// NullTime implements the Scanner interface so
+// it can be used as a scan destination:
+//
+// var nt NullTime
+// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
+// ...
+// if nt.Valid {
+// // use nt.Time
+// } else {
+// // NULL value
+// }
+//
+// This NullTime implementation is not driver-specific
+//
+// Deprecated: NullTime doesn't honor the loc DSN parameter.
+// NullTime.Scan interprets a time as UTC, not the loc DSN parameter.
+// Use sql.NullTime instead.
+type NullTime sql.NullTime
+
+// for internal use.
+// the mysql package uses sql.NullTime if it is available.
+// if not, the package uses mysql.NullTime.
+type nullTime = sql.NullTime // sql.NullTime is available
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
new file mode 100644
index 000000000000..9f7ae27a8eb3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
@@ -0,0 +1,39 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build !go1.13
+
+package mysql
+
+import (
+ "time"
+)
+
+// NullTime represents a time.Time that may be NULL.
+// NullTime implements the Scanner interface so
+// it can be used as a scan destination:
+//
+// var nt NullTime
+// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
+// ...
+// if nt.Valid {
+// // use nt.Time
+// } else {
+// // NULL value
+// }
+//
+// This NullTime implementation is not driver-specific
+type NullTime struct {
+ Time time.Time
+ Valid bool // Valid is true if Time is not NULL
+}
+
+// for internal use.
+// the mysql package uses sql.NullTime if it is available.
+// if not, the package uses mysql.NullTime.
+type nullTime = NullTime // sql.NullTime is not available
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/packets.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/packets.go
new file mode 100644
index 000000000000..6664e5ae5d32
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/packets.go
@@ -0,0 +1,1349 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "bytes"
+ "crypto/tls"
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "time"
+)
+
+// Packets documentation:
+// http://dev.mysql.com/doc/internals/en/client-server-protocol.html
+
+// Read packet to buffer 'data'
+func (mc *mysqlConn) readPacket() ([]byte, error) {
+ var prevData []byte
+ for {
+ // read packet header
+ data, err := mc.buf.readNext(4)
+ if err != nil {
+ if cerr := mc.canceled.Value(); cerr != nil {
+ return nil, cerr
+ }
+ errLog.Print(err)
+ mc.Close()
+ return nil, ErrInvalidConn
+ }
+
+ // packet length [24 bit]
+ pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
+
+ // check packet sync [8 bit]
+ if data[3] != mc.sequence {
+ if data[3] > mc.sequence {
+ return nil, ErrPktSyncMul
+ }
+ return nil, ErrPktSync
+ }
+ mc.sequence++
+
+ // packets with length 0 terminate a previous packet which is a
+ // multiple of (2^24)-1 bytes long
+ if pktLen == 0 {
+ // there was no previous packet
+ if prevData == nil {
+ errLog.Print(ErrMalformPkt)
+ mc.Close()
+ return nil, ErrInvalidConn
+ }
+
+ return prevData, nil
+ }
+
+ // read packet body [pktLen bytes]
+ data, err = mc.buf.readNext(pktLen)
+ if err != nil {
+ if cerr := mc.canceled.Value(); cerr != nil {
+ return nil, cerr
+ }
+ errLog.Print(err)
+ mc.Close()
+ return nil, ErrInvalidConn
+ }
+
+ // return data if this was the last packet
+ if pktLen < maxPacketSize {
+ // zero allocations for non-split packets
+ if prevData == nil {
+ return data, nil
+ }
+
+ return append(prevData, data...), nil
+ }
+
+ prevData = append(prevData, data...)
+ }
+}
+
+// Write packet buffer 'data'
+func (mc *mysqlConn) writePacket(data []byte) error {
+ pktLen := len(data) - 4
+
+ if pktLen > mc.maxAllowedPacket {
+ return ErrPktTooLarge
+ }
+
+ // Perform a stale connection check. We only perform this check for
+ // the first query on a connection that has been checked out of the
+ // connection pool: a fresh connection from the pool is more likely
+ // to be stale, and it has not performed any previous writes that
+ // could cause data corruption, so it's safe to return ErrBadConn
+ // if the check fails.
+ if mc.reset {
+ mc.reset = false
+ conn := mc.netConn
+ if mc.rawConn != nil {
+ conn = mc.rawConn
+ }
+ var err error
+ // If this connection has a ReadTimeout which we've been setting on
+ // reads, reset it to its default value before we attempt a non-blocking
+ // read, otherwise the scheduler will just time us out before we can read
+ if mc.cfg.ReadTimeout != 0 {
+ err = conn.SetReadDeadline(time.Time{})
+ }
+ if err == nil && mc.cfg.CheckConnLiveness {
+ err = connCheck(conn)
+ }
+ if err != nil {
+ errLog.Print("closing bad idle connection: ", err)
+ mc.Close()
+ return driver.ErrBadConn
+ }
+ }
+
+ for {
+ var size int
+ if pktLen >= maxPacketSize {
+ data[0] = 0xff
+ data[1] = 0xff
+ data[2] = 0xff
+ size = maxPacketSize
+ } else {
+ data[0] = byte(pktLen)
+ data[1] = byte(pktLen >> 8)
+ data[2] = byte(pktLen >> 16)
+ size = pktLen
+ }
+ data[3] = mc.sequence
+
+ // Write packet
+ if mc.writeTimeout > 0 {
+ if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil {
+ return err
+ }
+ }
+
+ n, err := mc.netConn.Write(data[:4+size])
+ if err == nil && n == 4+size {
+ mc.sequence++
+ if size != maxPacketSize {
+ return nil
+ }
+ pktLen -= size
+ data = data[size:]
+ continue
+ }
+
+ // Handle error
+ if err == nil { // n != len(data)
+ mc.cleanup()
+ errLog.Print(ErrMalformPkt)
+ } else {
+ if cerr := mc.canceled.Value(); cerr != nil {
+ return cerr
+ }
+ if n == 0 && pktLen == len(data)-4 {
+ // only for the first loop iteration when nothing was written yet
+ return errBadConnNoWrite
+ }
+ mc.cleanup()
+ errLog.Print(err)
+ }
+ return ErrInvalidConn
+ }
+}
+
+/******************************************************************************
+* Initialization Process *
+******************************************************************************/
+
+// Handshake Initialization Packet
+// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
+func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) {
+ data, err = mc.readPacket()
+ if err != nil {
+ // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since
+ // in connection initialization we don't risk retrying non-idempotent actions.
+ if err == ErrInvalidConn {
+ return nil, "", driver.ErrBadConn
+ }
+ return
+ }
+
+ if data[0] == iERR {
+ return nil, "", mc.handleErrorPacket(data)
+ }
+
+ // protocol version [1 byte]
+ if data[0] < minProtocolVersion {
+ return nil, "", fmt.Errorf(
+ "unsupported protocol version %d. Version %d or higher is required",
+ data[0],
+ minProtocolVersion,
+ )
+ }
+
+ // server version [null terminated string]
+ // connection id [4 bytes]
+ pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4
+
+ // first part of the password cipher [8 bytes]
+ authData := data[pos : pos+8]
+
+ // (filler) always 0x00 [1 byte]
+ pos += 8 + 1
+
+ // capability flags (lower 2 bytes) [2 bytes]
+ mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
+ if mc.flags&clientProtocol41 == 0 {
+ return nil, "", ErrOldProtocol
+ }
+ if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
+ if mc.cfg.TLSConfig == "preferred" {
+ mc.cfg.tls = nil
+ } else {
+ return nil, "", ErrNoTLS
+ }
+ }
+ pos += 2
+
+ if len(data) > pos {
+ // character set [1 byte]
+ // status flags [2 bytes]
+ // capability flags (upper 2 bytes) [2 bytes]
+ // length of auth-plugin-data [1 byte]
+ // reserved (all [00]) [10 bytes]
+ pos += 1 + 2 + 2 + 1 + 10
+
+ // second part of the password cipher [mininum 13 bytes],
+ // where len=MAX(13, length of auth-plugin-data - 8)
+ //
+ // The web documentation is ambiguous about the length. However,
+ // according to mysql-5.7/sql/auth/sql_authentication.cc line 538,
+ // the 13th byte is "\0 byte, terminating the second part of
+ // a scramble". So the second part of the password cipher is
+ // a NULL terminated string that's at least 13 bytes with the
+ // last byte being NULL.
+ //
+ // The official Python library uses the fixed length 12
+ // which seems to work but technically could have a hidden bug.
+ authData = append(authData, data[pos:pos+12]...)
+ pos += 13
+
+ // EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2)
+ // \NUL otherwise
+ if end := bytes.IndexByte(data[pos:], 0x00); end != -1 {
+ plugin = string(data[pos : pos+end])
+ } else {
+ plugin = string(data[pos:])
+ }
+
+ // make a memory safe copy of the cipher slice
+ var b [20]byte
+ copy(b[:], authData)
+ return b[:], plugin, nil
+ }
+
+ // make a memory safe copy of the cipher slice
+ var b [8]byte
+ copy(b[:], authData)
+ return b[:], plugin, nil
+}
+
+// Client Authentication Packet
+// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
+func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error {
+ // Adjust client flags based on server support
+ clientFlags := clientProtocol41 |
+ clientSecureConn |
+ clientLongPassword |
+ clientTransactions |
+ clientLocalFiles |
+ clientPluginAuth |
+ clientMultiResults |
+ mc.flags&clientLongFlag
+
+ if mc.cfg.ClientFoundRows {
+ clientFlags |= clientFoundRows
+ }
+
+ // To enable TLS / SSL
+ if mc.cfg.tls != nil {
+ clientFlags |= clientSSL
+ }
+
+ if mc.cfg.MultiStatements {
+ clientFlags |= clientMultiStatements
+ }
+
+ // encode length of the auth plugin data
+ var authRespLEIBuf [9]byte
+ authRespLen := len(authResp)
+ authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen))
+ if len(authRespLEI) > 1 {
+ // if the length can not be written in 1 byte, it must be written as a
+ // length encoded integer
+ clientFlags |= clientPluginAuthLenEncClientData
+ }
+
+ pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1
+
+ // To specify a db name
+ if n := len(mc.cfg.DBName); n > 0 {
+ clientFlags |= clientConnectWithDB
+ pktLen += n + 1
+ }
+
+ // Calculate packet length and get buffer with that size
+ data, err := mc.buf.takeSmallBuffer(pktLen + 4)
+ if err != nil {
+ // cannot take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+
+ // ClientFlags [32 bit]
+ data[4] = byte(clientFlags)
+ data[5] = byte(clientFlags >> 8)
+ data[6] = byte(clientFlags >> 16)
+ data[7] = byte(clientFlags >> 24)
+
+ // MaxPacketSize [32 bit] (none)
+ data[8] = 0x00
+ data[9] = 0x00
+ data[10] = 0x00
+ data[11] = 0x00
+
+ // Charset [1 byte]
+ var found bool
+ data[12], found = collations[mc.cfg.Collation]
+ if !found {
+ // Note possibility for false negatives:
+ // could be triggered although the collation is valid if the
+ // collations map does not contain entries the server supports.
+ return errors.New("unknown collation")
+ }
+
+ // Filler [23 bytes] (all 0x00)
+ pos := 13
+ for ; pos < 13+23; pos++ {
+ data[pos] = 0
+ }
+
+ // SSL Connection Request Packet
+ // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
+ if mc.cfg.tls != nil {
+ // Send TLS / SSL request packet
+ if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil {
+ return err
+ }
+
+ // Switch to TLS
+ tlsConn := tls.Client(mc.netConn, mc.cfg.tls)
+ if err := tlsConn.Handshake(); err != nil {
+ return err
+ }
+ mc.rawConn = mc.netConn
+ mc.netConn = tlsConn
+ mc.buf.nc = tlsConn
+ }
+
+ // User [null terminated string]
+ if len(mc.cfg.User) > 0 {
+ pos += copy(data[pos:], mc.cfg.User)
+ }
+ data[pos] = 0x00
+ pos++
+
+ // Auth Data [length encoded integer]
+ pos += copy(data[pos:], authRespLEI)
+ pos += copy(data[pos:], authResp)
+
+ // Databasename [null terminated string]
+ if len(mc.cfg.DBName) > 0 {
+ pos += copy(data[pos:], mc.cfg.DBName)
+ data[pos] = 0x00
+ pos++
+ }
+
+ pos += copy(data[pos:], plugin)
+ data[pos] = 0x00
+ pos++
+
+ // Send Auth packet
+ return mc.writePacket(data[:pos])
+}
+
+// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
+func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
+ pktLen := 4 + len(authData)
+ data, err := mc.buf.takeSmallBuffer(pktLen)
+ if err != nil {
+ // cannot take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+
+ // Add the auth data [EOF]
+ copy(data[4:], authData)
+ return mc.writePacket(data)
+}
+
+/******************************************************************************
+* Command Packets *
+******************************************************************************/
+
+func (mc *mysqlConn) writeCommandPacket(command byte) error {
+ // Reset Packet Sequence
+ mc.sequence = 0
+
+ data, err := mc.buf.takeSmallBuffer(4 + 1)
+ if err != nil {
+ // cannot take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+
+ // Add command byte
+ data[4] = command
+
+ // Send CMD packet
+ return mc.writePacket(data)
+}
+
+func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
+ // Reset Packet Sequence
+ mc.sequence = 0
+
+ pktLen := 1 + len(arg)
+ data, err := mc.buf.takeBuffer(pktLen + 4)
+ if err != nil {
+ // cannot take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+
+ // Add command byte
+ data[4] = command
+
+ // Add arg
+ copy(data[5:], arg)
+
+ // Send CMD packet
+ return mc.writePacket(data)
+}
+
+func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
+ // Reset Packet Sequence
+ mc.sequence = 0
+
+ data, err := mc.buf.takeSmallBuffer(4 + 1 + 4)
+ if err != nil {
+ // cannot take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+
+ // Add command byte
+ data[4] = command
+
+ // Add arg [32 bit]
+ data[5] = byte(arg)
+ data[6] = byte(arg >> 8)
+ data[7] = byte(arg >> 16)
+ data[8] = byte(arg >> 24)
+
+ // Send CMD packet
+ return mc.writePacket(data)
+}
+
+/******************************************************************************
+* Result Packets *
+******************************************************************************/
+
+func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
+ data, err := mc.readPacket()
+ if err != nil {
+ return nil, "", err
+ }
+
+ // packet indicator
+ switch data[0] {
+
+ case iOK:
+ return nil, "", mc.handleOkPacket(data)
+
+ case iAuthMoreData:
+ return data[1:], "", err
+
+ case iEOF:
+ if len(data) == 1 {
+ // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
+ return nil, "mysql_old_password", nil
+ }
+ pluginEndIndex := bytes.IndexByte(data, 0x00)
+ if pluginEndIndex < 0 {
+ return nil, "", ErrMalformPkt
+ }
+ plugin := string(data[1:pluginEndIndex])
+ authData := data[pluginEndIndex+1:]
+ return authData, plugin, nil
+
+ default: // Error otherwise
+ return nil, "", mc.handleErrorPacket(data)
+ }
+}
+
+// Returns error if Packet is not an 'Result OK'-Packet
+func (mc *mysqlConn) readResultOK() error {
+ data, err := mc.readPacket()
+ if err != nil {
+ return err
+ }
+
+ if data[0] == iOK {
+ return mc.handleOkPacket(data)
+ }
+ return mc.handleErrorPacket(data)
+}
+
+// Result Set Header Packet
+// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset
+func (mc *mysqlConn) readResultSetHeaderPacket() (int, error) {
+ data, err := mc.readPacket()
+ if err == nil {
+ switch data[0] {
+
+ case iOK:
+ return 0, mc.handleOkPacket(data)
+
+ case iERR:
+ return 0, mc.handleErrorPacket(data)
+
+ case iLocalInFile:
+ return 0, mc.handleInFileRequest(string(data[1:]))
+ }
+
+ // column count
+ num, _, n := readLengthEncodedInteger(data)
+ if n-len(data) == 0 {
+ return int(num), nil
+ }
+
+ return 0, ErrMalformPkt
+ }
+ return 0, err
+}
+
+// Error Packet
+// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet
+func (mc *mysqlConn) handleErrorPacket(data []byte) error {
+ if data[0] != iERR {
+ return ErrMalformPkt
+ }
+
+ // 0xff [1 byte]
+
+ // Error Number [16 bit uint]
+ errno := binary.LittleEndian.Uint16(data[1:3])
+
+ // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
+ // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)
+ if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {
+ // Oops; we are connected to a read-only connection, and won't be able
+ // to issue any write statements. Since RejectReadOnly is configured,
+ // we throw away this connection hoping this one would have write
+ // permission. This is specifically for a possible race condition
+ // during failover (e.g. on AWS Aurora). See README.md for more.
+ //
+ // We explicitly close the connection before returning
+ // driver.ErrBadConn to ensure that `database/sql` purges this
+ // connection and initiates a new one for next statement next time.
+ mc.Close()
+ return driver.ErrBadConn
+ }
+
+ pos := 3
+
+ // SQL State [optional: # + 5bytes string]
+ if data[3] == 0x23 {
+ //sqlstate := string(data[4 : 4+5])
+ pos = 9
+ }
+
+ // Error Message [string]
+ return &MySQLError{
+ Number: errno,
+ Message: string(data[pos:]),
+ }
+}
+
+func readStatus(b []byte) statusFlag {
+ return statusFlag(b[0]) | statusFlag(b[1])<<8
+}
+
+// Ok Packet
+// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet
+func (mc *mysqlConn) handleOkPacket(data []byte) error {
+ var n, m int
+
+ // 0x00 [1 byte]
+
+ // Affected rows [Length Coded Binary]
+ mc.affectedRows, _, n = readLengthEncodedInteger(data[1:])
+
+ // Insert id [Length Coded Binary]
+ mc.insertId, _, m = readLengthEncodedInteger(data[1+n:])
+
+ // server_status [2 bytes]
+ mc.status = readStatus(data[1+n+m : 1+n+m+2])
+ if mc.status&statusMoreResultsExists != 0 {
+ return nil
+ }
+
+ // warning count [2 bytes]
+
+ return nil
+}
+
+// Read Packets as Field Packets until EOF-Packet or an Error appears
+// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41
+func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
+ columns := make([]mysqlField, count)
+
+ for i := 0; ; i++ {
+ data, err := mc.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ // EOF Packet
+ if data[0] == iEOF && (len(data) == 5 || len(data) == 1) {
+ if i == count {
+ return columns, nil
+ }
+ return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns))
+ }
+
+ // Catalog
+ pos, err := skipLengthEncodedString(data)
+ if err != nil {
+ return nil, err
+ }
+
+ // Database [len coded string]
+ n, err := skipLengthEncodedString(data[pos:])
+ if err != nil {
+ return nil, err
+ }
+ pos += n
+
+ // Table [len coded string]
+ if mc.cfg.ColumnsWithAlias {
+ tableName, _, n, err := readLengthEncodedString(data[pos:])
+ if err != nil {
+ return nil, err
+ }
+ pos += n
+ columns[i].tableName = string(tableName)
+ } else {
+ n, err = skipLengthEncodedString(data[pos:])
+ if err != nil {
+ return nil, err
+ }
+ pos += n
+ }
+
+ // Original table [len coded string]
+ n, err = skipLengthEncodedString(data[pos:])
+ if err != nil {
+ return nil, err
+ }
+ pos += n
+
+ // Name [len coded string]
+ name, _, n, err := readLengthEncodedString(data[pos:])
+ if err != nil {
+ return nil, err
+ }
+ columns[i].name = string(name)
+ pos += n
+
+ // Original name [len coded string]
+ n, err = skipLengthEncodedString(data[pos:])
+ if err != nil {
+ return nil, err
+ }
+ pos += n
+
+ // Filler [uint8]
+ pos++
+
+ // Charset [charset, collation uint8]
+ columns[i].charSet = data[pos]
+ pos += 2
+
+ // Length [uint32]
+ columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4])
+ pos += 4
+
+ // Field type [uint8]
+ columns[i].fieldType = fieldType(data[pos])
+ pos++
+
+ // Flags [uint16]
+ columns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
+ pos += 2
+
+ // Decimals [uint8]
+ columns[i].decimals = data[pos]
+ //pos++
+
+ // Default value [len coded binary]
+ //if pos < len(data) {
+ // defaultVal, _, err = bytesToLengthCodedBinary(data[pos:])
+ //}
+ }
+}
+
+// Read Packets as Field Packets until EOF-Packet or an Error appears
+// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow
+func (rows *textRows) readRow(dest []driver.Value) error {
+ mc := rows.mc
+
+ if rows.rs.done {
+ return io.EOF
+ }
+
+ data, err := mc.readPacket()
+ if err != nil {
+ return err
+ }
+
+ // EOF Packet
+ if data[0] == iEOF && len(data) == 5 {
+ // server_status [2 bytes]
+ rows.mc.status = readStatus(data[3:])
+ rows.rs.done = true
+ if !rows.HasNextResultSet() {
+ rows.mc = nil
+ }
+ return io.EOF
+ }
+ if data[0] == iERR {
+ rows.mc = nil
+ return mc.handleErrorPacket(data)
+ }
+
+ // RowSet Packet
+ var n int
+ var isNull bool
+ pos := 0
+
+ for i := range dest {
+ // Read bytes and convert to string
+ dest[i], isNull, n, err = readLengthEncodedString(data[pos:])
+ pos += n
+ if err == nil {
+ if !isNull {
+ if !mc.parseTime {
+ continue
+ } else {
+ switch rows.rs.columns[i].fieldType {
+ case fieldTypeTimestamp, fieldTypeDateTime,
+ fieldTypeDate, fieldTypeNewDate:
+ dest[i], err = parseDateTime(
+ dest[i].([]byte),
+ mc.cfg.Loc,
+ )
+ if err == nil {
+ continue
+ }
+ default:
+ continue
+ }
+ }
+
+ } else {
+ dest[i] = nil
+ continue
+ }
+ }
+ return err // err != nil
+ }
+
+ return nil
+}
+
+// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read
+func (mc *mysqlConn) readUntilEOF() error {
+ for {
+ data, err := mc.readPacket()
+ if err != nil {
+ return err
+ }
+
+ switch data[0] {
+ case iERR:
+ return mc.handleErrorPacket(data)
+ case iEOF:
+ if len(data) == 5 {
+ mc.status = readStatus(data[3:])
+ }
+ return nil
+ }
+ }
+}
+
+/******************************************************************************
+* Prepared Statements *
+******************************************************************************/
+
+// Prepare Result Packets
+// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html
+func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
+ data, err := stmt.mc.readPacket()
+ if err == nil {
+ // packet indicator [1 byte]
+ if data[0] != iOK {
+ return 0, stmt.mc.handleErrorPacket(data)
+ }
+
+ // statement id [4 bytes]
+ stmt.id = binary.LittleEndian.Uint32(data[1:5])
+
+ // Column count [16 bit uint]
+ columnCount := binary.LittleEndian.Uint16(data[5:7])
+
+ // Param count [16 bit uint]
+ stmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9]))
+
+ // Reserved [8 bit]
+
+ // Warning count [16 bit uint]
+
+ return columnCount, nil
+ }
+ return 0, err
+}
+
+// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html
+func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
+ maxLen := stmt.mc.maxAllowedPacket - 1
+ pktLen := maxLen
+
+ // After the header (bytes 0-3) follows before the data:
+ // 1 byte command
+ // 4 bytes stmtID
+ // 2 bytes paramID
+ const dataOffset = 1 + 4 + 2
+
+ // Cannot use the write buffer since
+ // a) the buffer is too small
+ // b) it is in use
+ data := make([]byte, 4+1+4+2+len(arg))
+
+ copy(data[4+dataOffset:], arg)
+
+ for argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset {
+ if dataOffset+argLen < maxLen {
+ pktLen = dataOffset + argLen
+ }
+
+ stmt.mc.sequence = 0
+ // Add command byte [1 byte]
+ data[4] = comStmtSendLongData
+
+ // Add stmtID [32 bit]
+ data[5] = byte(stmt.id)
+ data[6] = byte(stmt.id >> 8)
+ data[7] = byte(stmt.id >> 16)
+ data[8] = byte(stmt.id >> 24)
+
+ // Add paramID [16 bit]
+ data[9] = byte(paramID)
+ data[10] = byte(paramID >> 8)
+
+ // Send CMD packet
+ err := stmt.mc.writePacket(data[:4+pktLen])
+ if err == nil {
+ data = data[pktLen-dataOffset:]
+ continue
+ }
+ return err
+
+ }
+
+ // Reset Packet Sequence
+ stmt.mc.sequence = 0
+ return nil
+}
+
+// Execute Prepared Statement
+// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html
+func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
+ if len(args) != stmt.paramCount {
+ return fmt.Errorf(
+ "argument count mismatch (got: %d; has: %d)",
+ len(args),
+ stmt.paramCount,
+ )
+ }
+
+ const minPktLen = 4 + 1 + 4 + 1 + 4
+ mc := stmt.mc
+
+ // Determine threshold dynamically to avoid packet size shortage.
+ longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
+ if longDataSize < 64 {
+ longDataSize = 64
+ }
+
+ // Reset packet-sequence
+ mc.sequence = 0
+
+ var data []byte
+ var err error
+
+ if len(args) == 0 {
+ data, err = mc.buf.takeBuffer(minPktLen)
+ } else {
+ data, err = mc.buf.takeCompleteBuffer()
+ // In this case the len(data) == cap(data) which is used to optimise the flow below.
+ }
+ if err != nil {
+ // cannot take the buffer. Something must be wrong with the connection
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+
+ // command [1 byte]
+ data[4] = comStmtExecute
+
+ // statement_id [4 bytes]
+ data[5] = byte(stmt.id)
+ data[6] = byte(stmt.id >> 8)
+ data[7] = byte(stmt.id >> 16)
+ data[8] = byte(stmt.id >> 24)
+
+ // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]
+ data[9] = 0x00
+
+ // iteration_count (uint32(1)) [4 bytes]
+ data[10] = 0x01
+ data[11] = 0x00
+ data[12] = 0x00
+ data[13] = 0x00
+
+ if len(args) > 0 {
+ pos := minPktLen
+
+ var nullMask []byte
+ if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) {
+ // buffer has to be extended but we don't know by how much so
+ // we depend on append after all data with known sizes fit.
+ // We stop at that because we deal with a lot of columns here
+ // which makes the required allocation size hard to guess.
+ tmp := make([]byte, pos+maskLen+typesLen)
+ copy(tmp[:pos], data[:pos])
+ data = tmp
+ nullMask = data[pos : pos+maskLen]
+ // No need to clean nullMask as make ensures that.
+ pos += maskLen
+ } else {
+ nullMask = data[pos : pos+maskLen]
+ for i := range nullMask {
+ nullMask[i] = 0
+ }
+ pos += maskLen
+ }
+
+ // newParameterBoundFlag 1 [1 byte]
+ data[pos] = 0x01
+ pos++
+
+ // type of each parameter [len(args)*2 bytes]
+ paramTypes := data[pos:]
+ pos += len(args) * 2
+
+ // value of each parameter [n bytes]
+ paramValues := data[pos:pos]
+ valuesCap := cap(paramValues)
+
+ for i, arg := range args {
+ // build NULL-bitmap
+ if arg == nil {
+ nullMask[i/8] |= 1 << (uint(i) & 7)
+ paramTypes[i+i] = byte(fieldTypeNULL)
+ paramTypes[i+i+1] = 0x00
+ continue
+ }
+
+ if v, ok := arg.(json.RawMessage); ok {
+ arg = []byte(v)
+ }
+ // cache types and values
+ switch v := arg.(type) {
+ case int64:
+ paramTypes[i+i] = byte(fieldTypeLongLong)
+ paramTypes[i+i+1] = 0x00
+
+ if cap(paramValues)-len(paramValues)-8 >= 0 {
+ paramValues = paramValues[:len(paramValues)+8]
+ binary.LittleEndian.PutUint64(
+ paramValues[len(paramValues)-8:],
+ uint64(v),
+ )
+ } else {
+ paramValues = append(paramValues,
+ uint64ToBytes(uint64(v))...,
+ )
+ }
+
+ case uint64:
+ paramTypes[i+i] = byte(fieldTypeLongLong)
+ paramTypes[i+i+1] = 0x80 // type is unsigned
+
+ if cap(paramValues)-len(paramValues)-8 >= 0 {
+ paramValues = paramValues[:len(paramValues)+8]
+ binary.LittleEndian.PutUint64(
+ paramValues[len(paramValues)-8:],
+ uint64(v),
+ )
+ } else {
+ paramValues = append(paramValues,
+ uint64ToBytes(uint64(v))...,
+ )
+ }
+
+ case float64:
+ paramTypes[i+i] = byte(fieldTypeDouble)
+ paramTypes[i+i+1] = 0x00
+
+ if cap(paramValues)-len(paramValues)-8 >= 0 {
+ paramValues = paramValues[:len(paramValues)+8]
+ binary.LittleEndian.PutUint64(
+ paramValues[len(paramValues)-8:],
+ math.Float64bits(v),
+ )
+ } else {
+ paramValues = append(paramValues,
+ uint64ToBytes(math.Float64bits(v))...,
+ )
+ }
+
+ case bool:
+ paramTypes[i+i] = byte(fieldTypeTiny)
+ paramTypes[i+i+1] = 0x00
+
+ if v {
+ paramValues = append(paramValues, 0x01)
+ } else {
+ paramValues = append(paramValues, 0x00)
+ }
+
+ case []byte:
+ // Common case (non-nil value) first
+ if v != nil {
+ paramTypes[i+i] = byte(fieldTypeString)
+ paramTypes[i+i+1] = 0x00
+
+ if len(v) < longDataSize {
+ paramValues = appendLengthEncodedInteger(paramValues,
+ uint64(len(v)),
+ )
+ paramValues = append(paramValues, v...)
+ } else {
+ if err := stmt.writeCommandLongData(i, v); err != nil {
+ return err
+ }
+ }
+ continue
+ }
+
+ // Handle []byte(nil) as a NULL value
+ nullMask[i/8] |= 1 << (uint(i) & 7)
+ paramTypes[i+i] = byte(fieldTypeNULL)
+ paramTypes[i+i+1] = 0x00
+
+ case string:
+ paramTypes[i+i] = byte(fieldTypeString)
+ paramTypes[i+i+1] = 0x00
+
+ if len(v) < longDataSize {
+ paramValues = appendLengthEncodedInteger(paramValues,
+ uint64(len(v)),
+ )
+ paramValues = append(paramValues, v...)
+ } else {
+ if err := stmt.writeCommandLongData(i, []byte(v)); err != nil {
+ return err
+ }
+ }
+
+ case time.Time:
+ paramTypes[i+i] = byte(fieldTypeString)
+ paramTypes[i+i+1] = 0x00
+
+ var a [64]byte
+ var b = a[:0]
+
+ if v.IsZero() {
+ b = append(b, "0000-00-00"...)
+ } else {
+ b, err = appendDateTime(b, v.In(mc.cfg.Loc))
+ if err != nil {
+ return err
+ }
+ }
+
+ paramValues = appendLengthEncodedInteger(paramValues,
+ uint64(len(b)),
+ )
+ paramValues = append(paramValues, b...)
+
+ default:
+ return fmt.Errorf("cannot convert type: %T", arg)
+ }
+ }
+
+ // Check if param values exceeded the available buffer
+ // In that case we must build the data packet with the new values buffer
+ if valuesCap != cap(paramValues) {
+ data = append(data[:pos], paramValues...)
+ if err = mc.buf.store(data); err != nil {
+ errLog.Print(err)
+ return errBadConnNoWrite
+ }
+ }
+
+ pos += len(paramValues)
+ data = data[:pos]
+ }
+
+ return mc.writePacket(data)
+}
+
+func (mc *mysqlConn) discardResults() error {
+ for mc.status&statusMoreResultsExists != 0 {
+ resLen, err := mc.readResultSetHeaderPacket()
+ if err != nil {
+ return err
+ }
+ if resLen > 0 {
+ // columns
+ if err := mc.readUntilEOF(); err != nil {
+ return err
+ }
+ // rows
+ if err := mc.readUntilEOF(); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html
+func (rows *binaryRows) readRow(dest []driver.Value) error {
+ data, err := rows.mc.readPacket()
+ if err != nil {
+ return err
+ }
+
+ // packet indicator [1 byte]
+ if data[0] != iOK {
+ // EOF Packet
+ if data[0] == iEOF && len(data) == 5 {
+ rows.mc.status = readStatus(data[3:])
+ rows.rs.done = true
+ if !rows.HasNextResultSet() {
+ rows.mc = nil
+ }
+ return io.EOF
+ }
+ mc := rows.mc
+ rows.mc = nil
+
+ // Error otherwise
+ return mc.handleErrorPacket(data)
+ }
+
+ // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes]
+ pos := 1 + (len(dest)+7+2)>>3
+ nullMask := data[1:pos]
+
+ for i := range dest {
+ // Field is NULL
+ // (byte >> bit-pos) % 2 == 1
+ if ((nullMask[(i+2)>>3] >> uint((i+2)&7)) & 1) == 1 {
+ dest[i] = nil
+ continue
+ }
+
+ // Convert to byte-coded string
+ switch rows.rs.columns[i].fieldType {
+ case fieldTypeNULL:
+ dest[i] = nil
+ continue
+
+ // Numeric Types
+ case fieldTypeTiny:
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
+ dest[i] = int64(data[pos])
+ } else {
+ dest[i] = int64(int8(data[pos]))
+ }
+ pos++
+ continue
+
+ case fieldTypeShort, fieldTypeYear:
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
+ dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))
+ } else {
+ dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))
+ }
+ pos += 2
+ continue
+
+ case fieldTypeInt24, fieldTypeLong:
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
+ dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))
+ } else {
+ dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))
+ }
+ pos += 4
+ continue
+
+ case fieldTypeLongLong:
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
+ val := binary.LittleEndian.Uint64(data[pos : pos+8])
+ if val > math.MaxInt64 {
+ dest[i] = uint64ToString(val)
+ } else {
+ dest[i] = int64(val)
+ }
+ } else {
+ dest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8]))
+ }
+ pos += 8
+ continue
+
+ case fieldTypeFloat:
+ dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))
+ pos += 4
+ continue
+
+ case fieldTypeDouble:
+ dest[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[pos : pos+8]))
+ pos += 8
+ continue
+
+ // Length coded Binary Strings
+ case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
+ fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
+ fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
+ fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON:
+ var isNull bool
+ var n int
+ dest[i], isNull, n, err = readLengthEncodedString(data[pos:])
+ pos += n
+ if err == nil {
+ if !isNull {
+ continue
+ } else {
+ dest[i] = nil
+ continue
+ }
+ }
+ return err
+
+ case
+ fieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD
+ fieldTypeTime, // Time [-][H]HH:MM:SS[.fractal]
+ fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal]
+
+ num, isNull, n := readLengthEncodedInteger(data[pos:])
+ pos += n
+
+ switch {
+ case isNull:
+ dest[i] = nil
+ continue
+ case rows.rs.columns[i].fieldType == fieldTypeTime:
+ // database/sql does not support an equivalent to TIME, return a string
+ var dstlen uint8
+ switch decimals := rows.rs.columns[i].decimals; decimals {
+ case 0x00, 0x1f:
+ dstlen = 8
+ case 1, 2, 3, 4, 5, 6:
+ dstlen = 8 + 1 + decimals
+ default:
+ return fmt.Errorf(
+ "protocol error, illegal decimals value %d",
+ rows.rs.columns[i].decimals,
+ )
+ }
+ dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen)
+ case rows.mc.parseTime:
+ dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
+ default:
+ var dstlen uint8
+ if rows.rs.columns[i].fieldType == fieldTypeDate {
+ dstlen = 10
+ } else {
+ switch decimals := rows.rs.columns[i].decimals; decimals {
+ case 0x00, 0x1f:
+ dstlen = 19
+ case 1, 2, 3, 4, 5, 6:
+ dstlen = 19 + 1 + decimals
+ default:
+ return fmt.Errorf(
+ "protocol error, illegal decimals value %d",
+ rows.rs.columns[i].decimals,
+ )
+ }
+ }
+ dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen)
+ }
+
+ if err == nil {
+ pos += int(num)
+ continue
+ } else {
+ return err
+ }
+
+ // Please report if this happens!
+ default:
+ return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType)
+ }
+ }
+
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/result.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/result.go
new file mode 100644
index 000000000000..c6438d0347db
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/result.go
@@ -0,0 +1,22 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+type mysqlResult struct {
+ affectedRows int64
+ insertId int64
+}
+
+func (res *mysqlResult) LastInsertId() (int64, error) {
+ return res.insertId, nil
+}
+
+func (res *mysqlResult) RowsAffected() (int64, error) {
+ return res.affectedRows, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/rows.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/rows.go
new file mode 100644
index 000000000000..888bdb5f0ada
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/rows.go
@@ -0,0 +1,223 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "database/sql/driver"
+ "io"
+ "math"
+ "reflect"
+)
+
+type resultSet struct {
+ columns []mysqlField
+ columnNames []string
+ done bool
+}
+
+type mysqlRows struct {
+ mc *mysqlConn
+ rs resultSet
+ finish func()
+}
+
+type binaryRows struct {
+ mysqlRows
+}
+
+type textRows struct {
+ mysqlRows
+}
+
+func (rows *mysqlRows) Columns() []string {
+ if rows.rs.columnNames != nil {
+ return rows.rs.columnNames
+ }
+
+ columns := make([]string, len(rows.rs.columns))
+ if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {
+ for i := range columns {
+ if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 {
+ columns[i] = tableName + "." + rows.rs.columns[i].name
+ } else {
+ columns[i] = rows.rs.columns[i].name
+ }
+ }
+ } else {
+ for i := range columns {
+ columns[i] = rows.rs.columns[i].name
+ }
+ }
+
+ rows.rs.columnNames = columns
+ return columns
+}
+
+func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string {
+ return rows.rs.columns[i].typeDatabaseName()
+}
+
+// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) {
+// return int64(rows.rs.columns[i].length), true
+// }
+
+func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) {
+ return rows.rs.columns[i].flags&flagNotNULL == 0, true
+}
+
+func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) {
+ column := rows.rs.columns[i]
+ decimals := int64(column.decimals)
+
+ switch column.fieldType {
+ case fieldTypeDecimal, fieldTypeNewDecimal:
+ if decimals > 0 {
+ return int64(column.length) - 2, decimals, true
+ }
+ return int64(column.length) - 1, decimals, true
+ case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime:
+ return decimals, decimals, true
+ case fieldTypeFloat, fieldTypeDouble:
+ if decimals == 0x1f {
+ return math.MaxInt64, math.MaxInt64, true
+ }
+ return math.MaxInt64, decimals, true
+ }
+
+ return 0, 0, false
+}
+
+func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type {
+ return rows.rs.columns[i].scanType()
+}
+
+func (rows *mysqlRows) Close() (err error) {
+ if f := rows.finish; f != nil {
+ f()
+ rows.finish = nil
+ }
+
+ mc := rows.mc
+ if mc == nil {
+ return nil
+ }
+ if err := mc.error(); err != nil {
+ return err
+ }
+
+ // flip the buffer for this connection if we need to drain it.
+ // note that for a successful query (i.e. one where rows.next()
+ // has been called until it returns false), `rows.mc` will be nil
+ // by the time the user calls `(*Rows).Close`, so we won't reach this
+ // see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47
+ mc.buf.flip()
+
+ // Remove unread packets from stream
+ if !rows.rs.done {
+ err = mc.readUntilEOF()
+ }
+ if err == nil {
+ if err = mc.discardResults(); err != nil {
+ return err
+ }
+ }
+
+ rows.mc = nil
+ return err
+}
+
+func (rows *mysqlRows) HasNextResultSet() (b bool) {
+ if rows.mc == nil {
+ return false
+ }
+ return rows.mc.status&statusMoreResultsExists != 0
+}
+
+func (rows *mysqlRows) nextResultSet() (int, error) {
+ if rows.mc == nil {
+ return 0, io.EOF
+ }
+ if err := rows.mc.error(); err != nil {
+ return 0, err
+ }
+
+ // Remove unread packets from stream
+ if !rows.rs.done {
+ if err := rows.mc.readUntilEOF(); err != nil {
+ return 0, err
+ }
+ rows.rs.done = true
+ }
+
+ if !rows.HasNextResultSet() {
+ rows.mc = nil
+ return 0, io.EOF
+ }
+ rows.rs = resultSet{}
+ return rows.mc.readResultSetHeaderPacket()
+}
+
+func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) {
+ for {
+ resLen, err := rows.nextResultSet()
+ if err != nil {
+ return 0, err
+ }
+
+ if resLen > 0 {
+ return resLen, nil
+ }
+
+ rows.rs.done = true
+ }
+}
+
+func (rows *binaryRows) NextResultSet() error {
+ resLen, err := rows.nextNotEmptyResultSet()
+ if err != nil {
+ return err
+ }
+
+ rows.rs.columns, err = rows.mc.readColumns(resLen)
+ return err
+}
+
+func (rows *binaryRows) Next(dest []driver.Value) error {
+ if mc := rows.mc; mc != nil {
+ if err := mc.error(); err != nil {
+ return err
+ }
+
+ // Fetch next row from stream
+ return rows.readRow(dest)
+ }
+ return io.EOF
+}
+
+func (rows *textRows) NextResultSet() (err error) {
+ resLen, err := rows.nextNotEmptyResultSet()
+ if err != nil {
+ return err
+ }
+
+ rows.rs.columns, err = rows.mc.readColumns(resLen)
+ return err
+}
+
+func (rows *textRows) Next(dest []driver.Value) error {
+ if mc := rows.mc; mc != nil {
+ if err := mc.error(); err != nil {
+ return err
+ }
+
+ // Fetch next row from stream
+ return rows.readRow(dest)
+ }
+ return io.EOF
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/statement.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/statement.go
new file mode 100644
index 000000000000..18a3ae498926
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/statement.go
@@ -0,0 +1,220 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "fmt"
+ "io"
+ "reflect"
+)
+
+type mysqlStmt struct {
+ mc *mysqlConn
+ id uint32
+ paramCount int
+}
+
+func (stmt *mysqlStmt) Close() error {
+ if stmt.mc == nil || stmt.mc.closed.IsSet() {
+ // driver.Stmt.Close can be called more than once, thus this function
+ // has to be idempotent.
+ // See also Issue #450 and golang/go#16019.
+ //errLog.Print(ErrInvalidConn)
+ return driver.ErrBadConn
+ }
+
+ err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
+ stmt.mc = nil
+ return err
+}
+
+func (stmt *mysqlStmt) NumInput() int {
+ return stmt.paramCount
+}
+
+func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
+ return converter{}
+}
+
+func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) {
+ nv.Value, err = converter{}.ConvertValue(nv.Value)
+ return
+}
+
+func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
+ if stmt.mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return nil, driver.ErrBadConn
+ }
+ // Send command
+ err := stmt.writeExecutePacket(args)
+ if err != nil {
+ return nil, stmt.mc.markBadConn(err)
+ }
+
+ mc := stmt.mc
+
+ mc.affectedRows = 0
+ mc.insertId = 0
+
+ // Read Result
+ resLen, err := mc.readResultSetHeaderPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ if resLen > 0 {
+ // Columns
+ if err = mc.readUntilEOF(); err != nil {
+ return nil, err
+ }
+
+ // Rows
+ if err := mc.readUntilEOF(); err != nil {
+ return nil, err
+ }
+ }
+
+ if err := mc.discardResults(); err != nil {
+ return nil, err
+ }
+
+ return &mysqlResult{
+ affectedRows: int64(mc.affectedRows),
+ insertId: int64(mc.insertId),
+ }, nil
+}
+
+func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
+ return stmt.query(args)
+}
+
+func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
+ if stmt.mc.closed.IsSet() {
+ errLog.Print(ErrInvalidConn)
+ return nil, driver.ErrBadConn
+ }
+ // Send command
+ err := stmt.writeExecutePacket(args)
+ if err != nil {
+ return nil, stmt.mc.markBadConn(err)
+ }
+
+ mc := stmt.mc
+
+ // Read Result
+ resLen, err := mc.readResultSetHeaderPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ rows := new(binaryRows)
+
+ if resLen > 0 {
+ rows.mc = mc
+ rows.rs.columns, err = mc.readColumns(resLen)
+ } else {
+ rows.rs.done = true
+
+ switch err := rows.NextResultSet(); err {
+ case nil, io.EOF:
+ return rows, nil
+ default:
+ return nil, err
+ }
+ }
+
+ return rows, err
+}
+
+var jsonType = reflect.TypeOf(json.RawMessage{})
+
+type converter struct{}
+
+// ConvertValue mirrors the reference/default converter in database/sql/driver
+// with _one_ exception. We support uint64 with their high bit and the default
+// implementation does not. This function should be kept in sync with
+// database/sql/driver defaultConverter.ConvertValue() except for that
+// deliberate difference.
+func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
+ if driver.IsValue(v) {
+ return v, nil
+ }
+
+ if vr, ok := v.(driver.Valuer); ok {
+ sv, err := callValuerValue(vr)
+ if err != nil {
+ return nil, err
+ }
+ if driver.IsValue(sv) {
+ return sv, nil
+ }
+ // A value returend from the Valuer interface can be "a type handled by
+ // a database driver's NamedValueChecker interface" so we should accept
+ // uint64 here as well.
+ if u, ok := sv.(uint64); ok {
+ return u, nil
+ }
+ return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
+ }
+ rv := reflect.ValueOf(v)
+ switch rv.Kind() {
+ case reflect.Ptr:
+ // indirect pointers
+ if rv.IsNil() {
+ return nil, nil
+ } else {
+ return c.ConvertValue(rv.Elem().Interface())
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return rv.Int(), nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return rv.Uint(), nil
+ case reflect.Float32, reflect.Float64:
+ return rv.Float(), nil
+ case reflect.Bool:
+ return rv.Bool(), nil
+ case reflect.Slice:
+ switch t := rv.Type(); {
+ case t == jsonType:
+ return v, nil
+ case t.Elem().Kind() == reflect.Uint8:
+ return rv.Bytes(), nil
+ default:
+ return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind())
+ }
+ case reflect.String:
+ return rv.String(), nil
+ }
+ return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
+}
+
+var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+
+// callValuerValue returns vr.Value(), with one exception:
+// If vr.Value is an auto-generated method on a pointer type and the
+// pointer is nil, it would panic at runtime in the panicwrap
+// method. Treat it like nil instead.
+//
+// This is so people can implement driver.Value on value types and
+// still use nil pointers to those types to mean nil/NULL, just like
+// string/*string.
+//
+// This is an exact copy of the same-named unexported function from the
+// database/sql package.
+func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
+ if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+ rv.IsNil() &&
+ rv.Type().Elem().Implements(valuerReflectType) {
+ return nil, nil
+ }
+ return vr.Value()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/transaction.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/transaction.go
new file mode 100644
index 000000000000..417d72793b1f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/transaction.go
@@ -0,0 +1,31 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+type mysqlTx struct {
+ mc *mysqlConn
+}
+
+func (tx *mysqlTx) Commit() (err error) {
+ if tx.mc == nil || tx.mc.closed.IsSet() {
+ return ErrInvalidConn
+ }
+ err = tx.mc.exec("COMMIT")
+ tx.mc = nil
+ return
+}
+
+func (tx *mysqlTx) Rollback() (err error) {
+ if tx.mc == nil || tx.mc.closed.IsSet() {
+ return ErrInvalidConn
+ }
+ err = tx.mc.exec("ROLLBACK")
+ tx.mc = nil
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/utils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/utils.go
new file mode 100644
index 000000000000..d6545f5be88d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-sql-driver/mysql/utils.go
@@ -0,0 +1,868 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "crypto/tls"
+ "database/sql"
+ "database/sql/driver"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// Registry for custom tls.Configs
+var (
+ tlsConfigLock sync.RWMutex
+ tlsConfigRegistry map[string]*tls.Config
+)
+
+// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open.
+// Use the key as a value in the DSN where tls=value.
+//
+// Note: The provided tls.Config is exclusively owned by the driver after
+// registering it.
+//
+// rootCertPool := x509.NewCertPool()
+// pem, err := ioutil.ReadFile("/path/ca-cert.pem")
+// if err != nil {
+// log.Fatal(err)
+// }
+// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
+// log.Fatal("Failed to append PEM.")
+// }
+// clientCert := make([]tls.Certificate, 0, 1)
+// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
+// if err != nil {
+// log.Fatal(err)
+// }
+// clientCert = append(clientCert, certs)
+// mysql.RegisterTLSConfig("custom", &tls.Config{
+// RootCAs: rootCertPool,
+// Certificates: clientCert,
+// })
+// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
+//
+func RegisterTLSConfig(key string, config *tls.Config) error {
+ if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" {
+ return fmt.Errorf("key '%s' is reserved", key)
+ }
+
+ tlsConfigLock.Lock()
+ if tlsConfigRegistry == nil {
+ tlsConfigRegistry = make(map[string]*tls.Config)
+ }
+
+ tlsConfigRegistry[key] = config
+ tlsConfigLock.Unlock()
+ return nil
+}
+
+// DeregisterTLSConfig removes the tls.Config associated with key.
+func DeregisterTLSConfig(key string) {
+ tlsConfigLock.Lock()
+ if tlsConfigRegistry != nil {
+ delete(tlsConfigRegistry, key)
+ }
+ tlsConfigLock.Unlock()
+}
+
+func getTLSConfigClone(key string) (config *tls.Config) {
+ tlsConfigLock.RLock()
+ if v, ok := tlsConfigRegistry[key]; ok {
+ config = v.Clone()
+ }
+ tlsConfigLock.RUnlock()
+ return
+}
+
+// Returns the bool value of the input.
+// The 2nd return value indicates if the input was a valid bool value
+func readBool(input string) (value bool, valid bool) {
+ switch input {
+ case "1", "true", "TRUE", "True":
+ return true, true
+ case "0", "false", "FALSE", "False":
+ return false, true
+ }
+
+ // Not a valid bool value
+ return
+}
+
+/******************************************************************************
+* Time related utils *
+******************************************************************************/
+
+func parseDateTime(b []byte, loc *time.Location) (time.Time, error) {
+ const base = "0000-00-00 00:00:00.000000"
+ switch len(b) {
+ case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
+ if string(b) == base[:len(b)] {
+ return time.Time{}, nil
+ }
+
+ year, err := parseByteYear(b)
+ if err != nil {
+ return time.Time{}, err
+ }
+ if year <= 0 {
+ year = 1
+ }
+
+ if b[4] != '-' {
+ return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[4])
+ }
+
+ m, err := parseByte2Digits(b[5], b[6])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if m <= 0 {
+ m = 1
+ }
+ month := time.Month(m)
+
+ if b[7] != '-' {
+ return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[7])
+ }
+
+ day, err := parseByte2Digits(b[8], b[9])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if day <= 0 {
+ day = 1
+ }
+ if len(b) == 10 {
+ return time.Date(year, month, day, 0, 0, 0, 0, loc), nil
+ }
+
+ if b[10] != ' ' {
+ return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[10])
+ }
+
+ hour, err := parseByte2Digits(b[11], b[12])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if b[13] != ':' {
+ return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[13])
+ }
+
+ min, err := parseByte2Digits(b[14], b[15])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if b[16] != ':' {
+ return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[16])
+ }
+
+ sec, err := parseByte2Digits(b[17], b[18])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if len(b) == 19 {
+ return time.Date(year, month, day, hour, min, sec, 0, loc), nil
+ }
+
+ if b[19] != '.' {
+ return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[19])
+ }
+ nsec, err := parseByteNanoSec(b[20:])
+ if err != nil {
+ return time.Time{}, err
+ }
+ return time.Date(year, month, day, hour, min, sec, nsec, loc), nil
+ default:
+ return time.Time{}, fmt.Errorf("invalid time bytes: %s", b)
+ }
+}
+
+func parseByteYear(b []byte) (int, error) {
+ year, n := 0, 1000
+ for i := 0; i < 4; i++ {
+ v, err := bToi(b[i])
+ if err != nil {
+ return 0, err
+ }
+ year += v * n
+ n = n / 10
+ }
+ return year, nil
+}
+
+func parseByte2Digits(b1, b2 byte) (int, error) {
+ d1, err := bToi(b1)
+ if err != nil {
+ return 0, err
+ }
+ d2, err := bToi(b2)
+ if err != nil {
+ return 0, err
+ }
+ return d1*10 + d2, nil
+}
+
+func parseByteNanoSec(b []byte) (int, error) {
+ ns, digit := 0, 100000 // max is 6-digits
+ for i := 0; i < len(b); i++ {
+ v, err := bToi(b[i])
+ if err != nil {
+ return 0, err
+ }
+ ns += v * digit
+ digit /= 10
+ }
+ // nanoseconds has 10-digits. (needs to scale digits)
+ // 10 - 6 = 4, so we have to multiple 1000.
+ return ns * 1000, nil
+}
+
+func bToi(b byte) (int, error) {
+ if b < '0' || b > '9' {
+ return 0, errors.New("not [0-9]")
+ }
+ return int(b - '0'), nil
+}
+
+func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {
+ switch num {
+ case 0:
+ return time.Time{}, nil
+ case 4:
+ return time.Date(
+ int(binary.LittleEndian.Uint16(data[:2])), // year
+ time.Month(data[2]), // month
+ int(data[3]), // day
+ 0, 0, 0, 0,
+ loc,
+ ), nil
+ case 7:
+ return time.Date(
+ int(binary.LittleEndian.Uint16(data[:2])), // year
+ time.Month(data[2]), // month
+ int(data[3]), // day
+ int(data[4]), // hour
+ int(data[5]), // minutes
+ int(data[6]), // seconds
+ 0,
+ loc,
+ ), nil
+ case 11:
+ return time.Date(
+ int(binary.LittleEndian.Uint16(data[:2])), // year
+ time.Month(data[2]), // month
+ int(data[3]), // day
+ int(data[4]), // hour
+ int(data[5]), // minutes
+ int(data[6]), // seconds
+ int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds
+ loc,
+ ), nil
+ }
+ return nil, fmt.Errorf("invalid DATETIME packet length %d", num)
+}
+
+func appendDateTime(buf []byte, t time.Time) ([]byte, error) {
+ year, month, day := t.Date()
+ hour, min, sec := t.Clock()
+ nsec := t.Nanosecond()
+
+ if year < 1 || year > 9999 {
+ return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap
+ }
+ year100 := year / 100
+ year1 := year % 100
+
+ var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape
+ localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1]
+ localBuf[4] = '-'
+ localBuf[5], localBuf[6] = digits10[month], digits01[month]
+ localBuf[7] = '-'
+ localBuf[8], localBuf[9] = digits10[day], digits01[day]
+
+ if hour == 0 && min == 0 && sec == 0 && nsec == 0 {
+ return append(buf, localBuf[:10]...), nil
+ }
+
+ localBuf[10] = ' '
+ localBuf[11], localBuf[12] = digits10[hour], digits01[hour]
+ localBuf[13] = ':'
+ localBuf[14], localBuf[15] = digits10[min], digits01[min]
+ localBuf[16] = ':'
+ localBuf[17], localBuf[18] = digits10[sec], digits01[sec]
+
+ if nsec == 0 {
+ return append(buf, localBuf[:19]...), nil
+ }
+ nsec100000000 := nsec / 100000000
+ nsec1000000 := (nsec / 1000000) % 100
+ nsec10000 := (nsec / 10000) % 100
+ nsec100 := (nsec / 100) % 100
+ nsec1 := nsec % 100
+ localBuf[19] = '.'
+
+ // milli second
+ localBuf[20], localBuf[21], localBuf[22] =
+ digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000]
+ // micro second
+ localBuf[23], localBuf[24], localBuf[25] =
+ digits10[nsec10000], digits01[nsec10000], digits10[nsec100]
+ // nano second
+ localBuf[26], localBuf[27], localBuf[28] =
+ digits01[nsec100], digits10[nsec1], digits01[nsec1]
+
+ // trim trailing zeros
+ n := len(localBuf)
+ for n > 0 && localBuf[n-1] == '0' {
+ n--
+ }
+
+ return append(buf, localBuf[:n]...), nil
+}
+
+// zeroDateTime is used in formatBinaryDateTime to avoid an allocation
+// if the DATE or DATETIME has the zero value.
+// It must never be changed.
+// The current behavior depends on database/sql copying the result.
+var zeroDateTime = []byte("0000-00-00 00:00:00.000000")
+
+const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
+
+func appendMicrosecs(dst, src []byte, decimals int) []byte {
+ if decimals <= 0 {
+ return dst
+ }
+ if len(src) == 0 {
+ return append(dst, ".000000"[:decimals+1]...)
+ }
+
+ microsecs := binary.LittleEndian.Uint32(src[:4])
+ p1 := byte(microsecs / 10000)
+ microsecs -= 10000 * uint32(p1)
+ p2 := byte(microsecs / 100)
+ microsecs -= 100 * uint32(p2)
+ p3 := byte(microsecs)
+
+ switch decimals {
+ default:
+ return append(dst, '.',
+ digits10[p1], digits01[p1],
+ digits10[p2], digits01[p2],
+ digits10[p3], digits01[p3],
+ )
+ case 1:
+ return append(dst, '.',
+ digits10[p1],
+ )
+ case 2:
+ return append(dst, '.',
+ digits10[p1], digits01[p1],
+ )
+ case 3:
+ return append(dst, '.',
+ digits10[p1], digits01[p1],
+ digits10[p2],
+ )
+ case 4:
+ return append(dst, '.',
+ digits10[p1], digits01[p1],
+ digits10[p2], digits01[p2],
+ )
+ case 5:
+ return append(dst, '.',
+ digits10[p1], digits01[p1],
+ digits10[p2], digits01[p2],
+ digits10[p3],
+ )
+ }
+}
+
+func formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) {
+ // length expects the deterministic length of the zero value,
+ // negative time and 100+ hours are automatically added if needed
+ if len(src) == 0 {
+ return zeroDateTime[:length], nil
+ }
+ var dst []byte // return value
+ var p1, p2, p3 byte // current digit pair
+
+ switch length {
+ case 10, 19, 21, 22, 23, 24, 25, 26:
+ default:
+ t := "DATE"
+ if length > 10 {
+ t += "TIME"
+ }
+ return nil, fmt.Errorf("illegal %s length %d", t, length)
+ }
+ switch len(src) {
+ case 4, 7, 11:
+ default:
+ t := "DATE"
+ if length > 10 {
+ t += "TIME"
+ }
+ return nil, fmt.Errorf("illegal %s packet length %d", t, len(src))
+ }
+ dst = make([]byte, 0, length)
+ // start with the date
+ year := binary.LittleEndian.Uint16(src[:2])
+ pt := year / 100
+ p1 = byte(year - 100*uint16(pt))
+ p2, p3 = src[2], src[3]
+ dst = append(dst,
+ digits10[pt], digits01[pt],
+ digits10[p1], digits01[p1], '-',
+ digits10[p2], digits01[p2], '-',
+ digits10[p3], digits01[p3],
+ )
+ if length == 10 {
+ return dst, nil
+ }
+ if len(src) == 4 {
+ return append(dst, zeroDateTime[10:length]...), nil
+ }
+ dst = append(dst, ' ')
+ p1 = src[4] // hour
+ src = src[5:]
+
+ // p1 is 2-digit hour, src is after hour
+ p2, p3 = src[0], src[1]
+ dst = append(dst,
+ digits10[p1], digits01[p1], ':',
+ digits10[p2], digits01[p2], ':',
+ digits10[p3], digits01[p3],
+ )
+ return appendMicrosecs(dst, src[2:], int(length)-20), nil
+}
+
+func formatBinaryTime(src []byte, length uint8) (driver.Value, error) {
+ // length expects the deterministic length of the zero value,
+ // negative time and 100+ hours are automatically added if needed
+ if len(src) == 0 {
+ return zeroDateTime[11 : 11+length], nil
+ }
+ var dst []byte // return value
+
+ switch length {
+ case
+ 8, // time (can be up to 10 when negative and 100+ hours)
+ 10, 11, 12, 13, 14, 15: // time with fractional seconds
+ default:
+ return nil, fmt.Errorf("illegal TIME length %d", length)
+ }
+ switch len(src) {
+ case 8, 12:
+ default:
+ return nil, fmt.Errorf("invalid TIME packet length %d", len(src))
+ }
+ // +2 to enable negative time and 100+ hours
+ dst = make([]byte, 0, length+2)
+ if src[0] == 1 {
+ dst = append(dst, '-')
+ }
+ days := binary.LittleEndian.Uint32(src[1:5])
+ hours := int64(days)*24 + int64(src[5])
+
+ if hours >= 100 {
+ dst = strconv.AppendInt(dst, hours, 10)
+ } else {
+ dst = append(dst, digits10[hours], digits01[hours])
+ }
+
+ min, sec := src[6], src[7]
+ dst = append(dst, ':',
+ digits10[min], digits01[min], ':',
+ digits10[sec], digits01[sec],
+ )
+ return appendMicrosecs(dst, src[8:], int(length)-9), nil
+}
+
+/******************************************************************************
+* Convert from and to bytes *
+******************************************************************************/
+
+func uint64ToBytes(n uint64) []byte {
+ return []byte{
+ byte(n),
+ byte(n >> 8),
+ byte(n >> 16),
+ byte(n >> 24),
+ byte(n >> 32),
+ byte(n >> 40),
+ byte(n >> 48),
+ byte(n >> 56),
+ }
+}
+
+func uint64ToString(n uint64) []byte {
+ var a [20]byte
+ i := 20
+
+ // U+0030 = 0
+ // ...
+ // U+0039 = 9
+
+ var q uint64
+ for n >= 10 {
+ i--
+ q = n / 10
+ a[i] = uint8(n-q*10) + 0x30
+ n = q
+ }
+
+ i--
+ a[i] = uint8(n) + 0x30
+
+ return a[i:]
+}
+
+// treats string value as unsigned integer representation
+func stringToInt(b []byte) int {
+ val := 0
+ for i := range b {
+ val *= 10
+ val += int(b[i] - 0x30)
+ }
+ return val
+}
+
+// returns the string read as a bytes slice, wheter the value is NULL,
+// the number of bytes read and an error, in case the string is longer than
+// the input slice
+func readLengthEncodedString(b []byte) ([]byte, bool, int, error) {
+ // Get length
+ num, isNull, n := readLengthEncodedInteger(b)
+ if num < 1 {
+ return b[n:n], isNull, n, nil
+ }
+
+ n += int(num)
+
+ // Check data length
+ if len(b) >= n {
+ return b[n-int(num) : n : n], false, n, nil
+ }
+ return nil, false, n, io.EOF
+}
+
+// returns the number of bytes skipped and an error, in case the string is
+// longer than the input slice
+func skipLengthEncodedString(b []byte) (int, error) {
+ // Get length
+ num, _, n := readLengthEncodedInteger(b)
+ if num < 1 {
+ return n, nil
+ }
+
+ n += int(num)
+
+ // Check data length
+ if len(b) >= n {
+ return n, nil
+ }
+ return n, io.EOF
+}
+
+// returns the number read, whether the value is NULL and the number of bytes read
+func readLengthEncodedInteger(b []byte) (uint64, bool, int) {
+ // See issue #349
+ if len(b) == 0 {
+ return 0, true, 1
+ }
+
+ switch b[0] {
+ // 251: NULL
+ case 0xfb:
+ return 0, true, 1
+
+ // 252: value of following 2
+ case 0xfc:
+ return uint64(b[1]) | uint64(b[2])<<8, false, 3
+
+ // 253: value of following 3
+ case 0xfd:
+ return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4
+
+ // 254: value of following 8
+ case 0xfe:
+ return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 |
+ uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 |
+ uint64(b[7])<<48 | uint64(b[8])<<56,
+ false, 9
+ }
+
+ // 0-250: value of first byte
+ return uint64(b[0]), false, 1
+}
+
+// encodes a uint64 value and appends it to the given bytes slice
+func appendLengthEncodedInteger(b []byte, n uint64) []byte {
+ switch {
+ case n <= 250:
+ return append(b, byte(n))
+
+ case n <= 0xffff:
+ return append(b, 0xfc, byte(n), byte(n>>8))
+
+ case n <= 0xffffff:
+ return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16))
+ }
+ return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24),
+ byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56))
+}
+
+// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize.
+// If cap(buf) is not enough, reallocate new buffer.
+func reserveBuffer(buf []byte, appendSize int) []byte {
+ newSize := len(buf) + appendSize
+ if cap(buf) < newSize {
+ // Grow buffer exponentially
+ newBuf := make([]byte, len(buf)*2+appendSize)
+ copy(newBuf, buf)
+ buf = newBuf
+ }
+ return buf[:newSize]
+}
+
+// escapeBytesBackslash escapes []byte with backslashes (\)
+// This escapes the contents of a string (provided as []byte) by adding backslashes before special
+// characters, and turning others into specific escape sequences, such as
+// turning newlines into \n and null bytes into \0.
+// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932
+func escapeBytesBackslash(buf, v []byte) []byte {
+ pos := len(buf)
+ buf = reserveBuffer(buf, len(v)*2)
+
+ for _, c := range v {
+ switch c {
+ case '\x00':
+ buf[pos] = '\\'
+ buf[pos+1] = '0'
+ pos += 2
+ case '\n':
+ buf[pos] = '\\'
+ buf[pos+1] = 'n'
+ pos += 2
+ case '\r':
+ buf[pos] = '\\'
+ buf[pos+1] = 'r'
+ pos += 2
+ case '\x1a':
+ buf[pos] = '\\'
+ buf[pos+1] = 'Z'
+ pos += 2
+ case '\'':
+ buf[pos] = '\\'
+ buf[pos+1] = '\''
+ pos += 2
+ case '"':
+ buf[pos] = '\\'
+ buf[pos+1] = '"'
+ pos += 2
+ case '\\':
+ buf[pos] = '\\'
+ buf[pos+1] = '\\'
+ pos += 2
+ default:
+ buf[pos] = c
+ pos++
+ }
+ }
+
+ return buf[:pos]
+}
+
+// escapeStringBackslash is similar to escapeBytesBackslash but for string.
+func escapeStringBackslash(buf []byte, v string) []byte {
+ pos := len(buf)
+ buf = reserveBuffer(buf, len(v)*2)
+
+ for i := 0; i < len(v); i++ {
+ c := v[i]
+ switch c {
+ case '\x00':
+ buf[pos] = '\\'
+ buf[pos+1] = '0'
+ pos += 2
+ case '\n':
+ buf[pos] = '\\'
+ buf[pos+1] = 'n'
+ pos += 2
+ case '\r':
+ buf[pos] = '\\'
+ buf[pos+1] = 'r'
+ pos += 2
+ case '\x1a':
+ buf[pos] = '\\'
+ buf[pos+1] = 'Z'
+ pos += 2
+ case '\'':
+ buf[pos] = '\\'
+ buf[pos+1] = '\''
+ pos += 2
+ case '"':
+ buf[pos] = '\\'
+ buf[pos+1] = '"'
+ pos += 2
+ case '\\':
+ buf[pos] = '\\'
+ buf[pos+1] = '\\'
+ pos += 2
+ default:
+ buf[pos] = c
+ pos++
+ }
+ }
+
+ return buf[:pos]
+}
+
+// escapeBytesQuotes escapes apostrophes in []byte by doubling them up.
+// This escapes the contents of a string by doubling up any apostrophes that
+// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in
+// effect on the server.
+// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038
+func escapeBytesQuotes(buf, v []byte) []byte {
+ pos := len(buf)
+ buf = reserveBuffer(buf, len(v)*2)
+
+ for _, c := range v {
+ if c == '\'' {
+ buf[pos] = '\''
+ buf[pos+1] = '\''
+ pos += 2
+ } else {
+ buf[pos] = c
+ pos++
+ }
+ }
+
+ return buf[:pos]
+}
+
+// escapeStringQuotes is similar to escapeBytesQuotes but for string.
+func escapeStringQuotes(buf []byte, v string) []byte {
+ pos := len(buf)
+ buf = reserveBuffer(buf, len(v)*2)
+
+ for i := 0; i < len(v); i++ {
+ c := v[i]
+ if c == '\'' {
+ buf[pos] = '\''
+ buf[pos+1] = '\''
+ pos += 2
+ } else {
+ buf[pos] = c
+ pos++
+ }
+ }
+
+ return buf[:pos]
+}
+
+/******************************************************************************
+* Sync utils *
+******************************************************************************/
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
+
+// atomicBool is a wrapper around uint32 for usage as a boolean value with
+// atomic access.
+type atomicBool struct {
+ _noCopy noCopy
+ value uint32
+}
+
+// IsSet returns whether the current boolean value is true
+func (ab *atomicBool) IsSet() bool {
+ return atomic.LoadUint32(&ab.value) > 0
+}
+
+// Set sets the value of the bool regardless of the previous value
+func (ab *atomicBool) Set(value bool) {
+ if value {
+ atomic.StoreUint32(&ab.value, 1)
+ } else {
+ atomic.StoreUint32(&ab.value, 0)
+ }
+}
+
+// TrySet sets the value of the bool and returns whether the value changed
+func (ab *atomicBool) TrySet(value bool) bool {
+ if value {
+ return atomic.SwapUint32(&ab.value, 1) == 0
+ }
+ return atomic.SwapUint32(&ab.value, 0) > 0
+}
+
+// atomicError is a wrapper for atomically accessed error values
+type atomicError struct {
+ _noCopy noCopy
+ value atomic.Value
+}
+
+// Set sets the error value regardless of the previous value.
+// The value must not be nil
+func (ae *atomicError) Set(value error) {
+ ae.value.Store(value)
+}
+
+// Value returns the current error value
+func (ae *atomicError) Value() error {
+ if v := ae.value.Load(); v != nil {
+ // this will panic if the value doesn't implement the error interface
+ return v.(error)
+ }
+ return nil
+}
+
+func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
+ dargs := make([]driver.Value, len(named))
+ for n, param := range named {
+ if len(param.Name) > 0 {
+ // TODO: support the use of Named Parameters #561
+ return nil, errors.New("mysql: driver does not support the use of Named Parameters")
+ }
+ dargs[n] = param.Value
+ }
+ return dargs, nil
+}
+
+func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
+ switch sql.IsolationLevel(level) {
+ case sql.LevelRepeatableRead:
+ return "REPEATABLE READ", nil
+ case sql.LevelReadCommitted:
+ return "READ COMMITTED", nil
+ case sql.LevelReadUncommitted:
+ return "READ UNCOMMITTED", nil
+ case sql.LevelSerializable:
+ return "SERIALIZABLE", nil
+ default:
+ return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/.gitignore
new file mode 100644
index 000000000000..63d8a7129a85
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+.idea/
+go.sum
+.vscode/
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/LICENSE
new file mode 100644
index 000000000000..e7af997874f2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 zhaopeng
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/README.md
new file mode 100644
index 000000000000..83ce6e8e0cd1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/README.md
@@ -0,0 +1,26 @@
+# gf-jwt v2
+
+## Use
+
+Download and install
+
+```sh
+$ go get github.com/gogf/gf-jwt/v2
+```
+
+Import
+
+```go
+import "github.com/gogf/gf-jwt/v2"
+```
+
+
+![login](screenshot/1.png)
+
+![check user info](screenshot/2.png)
+
+![refresh token](screenshot/3.png)
+
+![logout](screenshot/4.png)
+
+![check user info again](screenshot/5.png)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/README_zh.md b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/README_zh.md
new file mode 100644
index 000000000000..8af0db3f9934
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/README_zh.md
@@ -0,0 +1,26 @@
+# gf-jwt v2
+
+## Use
+
+Download and install
+
+```sh
+$ go get github.com/gogf/gf-jwt/v2
+```
+
+Import
+
+```go
+import "github.com/gogf/gf-jwt/v2"
+```
+
+
+![登录](screenshot/1.png)
+
+![查看用户信息](screenshot/2.png)
+
+![刷新](screenshot/3.png)
+
+![注销](screenshot/4.png)
+
+![再次查看用户信息](screenshot/5.png)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/auth_error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/auth_error.go
new file mode 100644
index 000000000000..8ebfd0687a1b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/auth_error.go
@@ -0,0 +1,71 @@
+package jwt
+
+import "errors"
+
+var (
+ // ErrMissingSecretKey indicates Secret key is required
+ ErrMissingSecretKey = errors.New("secret key is required")
+
+ // ErrForbidden when HTTP status 403 is given
+ ErrForbidden = errors.New("you don't have permission to access this resource")
+
+ // ErrMissingAuthenticatorFunc indicates Authenticator is required
+ ErrMissingAuthenticatorFunc = errors.New("ginJWTMiddleware.Authenticator func is undefined")
+
+ // ErrMissingLoginValues indicates a user tried to authenticate without username or password
+ ErrMissingLoginValues = errors.New("missing Username or Password")
+
+ // ErrFailedAuthentication indicates authentication failed, could be faulty username or password
+ ErrFailedAuthentication = errors.New("incorrect Username or Password")
+
+ // ErrFailedTokenCreation indicates JWT Token failed to create, reason unknown
+ ErrFailedTokenCreation = errors.New("failed to create JWT Token")
+
+ // ErrExpiredToken indicates JWT token has expired. Can't refresh.
+ ErrExpiredToken = errors.New("token is expired") // in practice, this is generated from the jwt library not by us
+
+ // ErrEmptyAuthHeader can be thrown if authing with a HTTP header, the Auth header needs to be set
+ ErrEmptyAuthHeader = errors.New("auth header is empty")
+
+ // ErrMissingExpField missing exp field in token
+ ErrMissingExpField = errors.New("missing exp field")
+
+ // ErrWrongFormatOfExp field must be float64 format
+ ErrWrongFormatOfExp = errors.New("exp must be float64 format")
+
+ // ErrInvalidAuthHeader indicates auth header is invalid, could for example have the wrong Realm name
+ ErrInvalidAuthHeader = errors.New("auth header is invalid")
+
+ // ErrEmptyQueryToken can be thrown if authing with URL Query, the query token variable is empty
+ ErrEmptyQueryToken = errors.New("query token is empty")
+
+ // ErrEmptyCookieToken can be thrown if authing with a cookie, the token cookie is empty
+ ErrEmptyCookieToken = errors.New("cookie token is empty")
+
+ // ErrEmptyParamToken can be thrown if authing with parameter in path, the parameter in path is empty
+ ErrEmptyParamToken = errors.New("parameter token is empty")
+
+ // ErrInvalidSigningAlgorithm indicates signing algorithm is invalid, needs to be HS256, HS384, HS512, RS256, RS384 or RS512
+ ErrInvalidSigningAlgorithm = errors.New("invalid signing algorithm")
+
+ // ErrNoPrivKeyFile indicates that the given private key is unreadable
+ ErrNoPrivKeyFile = errors.New("private key file unreadable")
+
+ // ErrNoPubKeyFile indicates that the given public key is unreadable
+ ErrNoPubKeyFile = errors.New("public key file unreadable")
+
+ // ErrInvalidPrivKey indicates that the given private key is invalid
+ ErrInvalidPrivKey = errors.New("private key invalid")
+
+ // ErrInvalidPubKey indicates the the given public key is invalid
+ ErrInvalidPubKey = errors.New("public key invalid")
+
+ // ErrMissingIdentity identity key and identity value is null
+ ErrMissingIdentity = errors.New("payload don't have identity key and identity value")
+
+ // ErrMissingContext indicates Context is required
+ ErrMissingContext = errors.New("context is required")
+
+ // ErrInvalidToken indicates JWT token has invalid. Can't refresh.
+ ErrInvalidToken = errors.New("token is invalid")
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/auth_jwt.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/auth_jwt.go
new file mode 100644
index 000000000000..a738976e31f9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/auth_jwt.go
@@ -0,0 +1,803 @@
+package jwt
+
+import (
+ "context"
+ "crypto/rsa"
+ "github.com/gogf/gf/v2/crypto/gmd5"
+ "github.com/gogf/gf/v2/frame/g"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/gogf/gf/v2/os/gcache"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/golang-jwt/jwt/v4"
+)
+
+// MapClaims type that uses the map[string]interface{} for JSON decoding
+// This is the default claims type if you don't supply one
+type MapClaims map[string]interface{}
+
+// GfJWTMiddleware provides a Json-Web-Token authentication implementation. On failure, a 401 HTTP response
+// is returned. On success, the wrapped middleware is called, and the userID is made available as
+// c.Get("userID").(string).
+// Users can get a token by posting a json request to LoginHandler. The token then needs to be passed in
+// the Authentication header. Example: Authorization:Bearer XXX_TOKEN_XXX
+type GfJWTMiddleware struct {
+ // Realm name to display to the user. Required.
+ Realm string
+
+ // signing algorithm - possible values are HS256, HS384, HS512, RS256, RS384 or RS512
+ // Optional, default is HS256.
+ SigningAlgorithm string
+
+ // Secret key used for signing. Required.
+ Key []byte
+
+ // Callback to retrieve key used for signing. Setting KeyFunc will bypass
+ // all other key settings
+ KeyFunc func(token *jwt.Token) (interface{}, error)
+
+ // Duration that a jwt token is valid. Optional, defaults to one hour.
+ Timeout time.Duration
+
+ // This field allows clients to refresh their token until MaxRefresh has passed.
+ // Note that clients can refresh their token in the last moment of MaxRefresh.
+ // This means that the maximum validity timespan for a token is TokenTime + MaxRefresh.
+ // Optional, defaults to 0 meaning not refreshable.
+ MaxRefresh time.Duration
+
+ // Callback function that should perform the authentication of the user based on login info.
+ // Must return user data as user identifier, it will be stored in Claim Array. Required.
+ // Check error (e) to determine the appropriate error message.
+ Authenticator func(ctx context.Context) (interface{}, error)
+
+ // Callback function that should perform the authorization of the authenticated user. Called
+ // only after an authentication success. Must return true on success, false on failure.
+ // Optional, default to success.
+ Authorizator func(data interface{}, ctx context.Context) bool
+
+ // Callback function that will be called during login.
+ // Using this function it is possible to add additional payload data to the web token.
+ // The data is then made available during requests via c.Get(jwt.PayloadKey).
+ // Note that the payload is not encrypted.
+ // The attributes mentioned on jwt.io can't be used as keys for the map.
+ // Optional, by default no additional data will be set.
+ PayloadFunc func(data interface{}) MapClaims
+
+ // User can define own Unauthorized func.
+ Unauthorized func(ctx context.Context, code int, message string)
+
+ // Set the identity handler function
+ IdentityHandler func(ctx context.Context) interface{}
+
+ // Set the identity key
+ IdentityKey string
+
+ // TokenLookup is a string in the form of ":" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:"
+ // - "query:"
+ // - "cookie:"
+ TokenLookup string
+
+ // TokenHeadName is a string in the header. Default value is "Bearer"
+ TokenHeadName string
+
+ // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
+ TimeFunc func() time.Time
+
+ // HTTP Status messages for when something in the JWT middleware fails.
+ // Check error (e) to determine the appropriate error message.
+ HTTPStatusMessageFunc func(e error, ctx context.Context) string
+
+ // Private key file for asymmetric algorithms
+ PrivKeyFile string
+
+ // Private Key bytes for asymmetric algorithms
+ //
+ // Note: PrivKeyFile takes precedence over PrivKeyBytes if both are set
+ PrivKeyBytes []byte
+
+ // Public key file for asymmetric algorithms
+ PubKeyFile string
+
+ // Private key passphrase
+ PrivateKeyPassphrase string
+
+ // Public key bytes for asymmetric algorithms.
+ //
+ // Note: PubKeyFile takes precedence over PubKeyBytes if both are set
+ PubKeyBytes []byte
+
+ // Private key
+ privKey *rsa.PrivateKey
+
+ // Public key
+ pubKey *rsa.PublicKey
+
+ // Optionally return the token as a cookie
+ SendCookie bool
+
+ // Duration that a cookie is valid. Optional, by default equals to Timeout value.
+ CookieMaxAge time.Duration
+
+ // Allow insecure cookies for development over http
+ SecureCookie bool
+
+ // Allow cookies to be accessed client side for development
+ CookieHTTPOnly bool
+
+ // Allow cookie domain change for development
+ CookieDomain string
+
+ // SendAuthorization allow return authorization header for every request
+ SendAuthorization bool
+
+ // Disable abort() of context.
+ DisabledAbort bool
+
+ // CookieName allow cookie name change for development
+ CookieName string
+
+ // CacheAdapter
+ CacheAdapter gcache.Adapter
+}
+
+var (
+ // TokenKey default jwt token key in params
+ TokenKey = "JWT_TOKEN"
+ // PayloadKey default jwt payload key in params
+ PayloadKey = "JWT_PAYLOAD"
+ // IdentityKey default identity key
+ IdentityKey = "identity"
+ // The blacklist stores tokens that have not expired but have been deactivated.
+ blacklist = gcache.New()
+)
+
+// New for check error with GfJWTMiddleware
+func New(mw *GfJWTMiddleware) *GfJWTMiddleware {
+ if mw.TokenLookup == "" {
+ mw.TokenLookup = "header:Authorization"
+ }
+
+ if mw.SigningAlgorithm == "" {
+ mw.SigningAlgorithm = "HS256"
+ }
+
+ if mw.Timeout == 0 {
+ mw.Timeout = time.Hour
+ }
+
+ if mw.TimeFunc == nil {
+ mw.TimeFunc = time.Now
+ }
+
+ mw.TokenHeadName = strings.TrimSpace(mw.TokenHeadName)
+ if len(mw.TokenHeadName) == 0 {
+ mw.TokenHeadName = "Bearer"
+ }
+
+ if mw.Authorizator == nil {
+ mw.Authorizator = func(data interface{}, ctx context.Context) bool {
+ return true
+ }
+ }
+
+ if mw.Unauthorized == nil {
+ mw.Unauthorized = func(ctx context.Context, code int, message string) {
+ r := g.RequestFromCtx(ctx)
+ r.Response.WriteJson(g.Map{
+ "code": code,
+ "message": message,
+ })
+ }
+ }
+
+ if mw.IdentityKey == "" {
+ mw.IdentityKey = IdentityKey
+ }
+
+ if mw.IdentityHandler == nil {
+ mw.IdentityHandler = func(ctx context.Context) interface{} {
+ claims := ExtractClaims(ctx)
+ return claims[mw.IdentityKey]
+ }
+ }
+
+ if mw.HTTPStatusMessageFunc == nil {
+ mw.HTTPStatusMessageFunc = func(e error, ctx context.Context) string {
+ return e.Error()
+ }
+ }
+
+ if mw.Realm == "" {
+ mw.Realm = "gf jwt"
+ }
+
+ if mw.CookieMaxAge == 0 {
+ mw.CookieMaxAge = mw.Timeout
+ }
+
+ if mw.CookieName == "" {
+ mw.CookieName = "jwt"
+ }
+
+ // bypass other key settings if KeyFunc is set
+ if mw.KeyFunc != nil {
+ return nil
+ }
+
+ if mw.usingPublicKeyAlgo() {
+ if err := mw.readKeys(); err != nil {
+ panic(err)
+ }
+ }
+
+ if mw.Key == nil {
+ panic(ErrMissingSecretKey)
+ }
+
+ if mw.CacheAdapter != nil {
+ blacklist.SetAdapter(mw.CacheAdapter)
+ }
+
+ return mw
+}
+
+// MiddlewareFunc makes GfJWTMiddleware implement the Middleware interface.
+func (mw *GfJWTMiddleware) MiddlewareFunc() ghttp.HandlerFunc {
+ return func(r *ghttp.Request) {
+ mw.middlewareImpl(r.GetCtx())
+ }
+}
+
+// GetClaimsFromJWT get claims from JWT token
+func (mw *GfJWTMiddleware) GetClaimsFromJWT(ctx context.Context) (MapClaims, string, error) {
+ r := g.RequestFromCtx(ctx)
+
+ token, err := mw.parseToken(r)
+ if err != nil {
+ return nil, "", err
+ }
+
+ if mw.SendAuthorization {
+ token := r.Get(TokenKey).String()
+ if len(token) > 0 {
+ r.Header.Set("Authorization", mw.TokenHeadName+" "+token)
+ }
+ }
+
+ claims := MapClaims{}
+ for key, value := range token.Claims.(jwt.MapClaims) {
+ claims[key] = value
+ }
+
+ return claims, token.Raw, nil
+}
+
+// LoginHandler can be used by clients to get a jwt token.
+// Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
+// Reply will be of the form {"token": "TOKEN"}.
+func (mw *GfJWTMiddleware) LoginHandler(ctx context.Context) (tokenString string, expire time.Time) {
+ if mw.Authenticator == nil {
+ mw.unauthorized(ctx, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrMissingAuthenticatorFunc, ctx))
+ return
+ }
+
+ data, err := mw.Authenticator(ctx)
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx))
+ return
+ }
+
+ r := g.RequestFromCtx(ctx)
+ // Create the token
+ token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
+ claims := token.Claims.(jwt.MapClaims)
+
+ if mw.PayloadFunc != nil {
+ for key, value := range mw.PayloadFunc(data) {
+ claims[key] = value
+ }
+ }
+
+ if _, ok := claims[mw.IdentityKey]; !ok {
+ mw.unauthorized(ctx, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrMissingIdentity, ctx))
+ return
+ }
+
+ expire = mw.TimeFunc().Add(mw.Timeout)
+ claims["exp"] = expire.Unix()
+ claims["orig_iat"] = mw.TimeFunc().Unix()
+
+ tokenString, err = mw.signedString(token)
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrFailedTokenCreation, ctx))
+ return
+ }
+
+ // set cookie
+ if mw.SendCookie {
+ expireCookie := mw.TimeFunc().Add(mw.CookieMaxAge)
+ maxAge := int(expireCookie.Unix() - mw.TimeFunc().Unix())
+ r.Cookie.SetCookie(mw.CookieName, tokenString, mw.CookieDomain, "/", time.Duration(maxAge)*time.Second)
+ }
+
+ return
+}
+
+// LogoutHandler can be used by clients to remove the jwt cookie (if set)
+func (mw *GfJWTMiddleware) LogoutHandler(ctx context.Context) {
+ r := g.RequestFromCtx(ctx)
+
+ // delete auth cookie
+ if mw.SendCookie {
+ r.Cookie.SetCookie(mw.CookieName, "", mw.CookieDomain, "/", -1)
+ }
+
+ claims, token, err := mw.CheckIfTokenExpire(ctx)
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx))
+ return
+ }
+
+ err = mw.setBlacklist(ctx, token, claims)
+
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx))
+ return
+ }
+
+ return
+}
+
+// RefreshHandler can be used to refresh a token. The token still needs to be valid on refresh.
+// Shall be put under an endpoint that is using the GfJWTMiddleware.
+// Reply will be of the form {"token": "TOKEN"}.
+func (mw *GfJWTMiddleware) RefreshHandler(ctx context.Context) (tokenString string, expire time.Time) {
+ tokenString, expire, err := mw.RefreshToken(ctx)
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx))
+ return
+ }
+
+ return
+}
+
+// RefreshToken refresh token and check if token is expired
+func (mw *GfJWTMiddleware) RefreshToken(ctx context.Context) (string, time.Time, error) {
+ claims, token, err := mw.CheckIfTokenExpire(ctx)
+ if err != nil {
+ return "", time.Now(), err
+ }
+
+ r := g.RequestFromCtx(ctx)
+ // Create the token
+ newToken := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
+ newClaims := newToken.Claims.(jwt.MapClaims)
+
+ for key := range claims {
+ newClaims[key] = claims[key]
+ }
+
+ expire := mw.TimeFunc().Add(mw.Timeout)
+ newClaims["exp"] = expire.Unix()
+ newClaims["orig_iat"] = mw.TimeFunc().Unix()
+ tokenString, err := mw.signedString(newToken)
+ if err != nil {
+ return "", time.Now(), err
+ }
+
+ // set cookie
+ if mw.SendCookie {
+ expireCookie := mw.TimeFunc().Add(mw.CookieMaxAge)
+ maxAge := int(expireCookie.Unix() - time.Now().Unix())
+ r.Cookie.SetCookie(mw.CookieName, tokenString, mw.CookieDomain, "/", time.Duration(maxAge)*time.Second)
+ }
+
+ // set old token in blacklist
+ err = mw.setBlacklist(ctx, token, claims)
+ if err != nil {
+ return "", time.Now(), err
+ }
+
+ return tokenString, expire, nil
+}
+
+// CheckIfTokenExpire check if token expire
+func (mw *GfJWTMiddleware) CheckIfTokenExpire(ctx context.Context) (jwt.MapClaims, string, error) {
+ r := g.RequestFromCtx(ctx)
+
+ token, err := mw.parseToken(r)
+ if err != nil {
+ // If we receive an error, and the error is anything other than a single
+ // ValidationErrorExpired, we want to return the error.
+ // If the error is just ValidationErrorExpired, we want to continue, as we can still
+ // refresh the token if it's within the MaxRefresh time.
+ // (see https://github.com/appleboy/gin-jwt/issues/176)
+ validationErr, ok := err.(*jwt.ValidationError)
+ if !ok || validationErr.Errors != jwt.ValidationErrorExpired {
+ return nil, "", err
+ }
+ }
+
+ in, err := mw.inBlacklist(ctx, token.Raw)
+ if err != nil {
+ return nil, "", err
+ }
+ if in {
+ return nil, "", ErrInvalidToken
+ }
+
+ claims := token.Claims.(jwt.MapClaims)
+
+ origIat := int64(claims["orig_iat"].(float64))
+
+ if origIat < mw.TimeFunc().Add(-mw.MaxRefresh).Unix() {
+ return nil, "", ErrExpiredToken
+ }
+
+ return claims, token.Raw, nil
+}
+
+// TokenGenerator method that clients can use to get a jwt token.
+func (mw *GfJWTMiddleware) TokenGenerator(data interface{}) (string, time.Time, error) {
+ token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
+ claims := token.Claims.(jwt.MapClaims)
+
+ if mw.PayloadFunc != nil {
+ for key, value := range mw.PayloadFunc(data) {
+ claims[key] = value
+ }
+ }
+
+ expire := mw.TimeFunc().UTC().Add(mw.Timeout)
+ claims["exp"] = expire.Unix()
+ claims["orig_iat"] = mw.TimeFunc().Unix()
+ tokenString, err := mw.signedString(token)
+ if err != nil {
+ return "", time.Time{}, err
+ }
+
+ return tokenString, expire, nil
+}
+
+// GetToken help to get the JWT token string
+func (mw *GfJWTMiddleware) GetToken(ctx context.Context) string {
+ r := g.RequestFromCtx(ctx)
+ token := r.Get(TokenKey).String()
+ if len(token) == 0 {
+ return ""
+ }
+ return token
+}
+
+// GetPayload help to get the payload map
+func (mw *GfJWTMiddleware) GetPayload(ctx context.Context) string {
+ r := g.RequestFromCtx(ctx)
+ token := r.Get(PayloadKey).String()
+ if len(token) == 0 {
+ return ""
+ }
+ return token
+}
+
+// GetIdentity help to get the identity
+func (mw *GfJWTMiddleware) GetIdentity(ctx context.Context) interface{} {
+ r := g.RequestFromCtx(ctx)
+ return r.Get(mw.IdentityKey)
+}
+
+// ExtractClaims help to extract the JWT claims
+func ExtractClaims(ctx context.Context) MapClaims {
+ r := g.RequestFromCtx(ctx)
+ claims := r.GetParam(PayloadKey).Interface()
+ return claims.(MapClaims)
+}
+
+// ExtractClaimsFromToken help to extract the JWT claims from token
+func ExtractClaimsFromToken(token *jwt.Token) MapClaims {
+ if token == nil {
+ return make(MapClaims)
+ }
+
+ claims := MapClaims{}
+ for key, value := range token.Claims.(jwt.MapClaims) {
+ claims[key] = value
+ }
+
+ return claims
+}
+
+// ================= private func =================
+func (mw *GfJWTMiddleware) readKeys() error {
+ err := mw.privateKey()
+ if err != nil {
+ return err
+ }
+ err = mw.publicKey()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (mw *GfJWTMiddleware) privateKey() error {
+ var keyData []byte
+ if mw.PrivKeyFile == "" {
+ keyData = mw.PrivKeyBytes
+ } else {
+ fileContent, err := ioutil.ReadFile(mw.PrivKeyFile)
+ if err != nil {
+ return ErrNoPrivKeyFile
+ }
+ keyData = fileContent
+ }
+
+ if mw.PrivateKeyPassphrase != "" {
+ //nolint:static check
+ key, err := jwt.ParseRSAPrivateKeyFromPEMWithPassword(keyData, mw.PrivateKeyPassphrase)
+ if err != nil {
+ return ErrInvalidPrivKey
+ }
+ mw.privKey = key
+ return nil
+ }
+
+ key, err := jwt.ParseRSAPrivateKeyFromPEM(keyData)
+ if err != nil {
+ return ErrInvalidPrivKey
+ }
+ mw.privKey = key
+ return nil
+}
+
+func (mw *GfJWTMiddleware) publicKey() error {
+ var keyData []byte
+ if mw.PubKeyFile == "" {
+ keyData = mw.PubKeyBytes
+ } else {
+ fileContent, err := ioutil.ReadFile(mw.PubKeyFile)
+ if err != nil {
+ return ErrNoPubKeyFile
+ }
+ keyData = fileContent
+ }
+
+ key, err := jwt.ParseRSAPublicKeyFromPEM(keyData)
+ if err != nil {
+ return ErrInvalidPubKey
+ }
+ mw.pubKey = key
+ return nil
+}
+
+func (mw *GfJWTMiddleware) usingPublicKeyAlgo() bool {
+ switch mw.SigningAlgorithm {
+ case "RS256", "RS512", "RS384":
+ return true
+ }
+ return false
+}
+
+func (mw *GfJWTMiddleware) signedString(token *jwt.Token) (string, error) {
+ var tokenString string
+ var err error
+ if mw.usingPublicKeyAlgo() {
+ tokenString, err = token.SignedString(mw.privKey)
+ } else {
+ tokenString, err = token.SignedString(mw.Key)
+ }
+ return tokenString, err
+}
+
+func (mw *GfJWTMiddleware) jwtFromHeader(r *ghttp.Request, key string) (string, error) {
+ authHeader := r.Header.Get(key)
+
+ if authHeader == "" {
+ return "", ErrEmptyAuthHeader
+ }
+
+ parts := strings.SplitN(authHeader, " ", 2)
+ if !(len(parts) == 2 && parts[0] == mw.TokenHeadName) {
+ return "", ErrInvalidAuthHeader
+ }
+
+ return parts[1], nil
+}
+
+func (mw *GfJWTMiddleware) jwtFromQuery(r *ghttp.Request, key string) (string, error) {
+ token := r.Get(key).String()
+
+ if token == "" {
+ return "", ErrEmptyQueryToken
+ }
+
+ return token, nil
+}
+
+func (mw *GfJWTMiddleware) jwtFromCookie(r *ghttp.Request, key string) (string, error) {
+ cookie := r.Cookie.Get(key).String()
+
+ if cookie == "" {
+ return "", ErrEmptyCookieToken
+ }
+
+ return cookie, nil
+}
+
+func (mw *GfJWTMiddleware) jwtFromParam(r *ghttp.Request, key string) (string, error) {
+ token := r.Get(key).String()
+
+ if token == "" {
+ return "", ErrEmptyParamToken
+ }
+
+ return token, nil
+}
+
+func (mw *GfJWTMiddleware) parseToken(r *ghttp.Request) (*jwt.Token, error) {
+ var token string
+ var err error
+
+ methods := strings.Split(mw.TokenLookup, ",")
+ for _, method := range methods {
+ if len(token) > 0 {
+ break
+ }
+ parts := strings.Split(strings.TrimSpace(method), ":")
+ k := strings.TrimSpace(parts[0])
+ v := strings.TrimSpace(parts[1])
+ switch k {
+ case "header":
+ token, err = mw.jwtFromHeader(r, v)
+ case "query":
+ token, err = mw.jwtFromQuery(r, v)
+ case "cookie":
+ token, err = mw.jwtFromCookie(r, v)
+ case "param":
+ token, err = mw.jwtFromParam(r, v)
+ }
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ if mw.KeyFunc != nil {
+ return jwt.Parse(token, mw.KeyFunc)
+ }
+
+ return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
+ if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
+ return nil, ErrInvalidSigningAlgorithm
+ }
+ if mw.usingPublicKeyAlgo() {
+ return mw.pubKey, nil
+ }
+
+ // save token string if valid
+ r.SetParam(TokenKey, token)
+
+ return mw.Key, nil
+ })
+}
+
+func (mw *GfJWTMiddleware) parseTokenString(token string) (*jwt.Token, error) {
+ if mw.KeyFunc != nil {
+ return jwt.Parse(token, mw.KeyFunc)
+ }
+
+ return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
+ if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
+ return nil, ErrInvalidSigningAlgorithm
+ }
+ if mw.usingPublicKeyAlgo() {
+ return mw.pubKey, nil
+ }
+
+ return mw.Key, nil
+ })
+}
+
+func (mw *GfJWTMiddleware) unauthorized(ctx context.Context, code int, message string) {
+ r := g.RequestFromCtx(ctx)
+ r.Header.Set("WWW-Authenticate", "JWT realm="+mw.Realm)
+ mw.Unauthorized(ctx, code, message)
+ if !mw.DisabledAbort {
+ r.ExitAll()
+ }
+}
+
+func (mw *GfJWTMiddleware) middlewareImpl(ctx context.Context) {
+ r := g.RequestFromCtx(ctx)
+
+ claims, token, err := mw.GetClaimsFromJWT(ctx)
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx))
+ return
+ }
+
+ if claims["exp"] == nil {
+ mw.unauthorized(ctx, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrMissingExpField, ctx))
+ return
+ }
+
+ if _, ok := claims["exp"].(float64); !ok {
+ mw.unauthorized(ctx, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrWrongFormatOfExp, ctx))
+ return
+ }
+
+ if int64(claims["exp"].(float64)) < mw.TimeFunc().Unix() {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrExpiredToken, ctx))
+ return
+ }
+
+ in, err := mw.inBlacklist(ctx, token)
+ if err != nil {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, ctx))
+ return
+ }
+
+ if in {
+ mw.unauthorized(ctx, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrInvalidToken, ctx))
+ return
+ }
+
+ r.SetParam(PayloadKey, claims)
+
+ identity := mw.IdentityHandler(ctx)
+ if identity != nil {
+ r.SetParam(mw.IdentityKey, identity)
+ }
+
+ if !mw.Authorizator(identity, ctx) {
+ mw.unauthorized(ctx, http.StatusForbidden, mw.HTTPStatusMessageFunc(ErrForbidden, ctx))
+ return
+ }
+
+ //c.Next() todo
+}
+
+func (mw *GfJWTMiddleware) setBlacklist(ctx context.Context, token string, claims jwt.MapClaims) error {
+ // The goal of MD5 is to reduce the key length.
+ token, err := gmd5.EncryptString(token)
+
+ if err != nil {
+ return err
+ }
+
+ exp := int64(claims["exp"].(float64))
+
+ // save duration time = (exp + max_refresh) - now
+ duration := time.Unix(exp, 0).Add(mw.MaxRefresh).Sub(mw.TimeFunc()).Truncate(time.Second)
+
+ // global gcache
+ err = blacklist.Set(ctx, token, true, duration)
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (mw *GfJWTMiddleware) inBlacklist(ctx context.Context, token string) (bool, error) {
+ // The goal of MD5 is to reduce the key length.
+ tokenRaw, err := gmd5.EncryptString(token)
+
+ if err != nil {
+ return false, nil
+ }
+
+ // Global gcache
+ if in, err := blacklist.Contains(ctx, tokenRaw); err != nil {
+ return false, nil
+ } else {
+ return in, nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/stub.go
deleted file mode 100644
index 343b5f84dca4..000000000000
--- a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf-jwt/v2/stub.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/gogf/gf-jwt/v2, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/gogf/gf-jwt/v2 (exports: GfJWTMiddleware; functions: )
-
-// Package gf is a stub of github.com/gogf/gf-jwt/v2, generated by depstubber.
-package gf
-
-import (
- context "context"
- time "time"
-)
-
-type GfJWTMiddleware struct {
- Realm string
- SigningAlgorithm string
- Key []byte
- KeyFunc func(interface{}) (interface{}, error)
- Timeout time.Duration
- MaxRefresh time.Duration
- Authenticator func(context.Context) (interface{}, error)
- Authorizator func(interface{}, context.Context) bool
- PayloadFunc func(interface{}) MapClaims
- Unauthorized func(context.Context, int, string)
- IdentityHandler func(context.Context) interface{}
- IdentityKey string
- TokenLookup string
- TokenHeadName string
- TimeFunc func() time.Time
- HTTPStatusMessageFunc func(error, context.Context) string
- PrivKeyFile string
- PrivKeyBytes []byte
- PubKeyFile string
- PrivateKeyPassphrase string
- PubKeyBytes []byte
- SendCookie bool
- CookieMaxAge time.Duration
- SecureCookie bool
- CookieHTTPOnly bool
- CookieDomain string
- SendAuthorization bool
- DisabledAbort bool
- CookieName string
- CacheAdapter interface{}
-}
-
-func (_ *GfJWTMiddleware) CheckIfTokenExpire(_ context.Context) (interface{}, string, error) {
- return nil, "", nil
-}
-
-func (_ *GfJWTMiddleware) GetClaimsFromJWT(_ context.Context) (MapClaims, string, error) {
- return nil, "", nil
-}
-
-func (_ *GfJWTMiddleware) GetIdentity(_ context.Context) interface{} {
- return nil
-}
-
-func (_ *GfJWTMiddleware) GetPayload(_ context.Context) string {
- return ""
-}
-
-func (_ *GfJWTMiddleware) GetToken(_ context.Context) string {
- return ""
-}
-
-func (_ *GfJWTMiddleware) LoginHandler(_ context.Context) (string, time.Time) {
- return "", time.Time{}
-}
-
-func (_ *GfJWTMiddleware) LogoutHandler(_ context.Context) {}
-
-func (_ *GfJWTMiddleware) MiddlewareFunc() func(interface{}) {
- return nil
-}
-
-func (_ *GfJWTMiddleware) RefreshHandler(_ context.Context) (string, time.Time) {
- return "", time.Time{}
-}
-
-func (_ *GfJWTMiddleware) RefreshToken(_ context.Context) (string, time.Time, error) {
- return "", time.Time{}, nil
-}
-
-func (_ *GfJWTMiddleware) TokenGenerator(_ interface{}) (string, time.Time, error) {
- return "", time.Time{}, nil
-}
-
-type MapClaims map[string]interface{}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.gitattributes b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.gitattributes
new file mode 100644
index 000000000000..8d6f5cfa6bac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.gitattributes
@@ -0,0 +1,3 @@
+*.js linguist-language=GO
+*.css linguist-language=GO
+*.html linguist-language=GO
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.gitignore
new file mode 100644
index 000000000000..5af57e523f00
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.gitignore
@@ -0,0 +1,19 @@
+.buildpath
+.hgignore.swp
+.project
+.orig
+.swp
+.idea/
+.settings/
+.vscode/
+vendor/
+composer.lock
+gitpush.sh
+pkg/
+bin/
+cbuild
+**/.DS_Store
+.vscode/
+.test/
+main
+gf
\ No newline at end of file
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.golangci.yml b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.golangci.yml
new file mode 100644
index 000000000000..c5481fc9588e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/.golangci.yml
@@ -0,0 +1,949 @@
+# This file contains all available configuration options
+# with their default values.
+
+# options for analysis running
+run:
+ # default concurrency is a available CPU number
+ concurrency: 4
+
+ # timeout for analysis, e.g. 30s, 5m, default is 1m
+ timeout: 5m
+
+ # exit code when at least one issue was found, default is 1
+ issues-exit-code: 1
+
+ # include test files or not, default is true
+ tests: false
+
+ # list of build tags, all linters use it. Default is empty list.
+ build-tags:
+# - mytag
+
+ # which dirs to skip: issues from them won't be reported;
+ # can use regexp here: generated.*, regexp is applied on full path;
+ # default value is empty list, but default dirs are skipped independently
+ # from this option's value (see skip-dirs-use-default).
+ # "/" will be replaced by current OS file path separator to properly work
+ # on Windows.
+ skip-dirs:
+ - .example
+ - .test
+
+ # default is true. Enables skipping of directories:
+ # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
+ skip-dirs-use-default: true
+
+ # which files to skip: they will be analyzed, but issues from them
+ # won't be reported. Default value is empty list, but there is
+ # no need to include all autogenerated files, we confidently recognize
+ # autogenerated files. If it's not please let us know.
+ # "/" will be replaced by current OS file path separator to properly work
+ # on Windows.
+ skip-files:
+ - ".*_test\\.go$"
+ - ".*_packed\\.go$"
+
+ # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
+ # If invoked with -mod=readonly, the go command is disallowed from the implicit
+ # automatic updating of go.mod described above. Instead, it fails when any changes
+ # to go.mod are needed. This setting is most useful to check that go.mod does
+ # not need updates, such as in a continuous integration and testing system.
+ # If invoked with -mod=vendor, the go command assumes that the vendor
+ # directory holds the correct copies of dependencies and ignores
+ # the dependency descriptions in go.mod.
+ #modules-download-mode: release|readonly|vendor
+
+ # Allow multiple parallel golangci-lint instances running.
+ # If false (default) - golangci-lint acquires file lock on start.
+ allow-parallel-runners: true
+
+
+# output configuration options
+output:
+ # colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml|github-actions
+ # default is "colored-line-number"
+ format: colored-line-number
+
+ # print lines of code with issue, default is true
+ print-issued-lines: true
+
+ # print linter name in the end of issue text, default is true
+ print-linter-name: true
+
+ # make issues output unique by line, default is true
+ uniq-by-line: true
+
+ # add a prefix to the output file references; default is no prefix
+ path-prefix: ""
+
+ # sorts results by: filepath, line and column
+ sort-results: true
+
+
+# all available settings of specific linters
+linters-settings:
+ bidichk:
+ # The following configurations check for all mentioned invisible unicode
+ # runes. It can be omitted because all runes are enabled by default.
+ left-to-right-embedding: true
+ right-to-left-embedding: true
+ pop-directional-formatting: true
+ left-to-right-override: true
+ right-to-left-override: true
+ left-to-right-isolate: true
+ right-to-left-isolate: true
+ first-strong-isolate: true
+ pop-directional-isolate: true
+
+ cyclop:
+ # the maximal code complexity to report
+ max-complexity: 50
+ # the maximal average package complexity. If it's higher than 0.0 (float) the check is enabled (default 0.0)
+ package-average: 0.0
+ # should ignore tests (default false)
+ skip-tests: false
+
+ dogsled:
+ # checks assignments with too many blank identifiers; default is 2
+ max-blank-identifiers: 2
+
+ dupl:
+ # tokens count to trigger issue, 150 by default
+ threshold: 100
+
+ errcheck:
+ # report about not checking of errors in type assertions: `a := b.(MyStruct)`;
+ # default is false: such cases aren't reported by default.
+ check-type-assertions: false
+
+ # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
+ # default is false: such cases aren't reported by default.
+ check-blank: false
+
+ # [deprecated] comma-separated list of pairs of the form pkg:regex
+ # the regex is used to ignore names within pkg. (default "fmt:.*").
+ # see https://github.com/kisielk/errcheck#the-deprecated-method for details
+ #ignore: fmt:.*,io/ioutil:^Read.*
+
+ # [deprecated] use exclude-functions instead.
+ # path to a file containing a list of functions to exclude from checking
+ # see https://github.com/kisielk/errcheck#excluding-functions for details
+ # exclude: /path/to/file.txt
+
+ # list of functions to exclude from checking, where each entry is a single function to exclude.
+ # see https://github.com/kisielk/errcheck#excluding-functions for details
+ exclude-functions:
+# - io/ioutil.ReadFile
+# - io.Copy(*bytes.Buffer)
+# - io.Copy(os.Stdout)
+
+ errorlint:
+ # Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats
+ errorf: true
+ # Check for plain type assertions and type switches
+ asserts: true
+ # Check for plain error comparisons
+ comparison: true
+
+ exhaustive:
+ # check switch statements in generated files also
+ check-generated: false
+ # presence of "default" case in switch statements satisfies exhaustiveness,
+ # even if all enum members are not listed
+ default-signifies-exhaustive: false
+ # enum members matching the supplied regex do not have to be listed in
+ # switch statements to satisfy exhaustiveness
+ ignore-enum-members: ""
+ # consider enums only in package scopes, not in inner scopes
+ package-scope-only: false
+
+ exhaustivestruct:
+ # Struct Patterns is list of expressions to match struct packages and names
+ # The struct packages have the form example.com/package.ExampleStruct
+ # The matching patterns can use matching syntax from https://pkg.go.dev/path#Match
+ # If this list is empty, all structs are tested.
+ struct-patterns:
+# - '*.Test'
+# - 'example.com/package.ExampleStruct'
+# - '*.Test2'
+# - '*.Embedded'
+# - '*.External'
+
+ forbidigo:
+ # Forbid the following identifiers (identifiers are written using regexp):
+ forbid:
+# - ^print.*$
+# - 'fmt\.Print.*'
+# - fmt.Println.* # too much log noise
+# - ginkgo\\.F.* # these are used just for local development
+ # Exclude godoc examples from forbidigo checks. Default is true.
+ exclude_godoc_examples: false
+
+ funlen:
+ lines: 150
+ statements: 50
+
+ gci:
+ # put imports beginning with prefix after 3rd-party packages;
+ # only support one prefix
+ # if not set, use goimports.local-prefixes
+ local-prefixes: github.com/gogf/gf
+
+ gocognit:
+ # minimal code complexity to report, 30 by default (but we recommend 10-20)
+ min-complexity: 50
+
+ goconst:
+ # minimal length of string constant, 3 by default
+ min-len: 3
+ # minimum occurrences of constant string count to trigger issue, 3 by default
+ min-occurrences: 3
+ # ignore test files, false by default
+ ignore-tests: true
+ # look for existing constants matching the values, true by default
+ match-constant: true
+ # search also for duplicated numbers, false by default
+ numbers: false
+ # minimum value, only works with goconst.numbers, 3 by default
+ min: 3
+ # maximum value, only works with goconst.numbers, 3 by default
+ max: 3
+ # ignore when constant is not used as function argument, true by default
+ ignore-calls: true
+
+ gocritic:
+ # Which checks should be enabled; can't be combined with 'disabled-checks';
+ # See https://go-critic.github.io/overview#checks-overview
+ # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
+ # By default list of stable checks is used.
+ enabled-checks:
+ - nestingReduce
+ - unnamedresult
+ - ruleguard
+ - truncateCmp
+
+ # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
+ disabled-checks:
+ - regexpMust
+ - ifElseChain
+ - exitAfterDefer
+
+ # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
+ # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
+ enabled-tags:
+ - performance
+ disabled-tags:
+ - experimental
+
+ # Settings passed to gocritic.
+ # The settings key is the name of a supported gocritic checker.
+ # The list of supported checkers can be find in https://go-critic.github.io/overview.
+ settings:
+ captLocal: # must be valid enabled check name
+ # whether to restrict checker to params only (default true)
+ paramsOnly: true
+ elseif:
+ # whether to skip balanced if-else pairs (default true)
+ skipBalanced: true
+ hugeParam:
+ # size in bytes that makes the warning trigger (default 80)
+ sizeThreshold: 80
+ nestingReduce:
+ # min number of statements inside a branch to trigger a warning (default 5)
+ bodyWidth: 5
+ rangeExprCopy:
+ # size in bytes that makes the warning trigger (default 512)
+ sizeThreshold: 512
+ # whether to check test functions (default true)
+ skipTestFuncs: true
+ rangeValCopy:
+ # size in bytes that makes the warning trigger (default 128)
+ sizeThreshold: 32
+ # whether to check test functions (default true)
+ skipTestFuncs: true
+ ruleguard:
+ # Enable debug to identify which 'Where' condition was rejected.
+ # The value of the parameter is the name of a function in a ruleguard file.
+ #
+ # When a rule is evaluated:
+ # If:
+ # The Match() clause is accepted; and
+ # One of the conditions in the Where() clause is rejected,
+ # Then:
+ # ruleguard prints the specific Where() condition that was rejected.
+ #
+ # The flag is passed to the ruleguard 'debug-group' argument.
+ debug: 'emptyDecl'
+ # Deprecated, use 'failOn' param.
+ # If set to true, identical to failOn='all', otherwise failOn=''
+ failOnError: false
+ # Determines the behavior when an error occurs while parsing ruleguard files.
+ # If flag is not set, log error and skip rule files that contain an error.
+ # If flag is set, the value must be a comma-separated list of error conditions.
+ # - 'all': fail on all errors.
+ # - 'import': ruleguard rule imports a package that cannot be found.
+ # - 'dsl': gorule file does not comply with the ruleguard DSL.
+ failOn: dsl
+ # Comma-separated list of file paths containing ruleguard rules.
+ # If a path is relative, it is relative to the directory where the golangci-lint command is executed.
+ # The special '${configDir}' variable is substituted with the absolute directory containing the golangci config file.
+ # Glob patterns such as 'rules-*.go' may be specified.
+ rules: '' #${configDir}/ruleguard/rules-*.go,${configDir}/myrule1.go'
+ #tooManyResultsChecker:
+ # maximum number of results (default 5)
+ #maxResults: 10
+ truncateCmp:
+ # whether to skip int/uint/uintptr types (default true)
+ skipArchDependent: true
+ underef:
+ # whether to skip (*x).method() calls where x is a pointer receiver (default true)
+ skipRecvDeref: true
+ unnamedResult:
+ # whether to check exported functions
+ checkExported: true
+
+ gocyclo:
+ # minimal code complexity to report, 30 by default (but we recommend 10-20)
+ min-complexity: 30
+
+ godot:
+ # comments to be checked: `declarations`, `toplevel`, or `all`
+ scope: declarations
+ # list of regexps for excluding particular comment lines from check
+ exclude:
+ # example: exclude comments which contain numbers
+ # - '[0-9]+'
+ # check that each sentence starts with a capital letter
+ capital: false
+
+ godox:
+ # report any comments starting with keywords, this is useful for TODO or FIXME comments that
+ # might be left in the code accidentally and should be resolved before merging
+ keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
+ #- NOTE
+ - BUG
+ - FIXME
+ - OPTIMIZE # marks code that should be optimized before merging
+ - HACK # marks hack-arounds that should be removed before merging
+
+ gofmt:
+ # simplify code: gofmt with `-s` option, true by default
+ simplify: true
+
+ gofumpt:
+ # Select the Go version to target. The default is `1.15`.
+ lang-version: "1.16"
+
+ # Choose whether or not to use the extra rules that are disabled
+ # by default
+ extra-rules: false
+
+ goheader:
+ values:
+ const:
+ # define here const type values in format k:v, for example:
+ # COMPANY: MY COMPANY
+ regexp:
+ # define here regexp type values, for example
+ # AUTHOR: .*@mycompany\.com
+ template: # |-
+ # put here copyright header template for source code files, for example:
+ # Note: {{ YEAR }} is a builtin value that returns the year relative to the current machine time.
+ #
+ # {{ AUTHOR }} {{ COMPANY }} {{ YEAR }}
+ # SPDX-License-Identifier: Apache-2.0
+
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at:
+
+ # http://www.apache.org/licenses/LICENSE-2.0
+
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ template-path:
+ # also as alternative of directive 'template' you may put the path to file with the template source
+
+ goimports:
+ # put imports beginning with prefix after 3rd-party packages;
+ # it's a comma-separated list of prefixes
+ local-prefixes: github.com/gogf/gf
+
+ golint:
+ # minimal confidence for issues, default is 0.8
+ min-confidence: 0.9
+
+ gomnd:
+ settings:
+ mnd:
+ # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.
+ checks: argument,case,condition,operation,return,assign
+ # ignored-numbers: 1000
+ # ignored-files: magic_.*.go
+ # ignored-functions: math.*
+
+ gomoddirectives:
+ # Allow local `replace` directives. Default is false.
+ replace-local: false
+ # List of allowed `replace` directives. Default is empty.
+ replace-allow-list:
+ - launchpad.net/gocheck
+ - github.com/coreos/etcd
+ - google.golang.org/grpc
+ - gitlab.jntmedia.cn/lanren/core
+ # Allow to not explain why the version has been retracted in the `retract` directives. Default is false.
+ retract-allow-no-explanation: false
+ # Forbid the use of the `exclude` directives. Default is false.
+ exclude-forbidden: false
+
+ gomodguard:
+ allowed:
+ modules: # List of allowed modules
+ # - gopkg.in/yaml.v2
+ - gorm.io/gorm
+ - gorm.io/driver/mysql
+ - k8s.io/klog
+ domains: # List of allowed module domains
+ # - golang.org
+ - google.golang.org
+ - gopkg.in
+ - golang.org
+ - github.com
+ - go.uber.org
+ blocked:
+ modules: # List of blocked modules
+ # - github.com/uudashr/go-module: # Blocked module
+ # recommendations: # Recommended modules that should be used instead (Optional)
+ # - golang.org/x/mod
+ # reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional)
+ versions: # List of blocked module version constraints
+ # - github.com/mitchellh/go-homedir: # Blocked module with version constraint
+ # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons
+ # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional)
+ local_replace_directives: false # Set to true to raise lint issues for packages that are loaded from a local path via replace directive
+
+ gosec:
+ # To select a subset of rules to run.
+ # Available rules: https://github.com/securego/gosec#available-rules
+ includes:
+ - G401
+ - G306
+ - G101
+ # To specify a set of rules to explicitly exclude.
+ # Available rules: https://github.com/securego/gosec#available-rules
+ excludes:
+ - G204
+ # Exclude generated files
+ exclude-generated: true
+ # Filter out the issues with a lower severity than the given value. Valid options are: low, medium, high.
+ severity: "low"
+ # Filter out the issues with a lower confidence than the given value. Valid options are: low, medium, high.
+ confidence: "low"
+ # To specify the configuration of rules.
+ # The configuration of rules is not fully documented by gosec:
+ # https://github.com/securego/gosec#configuration
+ # https://github.com/securego/gosec/blob/569328eade2ccbad4ce2d0f21ee158ab5356a5cf/rules/rulelist.go#L60-L102
+ config:
+ G306: "0600"
+ G101:
+ pattern: "(?i)example"
+ ignore_entropy: false
+ entropy_threshold: "80.0"
+ per_char_threshold: "3.0"
+ truncate: "32"
+
+ gosimple:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.16"
+ # https://staticcheck.io/docs/options#checks
+ checks: [ "all" ]
+
+ govet:
+ # report about shadowed variables
+ check-shadowing: true
+
+ # settings per analyzer
+ settings:
+ printf: # analyzer name, run `go tool vet help` to see all analyzers
+ funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer
+ - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
+ - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
+ - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
+ - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
+
+ # enable or disable analyzers by name
+ # run `go tool vet help` to see all analyzers
+ enable:
+ - atomicalign
+ enable-all: false
+ disable:
+ - shadow
+ disable-all: false
+
+ depguard:
+ list-type: blacklist
+ include-go-root: false
+ packages:
+ - github.com/sirupsen/logrus
+ packages-with-error-message:
+ # specify an error message to output when a blacklisted package is used
+ - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
+
+ ifshort:
+ # Maximum length of variable declaration measured in number of lines, after which linter won't suggest using short syntax.
+ # Has higher priority than max-decl-chars.
+ max-decl-lines: 1
+ # Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax.
+ max-decl-chars: 30
+
+ importas:
+ # if set to `true`, force to use alias.
+ no-unaliased: true
+ # List of aliases
+ alias:
+ # using `servingv1` alias for `knative.dev/serving/pkg/apis/serving/v1` package
+ - pkg: knative.dev/serving/pkg/apis/serving/v1
+ alias: servingv1
+ # using `autoscalingv1alpha1` alias for `knative.dev/serving/pkg/apis/autoscaling/v1alpha1` package
+ - pkg: knative.dev/serving/pkg/apis/autoscaling/v1alpha1
+ alias: autoscalingv1alpha1
+ # You can specify the package path by regular expression,
+ # and alias by regular expression expansion syntax like below.
+ # see https://github.com/julz/importas#use-regular-expression for details
+ - pkg: knative.dev/serving/pkg/apis/(\w+)/(v[\w\d]+)
+ alias: $1$2
+
+ ireturn:
+ # ireturn allows using `allow` and `reject` settings at the same time.
+ # Both settings are lists of the keywords and regular expressions matched to interface or package names.
+ # keywords:
+ # - `empty` for `interface{}`
+ # - `error` for errors
+ # - `stdlib` for standard library
+ # - `anon` for anonymous interfaces
+
+ # By default, it allows using errors, empty interfaces, anonymous interfaces,
+ # and interfaces provided by the standard library.
+ allow:
+ - anon
+ - error
+ - empty
+ - stdlib
+ # You can specify idiomatic endings for interface
+ - (or|er)$
+
+ # Reject patterns
+# reject:
+# - github.com\/user\/package\/v4\.Type
+
+ lll:
+ # max line length, lines longer will be reported. Default is 120.
+ # '\t' is counted as 1 character by default, and can be changed with the tab-width option
+ line-length: 240
+ # tab width in spaces. Default to 1.
+ tab-width: 4
+
+ makezero:
+ # Allow only slices initialized with a length of zero. Default is false.
+ always: false
+
+ maligned:
+ # print struct with more effective memory layout or not, false by default
+ suggest-new: true
+
+ misspell:
+ # Correct spellings using locale preferences for US or UK.
+ # Default is to use a neutral variety of English.
+ # Setting locale to US will correct the British spelling of 'colour' to 'color'.
+ locale: US
+ ignore-words:
+ - someword
+
+ nakedret:
+ # make an issue if func has more lines of code than this setting and it has naked returns; default is 30
+ max-func-lines: 30
+
+ nestif:
+ # minimal complexity of if statements to report, 5 by default
+ min-complexity: 4
+
+ nilnil:
+ # By default, nilnil checks all returned types below.
+ checked-types:
+ - ptr
+ - func
+ - iface
+ - map
+ - chan
+
+ nlreturn:
+ # size of the block (including return statement that is still "OK")
+ # so no return split required.
+ block-size: 1
+
+ nolintlint:
+ # Disable to ensure that all nolint directives actually have an effect. Default is true.
+ allow-unused: true
+ # Disable to ensure that nolint directives don't have a leading space. Default is true.
+ allow-leading-space: true
+ # Exclude following linters from requiring an explanation. Default is [].
+ allow-no-explanation: [ ]
+ # Enable to require an explanation of nonzero length after each nolint directive. Default is false.
+ require-explanation: false
+ # Enable to require nolint directives to mention the specific linter being suppressed. Default is false.
+ require-specific: true
+
+ prealloc:
+ # XXX: we don't recommend using this linter before doing performance profiling.
+ # For most programs usage of prealloc will be a premature optimization.
+
+ # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
+ # True by default.
+ simple: true
+ range-loops: true # Report preallocation suggestions on range loops, true by default
+ for-loops: false # Report preallocation suggestions on for loops, false by default
+
+ promlinter:
+ # Promlinter cannot infer all metrics name in static analysis.
+ # Enable strict mode will also include the errors caused by failing to parse the args.
+ strict: false
+ # Please refer to https://github.com/yeya24/promlinter#usage for detailed usage.
+ disabled-linters:
+ # - "Help"
+ # - "MetricUnits"
+ # - "Counter"
+ # - "HistogramSummaryReserved"
+ # - "MetricTypeInName"
+ # - "ReservedChars"
+ # - "CamelCase"
+ # - "lintUnitAbbreviations"
+
+ predeclared:
+ # comma-separated list of predeclared identifiers to not report on
+ ignore: ""
+ # include method names and field names (i.e., qualified names) in checks
+ q: false
+
+ rowserrcheck:
+ packages:
+ - github.com/jmoiron/sqlx
+
+ revive:
+ # see https://github.com/mgechev/revive#available-rules for details.
+ ignore-generated-header: true
+ severity: warning
+ rules:
+ - name: indent-error-flow
+ severity: warning
+ - name: add-constant
+ severity: warning
+ arguments:
+ - maxLitCount: "3"
+ allowStrs: '""'
+ allowInts: "0,1,2"
+ allowFloats: "0.0,0.,1.0,1.,2.0,2."
+
+ staticcheck:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.16"
+ # https://staticcheck.io/docs/options#checks
+ checks: [ "all" ]
+
+ stylecheck:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.16"
+ # https://staticcheck.io/docs/options#checks
+ checks: [ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022" ]
+ # https://staticcheck.io/docs/options#dot_import_whitelist
+ dot-import-whitelist:
+ - fmt
+ # https://staticcheck.io/docs/options#initialisms
+ initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS" ]
+ # https://staticcheck.io/docs/options#http_status_code_whitelist
+ http-status-code-whitelist: [ "200", "400", "404", "500" ]
+
+ tagliatelle:
+ # check the struck tag name case
+ case:
+ # use the struct field name to check the name of the struct tag
+ use-field-name: true
+ rules:
+ # any struct tag type can be used.
+ # support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`
+ json: camel
+ yaml: camel
+ xml: camel
+ bson: camel
+ avro: snake
+ mapstructure: kebab
+
+ testpackage:
+ # regexp pattern to skip files
+ skip-regexp: (export|internal)_test\.go
+
+ thelper:
+ # The following configurations enable all checks. It can be omitted because all checks are enabled by default.
+ # You can enable only required checks deleting unnecessary checks.
+ test:
+ first: true
+ name: true
+ begin: true
+ benchmark:
+ first: true
+ name: true
+ begin: true
+ tb:
+ first: true
+ name: true
+ begin: true
+
+ tenv:
+ # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
+ # By default, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
+ all: false
+
+ unparam:
+ # Inspect exported functions, default is false. Set to true if no external program/library imports your code.
+ # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
+ # if it's called for subdir of a project it can't find external interfaces. All text editor integrations
+ # with golangci-lint call it on a directory with the changed file.
+ check-exported: false
+
+ unused:
+ # Select the Go version to target. The default is '1.13'.
+ go: "1.16"
+
+ varnamelen:
+ # The longest distance, in source lines, that is being considered a "small scope." (defaults to 5)
+ # Variables used in at most this many lines will be ignored.
+ max-distance: 5
+ # The minimum length of a variable's name that is considered "long." (defaults to 3)
+ # Variable names that are at least this long will be ignored.
+ min-name-length: 1
+ # Check method receiver names. (defaults to false)
+ check-receiver: false
+ # Check named return values. (defaults to false)
+ check-return: false
+ # Ignore "ok" variables that hold the bool return value of a type assertion. (defaults to false)
+ ignore-type-assert-ok: false
+ # Ignore "ok" variables that hold the bool return value of a map index. (defaults to false)
+ ignore-map-index-ok: false
+ # Ignore "ok" variables that hold the bool return value of a channel receive. (defaults to false)
+ ignore-chan-recv-ok: false
+ # Optional list of variable names that should be ignored completely. (defaults to empty list)
+ ignore-names:
+ - err
+ # Optional list of variable declarations that should be ignored completely. (defaults to empty list)
+ # Entries must be in the form of " " or " *".
+ ignore-decls:
+ - c echo.Context
+ - t testing.T
+ - f *foo.Bar
+ - e error
+ - i int
+
+ whitespace:
+ multi-if: false # Enforces newlines (or comments) after every multi-line if statement
+ multi-func: false # Enforces newlines (or comments) after every multi-line function signature
+
+ wrapcheck:
+ # An array of strings that specify substrings of signatures to ignore.
+ # If this set, it will override the default set of ignored signatures.
+ # See https://github.com/tomarrell/wrapcheck#configuration for more information.
+ ignoreSigs:
+ - .Errorf(
+ - errors.New(
+ - errors.Unwrap(
+ - .Wrap(
+ - .Wrapf(
+ - .WithMessage(
+ - .WithMessagef(
+ - .WithStack(
+ ignorePackageGlobs:
+ - encoding/*
+ - github.com/pkg/*
+
+ wsl:
+ # See https://github.com/bombsimon/wsl/blob/master/doc/configuration.md for
+ # documentation of available settings. These are the defaults for
+ # `golangci-lint`.
+ allow-assign-and-anything: false
+ allow-assign-and-call: true
+ allow-cuddle-declarations: false
+ allow-multiline-assign: true
+ allow-separated-leading-comment: false
+ allow-trailing-comment: false
+ force-case-trailing-whitespace: 0
+ force-err-cuddling: false
+ force-short-decl-cuddling: false
+ strict-append: true
+
+ # The custom section can be used to define linter plugins to be loaded at runtime.
+ # See README doc for more info.
+ # custom:
+ # Each custom linter should have a unique name.
+ # example:
+ # The path to the plugin *.so. Can be absolute or local. Required for each custom linter
+ # path: /path/to/example.so
+ # The description of the linter. Optional, just for documentation purposes.
+ # description: This is an example usage of a plugin linter.
+ # Intended to point to the repo location of the linter. Optional, just for documentation purposes.
+ # original-url: github.com/golangci/example-linter
+
+linters:
+ #disable-all: true
+ #enable:
+ # - megacheck
+ # - govet
+ enable-all: true
+ disable:
+ - maligned
+ - prealloc
+ #- tagliatelle
+ #- wrapcheck
+ #- forcetypeassert
+ - goerr113
+ - gomnd
+ - wsl
+ - testpackage
+ - gochecknoglobals
+ - interfacer
+ - maligned
+ - scopelint
+ - gocritic
+ - typecheck
+# presets:
+# - bugs
+# - unused
+ fast: false
+
+
+issues:
+ # List of regexps of issue texts to exclude, empty list by default.
+ # But independently from this option we use default exclude patterns,
+ # it can be disabled by `exclude-use-default: false`. To list all
+ # excluded by default patterns execute `golangci-lint run --help`
+ exclude:
+ - abcdef
+ - tools/.*
+ - test/.*
+ - third_party/.*
+
+ # Excluding configuration per-path, per-linter, per-text and per-source
+ exclude-rules:
+ # Exclude some linters from running on tests files.
+ - linters:
+ - revive
+ path: (log/.*)\.go
+ - linters:
+ - wrapcheck
+ path: (cmd/.*|pkg/.*)\.go
+ - linters:
+ - typecheck
+ path: (pkg/storage/.*)\.go
+
+ - path: (cmd/.*|test/.*|tools/.*)\.go
+ linters:
+ - forbidigo
+ - path: (cmd/[a-z]*/.*|store/.*)\.go
+ linters:
+ - dupl
+ - linters:
+ - gocritic
+ text: (hugeParam:|rangeValCopy:)
+
+ - path: (cmd/[a-z]*/.*)\.go
+ linters:
+ - lll
+
+ - path: (validator/.*|code/.*|validator/.*)
+ linters:
+ - gochecknoinits
+ - path: (pkg/app/.*)\.go
+ linters:
+ - gocyclo
+ - errcheck
+ - dupl
+ - gosec
+
+ # Exclude known linters from partially hard-vendored code,
+ # which is impossible to exclude via "nolint" comments.
+ - path: internal/hmac/
+ text: "weak cryptographic primitive"
+ linters:
+ - gosec
+
+ # Exclude some staticcheck messages
+ - linters:
+ - staticcheck
+ text: "SA9003:"
+
+ # Exclude lll issues for long lines with go:generate
+ - linters:
+ - lll
+ source: "^//go:generate "
+
+ # Independently from option `exclude` we use default exclude patterns,
+ # it can be disabled by this option. To list all
+ # excluded by default patterns execute `golangci-lint run --help`.
+ # Default value for this option is true.
+ exclude-use-default: false
+
+ # The default value is false. If set to true exclude and exclude-rules
+ # regular expressions become case sensitive.
+ exclude-case-sensitive: false
+
+ # The list of ids of default excludes to include or disable. By default it's empty.
+ include:
+ - EXC0002 # disable excluding of issues about comments from golint
+
+ # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
+ max-issues-per-linter: 0
+
+ # Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
+ max-same-issues: 0
+
+ # Show only new issues: if there are unstaged changes or untracked files,
+ # only those changes are analyzed, else only changes in HEAD~ are analyzed.
+ # It's a super-useful option for integration of golangci-lint into existing
+ # large codebase. It's not practical to fix all existing issues at the moment
+ # of integration: much better don't allow issues in new code.
+ # Default is false.
+ new: false
+
+ # Show only new issues created after git revision `REV`
+ new-from-rev: REV
+
+ # Show only new issues created in git patch with set file path.
+ # new-from-patch: path/to/patch/file
+
+ # Fix found issues (if it's supported by the linter)
+ fix: true
+
+severity:
+ # Default value is empty string.
+ # Set the default severity for issues. If severity rules are defined and the issues
+ # do not match or no severity is provided to the rule this will be the default
+ # severity applied. Severities should match the supported severity names of the
+ # selected out format.
+ # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity
+ # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity
+ # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
+ default-severity: error
+
+ # The default value is false.
+ # If set to true severity-rules regular expressions become case sensitive.
+ case-sensitive: false
+
+ # Default value is empty list.
+ # When a list of severity rules are provided, severity information will be added to lint
+ # issues. Severity rules have the same filtering capability as exclude rules except you
+ # are allowed to specify one matcher per severity rule.
+ # Only affects out formats that support setting severity information.
+ rules:
+ - linters:
+ - dupl
+ severity: info
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/LICENSE
new file mode 100644
index 000000000000..0c20e2aaa87f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 john@goframe.org https://goframe.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/README.MD b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/README.MD
new file mode 100644
index 000000000000..7c448b928754
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/README.MD
@@ -0,0 +1,107 @@
+# GoFrame
+
+
+
+[![Go Doc](https://godoc.org/github.com/gogf/gf?status.svg)](https://godoc.org/github.com/gogf/gf)
+[![GoFrame CI](https://github.com/gogf/gf/actions/workflows/gf.yml/badge.svg)](https://github.com/gogf/gf/actions/workflows/gf.yml)
+[![Go Report](https://goreportcard.com/badge/github.com/gogf/gf?v=1)](https://goreportcard.com/report/github.com/gogf/gf)
+[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf/branch/master)
+[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg)](https://github.com/gogf/gf)
+[![License](https://img.shields.io/github/license/gogf/gf.svg?style=flat)](https://github.com/gogf/gf)
+
+
+`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
+
+# Features
+- modular, loosely coupled design
+- rich components, out-of-the-box
+- automatic codes generating for efficiency
+- simple and easy to use, detailed documentation
+- interface designed components, with high scalability
+- fully supported tracing and error stack feature
+- specially developed and powerful ORM component
+- robust engineering design specifications
+- convenient development CLI tool provide
+- OpenTelemetry observability features support
+- OpenAPIV3 documentation generating, automatically
+- much, much more...ready to explore?
+
+# Installation
+Enter your repo. directory and execute following command:
+
+## primary module
+```bash
+go get -u -v github.com/gogf/gf/v2
+```
+
+## cli tool
+```bash
+go install github.com/gogf/gf/cmd/gf/v2
+```
+
+# Limitation
+```
+golang version >= 1.15
+```
+
+# Architecture
+
+
+
+
+
+# Documentation
+
+* Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
+* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf](https://pkg.go.dev/github.com/gogf/gf)
+
+
+# License
+
+`GoFrame` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.
+
+# Part Of Users
+
+- [Tencent](https://www.tencent.com/)
+- [ZTE](https://www.zte.com.cn/china/)
+- [Ant Financial Services](https://www.antfin.com/)
+- [VIVO](https://www.vivo.com/)
+- [MedLinker](https://www.medlinker.com/)
+- [KuCoin](https://www.kucoin.io/)
+- [LeYouJia](https://www.leyoujia.com/)
+- [IGG](https://igg.com)
+- [37](https://www.37.com)
+- [XiMaLaYa](https://www.ximalaya.com)
+- [ZYBang](https://www.zybang.com/)
+
+> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://goframe.org/pages/viewpage.action?pageId=1114415).
+
+
+# Contributors
+This project exists thanks to all the people who contribute. [[Contributors](https://github.com/gogf/gf/graphs/contributors)].
+
+
+
+# Donators
+
+If you love `GoFrame`, why not [buy developer a cup of coffee](https://goframe.org/pages/viewpage.action?pageId=1115633)?
+
+# Sponsors
+We appreciate any kind of sponsorship for `GoFrame` development. If you've got some interesting, please contact WeChat `389961817` / Email `john@goframe.org`.
+
+
+
+# Thanks
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray.go
new file mode 100644
index 000000000000..08e9ece89201
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package garray provides most commonly used array containers which also support concurrent-safe/unsafe switch feature.
+package garray
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_func.go
new file mode 100644
index 000000000000..155cca0d8f04
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_func.go
@@ -0,0 +1,69 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import "strings"
+
+// defaultComparatorInt for int comparison.
+func defaultComparatorInt(a, b int) int {
+ if a < b {
+ return -1
+ }
+ if a > b {
+ return 1
+ }
+ return 0
+}
+
+// defaultComparatorStr for string comparison.
+func defaultComparatorStr(a, b string) int {
+ return strings.Compare(a, b)
+}
+
+// quickSortInt is the quick-sorting algorithm implements for int.
+func quickSortInt(values []int, comparator func(a, b int) int) {
+ if len(values) <= 1 {
+ return
+ }
+ mid, i := values[0], 1
+ head, tail := 0, len(values)-1
+ for head < tail {
+ if comparator(values[i], mid) > 0 {
+ values[i], values[tail] = values[tail], values[i]
+ tail--
+ } else {
+ values[i], values[head] = values[head], values[i]
+ head++
+ i++
+ }
+ }
+ values[head] = mid
+ quickSortInt(values[:head], comparator)
+ quickSortInt(values[head+1:], comparator)
+}
+
+// quickSortStr is the quick-sorting algorithm implements for string.
+func quickSortStr(values []string, comparator func(a, b string) int) {
+ if len(values) <= 1 {
+ return
+ }
+ mid, i := values[0], 1
+ head, tail := 0, len(values)-1
+ for head < tail {
+ if comparator(values[i], mid) > 0 {
+ values[i], values[tail] = values[tail], values[i]
+ tail--
+ } else {
+ values[i], values[head] = values[head], values[i]
+ head++
+ i++
+ }
+ }
+ values[head] = mid
+ quickSortStr(values[:head], comparator)
+ quickSortStr(values[head+1:], comparator)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_any.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_any.go
new file mode 100644
index 000000000000..fe43a82ab57f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_any.go
@@ -0,0 +1,810 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "sort"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// Array is a golang array with rich features.
+// It contains a concurrent-safe/unsafe switch, which should be set
+// when its initialization and cannot be changed then.
+type Array struct {
+ mu rwmutex.RWMutex
+ array []interface{}
+}
+
+// New creates and returns an empty array.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func New(safe ...bool) *Array {
+ return NewArraySize(0, 0, safe...)
+}
+
+// NewArray is alias of New, please see New.
+func NewArray(safe ...bool) *Array {
+ return NewArraySize(0, 0, safe...)
+}
+
+// NewArraySize create and returns an array with given size and cap.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewArraySize(size int, cap int, safe ...bool) *Array {
+ return &Array{
+ mu: rwmutex.Create(safe...),
+ array: make([]interface{}, size, cap),
+ }
+}
+
+// NewArrayRange creates and returns a array by a range from `start` to `end`
+// with step value `step`.
+func NewArrayRange(start, end, step int, safe ...bool) *Array {
+ if step == 0 {
+ panic(fmt.Sprintf(`invalid step value: %d`, step))
+ }
+ slice := make([]interface{}, (end-start+1)/step)
+ index := 0
+ for i := start; i <= end; i += step {
+ slice[index] = i
+ index++
+ }
+ return NewArrayFrom(slice, safe...)
+}
+
+// NewFrom is alias of NewArrayFrom.
+// See NewArrayFrom.
+func NewFrom(array []interface{}, safe ...bool) *Array {
+ return NewArrayFrom(array, safe...)
+}
+
+// NewFromCopy is alias of NewArrayFromCopy.
+// See NewArrayFromCopy.
+func NewFromCopy(array []interface{}, safe ...bool) *Array {
+ return NewArrayFromCopy(array, safe...)
+}
+
+// NewArrayFrom creates and returns an array with given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewArrayFrom(array []interface{}, safe ...bool) *Array {
+ return &Array{
+ mu: rwmutex.Create(safe...),
+ array: array,
+ }
+}
+
+// NewArrayFromCopy creates and returns an array from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewArrayFromCopy(array []interface{}, safe ...bool) *Array {
+ newArray := make([]interface{}, len(array))
+ copy(newArray, array)
+ return &Array{
+ mu: rwmutex.Create(safe...),
+ array: newArray,
+ }
+}
+
+// At returns the value by the specified index.
+// If the given `index` is out of range of the array, it returns `nil`.
+func (a *Array) At(index int) (value interface{}) {
+ value, _ = a.Get(index)
+ return
+}
+
+// Get returns the value by the specified index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *Array) Get(index int) (value interface{}, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if index < 0 || index >= len(a.array) {
+ return nil, false
+ }
+ return a.array[index], true
+}
+
+// Set sets value to specified index.
+func (a *Array) Set(index int, value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ a.array[index] = value
+ return nil
+}
+
+// SetArray sets the underlying slice array with the given `array`.
+func (a *Array) SetArray(array []interface{}) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.array = array
+ return a
+}
+
+// Replace replaces the array items by given `array` from the beginning of array.
+func (a *Array) Replace(array []interface{}) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ max := len(array)
+ if max > len(a.array) {
+ max = len(a.array)
+ }
+ for i := 0; i < max; i++ {
+ a.array[i] = array[i]
+ }
+ return a
+}
+
+// Sum returns the sum of values in an array.
+func (a *Array) Sum() (sum int) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ sum += gconv.Int(v)
+ }
+ return
+}
+
+// SortFunc sorts the array by custom function `less`.
+func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ sort.Slice(a.array, func(i, j int) bool {
+ return less(a.array[i], a.array[j])
+ })
+ return a
+}
+
+// InsertBefore inserts the `value` to the front of `index`.
+func (a *Array) InsertBefore(index int, value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ rear := append([]interface{}{}, a.array[index:]...)
+ a.array = append(a.array[0:index], value)
+ a.array = append(a.array, rear...)
+ return nil
+}
+
+// InsertAfter inserts the `value` to the back of `index`.
+func (a *Array) InsertAfter(index int, value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ rear := append([]interface{}{}, a.array[index+1:]...)
+ a.array = append(a.array[0:index+1], value)
+ a.array = append(a.array, rear...)
+ return nil
+}
+
+// Remove removes an item by index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *Array) Remove(index int) (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(index)
+}
+
+// doRemoveWithoutLock removes an item by index without lock.
+func (a *Array) doRemoveWithoutLock(index int) (value interface{}, found bool) {
+ if index < 0 || index >= len(a.array) {
+ return nil, false
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ value := a.array[0]
+ a.array = a.array[1:]
+ return value, true
+ } else if index == len(a.array)-1 {
+ value := a.array[index]
+ a.array = a.array[:index]
+ return value, true
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ value = a.array[index]
+ a.array = append(a.array[:index], a.array[index+1:]...)
+ return value, true
+}
+
+// RemoveValue removes an item by value.
+// It returns true if value is found in the array, or else false if not found.
+func (a *Array) RemoveValue(value interface{}) bool {
+ if i := a.Search(value); i != -1 {
+ a.Remove(i)
+ return true
+ }
+ return false
+}
+
+// PushLeft pushes one or multiple items to the beginning of array.
+func (a *Array) PushLeft(value ...interface{}) *Array {
+ a.mu.Lock()
+ a.array = append(value, a.array...)
+ a.mu.Unlock()
+ return a
+}
+
+// PushRight pushes one or multiple items to the end of array.
+// It equals to Append.
+func (a *Array) PushRight(value ...interface{}) *Array {
+ a.mu.Lock()
+ a.array = append(a.array, value...)
+ a.mu.Unlock()
+ return a
+}
+
+// PopRand randomly pops and return an item out of array.
+// Note that if the array is empty, the `found` is false.
+func (a *Array) PopRand() (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+}
+
+// PopRands randomly pops and returns `size` items out of array.
+func (a *Array) PopRands(size int) []interface{} {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ size = len(a.array)
+ }
+ array := make([]interface{}, size)
+ for i := 0; i < size; i++ {
+ array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+ }
+ return array
+}
+
+// PopLeft pops and returns an item from the beginning of array.
+// Note that if the array is empty, the `found` is false.
+func (a *Array) PopLeft() (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return nil, false
+ }
+ value = a.array[0]
+ a.array = a.array[1:]
+ return value, true
+}
+
+// PopRight pops and returns an item from the end of array.
+// Note that if the array is empty, the `found` is false.
+func (a *Array) PopRight() (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ index := len(a.array) - 1
+ if index < 0 {
+ return nil, false
+ }
+ value = a.array[index]
+ a.array = a.array[:index]
+ return value, true
+}
+
+// PopLefts pops and returns `size` items from the beginning of array.
+func (a *Array) PopLefts(size int) []interface{} {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[0:size]
+ a.array = a.array[size:]
+ return value
+}
+
+// PopRights pops and returns `size` items from the end of array.
+func (a *Array) PopRights(size int) []interface{} {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ index := len(a.array) - size
+ if index <= 0 {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[index:]
+ a.array = a.array[:index]
+ return value
+}
+
+// Range picks and returns items by range, like array[start:end].
+// Notice, if in concurrent-safe usage, it returns a copy of slice;
+// else a pointer to the underlying data.
+//
+// If `end` is negative, then the offset will start from the end of array.
+// If `end` is omitted, then the sequence will have everything from start up
+// until the end of the array.
+func (a *Array) Range(start int, end ...int) []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ offsetEnd := len(a.array)
+ if len(end) > 0 && end[0] < offsetEnd {
+ offsetEnd = end[0]
+ }
+ if start > offsetEnd {
+ return nil
+ }
+ if start < 0 {
+ start = 0
+ }
+ array := ([]interface{})(nil)
+ if a.mu.IsSafe() {
+ array = make([]interface{}, offsetEnd-start)
+ copy(array, a.array[start:offsetEnd])
+ } else {
+ array = a.array[start:offsetEnd]
+ }
+ return array
+}
+
+// SubSlice returns a slice of elements from the array as specified
+// by the `offset` and `size` parameters.
+// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
+//
+// If offset is non-negative, the sequence will start at that offset in the array.
+// If offset is negative, the sequence will start that far from the end of the array.
+//
+// If length is given and is positive, then the sequence will have up to that many elements in it.
+// If the array is shorter than the length, then only the available array elements will be present.
+// If length is given and is negative then the sequence will stop that many elements from the end of the array.
+// If it is omitted, then the sequence will have everything from offset up until the end of the array.
+//
+// Any possibility crossing the left border of array, it will fail.
+func (a *Array) SubSlice(offset int, length ...int) []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ size := len(a.array)
+ if len(length) > 0 {
+ size = length[0]
+ }
+ if offset > len(a.array) {
+ return nil
+ }
+ if offset < 0 {
+ offset = len(a.array) + offset
+ if offset < 0 {
+ return nil
+ }
+ }
+ if size < 0 {
+ offset += size
+ size = -size
+ if offset < 0 {
+ return nil
+ }
+ }
+ end := offset + size
+ if end > len(a.array) {
+ end = len(a.array)
+ size = len(a.array) - offset
+ }
+ if a.mu.IsSafe() {
+ s := make([]interface{}, size)
+ copy(s, a.array[offset:])
+ return s
+ } else {
+ return a.array[offset:end]
+ }
+}
+
+// Append is alias of PushRight, please See PushRight.
+func (a *Array) Append(value ...interface{}) *Array {
+ a.PushRight(value...)
+ return a
+}
+
+// Len returns the length of array.
+func (a *Array) Len() int {
+ a.mu.RLock()
+ length := len(a.array)
+ a.mu.RUnlock()
+ return length
+}
+
+// Slice returns the underlying data of array.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (a *Array) Slice() []interface{} {
+ if a.mu.IsSafe() {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array := make([]interface{}, len(a.array))
+ copy(array, a.array)
+ return array
+ } else {
+ return a.array
+ }
+}
+
+// Interfaces returns current array as []interface{}.
+func (a *Array) Interfaces() []interface{} {
+ return a.Slice()
+}
+
+// Clone returns a new array, which is a copy of current array.
+func (a *Array) Clone() (newArray *Array) {
+ a.mu.RLock()
+ array := make([]interface{}, len(a.array))
+ copy(array, a.array)
+ a.mu.RUnlock()
+ return NewArrayFrom(array, a.mu.IsSafe())
+}
+
+// Clear deletes all items of current array.
+func (a *Array) Clear() *Array {
+ a.mu.Lock()
+ if len(a.array) > 0 {
+ a.array = make([]interface{}, 0)
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// Contains checks whether a value exists in the array.
+func (a *Array) Contains(value interface{}) bool {
+ return a.Search(value) != -1
+}
+
+// Search searches array by `value`, returns the index of `value`,
+// or returns -1 if not exists.
+func (a *Array) Search(value interface{}) int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return -1
+ }
+ result := -1
+ for index, v := range a.array {
+ if v == value {
+ result = index
+ break
+ }
+ }
+ return result
+}
+
+// Unique uniques the array, clear repeated items.
+// Example: [1,1,2,3,2] -> [1,2,3]
+func (a *Array) Unique() *Array {
+ a.mu.Lock()
+ for i := 0; i < len(a.array)-1; i++ {
+ for j := i + 1; j < len(a.array); {
+ if a.array[i] == a.array[j] {
+ a.array = append(a.array[:j], a.array[j+1:]...)
+ } else {
+ j++
+ }
+ }
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// LockFunc locks writing by callback function `f`.
+func (a *Array) LockFunc(f func(array []interface{})) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ f(a.array)
+ return a
+}
+
+// RLockFunc locks reading by callback function `f`.
+func (a *Array) RLockFunc(f func(array []interface{})) *Array {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ f(a.array)
+ return a
+}
+
+// Merge merges `array` into current array.
+// The parameter `array` can be any garray or slice type.
+// The difference between Merge and Append is Append supports only specified slice type,
+// but Merge supports more parameter types.
+func (a *Array) Merge(array interface{}) *Array {
+ return a.Append(gconv.Interfaces(array)...)
+}
+
+// Fill fills an array with num entries of the value `value`,
+// keys starting at the `startIndex` parameter.
+func (a *Array) Fill(startIndex int, num int, value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if startIndex < 0 || startIndex > len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
+ }
+ for i := startIndex; i < startIndex+num; i++ {
+ if i > len(a.array)-1 {
+ a.array = append(a.array, value)
+ } else {
+ a.array[i] = value
+ }
+ }
+ return nil
+}
+
+// Chunk splits an array into multiple arrays,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (a *Array) Chunk(size int) [][]interface{} {
+ if size < 1 {
+ return nil
+ }
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ length := len(a.array)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n [][]interface{}
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, a.array[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Pad pads array to the specified length with `value`.
+// If size is positive then the array is padded on the right, or negative on the left.
+// If the absolute value of `size` is less than or equal to the length of the array
+// then no padding takes place.
+func (a *Array) Pad(size int, val interface{}) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) {
+ return a
+ }
+ n := size
+ if size < 0 {
+ n = -size
+ }
+ n -= len(a.array)
+ tmp := make([]interface{}, n)
+ for i := 0; i < n; i++ {
+ tmp[i] = val
+ }
+ if size > 0 {
+ a.array = append(a.array, tmp...)
+ } else {
+ a.array = append(tmp, a.array...)
+ }
+ return a
+}
+
+// Rand randomly returns one item from array(no deleting).
+func (a *Array) Rand() (value interface{}, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return nil, false
+ }
+ return a.array[grand.Intn(len(a.array))], true
+}
+
+// Rands randomly returns `size` items from array(no deleting).
+func (a *Array) Rands(size int) []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ array := make([]interface{}, size)
+ for i := 0; i < size; i++ {
+ array[i] = a.array[grand.Intn(len(a.array))]
+ }
+ return array
+}
+
+// Shuffle randomly shuffles the array.
+func (a *Array) Shuffle() *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range grand.Perm(len(a.array)) {
+ a.array[i], a.array[v] = a.array[v], a.array[i]
+ }
+ return a
+}
+
+// Reverse makes array with elements in reverse order.
+func (a *Array) Reverse() *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 {
+ a.array[i], a.array[j] = a.array[j], a.array[i]
+ }
+ return a
+}
+
+// Join joins array elements with a string `glue`.
+func (a *Array) Join(glue string) string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ for k, v := range a.array {
+ buffer.WriteString(gconv.String(v))
+ if k != len(a.array)-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ return buffer.String()
+}
+
+// CountValues counts the number of occurrences of all values in the array.
+func (a *Array) CountValues() map[interface{}]int {
+ m := make(map[interface{}]int)
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ m[v]++
+ }
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (a *Array) Iterator(f func(k int, v interface{}) bool) {
+ a.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *Array) IteratorAsc(f func(k int, v interface{}) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for k, v := range a.array {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *Array) IteratorDesc(f func(k int, v interface{}) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for i := len(a.array) - 1; i >= 0; i-- {
+ if !f(i, a.array[i]) {
+ break
+ }
+ }
+}
+
+// String returns current array as a string, which implements like json.Marshal does.
+func (a *Array) String() string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteByte('[')
+ s := ""
+ for k, v := range a.array {
+ s = gconv.String(v)
+ if gstr.IsNumeric(s) {
+ buffer.WriteString(s)
+ } else {
+ buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
+ }
+ if k != len(a.array)-1 {
+ buffer.WriteByte(',')
+ }
+ }
+ buffer.WriteByte(']')
+ return buffer.String()
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (a Array) MarshalJSON() ([]byte, error) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ return json.Marshal(a.array)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (a *Array) UnmarshalJSON(b []byte) error {
+ if a.array == nil {
+ a.array = make([]interface{}, 0)
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for array.
+func (a *Array) UnmarshalValue(value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
+ default:
+ a.array = gconv.SliceAny(value)
+ }
+ return nil
+}
+
+// FilterNil removes all nil value of the array.
+func (a *Array) FilterNil() *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if empty.IsNil(a.array[i]) {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// FilterEmpty removes all empty value of the array.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (a *Array) FilterEmpty() *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if empty.IsEmpty(a.array[i]) {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// Walk applies a user supplied function `f` to every item of array.
+func (a *Array) Walk(f func(value interface{}) interface{}) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
+// IsEmpty checks whether the array is empty.
+func (a *Array) IsEmpty() bool {
+ return a.Len() == 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_int.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_int.go
new file mode 100644
index 000000000000..5dacdc95b0fb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_int.go
@@ -0,0 +1,789 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "sort"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// IntArray is a golang int array with rich features.
+// It contains a concurrent-safe/unsafe switch, which should be set
+// when its initialization and cannot be changed then.
+type IntArray struct {
+ mu rwmutex.RWMutex
+ array []int
+}
+
+// NewIntArray creates and returns an empty array.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewIntArray(safe ...bool) *IntArray {
+ return NewIntArraySize(0, 0, safe...)
+}
+
+// NewIntArraySize create and returns an array with given size and cap.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
+ return &IntArray{
+ mu: rwmutex.Create(safe...),
+ array: make([]int, size, cap),
+ }
+}
+
+// NewIntArrayRange creates and returns a array by a range from `start` to `end`
+// with step value `step`.
+func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
+ if step == 0 {
+ panic(fmt.Sprintf(`invalid step value: %d`, step))
+ }
+ slice := make([]int, (end-start+1)/step)
+ index := 0
+ for i := start; i <= end; i += step {
+ slice[index] = i
+ index++
+ }
+ return NewIntArrayFrom(slice, safe...)
+}
+
+// NewIntArrayFrom creates and returns an array with given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewIntArrayFrom(array []int, safe ...bool) *IntArray {
+ return &IntArray{
+ mu: rwmutex.Create(safe...),
+ array: array,
+ }
+}
+
+// NewIntArrayFromCopy creates and returns an array from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewIntArrayFromCopy(array []int, safe ...bool) *IntArray {
+ newArray := make([]int, len(array))
+ copy(newArray, array)
+ return &IntArray{
+ mu: rwmutex.Create(safe...),
+ array: newArray,
+ }
+}
+
+// At returns the value by the specified index.
+// If the given `index` is out of range of the array, it returns `0`.
+func (a *IntArray) At(index int) (value int) {
+ value, _ = a.Get(index)
+ return
+}
+
+// Get returns the value by the specified index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *IntArray) Get(index int) (value int, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if index < 0 || index >= len(a.array) {
+ return 0, false
+ }
+ return a.array[index], true
+}
+
+// Set sets value to specified index.
+func (a *IntArray) Set(index int, value int) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ a.array[index] = value
+ return nil
+}
+
+// SetArray sets the underlying slice array with the given `array`.
+func (a *IntArray) SetArray(array []int) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.array = array
+ return a
+}
+
+// Replace replaces the array items by given `array` from the beginning of array.
+func (a *IntArray) Replace(array []int) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ max := len(array)
+ if max > len(a.array) {
+ max = len(a.array)
+ }
+ for i := 0; i < max; i++ {
+ a.array[i] = array[i]
+ }
+ return a
+}
+
+// Sum returns the sum of values in an array.
+func (a *IntArray) Sum() (sum int) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ sum += v
+ }
+ return
+}
+
+// Sort sorts the array in increasing order.
+// The parameter `reverse` controls whether sort in increasing order(default) or decreasing order.
+func (a *IntArray) Sort(reverse ...bool) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(reverse) > 0 && reverse[0] {
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.array[i] >= a.array[j]
+ })
+ } else {
+ sort.Ints(a.array)
+ }
+ return a
+}
+
+// SortFunc sorts the array by custom function `less`.
+func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ sort.Slice(a.array, func(i, j int) bool {
+ return less(a.array[i], a.array[j])
+ })
+ return a
+}
+
+// InsertBefore inserts the `value` to the front of `index`.
+func (a *IntArray) InsertBefore(index int, value int) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ rear := append([]int{}, a.array[index:]...)
+ a.array = append(a.array[0:index], value)
+ a.array = append(a.array, rear...)
+ return nil
+}
+
+// InsertAfter inserts the `value` to the back of `index`.
+func (a *IntArray) InsertAfter(index int, value int) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ rear := append([]int{}, a.array[index+1:]...)
+ a.array = append(a.array[0:index+1], value)
+ a.array = append(a.array, rear...)
+ return nil
+}
+
+// Remove removes an item by index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *IntArray) Remove(index int) (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(index)
+}
+
+// doRemoveWithoutLock removes an item by index without lock.
+func (a *IntArray) doRemoveWithoutLock(index int) (value int, found bool) {
+ if index < 0 || index >= len(a.array) {
+ return 0, false
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ value := a.array[0]
+ a.array = a.array[1:]
+ return value, true
+ } else if index == len(a.array)-1 {
+ value := a.array[index]
+ a.array = a.array[:index]
+ return value, true
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ value = a.array[index]
+ a.array = append(a.array[:index], a.array[index+1:]...)
+ return value, true
+}
+
+// RemoveValue removes an item by value.
+// It returns true if value is found in the array, or else false if not found.
+func (a *IntArray) RemoveValue(value int) bool {
+ if i := a.Search(value); i != -1 {
+ _, found := a.Remove(i)
+ return found
+ }
+ return false
+}
+
+// PushLeft pushes one or multiple items to the beginning of array.
+func (a *IntArray) PushLeft(value ...int) *IntArray {
+ a.mu.Lock()
+ a.array = append(value, a.array...)
+ a.mu.Unlock()
+ return a
+}
+
+// PushRight pushes one or multiple items to the end of array.
+// It equals to Append.
+func (a *IntArray) PushRight(value ...int) *IntArray {
+ a.mu.Lock()
+ a.array = append(a.array, value...)
+ a.mu.Unlock()
+ return a
+}
+
+// PopLeft pops and returns an item from the beginning of array.
+// Note that if the array is empty, the `found` is false.
+func (a *IntArray) PopLeft() (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return 0, false
+ }
+ value = a.array[0]
+ a.array = a.array[1:]
+ return value, true
+}
+
+// PopRight pops and returns an item from the end of array.
+// Note that if the array is empty, the `found` is false.
+func (a *IntArray) PopRight() (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ index := len(a.array) - 1
+ if index < 0 {
+ return 0, false
+ }
+ value = a.array[index]
+ a.array = a.array[:index]
+ return value, true
+}
+
+// PopRand randomly pops and return an item out of array.
+// Note that if the array is empty, the `found` is false.
+func (a *IntArray) PopRand() (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+}
+
+// PopRands randomly pops and returns `size` items out of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *IntArray) PopRands(size int) []int {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ size = len(a.array)
+ }
+ array := make([]int, size)
+ for i := 0; i < size; i++ {
+ array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+ }
+ return array
+}
+
+// PopLefts pops and returns `size` items from the beginning of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *IntArray) PopLefts(size int) []int {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[0:size]
+ a.array = a.array[size:]
+ return value
+}
+
+// PopRights pops and returns `size` items from the end of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *IntArray) PopRights(size int) []int {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ index := len(a.array) - size
+ if index <= 0 {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[index:]
+ a.array = a.array[:index]
+ return value
+}
+
+// Range picks and returns items by range, like array[start:end].
+// Notice, if in concurrent-safe usage, it returns a copy of slice;
+// else a pointer to the underlying data.
+//
+// If `end` is negative, then the offset will start from the end of array.
+// If `end` is omitted, then the sequence will have everything from start up
+// until the end of the array.
+func (a *IntArray) Range(start int, end ...int) []int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ offsetEnd := len(a.array)
+ if len(end) > 0 && end[0] < offsetEnd {
+ offsetEnd = end[0]
+ }
+ if start > offsetEnd {
+ return nil
+ }
+ if start < 0 {
+ start = 0
+ }
+ array := ([]int)(nil)
+ if a.mu.IsSafe() {
+ array = make([]int, offsetEnd-start)
+ copy(array, a.array[start:offsetEnd])
+ } else {
+ array = a.array[start:offsetEnd]
+ }
+ return array
+}
+
+// SubSlice returns a slice of elements from the array as specified
+// by the `offset` and `size` parameters.
+// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
+//
+// If offset is non-negative, the sequence will start at that offset in the array.
+// If offset is negative, the sequence will start that far from the end of the array.
+//
+// If length is given and is positive, then the sequence will have up to that many elements in it.
+// If the array is shorter than the length, then only the available array elements will be present.
+// If length is given and is negative then the sequence will stop that many elements from the end of the array.
+// If it is omitted, then the sequence will have everything from offset up until the end of the array.
+//
+// Any possibility crossing the left border of array, it will fail.
+func (a *IntArray) SubSlice(offset int, length ...int) []int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ size := len(a.array)
+ if len(length) > 0 {
+ size = length[0]
+ }
+ if offset > len(a.array) {
+ return nil
+ }
+ if offset < 0 {
+ offset = len(a.array) + offset
+ if offset < 0 {
+ return nil
+ }
+ }
+ if size < 0 {
+ offset += size
+ size = -size
+ if offset < 0 {
+ return nil
+ }
+ }
+ end := offset + size
+ if end > len(a.array) {
+ end = len(a.array)
+ size = len(a.array) - offset
+ }
+ if a.mu.IsSafe() {
+ s := make([]int, size)
+ copy(s, a.array[offset:])
+ return s
+ } else {
+ return a.array[offset:end]
+ }
+}
+
+// Append is alias of PushRight,please See PushRight.
+func (a *IntArray) Append(value ...int) *IntArray {
+ a.mu.Lock()
+ a.array = append(a.array, value...)
+ a.mu.Unlock()
+ return a
+}
+
+// Len returns the length of array.
+func (a *IntArray) Len() int {
+ a.mu.RLock()
+ length := len(a.array)
+ a.mu.RUnlock()
+ return length
+}
+
+// Slice returns the underlying data of array.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (a *IntArray) Slice() []int {
+ array := ([]int)(nil)
+ if a.mu.IsSafe() {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array = make([]int, len(a.array))
+ copy(array, a.array)
+ } else {
+ array = a.array
+ }
+ return array
+}
+
+// Interfaces returns current array as []interface{}.
+func (a *IntArray) Interfaces() []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array := make([]interface{}, len(a.array))
+ for k, v := range a.array {
+ array[k] = v
+ }
+ return array
+}
+
+// Clone returns a new array, which is a copy of current array.
+func (a *IntArray) Clone() (newArray *IntArray) {
+ a.mu.RLock()
+ array := make([]int, len(a.array))
+ copy(array, a.array)
+ a.mu.RUnlock()
+ return NewIntArrayFrom(array, a.mu.IsSafe())
+}
+
+// Clear deletes all items of current array.
+func (a *IntArray) Clear() *IntArray {
+ a.mu.Lock()
+ if len(a.array) > 0 {
+ a.array = make([]int, 0)
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// Contains checks whether a value exists in the array.
+func (a *IntArray) Contains(value int) bool {
+ return a.Search(value) != -1
+}
+
+// Search searches array by `value`, returns the index of `value`,
+// or returns -1 if not exists.
+func (a *IntArray) Search(value int) int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return -1
+ }
+ result := -1
+ for index, v := range a.array {
+ if v == value {
+ result = index
+ break
+ }
+ }
+ return result
+}
+
+// Unique uniques the array, clear repeated items.
+// Example: [1,1,2,3,2] -> [1,2,3]
+func (a *IntArray) Unique() *IntArray {
+ a.mu.Lock()
+ for i := 0; i < len(a.array)-1; i++ {
+ for j := i + 1; j < len(a.array); {
+ if a.array[i] == a.array[j] {
+ a.array = append(a.array[:j], a.array[j+1:]...)
+ } else {
+ j++
+ }
+ }
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// LockFunc locks writing by callback function `f`.
+func (a *IntArray) LockFunc(f func(array []int)) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ f(a.array)
+ return a
+}
+
+// RLockFunc locks reading by callback function `f`.
+func (a *IntArray) RLockFunc(f func(array []int)) *IntArray {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ f(a.array)
+ return a
+}
+
+// Merge merges `array` into current array.
+// The parameter `array` can be any garray or slice type.
+// The difference between Merge and Append is Append supports only specified slice type,
+// but Merge supports more parameter types.
+func (a *IntArray) Merge(array interface{}) *IntArray {
+ return a.Append(gconv.Ints(array)...)
+}
+
+// Fill fills an array with num entries of the value `value`,
+// keys starting at the `startIndex` parameter.
+func (a *IntArray) Fill(startIndex int, num int, value int) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if startIndex < 0 || startIndex > len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
+ }
+ for i := startIndex; i < startIndex+num; i++ {
+ if i > len(a.array)-1 {
+ a.array = append(a.array, value)
+ } else {
+ a.array[i] = value
+ }
+ }
+ return nil
+}
+
+// Chunk splits an array into multiple arrays,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (a *IntArray) Chunk(size int) [][]int {
+ if size < 1 {
+ return nil
+ }
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ length := len(a.array)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n [][]int
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, a.array[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Pad pads array to the specified length with `value`.
+// If size is positive then the array is padded on the right, or negative on the left.
+// If the absolute value of `size` is less than or equal to the length of the array
+// then no padding takes place.
+func (a *IntArray) Pad(size int, value int) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) {
+ return a
+ }
+ n := size
+ if size < 0 {
+ n = -size
+ }
+ n -= len(a.array)
+ tmp := make([]int, n)
+ for i := 0; i < n; i++ {
+ tmp[i] = value
+ }
+ if size > 0 {
+ a.array = append(a.array, tmp...)
+ } else {
+ a.array = append(tmp, a.array...)
+ }
+ return a
+}
+
+// Rand randomly returns one item from array(no deleting).
+func (a *IntArray) Rand() (value int, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return 0, false
+ }
+ return a.array[grand.Intn(len(a.array))], true
+}
+
+// Rands randomly returns `size` items from array(no deleting).
+func (a *IntArray) Rands(size int) []int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ array := make([]int, size)
+ for i := 0; i < size; i++ {
+ array[i] = a.array[grand.Intn(len(a.array))]
+ }
+ return array
+}
+
+// Shuffle randomly shuffles the array.
+func (a *IntArray) Shuffle() *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range grand.Perm(len(a.array)) {
+ a.array[i], a.array[v] = a.array[v], a.array[i]
+ }
+ return a
+}
+
+// Reverse makes array with elements in reverse order.
+func (a *IntArray) Reverse() *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 {
+ a.array[i], a.array[j] = a.array[j], a.array[i]
+ }
+ return a
+}
+
+// Join joins array elements with a string `glue`.
+func (a *IntArray) Join(glue string) string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ for k, v := range a.array {
+ buffer.WriteString(gconv.String(v))
+ if k != len(a.array)-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ return buffer.String()
+}
+
+// CountValues counts the number of occurrences of all values in the array.
+func (a *IntArray) CountValues() map[int]int {
+ m := make(map[int]int)
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ m[v]++
+ }
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (a *IntArray) Iterator(f func(k int, v int) bool) {
+ a.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *IntArray) IteratorAsc(f func(k int, v int) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for k, v := range a.array {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *IntArray) IteratorDesc(f func(k int, v int) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for i := len(a.array) - 1; i >= 0; i-- {
+ if !f(i, a.array[i]) {
+ break
+ }
+ }
+}
+
+// String returns current array as a string, which implements like json.Marshal does.
+func (a *IntArray) String() string {
+ return "[" + a.Join(",") + "]"
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (a IntArray) MarshalJSON() ([]byte, error) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ return json.Marshal(a.array)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (a *IntArray) UnmarshalJSON(b []byte) error {
+ if a.array == nil {
+ a.array = make([]int, 0)
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for array.
+func (a *IntArray) UnmarshalValue(value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
+ default:
+ a.array = gconv.SliceInt(value)
+ }
+ return nil
+}
+
+// FilterEmpty removes all zero value of the array.
+func (a *IntArray) FilterEmpty() *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if a.array[i] == 0 {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// Walk applies a user supplied function `f` to every item of array.
+func (a *IntArray) Walk(f func(value int) int) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
+// IsEmpty checks whether the array is empty.
+func (a *IntArray) IsEmpty() bool {
+ return a.Len() == 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_str.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_str.go
new file mode 100644
index 000000000000..0e178e156b09
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_normal_str.go
@@ -0,0 +1,802 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import (
+ "bytes"
+ "math"
+ "sort"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// StrArray is a golang string array with rich features.
+// It contains a concurrent-safe/unsafe switch, which should be set
+// when its initialization and cannot be changed then.
+type StrArray struct {
+ mu rwmutex.RWMutex
+ array []string
+}
+
+// NewStrArray creates and returns an empty array.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewStrArray(safe ...bool) *StrArray {
+ return NewStrArraySize(0, 0, safe...)
+}
+
+// NewStrArraySize create and returns an array with given size and cap.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
+ return &StrArray{
+ mu: rwmutex.Create(safe...),
+ array: make([]string, size, cap),
+ }
+}
+
+// NewStrArrayFrom creates and returns an array with given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewStrArrayFrom(array []string, safe ...bool) *StrArray {
+ return &StrArray{
+ mu: rwmutex.Create(safe...),
+ array: array,
+ }
+}
+
+// NewStrArrayFromCopy creates and returns an array from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {
+ newArray := make([]string, len(array))
+ copy(newArray, array)
+ return &StrArray{
+ mu: rwmutex.Create(safe...),
+ array: newArray,
+ }
+}
+
+// At returns the value by the specified index.
+// If the given `index` is out of range of the array, it returns an empty string.
+func (a *StrArray) At(index int) (value string) {
+ value, _ = a.Get(index)
+ return
+}
+
+// Get returns the value by the specified index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *StrArray) Get(index int) (value string, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if index < 0 || index >= len(a.array) {
+ return "", false
+ }
+ return a.array[index], true
+}
+
+// Set sets value to specified index.
+func (a *StrArray) Set(index int, value string) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ a.array[index] = value
+ return nil
+}
+
+// SetArray sets the underlying slice array with the given `array`.
+func (a *StrArray) SetArray(array []string) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.array = array
+ return a
+}
+
+// Replace replaces the array items by given `array` from the beginning of array.
+func (a *StrArray) Replace(array []string) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ max := len(array)
+ if max > len(a.array) {
+ max = len(a.array)
+ }
+ for i := 0; i < max; i++ {
+ a.array[i] = array[i]
+ }
+ return a
+}
+
+// Sum returns the sum of values in an array.
+func (a *StrArray) Sum() (sum int) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ sum += gconv.Int(v)
+ }
+ return
+}
+
+// Sort sorts the array in increasing order.
+// The parameter `reverse` controls whether sort
+// in increasing order(default) or decreasing order
+func (a *StrArray) Sort(reverse ...bool) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(reverse) > 0 && reverse[0] {
+ sort.Slice(a.array, func(i, j int) bool {
+ return strings.Compare(a.array[i], a.array[j]) >= 0
+ })
+ } else {
+ sort.Strings(a.array)
+ }
+ return a
+}
+
+// SortFunc sorts the array by custom function `less`.
+func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ sort.Slice(a.array, func(i, j int) bool {
+ return less(a.array[i], a.array[j])
+ })
+ return a
+}
+
+// InsertBefore inserts the `value` to the front of `index`.
+func (a *StrArray) InsertBefore(index int, value string) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ rear := append([]string{}, a.array[index:]...)
+ a.array = append(a.array[0:index], value)
+ a.array = append(a.array, rear...)
+ return nil
+}
+
+// InsertAfter inserts the `value` to the back of `index`.
+func (a *StrArray) InsertAfter(index int, value string) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if index < 0 || index >= len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
+ }
+ rear := append([]string{}, a.array[index+1:]...)
+ a.array = append(a.array[0:index+1], value)
+ a.array = append(a.array, rear...)
+ return nil
+}
+
+// Remove removes an item by index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *StrArray) Remove(index int) (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(index)
+}
+
+// doRemoveWithoutLock removes an item by index without lock.
+func (a *StrArray) doRemoveWithoutLock(index int) (value string, found bool) {
+ if index < 0 || index >= len(a.array) {
+ return "", false
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ value := a.array[0]
+ a.array = a.array[1:]
+ return value, true
+ } else if index == len(a.array)-1 {
+ value := a.array[index]
+ a.array = a.array[:index]
+ return value, true
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ value = a.array[index]
+ a.array = append(a.array[:index], a.array[index+1:]...)
+ return value, true
+}
+
+// RemoveValue removes an item by value.
+// It returns true if value is found in the array, or else false if not found.
+func (a *StrArray) RemoveValue(value string) bool {
+ if i := a.Search(value); i != -1 {
+ _, found := a.Remove(i)
+ return found
+ }
+ return false
+}
+
+// PushLeft pushes one or multiple items to the beginning of array.
+func (a *StrArray) PushLeft(value ...string) *StrArray {
+ a.mu.Lock()
+ a.array = append(value, a.array...)
+ a.mu.Unlock()
+ return a
+}
+
+// PushRight pushes one or multiple items to the end of array.
+// It equals to Append.
+func (a *StrArray) PushRight(value ...string) *StrArray {
+ a.mu.Lock()
+ a.array = append(a.array, value...)
+ a.mu.Unlock()
+ return a
+}
+
+// PopLeft pops and returns an item from the beginning of array.
+// Note that if the array is empty, the `found` is false.
+func (a *StrArray) PopLeft() (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return "", false
+ }
+ value = a.array[0]
+ a.array = a.array[1:]
+ return value, true
+}
+
+// PopRight pops and returns an item from the end of array.
+// Note that if the array is empty, the `found` is false.
+func (a *StrArray) PopRight() (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ index := len(a.array) - 1
+ if index < 0 {
+ return "", false
+ }
+ value = a.array[index]
+ a.array = a.array[:index]
+ return value, true
+}
+
+// PopRand randomly pops and return an item out of array.
+// Note that if the array is empty, the `found` is false.
+func (a *StrArray) PopRand() (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+}
+
+// PopRands randomly pops and returns `size` items out of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *StrArray) PopRands(size int) []string {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ size = len(a.array)
+ }
+ array := make([]string, size)
+ for i := 0; i < size; i++ {
+ array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+ }
+ return array
+}
+
+// PopLefts pops and returns `size` items from the beginning of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *StrArray) PopLefts(size int) []string {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[0:size]
+ a.array = a.array[size:]
+ return value
+}
+
+// PopRights pops and returns `size` items from the end of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *StrArray) PopRights(size int) []string {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ index := len(a.array) - size
+ if index <= 0 {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[index:]
+ a.array = a.array[:index]
+ return value
+}
+
+// Range picks and returns items by range, like array[start:end].
+// Notice, if in concurrent-safe usage, it returns a copy of slice;
+// else a pointer to the underlying data.
+//
+// If `end` is negative, then the offset will start from the end of array.
+// If `end` is omitted, then the sequence will have everything from start up
+// until the end of the array.
+func (a *StrArray) Range(start int, end ...int) []string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ offsetEnd := len(a.array)
+ if len(end) > 0 && end[0] < offsetEnd {
+ offsetEnd = end[0]
+ }
+ if start > offsetEnd {
+ return nil
+ }
+ if start < 0 {
+ start = 0
+ }
+ array := ([]string)(nil)
+ if a.mu.IsSafe() {
+ array = make([]string, offsetEnd-start)
+ copy(array, a.array[start:offsetEnd])
+ } else {
+ array = a.array[start:offsetEnd]
+ }
+ return array
+}
+
+// SubSlice returns a slice of elements from the array as specified
+// by the `offset` and `size` parameters.
+// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
+//
+// If offset is non-negative, the sequence will start at that offset in the array.
+// If offset is negative, the sequence will start that far from the end of the array.
+//
+// If length is given and is positive, then the sequence will have up to that many elements in it.
+// If the array is shorter than the length, then only the available array elements will be present.
+// If length is given and is negative then the sequence will stop that many elements from the end of the array.
+// If it is omitted, then the sequence will have everything from offset up until the end of the array.
+//
+// Any possibility crossing the left border of array, it will fail.
+func (a *StrArray) SubSlice(offset int, length ...int) []string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ size := len(a.array)
+ if len(length) > 0 {
+ size = length[0]
+ }
+ if offset > len(a.array) {
+ return nil
+ }
+ if offset < 0 {
+ offset = len(a.array) + offset
+ if offset < 0 {
+ return nil
+ }
+ }
+ if size < 0 {
+ offset += size
+ size = -size
+ if offset < 0 {
+ return nil
+ }
+ }
+ end := offset + size
+ if end > len(a.array) {
+ end = len(a.array)
+ size = len(a.array) - offset
+ }
+ if a.mu.IsSafe() {
+ s := make([]string, size)
+ copy(s, a.array[offset:])
+ return s
+ }
+ return a.array[offset:end]
+}
+
+// Append is alias of PushRight,please See PushRight.
+func (a *StrArray) Append(value ...string) *StrArray {
+ a.mu.Lock()
+ a.array = append(a.array, value...)
+ a.mu.Unlock()
+ return a
+}
+
+// Len returns the length of array.
+func (a *StrArray) Len() int {
+ a.mu.RLock()
+ length := len(a.array)
+ a.mu.RUnlock()
+ return length
+}
+
+// Slice returns the underlying data of array.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (a *StrArray) Slice() []string {
+ array := ([]string)(nil)
+ if a.mu.IsSafe() {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array = make([]string, len(a.array))
+ copy(array, a.array)
+ } else {
+ array = a.array
+ }
+ return array
+}
+
+// Interfaces returns current array as []interface{}.
+func (a *StrArray) Interfaces() []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array := make([]interface{}, len(a.array))
+ for k, v := range a.array {
+ array[k] = v
+ }
+ return array
+}
+
+// Clone returns a new array, which is a copy of current array.
+func (a *StrArray) Clone() (newArray *StrArray) {
+ a.mu.RLock()
+ array := make([]string, len(a.array))
+ copy(array, a.array)
+ a.mu.RUnlock()
+ return NewStrArrayFrom(array, a.mu.IsSafe())
+}
+
+// Clear deletes all items of current array.
+func (a *StrArray) Clear() *StrArray {
+ a.mu.Lock()
+ if len(a.array) > 0 {
+ a.array = make([]string, 0)
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// Contains checks whether a value exists in the array.
+func (a *StrArray) Contains(value string) bool {
+ return a.Search(value) != -1
+}
+
+// ContainsI checks whether a value exists in the array with case-insensitively.
+// Note that it internally iterates the whole array to do the comparison with case-insensitively.
+func (a *StrArray) ContainsI(value string) bool {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return false
+ }
+ for _, v := range a.array {
+ if strings.EqualFold(v, value) {
+ return true
+ }
+ }
+ return false
+}
+
+// Search searches array by `value`, returns the index of `value`,
+// or returns -1 if not exists.
+func (a *StrArray) Search(value string) int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return -1
+ }
+ result := -1
+ for index, v := range a.array {
+ if strings.Compare(v, value) == 0 {
+ result = index
+ break
+ }
+ }
+ return result
+}
+
+// Unique uniques the array, clear repeated items.
+// Example: [1,1,2,3,2] -> [1,2,3]
+func (a *StrArray) Unique() *StrArray {
+ a.mu.Lock()
+ for i := 0; i < len(a.array)-1; i++ {
+ for j := i + 1; j < len(a.array); {
+ if a.array[i] == a.array[j] {
+ a.array = append(a.array[:j], a.array[j+1:]...)
+ } else {
+ j++
+ }
+ }
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// LockFunc locks writing by callback function `f`.
+func (a *StrArray) LockFunc(f func(array []string)) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ f(a.array)
+ return a
+}
+
+// RLockFunc locks reading by callback function `f`.
+func (a *StrArray) RLockFunc(f func(array []string)) *StrArray {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ f(a.array)
+ return a
+}
+
+// Merge merges `array` into current array.
+// The parameter `array` can be any garray or slice type.
+// The difference between Merge and Append is Append supports only specified slice type,
+// but Merge supports more parameter types.
+func (a *StrArray) Merge(array interface{}) *StrArray {
+ return a.Append(gconv.Strings(array)...)
+}
+
+// Fill fills an array with num entries of the value `value`,
+// keys starting at the `startIndex` parameter.
+func (a *StrArray) Fill(startIndex int, num int, value string) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if startIndex < 0 || startIndex > len(a.array) {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
+ }
+ for i := startIndex; i < startIndex+num; i++ {
+ if i > len(a.array)-1 {
+ a.array = append(a.array, value)
+ } else {
+ a.array[i] = value
+ }
+ }
+ return nil
+}
+
+// Chunk splits an array into multiple arrays,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (a *StrArray) Chunk(size int) [][]string {
+ if size < 1 {
+ return nil
+ }
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ length := len(a.array)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n [][]string
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, a.array[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Pad pads array to the specified length with `value`.
+// If size is positive then the array is padded on the right, or negative on the left.
+// If the absolute value of `size` is less than or equal to the length of the array
+// then no padding takes place.
+func (a *StrArray) Pad(size int, value string) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) {
+ return a
+ }
+ n := size
+ if size < 0 {
+ n = -size
+ }
+ n -= len(a.array)
+ tmp := make([]string, n)
+ for i := 0; i < n; i++ {
+ tmp[i] = value
+ }
+ if size > 0 {
+ a.array = append(a.array, tmp...)
+ } else {
+ a.array = append(tmp, a.array...)
+ }
+ return a
+}
+
+// Rand randomly returns one item from array(no deleting).
+func (a *StrArray) Rand() (value string, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return "", false
+ }
+ return a.array[grand.Intn(len(a.array))], true
+}
+
+// Rands randomly returns `size` items from array(no deleting).
+func (a *StrArray) Rands(size int) []string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ array := make([]string, size)
+ for i := 0; i < size; i++ {
+ array[i] = a.array[grand.Intn(len(a.array))]
+ }
+ return array
+}
+
+// Shuffle randomly shuffles the array.
+func (a *StrArray) Shuffle() *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range grand.Perm(len(a.array)) {
+ a.array[i], a.array[v] = a.array[v], a.array[i]
+ }
+ return a
+}
+
+// Reverse makes array with elements in reverse order.
+func (a *StrArray) Reverse() *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 {
+ a.array[i], a.array[j] = a.array[j], a.array[i]
+ }
+ return a
+}
+
+// Join joins array elements with a string `glue`.
+func (a *StrArray) Join(glue string) string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ for k, v := range a.array {
+ buffer.WriteString(v)
+ if k != len(a.array)-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ return buffer.String()
+}
+
+// CountValues counts the number of occurrences of all values in the array.
+func (a *StrArray) CountValues() map[string]int {
+ m := make(map[string]int)
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ m[v]++
+ }
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (a *StrArray) Iterator(f func(k int, v string) bool) {
+ a.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for k, v := range a.array {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for i := len(a.array) - 1; i >= 0; i-- {
+ if !f(i, a.array[i]) {
+ break
+ }
+ }
+}
+
+// String returns current array as a string, which implements like json.Marshal does.
+func (a *StrArray) String() string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteByte('[')
+ for k, v := range a.array {
+ buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
+ if k != len(a.array)-1 {
+ buffer.WriteByte(',')
+ }
+ }
+ buffer.WriteByte(']')
+ return buffer.String()
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (a StrArray) MarshalJSON() ([]byte, error) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ return json.Marshal(a.array)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (a *StrArray) UnmarshalJSON(b []byte) error {
+ if a.array == nil {
+ a.array = make([]string, 0)
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for array.
+func (a *StrArray) UnmarshalValue(value interface{}) error {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
+ default:
+ a.array = gconv.SliceStr(value)
+ }
+ return nil
+}
+
+// FilterEmpty removes all empty string value of the array.
+func (a *StrArray) FilterEmpty() *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if a.array[i] == "" {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// Walk applies a user supplied function `f` to every item of array.
+func (a *StrArray) Walk(f func(value string) string) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
+// IsEmpty checks whether the array is empty.
+func (a *StrArray) IsEmpty() bool {
+ return a.Len() == 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_any.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_any.go
new file mode 100644
index 000000000000..1b702dec09c0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_any.go
@@ -0,0 +1,795 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "sort"
+
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/grand"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// SortedArray is a golang sorted array with rich features.
+// It is using increasing order in default, which can be changed by
+// setting it a custom comparator.
+// It contains a concurrent-safe/unsafe switch, which should be set
+// when its initialization and cannot be changed then.
+type SortedArray struct {
+ mu rwmutex.RWMutex
+ array []interface{}
+ unique bool // Whether enable unique feature(false)
+ comparator func(a, b interface{}) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)
+}
+
+// NewSortedArray creates and returns an empty sorted array.
+// The parameter `safe` is used to specify whether using array in concurrent-safety, which is false in default.
+// The parameter `comparator` used to compare values to sort in array,
+// if it returns value < 0, means v1 < v2; the v1 will be inserted before v2;
+// if it returns value = 0, means v1 = v2; the v1 will be replaced by v2;
+// if it returns value > 0, means v1 > v2; the v1 will be inserted after v2;
+func NewSortedArray(comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
+ return NewSortedArraySize(0, comparator, safe...)
+}
+
+// NewSortedArraySize create and returns an sorted array with given size and cap.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
+ return &SortedArray{
+ mu: rwmutex.Create(safe...),
+ array: make([]interface{}, 0, cap),
+ comparator: comparator,
+ }
+}
+
+// NewSortedArrayRange creates and returns a array by a range from `start` to `end`
+// with step value `step`.
+func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
+ if step == 0 {
+ panic(fmt.Sprintf(`invalid step value: %d`, step))
+ }
+ slice := make([]interface{}, (end-start+1)/step)
+ index := 0
+ for i := start; i <= end; i += step {
+ slice[index] = i
+ index++
+ }
+ return NewSortedArrayFrom(slice, comparator, safe...)
+}
+
+// NewSortedArrayFrom creates and returns an sorted array with given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedArrayFrom(array []interface{}, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
+ a := NewSortedArraySize(0, comparator, safe...)
+ a.array = array
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+ return a
+}
+
+// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedArrayFromCopy(array []interface{}, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
+ newArray := make([]interface{}, len(array))
+ copy(newArray, array)
+ return NewSortedArrayFrom(newArray, comparator, safe...)
+}
+
+// At returns the value by the specified index.
+// If the given `index` is out of range of the array, it returns `nil`.
+func (a *SortedArray) At(index int) (value interface{}) {
+ value, _ = a.Get(index)
+ return
+}
+
+// SetArray sets the underlying slice array with the given `array`.
+func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.array = array
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+ return a
+}
+
+// SetComparator sets/changes the comparator for sorting.
+// It resorts the array as the comparator is changed.
+func (a *SortedArray) SetComparator(comparator func(a, b interface{}) int) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.comparator = comparator
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+}
+
+// Sort sorts the array in increasing order.
+// The parameter `reverse` controls whether sort
+// in increasing order(default) or decreasing order
+func (a *SortedArray) Sort() *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+ return a
+}
+
+// Add adds one or multiple values to sorted array, the array always keeps sorted.
+// It's alias of function Append, see Append.
+func (a *SortedArray) Add(values ...interface{}) *SortedArray {
+ return a.Append(values...)
+}
+
+// Append adds one or multiple values to sorted array, the array always keeps sorted.
+func (a *SortedArray) Append(values ...interface{}) *SortedArray {
+ if len(values) == 0 {
+ return a
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for _, value := range values {
+ index, cmp := a.binSearch(value, false)
+ if a.unique && cmp == 0 {
+ continue
+ }
+ if index < 0 {
+ a.array = append(a.array, value)
+ continue
+ }
+ if cmp > 0 {
+ index++
+ }
+ a.array = append(a.array[:index], append([]interface{}{value}, a.array[index:]...)...)
+ }
+ return a
+}
+
+// Get returns the value by the specified index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *SortedArray) Get(index int) (value interface{}, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if index < 0 || index >= len(a.array) {
+ return nil, false
+ }
+ return a.array[index], true
+}
+
+// Remove removes an item by index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *SortedArray) Remove(index int) (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(index)
+}
+
+// doRemoveWithoutLock removes an item by index without lock.
+func (a *SortedArray) doRemoveWithoutLock(index int) (value interface{}, found bool) {
+ if index < 0 || index >= len(a.array) {
+ return nil, false
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ value := a.array[0]
+ a.array = a.array[1:]
+ return value, true
+ } else if index == len(a.array)-1 {
+ value := a.array[index]
+ a.array = a.array[:index]
+ return value, true
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ value = a.array[index]
+ a.array = append(a.array[:index], a.array[index+1:]...)
+ return value, true
+}
+
+// RemoveValue removes an item by value.
+// It returns true if value is found in the array, or else false if not found.
+func (a *SortedArray) RemoveValue(value interface{}) bool {
+ if i := a.Search(value); i != -1 {
+ a.Remove(i)
+ return true
+ }
+ return false
+}
+
+// PopLeft pops and returns an item from the beginning of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedArray) PopLeft() (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return nil, false
+ }
+ value = a.array[0]
+ a.array = a.array[1:]
+ return value, true
+}
+
+// PopRight pops and returns an item from the end of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedArray) PopRight() (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ index := len(a.array) - 1
+ if index < 0 {
+ return nil, false
+ }
+ value = a.array[index]
+ a.array = a.array[:index]
+ return value, true
+}
+
+// PopRand randomly pops and return an item out of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedArray) PopRand() (value interface{}, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+}
+
+// PopRands randomly pops and returns `size` items out of array.
+func (a *SortedArray) PopRands(size int) []interface{} {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ size = len(a.array)
+ }
+ array := make([]interface{}, size)
+ for i := 0; i < size; i++ {
+ array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+ }
+ return array
+}
+
+// PopLefts pops and returns `size` items from the beginning of array.
+func (a *SortedArray) PopLefts(size int) []interface{} {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[0:size]
+ a.array = a.array[size:]
+ return value
+}
+
+// PopRights pops and returns `size` items from the end of array.
+func (a *SortedArray) PopRights(size int) []interface{} {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ index := len(a.array) - size
+ if index <= 0 {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[index:]
+ a.array = a.array[:index]
+ return value
+}
+
+// Range picks and returns items by range, like array[start:end].
+// Notice, if in concurrent-safe usage, it returns a copy of slice;
+// else a pointer to the underlying data.
+//
+// If `end` is negative, then the offset will start from the end of array.
+// If `end` is omitted, then the sequence will have everything from start up
+// until the end of the array.
+func (a *SortedArray) Range(start int, end ...int) []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ offsetEnd := len(a.array)
+ if len(end) > 0 && end[0] < offsetEnd {
+ offsetEnd = end[0]
+ }
+ if start > offsetEnd {
+ return nil
+ }
+ if start < 0 {
+ start = 0
+ }
+ array := ([]interface{})(nil)
+ if a.mu.IsSafe() {
+ array = make([]interface{}, offsetEnd-start)
+ copy(array, a.array[start:offsetEnd])
+ } else {
+ array = a.array[start:offsetEnd]
+ }
+ return array
+}
+
+// SubSlice returns a slice of elements from the array as specified
+// by the `offset` and `size` parameters.
+// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
+//
+// If offset is non-negative, the sequence will start at that offset in the array.
+// If offset is negative, the sequence will start that far from the end of the array.
+//
+// If length is given and is positive, then the sequence will have up to that many elements in it.
+// If the array is shorter than the length, then only the available array elements will be present.
+// If length is given and is negative then the sequence will stop that many elements from the end of the array.
+// If it is omitted, then the sequence will have everything from offset up until the end of the array.
+//
+// Any possibility crossing the left border of array, it will fail.
+func (a *SortedArray) SubSlice(offset int, length ...int) []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ size := len(a.array)
+ if len(length) > 0 {
+ size = length[0]
+ }
+ if offset > len(a.array) {
+ return nil
+ }
+ if offset < 0 {
+ offset = len(a.array) + offset
+ if offset < 0 {
+ return nil
+ }
+ }
+ if size < 0 {
+ offset += size
+ size = -size
+ if offset < 0 {
+ return nil
+ }
+ }
+ end := offset + size
+ if end > len(a.array) {
+ end = len(a.array)
+ size = len(a.array) - offset
+ }
+ if a.mu.IsSafe() {
+ s := make([]interface{}, size)
+ copy(s, a.array[offset:])
+ return s
+ } else {
+ return a.array[offset:end]
+ }
+}
+
+// Sum returns the sum of values in an array.
+func (a *SortedArray) Sum() (sum int) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ sum += gconv.Int(v)
+ }
+ return
+}
+
+// Len returns the length of array.
+func (a *SortedArray) Len() int {
+ a.mu.RLock()
+ length := len(a.array)
+ a.mu.RUnlock()
+ return length
+}
+
+// Slice returns the underlying data of array.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (a *SortedArray) Slice() []interface{} {
+ var array []interface{}
+ if a.mu.IsSafe() {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array = make([]interface{}, len(a.array))
+ copy(array, a.array)
+ } else {
+ array = a.array
+ }
+ return array
+}
+
+// Interfaces returns current array as []interface{}.
+func (a *SortedArray) Interfaces() []interface{} {
+ return a.Slice()
+}
+
+// Contains checks whether a value exists in the array.
+func (a *SortedArray) Contains(value interface{}) bool {
+ return a.Search(value) != -1
+}
+
+// Search searches array by `value`, returns the index of `value`,
+// or returns -1 if not exists.
+func (a *SortedArray) Search(value interface{}) (index int) {
+ if i, r := a.binSearch(value, true); r == 0 {
+ return i
+ }
+ return -1
+}
+
+// Binary search.
+// It returns the last compared index and the result.
+// If `result` equals to 0, it means the value at `index` is equals to `value`.
+// If `result` lesser than 0, it means the value at `index` is lesser than `value`.
+// If `result` greater than 0, it means the value at `index` is greater than `value`.
+func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result int) {
+ if lock {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ }
+ if len(a.array) == 0 {
+ return -1, -2
+ }
+ min := 0
+ max := len(a.array) - 1
+ mid := 0
+ cmp := -2
+ for min <= max {
+ mid = min + (max-min)/2
+ cmp = a.getComparator()(value, a.array[mid])
+ switch {
+ case cmp < 0:
+ max = mid - 1
+ case cmp > 0:
+ min = mid + 1
+ default:
+ return mid, cmp
+ }
+ }
+ return mid, cmp
+}
+
+// SetUnique sets unique mark to the array,
+// which means it does not contain any repeated items.
+// It also do unique check, remove all repeated items.
+func (a *SortedArray) SetUnique(unique bool) *SortedArray {
+ oldUnique := a.unique
+ a.unique = unique
+ if unique && oldUnique != unique {
+ a.Unique()
+ }
+ return a
+}
+
+// Unique uniques the array, clear repeated items.
+func (a *SortedArray) Unique() *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return a
+ }
+ i := 0
+ for {
+ if i == len(a.array)-1 {
+ break
+ }
+ if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
+ a.array = append(a.array[:i+1], a.array[i+1+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// Clone returns a new array, which is a copy of current array.
+func (a *SortedArray) Clone() (newArray *SortedArray) {
+ a.mu.RLock()
+ array := make([]interface{}, len(a.array))
+ copy(array, a.array)
+ a.mu.RUnlock()
+ return NewSortedArrayFrom(array, a.comparator, a.mu.IsSafe())
+}
+
+// Clear deletes all items of current array.
+func (a *SortedArray) Clear() *SortedArray {
+ a.mu.Lock()
+ if len(a.array) > 0 {
+ a.array = make([]interface{}, 0)
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// LockFunc locks writing by callback function `f`.
+func (a *SortedArray) LockFunc(f func(array []interface{})) *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ // Keep the array always sorted.
+ defer sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+
+ f(a.array)
+ return a
+}
+
+// RLockFunc locks reading by callback function `f`.
+func (a *SortedArray) RLockFunc(f func(array []interface{})) *SortedArray {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ f(a.array)
+ return a
+}
+
+// Merge merges `array` into current array.
+// The parameter `array` can be any garray or slice type.
+// The difference between Merge and Append is Append supports only specified slice type,
+// but Merge supports more parameter types.
+func (a *SortedArray) Merge(array interface{}) *SortedArray {
+ return a.Add(gconv.Interfaces(array)...)
+}
+
+// Chunk splits an array into multiple arrays,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (a *SortedArray) Chunk(size int) [][]interface{} {
+ if size < 1 {
+ return nil
+ }
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ length := len(a.array)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n [][]interface{}
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, a.array[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Rand randomly returns one item from array(no deleting).
+func (a *SortedArray) Rand() (value interface{}, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return nil, false
+ }
+ return a.array[grand.Intn(len(a.array))], true
+}
+
+// Rands randomly returns `size` items from array(no deleting).
+func (a *SortedArray) Rands(size int) []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ array := make([]interface{}, size)
+ for i := 0; i < size; i++ {
+ array[i] = a.array[grand.Intn(len(a.array))]
+ }
+ return array
+}
+
+// Join joins array elements with a string `glue`.
+func (a *SortedArray) Join(glue string) string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ for k, v := range a.array {
+ buffer.WriteString(gconv.String(v))
+ if k != len(a.array)-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ return buffer.String()
+}
+
+// CountValues counts the number of occurrences of all values in the array.
+func (a *SortedArray) CountValues() map[interface{}]int {
+ m := make(map[interface{}]int)
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ m[v]++
+ }
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (a *SortedArray) Iterator(f func(k int, v interface{}) bool) {
+ a.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *SortedArray) IteratorAsc(f func(k int, v interface{}) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for k, v := range a.array {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *SortedArray) IteratorDesc(f func(k int, v interface{}) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for i := len(a.array) - 1; i >= 0; i-- {
+ if !f(i, a.array[i]) {
+ break
+ }
+ }
+}
+
+// String returns current array as a string, which implements like json.Marshal does.
+func (a *SortedArray) String() string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteByte('[')
+ s := ""
+ for k, v := range a.array {
+ s = gconv.String(v)
+ if gstr.IsNumeric(s) {
+ buffer.WriteString(s)
+ } else {
+ buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
+ }
+ if k != len(a.array)-1 {
+ buffer.WriteByte(',')
+ }
+ }
+ buffer.WriteByte(']')
+ return buffer.String()
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (a SortedArray) MarshalJSON() ([]byte, error) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ return json.Marshal(a.array)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+// Note that the comparator is set as string comparator in default.
+func (a *SortedArray) UnmarshalJSON(b []byte) error {
+ if a.comparator == nil {
+ a.array = make([]interface{}, 0)
+ a.comparator = gutil.ComparatorString
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
+ return err
+ }
+ if a.comparator != nil && a.array != nil {
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.comparator(a.array[i], a.array[j]) < 0
+ })
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for array.
+// Note that the comparator is set as string comparator in default.
+func (a *SortedArray) UnmarshalValue(value interface{}) (err error) {
+ if a.comparator == nil {
+ a.comparator = gutil.ComparatorString
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
+ default:
+ a.array = gconv.SliceAny(value)
+ }
+ if a.comparator != nil && a.array != nil {
+ sort.Slice(a.array, func(i, j int) bool {
+ return a.comparator(a.array[i], a.array[j]) < 0
+ })
+ }
+ return err
+}
+
+// FilterNil removes all nil value of the array.
+func (a *SortedArray) FilterNil() *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if empty.IsNil(a.array[i]) {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ for i := len(a.array) - 1; i >= 0; {
+ if empty.IsNil(a.array[i]) {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ return a
+}
+
+// FilterEmpty removes all empty value of the array.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (a *SortedArray) FilterEmpty() *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if empty.IsEmpty(a.array[i]) {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ for i := len(a.array) - 1; i >= 0; {
+ if empty.IsEmpty(a.array[i]) {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ return a
+}
+
+// Walk applies a user supplied function `f` to every item of array.
+func (a *SortedArray) Walk(f func(value interface{}) interface{}) *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ // Keep the array always sorted.
+ defer sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
+// IsEmpty checks whether the array is empty.
+func (a *SortedArray) IsEmpty() bool {
+ return a.Len() == 0
+}
+
+// getComparator returns the comparator if it's previously set,
+// or else it panics.
+func (a *SortedArray) getComparator() func(a, b interface{}) int {
+ if a.comparator == nil {
+ panic("comparator is missing for sorted array")
+ }
+ return a.comparator
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_int.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_int.go
new file mode 100644
index 000000000000..fd2730438bc8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_int.go
@@ -0,0 +1,743 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "sort"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// SortedIntArray is a golang sorted int array with rich features.
+// It is using increasing order in default, which can be changed by
+// setting it a custom comparator.
+// It contains a concurrent-safe/unsafe switch, which should be set
+// when its initialization and cannot be changed then.
+type SortedIntArray struct {
+ mu rwmutex.RWMutex
+ array []int
+ unique bool // Whether enable unique feature(false)
+ comparator func(a, b int) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)
+}
+
+// NewSortedIntArray creates and returns an empty sorted array.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedIntArray(safe ...bool) *SortedIntArray {
+ return NewSortedIntArraySize(0, safe...)
+}
+
+// NewSortedIntArrayComparator creates and returns an empty sorted array with specified comparator.
+// The parameter `safe` is used to specify whether using array in concurrent-safety which is false in default.
+func NewSortedIntArrayComparator(comparator func(a, b int) int, safe ...bool) *SortedIntArray {
+ array := NewSortedIntArray(safe...)
+ array.comparator = comparator
+ return array
+}
+
+// NewSortedIntArraySize create and returns an sorted array with given size and cap.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
+ return &SortedIntArray{
+ mu: rwmutex.Create(safe...),
+ array: make([]int, 0, cap),
+ comparator: defaultComparatorInt,
+ }
+}
+
+// NewSortedIntArrayRange creates and returns a array by a range from `start` to `end`
+// with step value `step`.
+func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {
+ if step == 0 {
+ panic(fmt.Sprintf(`invalid step value: %d`, step))
+ }
+ slice := make([]int, (end-start+1)/step)
+ index := 0
+ for i := start; i <= end; i += step {
+ slice[index] = i
+ index++
+ }
+ return NewSortedIntArrayFrom(slice, safe...)
+}
+
+// NewSortedIntArrayFrom creates and returns an sorted array with given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedIntArrayFrom(array []int, safe ...bool) *SortedIntArray {
+ a := NewSortedIntArraySize(0, safe...)
+ a.array = array
+ sort.Ints(a.array)
+ return a
+}
+
+// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedIntArrayFromCopy(array []int, safe ...bool) *SortedIntArray {
+ newArray := make([]int, len(array))
+ copy(newArray, array)
+ return NewSortedIntArrayFrom(newArray, safe...)
+}
+
+// At returns the value by the specified index.
+// If the given `index` is out of range of the array, it returns `0`.
+func (a *SortedIntArray) At(index int) (value int) {
+ value, _ = a.Get(index)
+ return
+}
+
+// SetArray sets the underlying slice array with the given `array`.
+func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.array = array
+ quickSortInt(a.array, a.getComparator())
+ return a
+}
+
+// Sort sorts the array in increasing order.
+// The parameter `reverse` controls whether sort
+// in increasing order(default) or decreasing order.
+func (a *SortedIntArray) Sort() *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ quickSortInt(a.array, a.getComparator())
+ return a
+}
+
+// Add adds one or multiple values to sorted array, the array always keeps sorted.
+// It's alias of function Append, see Append.
+func (a *SortedIntArray) Add(values ...int) *SortedIntArray {
+ return a.Append(values...)
+}
+
+// Append adds one or multiple values to sorted array, the array always keeps sorted.
+func (a *SortedIntArray) Append(values ...int) *SortedIntArray {
+ if len(values) == 0 {
+ return a
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for _, value := range values {
+ index, cmp := a.binSearch(value, false)
+ if a.unique && cmp == 0 {
+ continue
+ }
+ if index < 0 {
+ a.array = append(a.array, value)
+ continue
+ }
+ if cmp > 0 {
+ index++
+ }
+ rear := append([]int{}, a.array[index:]...)
+ a.array = append(a.array[0:index], value)
+ a.array = append(a.array, rear...)
+ }
+ return a
+}
+
+// Get returns the value by the specified index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *SortedIntArray) Get(index int) (value int, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if index < 0 || index >= len(a.array) {
+ return 0, false
+ }
+ return a.array[index], true
+}
+
+// Remove removes an item by index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *SortedIntArray) Remove(index int) (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(index)
+}
+
+// doRemoveWithoutLock removes an item by index without lock.
+func (a *SortedIntArray) doRemoveWithoutLock(index int) (value int, found bool) {
+ if index < 0 || index >= len(a.array) {
+ return 0, false
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ value := a.array[0]
+ a.array = a.array[1:]
+ return value, true
+ } else if index == len(a.array)-1 {
+ value := a.array[index]
+ a.array = a.array[:index]
+ return value, true
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ value = a.array[index]
+ a.array = append(a.array[:index], a.array[index+1:]...)
+ return value, true
+}
+
+// RemoveValue removes an item by value.
+// It returns true if value is found in the array, or else false if not found.
+func (a *SortedIntArray) RemoveValue(value int) bool {
+ if i := a.Search(value); i != -1 {
+ _, found := a.Remove(i)
+ return found
+ }
+ return false
+}
+
+// PopLeft pops and returns an item from the beginning of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedIntArray) PopLeft() (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return 0, false
+ }
+ value = a.array[0]
+ a.array = a.array[1:]
+ return value, true
+}
+
+// PopRight pops and returns an item from the end of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedIntArray) PopRight() (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ index := len(a.array) - 1
+ if index < 0 {
+ return 0, false
+ }
+ value = a.array[index]
+ a.array = a.array[:index]
+ return value, true
+}
+
+// PopRand randomly pops and return an item out of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedIntArray) PopRand() (value int, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+}
+
+// PopRands randomly pops and returns `size` items out of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *SortedIntArray) PopRands(size int) []int {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ size = len(a.array)
+ }
+ array := make([]int, size)
+ for i := 0; i < size; i++ {
+ array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+ }
+ return array
+}
+
+// PopLefts pops and returns `size` items from the beginning of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *SortedIntArray) PopLefts(size int) []int {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[0:size]
+ a.array = a.array[size:]
+ return value
+}
+
+// PopRights pops and returns `size` items from the end of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *SortedIntArray) PopRights(size int) []int {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ index := len(a.array) - size
+ if index <= 0 {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[index:]
+ a.array = a.array[:index]
+ return value
+}
+
+// Range picks and returns items by range, like array[start:end].
+// Notice, if in concurrent-safe usage, it returns a copy of slice;
+// else a pointer to the underlying data.
+//
+// If `end` is negative, then the offset will start from the end of array.
+// If `end` is omitted, then the sequence will have everything from start up
+// until the end of the array.
+func (a *SortedIntArray) Range(start int, end ...int) []int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ offsetEnd := len(a.array)
+ if len(end) > 0 && end[0] < offsetEnd {
+ offsetEnd = end[0]
+ }
+ if start > offsetEnd {
+ return nil
+ }
+ if start < 0 {
+ start = 0
+ }
+ array := ([]int)(nil)
+ if a.mu.IsSafe() {
+ array = make([]int, offsetEnd-start)
+ copy(array, a.array[start:offsetEnd])
+ } else {
+ array = a.array[start:offsetEnd]
+ }
+ return array
+}
+
+// SubSlice returns a slice of elements from the array as specified
+// by the `offset` and `size` parameters.
+// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
+//
+// If offset is non-negative, the sequence will start at that offset in the array.
+// If offset is negative, the sequence will start that far from the end of the array.
+//
+// If length is given and is positive, then the sequence will have up to that many elements in it.
+// If the array is shorter than the length, then only the available array elements will be present.
+// If length is given and is negative then the sequence will stop that many elements from the end of the array.
+// If it is omitted, then the sequence will have everything from offset up until the end of the array.
+//
+// Any possibility crossing the left border of array, it will fail.
+func (a *SortedIntArray) SubSlice(offset int, length ...int) []int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ size := len(a.array)
+ if len(length) > 0 {
+ size = length[0]
+ }
+ if offset > len(a.array) {
+ return nil
+ }
+ if offset < 0 {
+ offset = len(a.array) + offset
+ if offset < 0 {
+ return nil
+ }
+ }
+ if size < 0 {
+ offset += size
+ size = -size
+ if offset < 0 {
+ return nil
+ }
+ }
+ end := offset + size
+ if end > len(a.array) {
+ end = len(a.array)
+ size = len(a.array) - offset
+ }
+ if a.mu.IsSafe() {
+ s := make([]int, size)
+ copy(s, a.array[offset:])
+ return s
+ } else {
+ return a.array[offset:end]
+ }
+}
+
+// Len returns the length of array.
+func (a *SortedIntArray) Len() int {
+ a.mu.RLock()
+ length := len(a.array)
+ a.mu.RUnlock()
+ return length
+}
+
+// Sum returns the sum of values in an array.
+func (a *SortedIntArray) Sum() (sum int) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ sum += v
+ }
+ return
+}
+
+// Slice returns the underlying data of array.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (a *SortedIntArray) Slice() []int {
+ array := ([]int)(nil)
+ if a.mu.IsSafe() {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array = make([]int, len(a.array))
+ copy(array, a.array)
+ } else {
+ array = a.array
+ }
+ return array
+}
+
+// Interfaces returns current array as []interface{}.
+func (a *SortedIntArray) Interfaces() []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array := make([]interface{}, len(a.array))
+ for k, v := range a.array {
+ array[k] = v
+ }
+ return array
+}
+
+// Contains checks whether a value exists in the array.
+func (a *SortedIntArray) Contains(value int) bool {
+ return a.Search(value) != -1
+}
+
+// Search searches array by `value`, returns the index of `value`,
+// or returns -1 if not exists.
+func (a *SortedIntArray) Search(value int) (index int) {
+ if i, r := a.binSearch(value, true); r == 0 {
+ return i
+ }
+ return -1
+}
+
+// Binary search.
+// It returns the last compared index and the result.
+// If `result` equals to 0, it means the value at `index` is equals to `value`.
+// If `result` lesser than 0, it means the value at `index` is lesser than `value`.
+// If `result` greater than 0, it means the value at `index` is greater than `value`.
+func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int) {
+ if lock {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ }
+ if len(a.array) == 0 {
+ return -1, -2
+ }
+ min := 0
+ max := len(a.array) - 1
+ mid := 0
+ cmp := -2
+ for min <= max {
+ mid = min + int((max-min)/2)
+ cmp = a.getComparator()(value, a.array[mid])
+ switch {
+ case cmp < 0:
+ max = mid - 1
+ case cmp > 0:
+ min = mid + 1
+ default:
+ return mid, cmp
+ }
+ }
+ return mid, cmp
+}
+
+// SetUnique sets unique mark to the array,
+// which means it does not contain any repeated items.
+// It also do unique check, remove all repeated items.
+func (a *SortedIntArray) SetUnique(unique bool) *SortedIntArray {
+ oldUnique := a.unique
+ a.unique = unique
+ if unique && oldUnique != unique {
+ a.Unique()
+ }
+ return a
+}
+
+// Unique uniques the array, clear repeated items.
+func (a *SortedIntArray) Unique() *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return a
+ }
+ i := 0
+ for {
+ if i == len(a.array)-1 {
+ break
+ }
+ if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
+ a.array = append(a.array[:i+1], a.array[i+1+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// Clone returns a new array, which is a copy of current array.
+func (a *SortedIntArray) Clone() (newArray *SortedIntArray) {
+ a.mu.RLock()
+ array := make([]int, len(a.array))
+ copy(array, a.array)
+ a.mu.RUnlock()
+ return NewSortedIntArrayFrom(array, a.mu.IsSafe())
+}
+
+// Clear deletes all items of current array.
+func (a *SortedIntArray) Clear() *SortedIntArray {
+ a.mu.Lock()
+ if len(a.array) > 0 {
+ a.array = make([]int, 0)
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// LockFunc locks writing by callback function `f`.
+func (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ f(a.array)
+ return a
+}
+
+// RLockFunc locks reading by callback function `f`.
+func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ f(a.array)
+ return a
+}
+
+// Merge merges `array` into current array.
+// The parameter `array` can be any garray or slice type.
+// The difference between Merge and Append is Append supports only specified slice type,
+// but Merge supports more parameter types.
+func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray {
+ return a.Add(gconv.Ints(array)...)
+}
+
+// Chunk splits an array into multiple arrays,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (a *SortedIntArray) Chunk(size int) [][]int {
+ if size < 1 {
+ return nil
+ }
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ length := len(a.array)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n [][]int
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, a.array[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Rand randomly returns one item from array(no deleting).
+func (a *SortedIntArray) Rand() (value int, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return 0, false
+ }
+ return a.array[grand.Intn(len(a.array))], true
+}
+
+// Rands randomly returns `size` items from array(no deleting).
+func (a *SortedIntArray) Rands(size int) []int {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ array := make([]int, size)
+ for i := 0; i < size; i++ {
+ array[i] = a.array[grand.Intn(len(a.array))]
+ }
+ return array
+}
+
+// Join joins array elements with a string `glue`.
+func (a *SortedIntArray) Join(glue string) string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ for k, v := range a.array {
+ buffer.WriteString(gconv.String(v))
+ if k != len(a.array)-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ return buffer.String()
+}
+
+// CountValues counts the number of occurrences of all values in the array.
+func (a *SortedIntArray) CountValues() map[int]int {
+ m := make(map[int]int)
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ m[v]++
+ }
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (a *SortedIntArray) Iterator(f func(k int, v int) bool) {
+ a.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for k, v := range a.array {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for i := len(a.array) - 1; i >= 0; i-- {
+ if !f(i, a.array[i]) {
+ break
+ }
+ }
+}
+
+// String returns current array as a string, which implements like json.Marshal does.
+func (a *SortedIntArray) String() string {
+ return "[" + a.Join(",") + "]"
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (a SortedIntArray) MarshalJSON() ([]byte, error) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ return json.Marshal(a.array)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (a *SortedIntArray) UnmarshalJSON(b []byte) error {
+ if a.comparator == nil {
+ a.array = make([]int, 0)
+ a.comparator = defaultComparatorInt
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
+ return err
+ }
+ if a.array != nil {
+ sort.Ints(a.array)
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for array.
+func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) {
+ if a.comparator == nil {
+ a.comparator = defaultComparatorInt
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
+ default:
+ a.array = gconv.SliceInt(value)
+ }
+ if a.array != nil {
+ sort.Ints(a.array)
+ }
+ return err
+}
+
+// FilterEmpty removes all zero value of the array.
+func (a *SortedIntArray) FilterEmpty() *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if a.array[i] == 0 {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ for i := len(a.array) - 1; i >= 0; {
+ if a.array[i] == 0 {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ return a
+}
+
+// Walk applies a user supplied function `f` to every item of array.
+func (a *SortedIntArray) Walk(f func(value int) int) *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ // Keep the array always sorted.
+ defer quickSortInt(a.array, a.getComparator())
+
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
+// IsEmpty checks whether the array is empty.
+func (a *SortedIntArray) IsEmpty() bool {
+ return a.Len() == 0
+}
+
+// getComparator returns the comparator if it's previously set,
+// or else it returns a default comparator.
+func (a *SortedIntArray) getComparator() func(a, b int) int {
+ if a.comparator == nil {
+ return defaultComparatorInt
+ }
+ return a.comparator
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_str.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_str.go
new file mode 100644
index 000000000000..768fec23a371
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/garray/garray_sorted_str.go
@@ -0,0 +1,756 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package garray
+
+import (
+ "bytes"
+ "math"
+ "sort"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// SortedStrArray is a golang sorted string array with rich features.
+// It is using increasing order in default, which can be changed by
+// setting it a custom comparator.
+// It contains a concurrent-safe/unsafe switch, which should be set
+// when its initialization and cannot be changed then.
+type SortedStrArray struct {
+ mu rwmutex.RWMutex
+ array []string
+ unique bool // Whether enable unique feature(false)
+ comparator func(a, b string) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)
+}
+
+// NewSortedStrArray creates and returns an empty sorted array.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedStrArray(safe ...bool) *SortedStrArray {
+ return NewSortedStrArraySize(0, safe...)
+}
+
+// NewSortedStrArrayComparator creates and returns an empty sorted array with specified comparator.
+// The parameter `safe` is used to specify whether using array in concurrent-safety which is false in default.
+func NewSortedStrArrayComparator(comparator func(a, b string) int, safe ...bool) *SortedStrArray {
+ array := NewSortedStrArray(safe...)
+ array.comparator = comparator
+ return array
+}
+
+// NewSortedStrArraySize create and returns an sorted array with given size and cap.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {
+ return &SortedStrArray{
+ mu: rwmutex.Create(safe...),
+ array: make([]string, 0, cap),
+ comparator: defaultComparatorStr,
+ }
+}
+
+// NewSortedStrArrayFrom creates and returns an sorted array with given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedStrArrayFrom(array []string, safe ...bool) *SortedStrArray {
+ a := NewSortedStrArraySize(0, safe...)
+ a.array = array
+ quickSortStr(a.array, a.getComparator())
+ return a
+}
+
+// NewSortedStrArrayFromCopy creates and returns an sorted array from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using array in concurrent-safety,
+// which is false in default.
+func NewSortedStrArrayFromCopy(array []string, safe ...bool) *SortedStrArray {
+ newArray := make([]string, len(array))
+ copy(newArray, array)
+ return NewSortedStrArrayFrom(newArray, safe...)
+}
+
+// SetArray sets the underlying slice array with the given `array`.
+func (a *SortedStrArray) SetArray(array []string) *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ a.array = array
+ quickSortStr(a.array, a.getComparator())
+ return a
+}
+
+// At returns the value by the specified index.
+// If the given `index` is out of range of the array, it returns an empty string.
+func (a *SortedStrArray) At(index int) (value string) {
+ value, _ = a.Get(index)
+ return
+}
+
+// Sort sorts the array in increasing order.
+// The parameter `reverse` controls whether sort
+// in increasing order(default) or decreasing order.
+func (a *SortedStrArray) Sort() *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ quickSortStr(a.array, a.getComparator())
+ return a
+}
+
+// Add adds one or multiple values to sorted array, the array always keeps sorted.
+// It's alias of function Append, see Append.
+func (a *SortedStrArray) Add(values ...string) *SortedStrArray {
+ return a.Append(values...)
+}
+
+// Append adds one or multiple values to sorted array, the array always keeps sorted.
+func (a *SortedStrArray) Append(values ...string) *SortedStrArray {
+ if len(values) == 0 {
+ return a
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for _, value := range values {
+ index, cmp := a.binSearch(value, false)
+ if a.unique && cmp == 0 {
+ continue
+ }
+ if index < 0 {
+ a.array = append(a.array, value)
+ continue
+ }
+ if cmp > 0 {
+ index++
+ }
+ rear := append([]string{}, a.array[index:]...)
+ a.array = append(a.array[0:index], value)
+ a.array = append(a.array, rear...)
+ }
+ return a
+}
+
+// Get returns the value by the specified index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *SortedStrArray) Get(index int) (value string, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if index < 0 || index >= len(a.array) {
+ return "", false
+ }
+ return a.array[index], true
+}
+
+// Remove removes an item by index.
+// If the given `index` is out of range of the array, the `found` is false.
+func (a *SortedStrArray) Remove(index int) (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(index)
+}
+
+// doRemoveWithoutLock removes an item by index without lock.
+func (a *SortedStrArray) doRemoveWithoutLock(index int) (value string, found bool) {
+ if index < 0 || index >= len(a.array) {
+ return "", false
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ value := a.array[0]
+ a.array = a.array[1:]
+ return value, true
+ } else if index == len(a.array)-1 {
+ value := a.array[index]
+ a.array = a.array[:index]
+ return value, true
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ value = a.array[index]
+ a.array = append(a.array[:index], a.array[index+1:]...)
+ return value, true
+}
+
+// RemoveValue removes an item by value.
+// It returns true if value is found in the array, or else false if not found.
+func (a *SortedStrArray) RemoveValue(value string) bool {
+ if i := a.Search(value); i != -1 {
+ a.Remove(i)
+ return true
+ }
+ return false
+}
+
+// PopLeft pops and returns an item from the beginning of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedStrArray) PopLeft() (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return "", false
+ }
+ value = a.array[0]
+ a.array = a.array[1:]
+ return value, true
+}
+
+// PopRight pops and returns an item from the end of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedStrArray) PopRight() (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ index := len(a.array) - 1
+ if index < 0 {
+ return "", false
+ }
+ value = a.array[index]
+ a.array = a.array[:index]
+ return value, true
+}
+
+// PopRand randomly pops and return an item out of array.
+// Note that if the array is empty, the `found` is false.
+func (a *SortedStrArray) PopRand() (value string, found bool) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+}
+
+// PopRands randomly pops and returns `size` items out of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *SortedStrArray) PopRands(size int) []string {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ size = len(a.array)
+ }
+ array := make([]string, size)
+ for i := 0; i < size; i++ {
+ array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
+ }
+ return array
+}
+
+// PopLefts pops and returns `size` items from the beginning of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *SortedStrArray) PopLefts(size int) []string {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ if size >= len(a.array) {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[0:size]
+ a.array = a.array[size:]
+ return value
+}
+
+// PopRights pops and returns `size` items from the end of array.
+// If the given `size` is greater than size of the array, it returns all elements of the array.
+// Note that if given `size` <= 0 or the array is empty, it returns nil.
+func (a *SortedStrArray) PopRights(size int) []string {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ index := len(a.array) - size
+ if index <= 0 {
+ array := a.array
+ a.array = a.array[:0]
+ return array
+ }
+ value := a.array[index:]
+ a.array = a.array[:index]
+ return value
+}
+
+// Range picks and returns items by range, like array[start:end].
+// Notice, if in concurrent-safe usage, it returns a copy of slice;
+// else a pointer to the underlying data.
+//
+// If `end` is negative, then the offset will start from the end of array.
+// If `end` is omitted, then the sequence will have everything from start up
+// until the end of the array.
+func (a *SortedStrArray) Range(start int, end ...int) []string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ offsetEnd := len(a.array)
+ if len(end) > 0 && end[0] < offsetEnd {
+ offsetEnd = end[0]
+ }
+ if start > offsetEnd {
+ return nil
+ }
+ if start < 0 {
+ start = 0
+ }
+ array := ([]string)(nil)
+ if a.mu.IsSafe() {
+ array = make([]string, offsetEnd-start)
+ copy(array, a.array[start:offsetEnd])
+ } else {
+ array = a.array[start:offsetEnd]
+ }
+ return array
+}
+
+// SubSlice returns a slice of elements from the array as specified
+// by the `offset` and `size` parameters.
+// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
+//
+// If offset is non-negative, the sequence will start at that offset in the array.
+// If offset is negative, the sequence will start that far from the end of the array.
+//
+// If length is given and is positive, then the sequence will have up to that many elements in it.
+// If the array is shorter than the length, then only the available array elements will be present.
+// If length is given and is negative then the sequence will stop that many elements from the end of the array.
+// If it is omitted, then the sequence will have everything from offset up until the end of the array.
+//
+// Any possibility crossing the left border of array, it will fail.
+func (a *SortedStrArray) SubSlice(offset int, length ...int) []string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ size := len(a.array)
+ if len(length) > 0 {
+ size = length[0]
+ }
+ if offset > len(a.array) {
+ return nil
+ }
+ if offset < 0 {
+ offset = len(a.array) + offset
+ if offset < 0 {
+ return nil
+ }
+ }
+ if size < 0 {
+ offset += size
+ size = -size
+ if offset < 0 {
+ return nil
+ }
+ }
+ end := offset + size
+ if end > len(a.array) {
+ end = len(a.array)
+ size = len(a.array) - offset
+ }
+ if a.mu.IsSafe() {
+ s := make([]string, size)
+ copy(s, a.array[offset:])
+ return s
+ } else {
+ return a.array[offset:end]
+ }
+}
+
+// Sum returns the sum of values in an array.
+func (a *SortedStrArray) Sum() (sum int) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ sum += gconv.Int(v)
+ }
+ return
+}
+
+// Len returns the length of array.
+func (a *SortedStrArray) Len() int {
+ a.mu.RLock()
+ length := len(a.array)
+ a.mu.RUnlock()
+ return length
+}
+
+// Slice returns the underlying data of array.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (a *SortedStrArray) Slice() []string {
+ array := ([]string)(nil)
+ if a.mu.IsSafe() {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array = make([]string, len(a.array))
+ copy(array, a.array)
+ } else {
+ array = a.array
+ }
+ return array
+}
+
+// Interfaces returns current array as []interface{}.
+func (a *SortedStrArray) Interfaces() []interface{} {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ array := make([]interface{}, len(a.array))
+ for k, v := range a.array {
+ array[k] = v
+ }
+ return array
+}
+
+// Contains checks whether a value exists in the array.
+func (a *SortedStrArray) Contains(value string) bool {
+ return a.Search(value) != -1
+}
+
+// ContainsI checks whether a value exists in the array with case-insensitively.
+// Note that it internally iterates the whole array to do the comparison with case-insensitively.
+func (a *SortedStrArray) ContainsI(value string) bool {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return false
+ }
+ for _, v := range a.array {
+ if strings.EqualFold(v, value) {
+ return true
+ }
+ }
+ return false
+}
+
+// Search searches array by `value`, returns the index of `value`,
+// or returns -1 if not exists.
+func (a *SortedStrArray) Search(value string) (index int) {
+ if i, r := a.binSearch(value, true); r == 0 {
+ return i
+ }
+ return -1
+}
+
+// Binary search.
+// It returns the last compared index and the result.
+// If `result` equals to 0, it means the value at `index` is equals to `value`.
+// If `result` lesser than 0, it means the value at `index` is lesser than `value`.
+// If `result` greater than 0, it means the value at `index` is greater than `value`.
+func (a *SortedStrArray) binSearch(value string, lock bool) (index int, result int) {
+ if lock {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ }
+ if len(a.array) == 0 {
+ return -1, -2
+ }
+ min := 0
+ max := len(a.array) - 1
+ mid := 0
+ cmp := -2
+ for min <= max {
+ mid = min + int((max-min)/2)
+ cmp = a.getComparator()(value, a.array[mid])
+ switch {
+ case cmp < 0:
+ max = mid - 1
+ case cmp > 0:
+ min = mid + 1
+ default:
+ return mid, cmp
+ }
+ }
+ return mid, cmp
+}
+
+// SetUnique sets unique mark to the array,
+// which means it does not contain any repeated items.
+// It also do unique check, remove all repeated items.
+func (a *SortedStrArray) SetUnique(unique bool) *SortedStrArray {
+ oldUnique := a.unique
+ a.unique = unique
+ if unique && oldUnique != unique {
+ a.Unique()
+ }
+ return a
+}
+
+// Unique uniques the array, clear repeated items.
+func (a *SortedStrArray) Unique() *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if len(a.array) == 0 {
+ return a
+ }
+ i := 0
+ for {
+ if i == len(a.array)-1 {
+ break
+ }
+ if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
+ a.array = append(a.array[:i+1], a.array[i+1+1:]...)
+ } else {
+ i++
+ }
+ }
+ return a
+}
+
+// Clone returns a new array, which is a copy of current array.
+func (a *SortedStrArray) Clone() (newArray *SortedStrArray) {
+ a.mu.RLock()
+ array := make([]string, len(a.array))
+ copy(array, a.array)
+ a.mu.RUnlock()
+ return NewSortedStrArrayFrom(array, a.mu.IsSafe())
+}
+
+// Clear deletes all items of current array.
+func (a *SortedStrArray) Clear() *SortedStrArray {
+ a.mu.Lock()
+ if len(a.array) > 0 {
+ a.array = make([]string, 0)
+ }
+ a.mu.Unlock()
+ return a
+}
+
+// LockFunc locks writing by callback function `f`.
+func (a *SortedStrArray) LockFunc(f func(array []string)) *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ f(a.array)
+ return a
+}
+
+// RLockFunc locks reading by callback function `f`.
+func (a *SortedStrArray) RLockFunc(f func(array []string)) *SortedStrArray {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ f(a.array)
+ return a
+}
+
+// Merge merges `array` into current array.
+// The parameter `array` can be any garray or slice type.
+// The difference between Merge and Append is Append supports only specified slice type,
+// but Merge supports more parameter types.
+func (a *SortedStrArray) Merge(array interface{}) *SortedStrArray {
+ return a.Add(gconv.Strings(array)...)
+}
+
+// Chunk splits an array into multiple arrays,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (a *SortedStrArray) Chunk(size int) [][]string {
+ if size < 1 {
+ return nil
+ }
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ length := len(a.array)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n [][]string
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, a.array[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Rand randomly returns one item from array(no deleting).
+func (a *SortedStrArray) Rand() (value string, found bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return "", false
+ }
+ return a.array[grand.Intn(len(a.array))], true
+}
+
+// Rands randomly returns `size` items from array(no deleting).
+func (a *SortedStrArray) Rands(size int) []string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if size <= 0 || len(a.array) == 0 {
+ return nil
+ }
+ array := make([]string, size)
+ for i := 0; i < size; i++ {
+ array[i] = a.array[grand.Intn(len(a.array))]
+ }
+ return array
+}
+
+// Join joins array elements with a string `glue`.
+func (a *SortedStrArray) Join(glue string) string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ for k, v := range a.array {
+ buffer.WriteString(v)
+ if k != len(a.array)-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ return buffer.String()
+}
+
+// CountValues counts the number of occurrences of all values in the array.
+func (a *SortedStrArray) CountValues() map[string]int {
+ m := make(map[string]int)
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for _, v := range a.array {
+ m[v]++
+ }
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (a *SortedStrArray) Iterator(f func(k int, v string) bool) {
+ a.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for k, v := range a.array {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// IteratorDesc iterates the array readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (a *SortedStrArray) IteratorDesc(f func(k int, v string) bool) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ for i := len(a.array) - 1; i >= 0; i-- {
+ if !f(i, a.array[i]) {
+ break
+ }
+ }
+}
+
+// String returns current array as a string, which implements like json.Marshal does.
+func (a *SortedStrArray) String() string {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteByte('[')
+ for k, v := range a.array {
+ buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
+ if k != len(a.array)-1 {
+ buffer.WriteByte(',')
+ }
+ }
+ buffer.WriteByte(']')
+ return buffer.String()
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (a SortedStrArray) MarshalJSON() ([]byte, error) {
+ a.mu.RLock()
+ defer a.mu.RUnlock()
+ return json.Marshal(a.array)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (a *SortedStrArray) UnmarshalJSON(b []byte) error {
+ if a.comparator == nil {
+ a.array = make([]string, 0)
+ a.comparator = defaultComparatorStr
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
+ return err
+ }
+ if a.array != nil {
+ sort.Strings(a.array)
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for array.
+func (a *SortedStrArray) UnmarshalValue(value interface{}) (err error) {
+ if a.comparator == nil {
+ a.comparator = defaultComparatorStr
+ }
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
+ default:
+ a.array = gconv.SliceStr(value)
+ }
+ if a.array != nil {
+ sort.Strings(a.array)
+ }
+ return err
+}
+
+// FilterEmpty removes all empty string value of the array.
+func (a *SortedStrArray) FilterEmpty() *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i := 0; i < len(a.array); {
+ if a.array[i] == "" {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ for i := len(a.array) - 1; i >= 0; {
+ if a.array[i] == "" {
+ a.array = append(a.array[:i], a.array[i+1:]...)
+ } else {
+ break
+ }
+ }
+ return a
+}
+
+// Walk applies a user supplied function `f` to every item of array.
+func (a *SortedStrArray) Walk(f func(value string) string) *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ // Keep the array always sorted.
+ defer quickSortStr(a.array, a.getComparator())
+
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
+// IsEmpty checks whether the array is empty.
+func (a *SortedStrArray) IsEmpty() bool {
+ return a.Len() == 0
+}
+
+// getComparator returns the comparator if it's previously set,
+// or else it returns a default comparator.
+func (a *SortedStrArray) getComparator() func(a, b string) int {
+ if a.comparator == nil {
+ return defaultComparatorStr
+ }
+ return a.comparator
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/glist/glist.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/glist/glist.go
new file mode 100644
index 000000000000..3dab3ee8631e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/glist/glist.go
@@ -0,0 +1,545 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with l file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+// Package glist provides most commonly used doubly linked list container which also supports concurrent-safe/unsafe switch feature.
+package glist
+
+import (
+ "bytes"
+ "container/list"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type (
+ // List is a doubly linked list containing a concurrent-safe/unsafe switch.
+ // The switch should be set when its initialization and cannot be changed then.
+ List struct {
+ mu rwmutex.RWMutex
+ list *list.List
+ }
+ // Element the item type of the list.
+ Element = list.Element
+)
+
+// New creates and returns a new empty doubly linked list.
+func New(safe ...bool) *List {
+ return &List{
+ mu: rwmutex.Create(safe...),
+ list: list.New(),
+ }
+}
+
+// NewFrom creates and returns a list from a copy of given slice `array`.
+// The parameter `safe` is used to specify whether using list in concurrent-safety,
+// which is false in default.
+func NewFrom(array []interface{}, safe ...bool) *List {
+ l := list.New()
+ for _, v := range array {
+ l.PushBack(v)
+ }
+ return &List{
+ mu: rwmutex.Create(safe...),
+ list: l,
+ }
+}
+
+// PushFront inserts a new element `e` with value `v` at the front of list `l` and returns `e`.
+func (l *List) PushFront(v interface{}) (e *Element) {
+ l.mu.Lock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ e = l.list.PushFront(v)
+ l.mu.Unlock()
+ return
+}
+
+// PushBack inserts a new element `e` with value `v` at the back of list `l` and returns `e`.
+func (l *List) PushBack(v interface{}) (e *Element) {
+ l.mu.Lock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ e = l.list.PushBack(v)
+ l.mu.Unlock()
+ return
+}
+
+// PushFronts inserts multiple new elements with values `values` at the front of list `l`.
+func (l *List) PushFronts(values []interface{}) {
+ l.mu.Lock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ for _, v := range values {
+ l.list.PushFront(v)
+ }
+ l.mu.Unlock()
+}
+
+// PushBacks inserts multiple new elements with values `values` at the back of list `l`.
+func (l *List) PushBacks(values []interface{}) {
+ l.mu.Lock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ for _, v := range values {
+ l.list.PushBack(v)
+ }
+ l.mu.Unlock()
+}
+
+// PopBack removes the element from back of `l` and returns the value of the element.
+func (l *List) PopBack() (value interface{}) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ return
+ }
+ if e := l.list.Back(); e != nil {
+ value = l.list.Remove(e)
+ }
+ return
+}
+
+// PopFront removes the element from front of `l` and returns the value of the element.
+func (l *List) PopFront() (value interface{}) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ return
+ }
+ if e := l.list.Front(); e != nil {
+ value = l.list.Remove(e)
+ }
+ return
+}
+
+// PopBacks removes `max` elements from back of `l`
+// and returns values of the removed elements as slice.
+func (l *List) PopBacks(max int) (values []interface{}) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ return
+ }
+ length := l.list.Len()
+ if length > 0 {
+ if max > 0 && max < length {
+ length = max
+ }
+ values = make([]interface{}, length)
+ for i := 0; i < length; i++ {
+ values[i] = l.list.Remove(l.list.Back())
+ }
+ }
+ return
+}
+
+// PopFronts removes `max` elements from front of `l`
+// and returns values of the removed elements as slice.
+func (l *List) PopFronts(max int) (values []interface{}) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ return
+ }
+ length := l.list.Len()
+ if length > 0 {
+ if max > 0 && max < length {
+ length = max
+ }
+ values = make([]interface{}, length)
+ for i := 0; i < length; i++ {
+ values[i] = l.list.Remove(l.list.Front())
+ }
+ }
+ return
+}
+
+// PopBackAll removes all elements from back of `l`
+// and returns values of the removed elements as slice.
+func (l *List) PopBackAll() []interface{} {
+ return l.PopBacks(-1)
+}
+
+// PopFrontAll removes all elements from front of `l`
+// and returns values of the removed elements as slice.
+func (l *List) PopFrontAll() []interface{} {
+ return l.PopFronts(-1)
+}
+
+// FrontAll copies and returns values of all elements from front of `l` as slice.
+func (l *List) FrontAll() (values []interface{}) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ length := l.list.Len()
+ if length > 0 {
+ values = make([]interface{}, length)
+ for i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {
+ values[i] = e.Value
+ }
+ }
+ return
+}
+
+// BackAll copies and returns values of all elements from back of `l` as slice.
+func (l *List) BackAll() (values []interface{}) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ length := l.list.Len()
+ if length > 0 {
+ values = make([]interface{}, length)
+ for i, e := 0, l.list.Back(); i < length; i, e = i+1, e.Prev() {
+ values[i] = e.Value
+ }
+ }
+ return
+}
+
+// FrontValue returns value of the first element of `l` or nil if the list is empty.
+func (l *List) FrontValue() (value interface{}) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ if e := l.list.Front(); e != nil {
+ value = e.Value
+ }
+ return
+}
+
+// BackValue returns value of the last element of `l` or nil if the list is empty.
+func (l *List) BackValue() (value interface{}) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ if e := l.list.Back(); e != nil {
+ value = e.Value
+ }
+ return
+}
+
+// Front returns the first element of list `l` or nil if the list is empty.
+func (l *List) Front() (e *Element) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ e = l.list.Front()
+ return
+}
+
+// Back returns the last element of list `l` or nil if the list is empty.
+func (l *List) Back() (e *Element) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ e = l.list.Back()
+ return
+}
+
+// Len returns the number of elements of list `l`.
+// The complexity is O(1).
+func (l *List) Len() (length int) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ length = l.list.Len()
+ return
+}
+
+// Size is alias of Len.
+func (l *List) Size() int {
+ return l.Len()
+}
+
+// MoveBefore moves element `e` to its new position before `p`.
+// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.
+// The element and `p` must not be nil.
+func (l *List) MoveBefore(e, p *Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ l.list.MoveBefore(e, p)
+}
+
+// MoveAfter moves element `e` to its new position after `p`.
+// If `e` or `p` is not an element of `l`, or `e` == `p`, the list is not modified.
+// The element and `p` must not be nil.
+func (l *List) MoveAfter(e, p *Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ l.list.MoveAfter(e, p)
+}
+
+// MoveToFront moves element `e` to the front of list `l`.
+// If `e` is not an element of `l`, the list is not modified.
+// The element must not be nil.
+func (l *List) MoveToFront(e *Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ l.list.MoveToFront(e)
+}
+
+// MoveToBack moves element `e` to the back of list `l`.
+// If `e` is not an element of `l`, the list is not modified.
+// The element must not be nil.
+func (l *List) MoveToBack(e *Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ l.list.MoveToBack(e)
+}
+
+// PushBackList inserts a copy of an other list at the back of list `l`.
+// The lists `l` and `other` may be the same, but they must not be nil.
+func (l *List) PushBackList(other *List) {
+ if l != other {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ l.list.PushBackList(other.list)
+}
+
+// PushFrontList inserts a copy of an other list at the front of list `l`.
+// The lists `l` and `other` may be the same, but they must not be nil.
+func (l *List) PushFrontList(other *List) {
+ if l != other {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ l.list.PushFrontList(other.list)
+}
+
+// InsertAfter inserts a new element `e` with value `v` immediately after `p` and returns `e`.
+// If `p` is not an element of `l`, the list is not modified.
+// The `p` must not be nil.
+func (l *List) InsertAfter(p *Element, v interface{}) (e *Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ e = l.list.InsertAfter(v, p)
+ return
+}
+
+// InsertBefore inserts a new element `e` with value `v` immediately before `p` and returns `e`.
+// If `p` is not an element of `l`, the list is not modified.
+// The `p` must not be nil.
+func (l *List) InsertBefore(p *Element, v interface{}) (e *Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ e = l.list.InsertBefore(v, p)
+ return
+}
+
+// Remove removes `e` from `l` if `e` is an element of list `l`.
+// It returns the element value e.Value.
+// The element must not be nil.
+func (l *List) Remove(e *Element) (value interface{}) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ value = l.list.Remove(e)
+ return
+}
+
+// Removes removes multiple elements `es` from `l` if `es` are elements of list `l`.
+func (l *List) Removes(es []*Element) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ for _, e := range es {
+ l.list.Remove(e)
+ }
+ return
+}
+
+// RemoveAll removes all elements from list `l`.
+func (l *List) RemoveAll() {
+ l.mu.Lock()
+ l.list = list.New()
+ l.mu.Unlock()
+}
+
+// Clear is alias of RemoveAll.
+func (l *List) Clear() {
+ l.RemoveAll()
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (l *List) RLockFunc(f func(list *list.List)) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list != nil {
+ f(l.list)
+ }
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (l *List) LockFunc(f func(list *list.List)) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ f(l.list)
+}
+
+// Iterator is alias of IteratorAsc.
+func (l *List) Iterator(f func(e *Element) bool) {
+ l.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the list readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (l *List) IteratorAsc(f func(e *Element) bool) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ length := l.list.Len()
+ if length > 0 {
+ for i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {
+ if !f(e) {
+ break
+ }
+ }
+ }
+}
+
+// IteratorDesc iterates the list readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (l *List) IteratorDesc(f func(e *Element) bool) {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return
+ }
+ length := l.list.Len()
+ if length > 0 {
+ for i, e := 0, l.list.Back(); i < length; i, e = i+1, e.Prev() {
+ if !f(e) {
+ break
+ }
+ }
+ }
+}
+
+// Join joins list elements with a string `glue`.
+func (l *List) Join(glue string) string {
+ l.mu.RLock()
+ defer l.mu.RUnlock()
+ if l.list == nil {
+ return ""
+ }
+ buffer := bytes.NewBuffer(nil)
+ length := l.list.Len()
+ if length > 0 {
+ for i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {
+ buffer.WriteString(gconv.String(e.Value))
+ if i != length-1 {
+ buffer.WriteString(glue)
+ }
+ }
+ }
+ return buffer.String()
+}
+
+// String returns current list as a string.
+func (l *List) String() string {
+ return "[" + l.Join(",") + "]"
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (l List) MarshalJSON() ([]byte, error) {
+ return json.Marshal(l.FrontAll())
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (l *List) UnmarshalJSON(b []byte) error {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ var array []interface{}
+ if err := json.UnmarshalUseNumber(b, &array); err != nil {
+ return err
+ }
+ l.PushBacks(array)
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for list.
+func (l *List) UnmarshalValue(value interface{}) (err error) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.list == nil {
+ l.list = list.New()
+ }
+ var array []interface{}
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
+ default:
+ array = gconv.SliceAny(value)
+ }
+ l.PushBacks(array)
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap.go
new file mode 100644
index 000000000000..4cff99d3a87c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap.go
@@ -0,0 +1,45 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gmap provides most commonly used map container which also support concurrent-safe/unsafe switch feature.
+package gmap
+
+type (
+ Map = AnyAnyMap // Map is alias of AnyAnyMap.
+ HashMap = AnyAnyMap // HashMap is alias of AnyAnyMap.
+)
+
+// New creates and returns an empty hash map.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func New(safe ...bool) *Map {
+ return NewAnyAnyMap(safe...)
+}
+
+// NewFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewFrom(data map[interface{}]interface{}, safe ...bool) *Map {
+ return NewAnyAnyMapFrom(data, safe...)
+}
+
+// NewHashMap creates and returns an empty hash map.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewHashMap(safe ...bool) *Map {
+ return NewAnyAnyMap(safe...)
+}
+
+// NewHashMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewHashMapFrom(data map[interface{}]interface{}, safe ...bool) *Map {
+ return NewAnyAnyMapFrom(data, safe...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_any_any_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_any_any_map.go
new file mode 100644
index 000000000000..05e451945486
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_any_any_map.go
@@ -0,0 +1,496 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type AnyAnyMap struct {
+ mu rwmutex.RWMutex
+ data map[interface{}]interface{}
+}
+
+// NewAnyAnyMap creates and returns an empty hash map.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewAnyAnyMap(safe ...bool) *AnyAnyMap {
+ return &AnyAnyMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[interface{}]interface{}),
+ }
+}
+
+// NewAnyAnyMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewAnyAnyMapFrom(data map[interface{}]interface{}, safe ...bool) *AnyAnyMap {
+ return &AnyAnyMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *AnyAnyMap) Iterator(f func(k interface{}, v interface{}) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *AnyAnyMap) Clone(safe ...bool) *AnyAnyMap {
+ return NewFrom(m.MapCopy(), safe...)
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *AnyAnyMap) Map() map[interface{}]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[interface{}]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *AnyAnyMap) MapCopy() map[interface{}]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[interface{}]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *AnyAnyMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[gconv.String(k)] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *AnyAnyMap) FilterEmpty() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+}
+
+// FilterNil deletes all key-value pair of which the value is nil.
+func (m *AnyAnyMap) FilterNil() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for k, v := range m.data {
+ if empty.IsNil(v) {
+ delete(m.data, k)
+ }
+ }
+}
+
+// Set sets key-value to the hash map.
+func (m *AnyAnyMap) Set(key interface{}, value interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
+ m.data[key] = value
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *AnyAnyMap) Sets(data map[interface{}]interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *AnyAnyMap) Search(key interface{}) (value interface{}, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *AnyAnyMap) Get(key interface{}) (value interface{}) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *AnyAnyMap) Pop() (key, value interface{}) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *AnyAnyMap) Pops(size int) map[interface{}]interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[interface{}]interface{}, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of `func() interface {}`,
+// it will be executed with mutex.Lock of the hash map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (m *AnyAnyMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
+ if v, ok := m.data[key]; ok {
+ return v
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ m.data[key] = value
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *AnyAnyMap) GetOrSet(key interface{}, value interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (m *AnyAnyMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *AnyAnyMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a Var with the value by given `key`.
+// The returned Var is un-concurrent safe.
+func (m *AnyAnyMap) GetVar(key interface{}) *gvar.Var {
+ return gvar.New(m.Get(key))
+}
+
+// GetVarOrSet returns a Var with result from GetOrSet.
+// The returned Var is un-concurrent safe.
+func (m *AnyAnyMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
+func (m *AnyAnyMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
+func (m *AnyAnyMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *AnyAnyMap) SetIfNotExist(key interface{}, value interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *AnyAnyMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *AnyAnyMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *AnyAnyMap) Remove(key interface{}) (value interface{}) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *AnyAnyMap) Removes(keys []interface{}) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *AnyAnyMap) Keys() []interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ var (
+ keys = make([]interface{}, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *AnyAnyMap) Values() []interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ var (
+ values = make([]interface{}, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *AnyAnyMap) Contains(key interface{}) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *AnyAnyMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *AnyAnyMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *AnyAnyMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[interface{}]interface{})
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *AnyAnyMap) Replace(data map[interface{}]interface{}) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *AnyAnyMap) LockFunc(f func(m map[interface{}]interface{})) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *AnyAnyMap) RLockFunc(f func(m map[interface{}]interface{})) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *AnyAnyMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[interface{}]interface{}, len(m.data))
+ for k, v := range m.data {
+ n[v] = k
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *AnyAnyMap) Merge(other *AnyAnyMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *AnyAnyMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m AnyAnyMap) MarshalJSON() ([]byte, error) {
+ return json.Marshal(gconv.Map(m.Map()))
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *AnyAnyMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
+ var data map[string]interface{}
+ if err := json.UnmarshalUseNumber(b, &data); err != nil {
+ return err
+ }
+ for k, v := range data {
+ m.data[k] = v
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *AnyAnyMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
+ for k, v := range gconv.Map(value) {
+ m.data[k] = v
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_any_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_any_map.go
new file mode 100644
index 000000000000..a4e509cd4538
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_any_map.go
@@ -0,0 +1,498 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type IntAnyMap struct {
+ mu rwmutex.RWMutex
+ data map[int]interface{}
+}
+
+// NewIntAnyMap returns an empty IntAnyMap object.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewIntAnyMap(safe ...bool) *IntAnyMap {
+ return &IntAnyMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[int]interface{}),
+ }
+}
+
+// NewIntAnyMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewIntAnyMapFrom(data map[int]interface{}, safe ...bool) *IntAnyMap {
+ return &IntAnyMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *IntAnyMap) Iterator(f func(k int, v interface{}) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *IntAnyMap) Clone() *IntAnyMap {
+ return NewIntAnyMapFrom(m.MapCopy(), m.mu.IsSafe())
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *IntAnyMap) Map() map[int]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[int]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *IntAnyMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[gconv.String(k)] = v
+ }
+ m.mu.RUnlock()
+ return data
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *IntAnyMap) MapCopy() map[int]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[int]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *IntAnyMap) FilterEmpty() {
+ m.mu.Lock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// FilterNil deletes all key-value pair of which the value is nil.
+func (m *IntAnyMap) FilterNil() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for k, v := range m.data {
+ if empty.IsNil(v) {
+ delete(m.data, k)
+ }
+ }
+}
+
+// Set sets key-value to the hash map.
+func (m *IntAnyMap) Set(key int, val interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
+ m.data[key] = val
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *IntAnyMap) Sets(data map[int]interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *IntAnyMap) Search(key int) (value interface{}, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *IntAnyMap) Get(key int) (value interface{}) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *IntAnyMap) Pop() (key int, value interface{}) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *IntAnyMap) Pops(size int) map[int]interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[int]interface{}, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of `func() interface {}`,
+// it will be executed with mutex.Lock of the hash map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (m *IntAnyMap) doSetWithLockCheck(key int, value interface{}) interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
+ if v, ok := m.data[key]; ok {
+ return v
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ m.data[key] = value
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *IntAnyMap) GetOrSet(key int, value interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist and returns this value.
+func (m *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist and returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *IntAnyMap) GetOrSetFuncLock(key int, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a Var with the value by given `key`.
+// The returned Var is un-concurrent safe.
+func (m *IntAnyMap) GetVar(key int) *gvar.Var {
+ return gvar.New(m.Get(key))
+}
+
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
+func (m *IntAnyMap) GetVarOrSet(key int, value interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
+func (m *IntAnyMap) GetVarOrSetFunc(key int, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
+func (m *IntAnyMap) GetVarOrSetFuncLock(key int, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *IntAnyMap) SetIfNotExist(key int, value interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *IntAnyMap) SetIfNotExistFunc(key int, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *IntAnyMap) SetIfNotExistFuncLock(key int, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *IntAnyMap) Removes(keys []int) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *IntAnyMap) Remove(key int) (value interface{}) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *IntAnyMap) Keys() []int {
+ m.mu.RLock()
+ var (
+ keys = make([]int, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *IntAnyMap) Values() []interface{} {
+ m.mu.RLock()
+ var (
+ values = make([]interface{}, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *IntAnyMap) Contains(key int) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *IntAnyMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *IntAnyMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *IntAnyMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[int]interface{})
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *IntAnyMap) Replace(data map[int]interface{}) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *IntAnyMap) LockFunc(f func(m map[int]interface{})) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *IntAnyMap) RLockFunc(f func(m map[int]interface{})) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *IntAnyMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[int]interface{}, len(m.data))
+ for k, v := range m.data {
+ n[gconv.Int(v)] = k
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *IntAnyMap) Merge(other *IntAnyMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *IntAnyMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m IntAnyMap) MarshalJSON() ([]byte, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return json.Marshal(m.data)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *IntAnyMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
+ if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *IntAnyMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
+ default:
+ for k, v := range gconv.Map(value) {
+ m.data[gconv.Int(k)] = v
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_int_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_int_map.go
new file mode 100644
index 000000000000..8fe1fa7f287b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_int_map.go
@@ -0,0 +1,469 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type IntIntMap struct {
+ mu rwmutex.RWMutex
+ data map[int]int
+}
+
+// NewIntIntMap returns an empty IntIntMap object.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewIntIntMap(safe ...bool) *IntIntMap {
+ return &IntIntMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[int]int),
+ }
+}
+
+// NewIntIntMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewIntIntMapFrom(data map[int]int, safe ...bool) *IntIntMap {
+ return &IntIntMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *IntIntMap) Iterator(f func(k int, v int) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *IntIntMap) Clone() *IntIntMap {
+ return NewIntIntMapFrom(m.MapCopy(), m.mu.IsSafe())
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *IntIntMap) Map() map[int]int {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[int]int, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *IntIntMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[gconv.String(k)] = v
+ }
+ m.mu.RUnlock()
+ return data
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *IntIntMap) MapCopy() map[int]int {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[int]int, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *IntIntMap) FilterEmpty() {
+ m.mu.Lock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Set sets key-value to the hash map.
+func (m *IntIntMap) Set(key int, val int) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
+ m.data[key] = val
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *IntIntMap) Sets(data map[int]int) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *IntIntMap) Search(key int) (value int, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *IntIntMap) Get(key int) (value int) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *IntIntMap) Pop() (key, value int) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *IntIntMap) Pops(size int) map[int]int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[int]int, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// It returns value with given `key`.
+func (m *IntIntMap) doSetWithLockCheck(key int, value int) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
+ if v, ok := m.data[key]; ok {
+ return v
+ }
+ m.data[key] = value
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *IntIntMap) GetOrSet(key int, value int) int {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist and returns this value.
+func (m *IntIntMap) GetOrSetFunc(key int, f func() int) int {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist and returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int {
+ if v, ok := m.Search(key); !ok {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
+ if v, ok = m.data[key]; ok {
+ return v
+ }
+ v = f()
+ m.data[key] = v
+ return v
+ } else {
+ return v
+ }
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *IntIntMap) SetIfNotExist(key int, value int) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *IntIntMap) SetIfNotExistFunc(key int, f func() int) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *IntIntMap) SetIfNotExistFuncLock(key int, f func() int) bool {
+ if !m.Contains(key) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
+ if _, ok := m.data[key]; !ok {
+ m.data[key] = f()
+ }
+ return true
+ }
+ return false
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *IntIntMap) Removes(keys []int) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *IntIntMap) Remove(key int) (value int) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *IntIntMap) Keys() []int {
+ m.mu.RLock()
+ var (
+ keys = make([]int, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *IntIntMap) Values() []int {
+ m.mu.RLock()
+ var (
+ values = make([]int, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *IntIntMap) Contains(key int) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *IntIntMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *IntIntMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *IntIntMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[int]int)
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *IntIntMap) Replace(data map[int]int) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *IntIntMap) LockFunc(f func(m map[int]int)) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *IntIntMap) RLockFunc(f func(m map[int]int)) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *IntIntMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[int]int, len(m.data))
+ for k, v := range m.data {
+ n[v] = k
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *IntIntMap) Merge(other *IntIntMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *IntIntMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m IntIntMap) MarshalJSON() ([]byte, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return json.Marshal(m.data)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *IntIntMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
+ if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *IntIntMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
+ default:
+ for k, v := range gconv.Map(value) {
+ m.data[gconv.Int(k)] = gconv.Int(v)
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_str_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_str_map.go
new file mode 100644
index 000000000000..27697bc44186
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_int_str_map.go
@@ -0,0 +1,469 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type IntStrMap struct {
+ mu rwmutex.RWMutex
+ data map[int]string
+}
+
+// NewIntStrMap returns an empty IntStrMap object.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewIntStrMap(safe ...bool) *IntStrMap {
+ return &IntStrMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[int]string),
+ }
+}
+
+// NewIntStrMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap {
+ return &IntStrMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *IntStrMap) Iterator(f func(k int, v string) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *IntStrMap) Clone() *IntStrMap {
+ return NewIntStrMapFrom(m.MapCopy(), m.mu.IsSafe())
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *IntStrMap) Map() map[int]string {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[int]string, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *IntStrMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[gconv.String(k)] = v
+ }
+ m.mu.RUnlock()
+ return data
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *IntStrMap) MapCopy() map[int]string {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[int]string, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *IntStrMap) FilterEmpty() {
+ m.mu.Lock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Set sets key-value to the hash map.
+func (m *IntStrMap) Set(key int, val string) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
+ m.data[key] = val
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *IntStrMap) Sets(data map[int]string) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *IntStrMap) Search(key int) (value string, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *IntStrMap) Get(key int) (value string) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *IntStrMap) Pop() (key int, value string) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *IntStrMap) Pops(size int) map[int]string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[int]string, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// It returns value with given `key`.
+func (m *IntStrMap) doSetWithLockCheck(key int, value string) string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
+ if v, ok := m.data[key]; ok {
+ return v
+ }
+ m.data[key] = value
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *IntStrMap) GetOrSet(key int, value string) string {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist and returns this value.
+func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist and returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {
+ if v, ok := m.Search(key); !ok {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
+ if v, ok = m.data[key]; ok {
+ return v
+ }
+ v = f()
+ m.data[key] = v
+ return v
+ } else {
+ return v
+ }
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *IntStrMap) SetIfNotExist(key int, value string) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) bool {
+ if !m.Contains(key) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
+ if _, ok := m.data[key]; !ok {
+ m.data[key] = f()
+ }
+ return true
+ }
+ return false
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *IntStrMap) Removes(keys []int) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *IntStrMap) Remove(key int) (value string) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *IntStrMap) Keys() []int {
+ m.mu.RLock()
+ var (
+ keys = make([]int, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *IntStrMap) Values() []string {
+ m.mu.RLock()
+ var (
+ values = make([]string, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *IntStrMap) Contains(key int) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *IntStrMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *IntStrMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *IntStrMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[int]string)
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *IntStrMap) Replace(data map[int]string) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *IntStrMap) LockFunc(f func(m map[int]string)) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *IntStrMap) RLockFunc(f func(m map[int]string)) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *IntStrMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[int]string, len(m.data))
+ for k, v := range m.data {
+ n[gconv.Int(v)] = gconv.String(k)
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *IntStrMap) Merge(other *IntStrMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *IntStrMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m IntStrMap) MarshalJSON() ([]byte, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return json.Marshal(m.data)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *IntStrMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
+ if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *IntStrMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
+ default:
+ for k, v := range gconv.Map(value) {
+ m.data[gconv.Int(k)] = gconv.String(v)
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_any_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_any_map.go
new file mode 100644
index 000000000000..27708b23071b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_any_map.go
@@ -0,0 +1,484 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type StrAnyMap struct {
+ mu rwmutex.RWMutex
+ data map[string]interface{}
+}
+
+// NewStrAnyMap returns an empty StrAnyMap object.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewStrAnyMap(safe ...bool) *StrAnyMap {
+ return &StrAnyMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[string]interface{}),
+ }
+}
+
+// NewStrAnyMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewStrAnyMapFrom(data map[string]interface{}, safe ...bool) *StrAnyMap {
+ return &StrAnyMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *StrAnyMap) Clone() *StrAnyMap {
+ return NewStrAnyMapFrom(m.MapCopy(), m.mu.IsSafe())
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *StrAnyMap) Map() map[string]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *StrAnyMap) MapStrAny() map[string]interface{} {
+ return m.Map()
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *StrAnyMap) MapCopy() map[string]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *StrAnyMap) FilterEmpty() {
+ m.mu.Lock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// FilterNil deletes all key-value pair of which the value is nil.
+func (m *StrAnyMap) FilterNil() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for k, v := range m.data {
+ if empty.IsNil(v) {
+ delete(m.data, k)
+ }
+ }
+}
+
+// Set sets key-value to the hash map.
+func (m *StrAnyMap) Set(key string, val interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]interface{})
+ }
+ m.data[key] = val
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *StrAnyMap) Sets(data map[string]interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *StrAnyMap) Search(key string) (value interface{}, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *StrAnyMap) Get(key string) (value interface{}) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *StrAnyMap) Pop() (key string, value interface{}) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *StrAnyMap) Pops(size int) map[string]interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[string]interface{}, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of `func() interface {}`,
+// it will be executed with mutex.Lock of the hash map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]interface{})
+ }
+ if v, ok := m.data[key]; ok {
+ return v
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ m.data[key] = value
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a Var with the value by given `key`.
+// The returned Var is un-concurrent safe.
+func (m *StrAnyMap) GetVar(key string) *gvar.Var {
+ return gvar.New(m.Get(key))
+}
+
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
+func (m *StrAnyMap) GetVarOrSet(key string, value interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
+func (m *StrAnyMap) GetVarOrSetFunc(key string, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
+func (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *StrAnyMap) SetIfNotExistFuncLock(key string, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *StrAnyMap) Removes(keys []string) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *StrAnyMap) Remove(key string) (value interface{}) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *StrAnyMap) Keys() []string {
+ m.mu.RLock()
+ var (
+ keys = make([]string, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *StrAnyMap) Values() []interface{} {
+ m.mu.RLock()
+ var (
+ values = make([]interface{}, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *StrAnyMap) Contains(key string) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *StrAnyMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *StrAnyMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *StrAnyMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[string]interface{})
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *StrAnyMap) Replace(data map[string]interface{}) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *StrAnyMap) LockFunc(f func(m map[string]interface{})) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *StrAnyMap) RLockFunc(f func(m map[string]interface{})) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *StrAnyMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ n[gconv.String(v)] = k
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *StrAnyMap) Merge(other *StrAnyMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *StrAnyMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m StrAnyMap) MarshalJSON() ([]byte, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return json.Marshal(m.data)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *StrAnyMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]interface{})
+ }
+ if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *StrAnyMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.data = gconv.Map(value)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_int_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_int_map.go
new file mode 100644
index 000000000000..2041473b72be
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_int_map.go
@@ -0,0 +1,473 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type StrIntMap struct {
+ mu rwmutex.RWMutex
+ data map[string]int
+}
+
+// NewStrIntMap returns an empty StrIntMap object.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewStrIntMap(safe ...bool) *StrIntMap {
+ return &StrIntMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[string]int),
+ }
+}
+
+// NewStrIntMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewStrIntMapFrom(data map[string]int, safe ...bool) *StrIntMap {
+ return &StrIntMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *StrIntMap) Iterator(f func(k string, v int) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *StrIntMap) Clone() *StrIntMap {
+ return NewStrIntMapFrom(m.MapCopy(), m.mu.IsSafe())
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *StrIntMap) Map() map[string]int {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[string]int, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *StrIntMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *StrIntMap) MapCopy() map[string]int {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[string]int, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *StrIntMap) FilterEmpty() {
+ m.mu.Lock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Set sets key-value to the hash map.
+func (m *StrIntMap) Set(key string, val int) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
+ m.data[key] = val
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *StrIntMap) Sets(data map[string]int) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *StrIntMap) Search(key string) (value int, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *StrIntMap) Get(key string) (value int) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *StrIntMap) Pop() (key string, value int) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *StrIntMap) Pops(size int) map[string]int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[string]int, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// It returns value with given `key`.
+func (m *StrIntMap) doSetWithLockCheck(key string, value int) int {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
+ if v, ok := m.data[key]; ok {
+ m.mu.Unlock()
+ return v
+ }
+ m.data[key] = value
+ m.mu.Unlock()
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *StrIntMap) GetOrSet(key string, value int) int {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int {
+ if v, ok := m.Search(key); !ok {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
+ if v, ok = m.data[key]; ok {
+ return v
+ }
+ v = f()
+ m.data[key] = v
+ return v
+ } else {
+ return v
+ }
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *StrIntMap) SetIfNotExist(key string, value int) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *StrIntMap) SetIfNotExistFunc(key string, f func() int) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *StrIntMap) SetIfNotExistFuncLock(key string, f func() int) bool {
+ if !m.Contains(key) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
+ if _, ok := m.data[key]; !ok {
+ m.data[key] = f()
+ }
+ return true
+ }
+ return false
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *StrIntMap) Removes(keys []string) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *StrIntMap) Remove(key string) (value int) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *StrIntMap) Keys() []string {
+ m.mu.RLock()
+ var (
+ keys = make([]string, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *StrIntMap) Values() []int {
+ m.mu.RLock()
+ var (
+ values = make([]int, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *StrIntMap) Contains(key string) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *StrIntMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *StrIntMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *StrIntMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[string]int)
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *StrIntMap) Replace(data map[string]int) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *StrIntMap) LockFunc(f func(m map[string]int)) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *StrIntMap) RLockFunc(f func(m map[string]int)) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *StrIntMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[string]int, len(m.data))
+ for k, v := range m.data {
+ n[gconv.String(v)] = gconv.Int(k)
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *StrIntMap) Merge(other *StrIntMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *StrIntMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m StrIntMap) MarshalJSON() ([]byte, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return json.Marshal(m.data)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *StrIntMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
+ if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *StrIntMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
+ switch value.(type) {
+ case string, []byte:
+ return json.UnmarshalUseNumber(gconv.Bytes(value), &m.data)
+ default:
+ for k, v := range gconv.Map(value) {
+ m.data[k] = gconv.Int(v)
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_str_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_str_map.go
new file mode 100644
index 000000000000..d2c8a0bd1aef
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_hash_str_str_map.go
@@ -0,0 +1,462 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type StrStrMap struct {
+ mu rwmutex.RWMutex
+ data map[string]string
+}
+
+// NewStrStrMap returns an empty StrStrMap object.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewStrStrMap(safe ...bool) *StrStrMap {
+ return &StrStrMap{
+ data: make(map[string]string),
+ mu: rwmutex.Create(safe...),
+ }
+}
+
+// NewStrStrMapFrom creates and returns a hash map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap {
+ return &StrStrMap{
+ mu: rwmutex.Create(safe...),
+ data: data,
+ }
+}
+
+// Iterator iterates the hash map readonly with custom callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *StrStrMap) Iterator(f func(k string, v string) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ for k, v := range m.data {
+ if !f(k, v) {
+ break
+ }
+ }
+}
+
+// Clone returns a new hash map with copy of current map data.
+func (m *StrStrMap) Clone() *StrStrMap {
+ return NewStrStrMapFrom(m.MapCopy(), m.mu.IsSafe())
+}
+
+// Map returns the underlying data map.
+// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
+// or else a pointer to the underlying data.
+func (m *StrStrMap) Map() map[string]string {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if !m.mu.IsSafe() {
+ return m.data
+ }
+ data := make(map[string]string, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *StrStrMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ data := make(map[string]interface{}, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ m.mu.RUnlock()
+ return data
+}
+
+// MapCopy returns a copy of the underlying data of the hash map.
+func (m *StrStrMap) MapCopy() map[string]string {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ data := make(map[string]string, len(m.data))
+ for k, v := range m.data {
+ data[k] = v
+ }
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
+func (m *StrStrMap) FilterEmpty() {
+ m.mu.Lock()
+ for k, v := range m.data {
+ if empty.IsEmpty(v) {
+ delete(m.data, k)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Set sets key-value to the hash map.
+func (m *StrStrMap) Set(key string, val string) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
+ m.data[key] = val
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the hash map.
+func (m *StrStrMap) Sets(data map[string]string) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *StrStrMap) Search(key string) (value string, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, found = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *StrStrMap) Get(key string) (value string) {
+ m.mu.RLock()
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *StrStrMap) Pop() (key, value string) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for key, value = range m.data {
+ delete(m.data, key)
+ return
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *StrStrMap) Pops(size int) map[string]string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ var (
+ index = 0
+ newMap = make(map[string]string, size)
+ )
+ for k, v := range m.data {
+ delete(m.data, k)
+ newMap[k] = v
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// It returns value with given `key`.
+func (m *StrStrMap) doSetWithLockCheck(key string, value string) string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
+ if v, ok := m.data[key]; ok {
+ return v
+ }
+ m.data[key] = value
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *StrStrMap) GetOrSet(key string, value string) string {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string {
+ if v, ok := m.Search(key); !ok {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
+ if v, ok = m.data[key]; ok {
+ return v
+ }
+ v = f()
+ m.data[key] = v
+ return v
+ } else {
+ return v
+ }
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *StrStrMap) SetIfNotExist(key string, value string) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (m *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) bool {
+ if !m.Contains(key) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
+ if _, ok := m.data[key]; !ok {
+ m.data[key] = f()
+ }
+ return true
+ }
+ return false
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *StrStrMap) Removes(keys []string) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *StrStrMap) Remove(key string) (value string) {
+ m.mu.Lock()
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Keys returns all keys of the map as a slice.
+func (m *StrStrMap) Keys() []string {
+ m.mu.RLock()
+ var (
+ keys = make([]string, len(m.data))
+ index = 0
+ )
+ for key := range m.data {
+ keys[index] = key
+ index++
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *StrStrMap) Values() []string {
+ m.mu.RLock()
+ var (
+ values = make([]string, len(m.data))
+ index = 0
+ )
+ for _, value := range m.data {
+ values[index] = value
+ index++
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *StrStrMap) Contains(key string) bool {
+ var ok bool
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return ok
+}
+
+// Size returns the size of the map.
+func (m *StrStrMap) Size() int {
+ m.mu.RLock()
+ length := len(m.data)
+ m.mu.RUnlock()
+ return length
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *StrStrMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *StrStrMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[string]string)
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *StrStrMap) Replace(data map[string]string) {
+ m.mu.Lock()
+ m.data = data
+ m.mu.Unlock()
+}
+
+// LockFunc locks writing with given callback function `f` within RWMutex.Lock.
+func (m *StrStrMap) LockFunc(f func(m map[string]string)) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ f(m.data)
+}
+
+// RLockFunc locks reading with given callback function `f` within RWMutex.RLock.
+func (m *StrStrMap) RLockFunc(f func(m map[string]string)) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ f(m.data)
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *StrStrMap) Flip() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ n := make(map[string]string, len(m.data))
+ for k, v := range m.data {
+ n[v] = k
+ }
+ m.data = n
+}
+
+// Merge merges two hash maps.
+// The `other` map will be merged into the map `m`.
+func (m *StrStrMap) Merge(other *StrStrMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ for k, v := range other.data {
+ m.data[k] = v
+ }
+}
+
+// String returns the map as a string.
+func (m *StrStrMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m StrStrMap) MarshalJSON() ([]byte, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ return json.Marshal(m.data)
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *StrStrMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
+ if err := json.UnmarshalUseNumber(b, &m.data); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *StrStrMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.data = gconv.MapStrStr(value)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_list_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_list_map.go
new file mode 100644
index 000000000000..eed95f1a6616
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_list_map.go
@@ -0,0 +1,559 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type ListMap struct {
+ mu rwmutex.RWMutex
+ data map[interface{}]*glist.Element
+ list *glist.List
+}
+
+type gListMapNode struct {
+ key interface{}
+ value interface{}
+}
+
+// NewListMap returns an empty link map.
+// ListMap is backed by a hash table to store values and doubly-linked list to store ordering.
+// The parameter `safe` is used to specify whether using map in concurrent-safety,
+// which is false in default.
+func NewListMap(safe ...bool) *ListMap {
+ return &ListMap{
+ mu: rwmutex.Create(safe...),
+ data: make(map[interface{}]*glist.Element),
+ list: glist.New(),
+ }
+}
+
+// NewListMapFrom returns a link map from given map `data`.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+func NewListMapFrom(data map[interface{}]interface{}, safe ...bool) *ListMap {
+ m := NewListMap(safe...)
+ m.Sets(data)
+ return m
+}
+
+// Iterator is alias of IteratorAsc.
+func (m *ListMap) Iterator(f func(key, value interface{}) bool) {
+ m.IteratorAsc(f)
+}
+
+// IteratorAsc iterates the map readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *ListMap) IteratorAsc(f func(key interface{}, value interface{}) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if m.list != nil {
+ node := (*gListMapNode)(nil)
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ return f(node.key, node.value)
+ })
+ }
+}
+
+// IteratorDesc iterates the map readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (m *ListMap) IteratorDesc(f func(key interface{}, value interface{}) bool) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ if m.list != nil {
+ node := (*gListMapNode)(nil)
+ m.list.IteratorDesc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ return f(node.key, node.value)
+ })
+ }
+}
+
+// Clone returns a new link map with copy of current map data.
+func (m *ListMap) Clone(safe ...bool) *ListMap {
+ return NewListMapFrom(m.Map(), safe...)
+}
+
+// Clear deletes all data of the map, it will remake a new underlying data map.
+func (m *ListMap) Clear() {
+ m.mu.Lock()
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ m.mu.Unlock()
+}
+
+// Replace the data of the map with given `data`.
+func (m *ListMap) Replace(data map[interface{}]interface{}) {
+ m.mu.Lock()
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ for key, value := range data {
+ if e, ok := m.data[key]; !ok {
+ m.data[key] = m.list.PushBack(&gListMapNode{key, value})
+ } else {
+ e.Value = &gListMapNode{key, value}
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Map returns a copy of the underlying data of the map.
+func (m *ListMap) Map() map[interface{}]interface{} {
+ m.mu.RLock()
+ var node *gListMapNode
+ var data map[interface{}]interface{}
+ if m.list != nil {
+ data = make(map[interface{}]interface{}, len(m.data))
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ data[node.key] = node.value
+ return true
+ })
+ }
+ m.mu.RUnlock()
+ return data
+}
+
+// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
+func (m *ListMap) MapStrAny() map[string]interface{} {
+ m.mu.RLock()
+ var node *gListMapNode
+ var data map[string]interface{}
+ if m.list != nil {
+ data = make(map[string]interface{}, len(m.data))
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ data[gconv.String(node.key)] = node.value
+ return true
+ })
+ }
+ m.mu.RUnlock()
+ return data
+}
+
+// FilterEmpty deletes all key-value pair of which the value is empty.
+func (m *ListMap) FilterEmpty() {
+ m.mu.Lock()
+ if m.list != nil {
+ keys := make([]interface{}, 0)
+ node := (*gListMapNode)(nil)
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ if empty.IsEmpty(node.value) {
+ keys = append(keys, node.key)
+ }
+ return true
+ })
+ if len(keys) > 0 {
+ for _, key := range keys {
+ if e, ok := m.data[key]; ok {
+ delete(m.data, key)
+ m.list.Remove(e)
+ }
+ }
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Set sets key-value to the map.
+func (m *ListMap) Set(key interface{}, value interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
+ if e, ok := m.data[key]; !ok {
+ m.data[key] = m.list.PushBack(&gListMapNode{key, value})
+ } else {
+ e.Value = &gListMapNode{key, value}
+ }
+ m.mu.Unlock()
+}
+
+// Sets batch sets key-values to the map.
+func (m *ListMap) Sets(data map[interface{}]interface{}) {
+ m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
+ for key, value := range data {
+ if e, ok := m.data[key]; !ok {
+ m.data[key] = m.list.PushBack(&gListMapNode{key, value})
+ } else {
+ e.Value = &gListMapNode{key, value}
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Search searches the map with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (m *ListMap) Search(key interface{}) (value interface{}, found bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ if e, ok := m.data[key]; ok {
+ value = e.Value.(*gListMapNode).value
+ found = ok
+ }
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Get returns the value by given `key`.
+func (m *ListMap) Get(key interface{}) (value interface{}) {
+ m.mu.RLock()
+ if m.data != nil {
+ if e, ok := m.data[key]; ok {
+ value = e.Value.(*gListMapNode).value
+ }
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Pop retrieves and deletes an item from the map.
+func (m *ListMap) Pop() (key, value interface{}) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for k, e := range m.data {
+ value = e.Value.(*gListMapNode).value
+ delete(m.data, k)
+ m.list.Remove(e)
+ return k, value
+ }
+ return
+}
+
+// Pops retrieves and deletes `size` items from the map.
+// It returns all items if size == -1.
+func (m *ListMap) Pops(size int) map[interface{}]interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if size > len(m.data) || size == -1 {
+ size = len(m.data)
+ }
+ if size == 0 {
+ return nil
+ }
+ index := 0
+ newMap := make(map[interface{}]interface{}, size)
+ for k, e := range m.data {
+ value := e.Value.(*gListMapNode).value
+ delete(m.data, k)
+ m.list.Remove(e)
+ newMap[k] = value
+ index++
+ if index == size {
+ break
+ }
+ }
+ return newMap
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of `func() interface {}`,
+// it will be executed with mutex.Lock of the map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
+ if e, ok := m.data[key]; ok {
+ return e.Value.(*gListMapNode).value
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ m.data[key] = m.list.PushBack(&gListMapNode{key, value})
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the map.
+func (m *ListMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
+ if v, ok := m.Search(key); !ok {
+ return m.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a Var with the value by given `key`.
+// The returned Var is un-concurrent safe.
+func (m *ListMap) GetVar(key interface{}) *gvar.Var {
+ return gvar.New(m.Get(key))
+}
+
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
+func (m *ListMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
+func (m *ListMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
+func (m *ListMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(m.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the map.
+func (m *ListMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
+ if !m.Contains(key) {
+ m.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Remove deletes value from map by given `key`, and return this deleted value.
+func (m *ListMap) Remove(key interface{}) (value interface{}) {
+ m.mu.Lock()
+ if m.data != nil {
+ if e, ok := m.data[key]; ok {
+ value = e.Value.(*gListMapNode).value
+ delete(m.data, key)
+ m.list.Remove(e)
+ }
+ }
+ m.mu.Unlock()
+ return
+}
+
+// Removes batch deletes values of the map by keys.
+func (m *ListMap) Removes(keys []interface{}) {
+ m.mu.Lock()
+ if m.data != nil {
+ for _, key := range keys {
+ if e, ok := m.data[key]; ok {
+ delete(m.data, key)
+ m.list.Remove(e)
+ }
+ }
+ }
+ m.mu.Unlock()
+}
+
+// Keys returns all keys of the map as a slice in ascending order.
+func (m *ListMap) Keys() []interface{} {
+ m.mu.RLock()
+ var (
+ keys = make([]interface{}, m.list.Len())
+ index = 0
+ )
+ if m.list != nil {
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ keys[index] = e.Value.(*gListMapNode).key
+ index++
+ return true
+ })
+ }
+ m.mu.RUnlock()
+ return keys
+}
+
+// Values returns all values of the map as a slice.
+func (m *ListMap) Values() []interface{} {
+ m.mu.RLock()
+ var (
+ values = make([]interface{}, m.list.Len())
+ index = 0
+ )
+ if m.list != nil {
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ values[index] = e.Value.(*gListMapNode).value
+ index++
+ return true
+ })
+ }
+ m.mu.RUnlock()
+ return values
+}
+
+// Contains checks whether a key exists.
+// It returns true if the `key` exists, or else false.
+func (m *ListMap) Contains(key interface{}) (ok bool) {
+ m.mu.RLock()
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
+ m.mu.RUnlock()
+ return
+}
+
+// Size returns the size of the map.
+func (m *ListMap) Size() (size int) {
+ m.mu.RLock()
+ size = len(m.data)
+ m.mu.RUnlock()
+ return
+}
+
+// IsEmpty checks whether the map is empty.
+// It returns true if map is empty, or else false.
+func (m *ListMap) IsEmpty() bool {
+ return m.Size() == 0
+}
+
+// Flip exchanges key-value of the map to value-key.
+func (m *ListMap) Flip() {
+ data := m.Map()
+ m.Clear()
+ for key, value := range data {
+ m.Set(value, key)
+ }
+}
+
+// Merge merges two link maps.
+// The `other` map will be merged into the map `m`.
+func (m *ListMap) Merge(other *ListMap) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
+ if other != m {
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ }
+ node := (*gListMapNode)(nil)
+ other.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ if e, ok := m.data[node.key]; !ok {
+ m.data[node.key] = m.list.PushBack(&gListMapNode{node.key, node.value})
+ } else {
+ e.Value = &gListMapNode{node.key, node.value}
+ }
+ return true
+ })
+}
+
+// String returns the map as a string.
+func (m *ListMap) String() string {
+ b, _ := m.MarshalJSON()
+ return string(b)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (m ListMap) MarshalJSON() ([]byte, error) {
+ return json.Marshal(gconv.Map(m.Map()))
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (m *ListMap) UnmarshalJSON(b []byte) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
+ var data map[string]interface{}
+ if err := json.UnmarshalUseNumber(b, &data); err != nil {
+ return err
+ }
+ for key, value := range data {
+ if e, ok := m.data[key]; !ok {
+ m.data[key] = m.list.PushBack(&gListMapNode{key, value})
+ } else {
+ e.Value = &gListMapNode{key, value}
+ }
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (m *ListMap) UnmarshalValue(value interface{}) (err error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
+ for k, v := range gconv.Map(value) {
+ if e, ok := m.data[k]; !ok {
+ m.data[k] = m.list.PushBack(&gListMapNode{k, v})
+ } else {
+ e.Value = &gListMapNode{k, v}
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_tree_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_tree_map.go
new file mode 100644
index 000000000000..c81caa48a582
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gmap/gmap_tree_map.go
@@ -0,0 +1,30 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with gm file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gmap
+
+import (
+ "github.com/gogf/gf/v2/container/gtree"
+)
+
+// TreeMap based on red-black tree, alias of RedBlackTree.
+type TreeMap = gtree.RedBlackTree
+
+// NewTreeMap instantiates a tree map with the custom comparator.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewTreeMap(comparator func(v1, v2 interface{}) int, safe ...bool) *TreeMap {
+ return gtree.NewRedBlackTree(comparator, safe...)
+}
+
+// NewTreeMapFrom instantiates a tree map with the custom comparator and `data` map.
+// Note that, the param `data` map will be set as the underlying data map(no deep copy),
+// there might be some concurrent-safe issues when changing the map outside.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewTreeMapFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *TreeMap {
+ return gtree.NewRedBlackTreeFrom(comparator, data, safe...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gpool/gpool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gpool/gpool.go
new file mode 100644
index 000000000000..12baececf63a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gpool/gpool.go
@@ -0,0 +1,182 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gpool provides object-reusable concurrent-safe pool.
+package gpool
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gtimer"
+)
+
+// Pool is an Object-Reusable Pool.
+type Pool struct {
+ list *glist.List // Available/idle items list.
+ closed *gtype.Bool // Whether the pool is closed.
+ TTL time.Duration // Time To Live for pool items.
+ NewFunc func() (interface{}, error) // Callback function to create pool item.
+ // ExpireFunc is the for expired items destruction.
+ // This function needs to be defined when the pool items
+ // need to perform additional destruction operations.
+ // Eg: net.Conn, os.File, etc.
+ ExpireFunc func(interface{})
+}
+
+// Pool item.
+type poolItem struct {
+ value interface{} // Item value.
+ expireAt int64 // Expire timestamp in milliseconds.
+}
+
+// NewFunc Creation function for object.
+type NewFunc func() (interface{}, error)
+
+// ExpireFunc Destruction function for object.
+type ExpireFunc func(interface{})
+
+// New creates and returns a new object pool.
+// To ensure execution efficiency, the expiration time cannot be modified once it is set.
+//
+// Note the expiration logic:
+// ttl = 0 : not expired;
+// ttl < 0 : immediate expired after use;
+// ttl > 0 : timeout expired;
+func New(ttl time.Duration, newFunc NewFunc, expireFunc ...ExpireFunc) *Pool {
+ r := &Pool{
+ list: glist.New(true),
+ closed: gtype.NewBool(),
+ TTL: ttl,
+ NewFunc: newFunc,
+ }
+ if len(expireFunc) > 0 {
+ r.ExpireFunc = expireFunc[0]
+ }
+ gtimer.AddSingleton(context.Background(), time.Second, r.checkExpireItems)
+ return r
+}
+
+// Put puts an item to pool.
+func (p *Pool) Put(value interface{}) error {
+ if p.closed.Val() {
+ return gerror.NewCode(gcode.CodeInvalidOperation, "pool is closed")
+ }
+ item := &poolItem{
+ value: value,
+ }
+ if p.TTL == 0 {
+ item.expireAt = 0
+ } else {
+ // As for Golang version < 1.13, there's no method Milliseconds for time.Duration.
+ // So we need calculate the milliseconds using its nanoseconds value.
+ item.expireAt = gtime.TimestampMilli() + p.TTL.Nanoseconds()/1000000
+ }
+ p.list.PushBack(item)
+ return nil
+}
+
+// Clear clears pool, which means it will remove all items from pool.
+func (p *Pool) Clear() {
+ if p.ExpireFunc != nil {
+ for {
+ if r := p.list.PopFront(); r != nil {
+ p.ExpireFunc(r.(*poolItem).value)
+ } else {
+ break
+ }
+ }
+ } else {
+ p.list.RemoveAll()
+ }
+
+}
+
+// Get picks and returns an item from pool. If the pool is empty and NewFunc is defined,
+// it creates and returns one from NewFunc.
+func (p *Pool) Get() (interface{}, error) {
+ for !p.closed.Val() {
+ if r := p.list.PopFront(); r != nil {
+ f := r.(*poolItem)
+ if f.expireAt == 0 || f.expireAt > gtime.TimestampMilli() {
+ return f.value, nil
+ } else if p.ExpireFunc != nil {
+ // TODO: move expire function calling asynchronously from `Get` operation.
+ p.ExpireFunc(f.value)
+ }
+ } else {
+ break
+ }
+ }
+ if p.NewFunc != nil {
+ return p.NewFunc()
+ }
+ return nil, gerror.NewCode(gcode.CodeInvalidOperation, "pool is empty")
+}
+
+// Size returns the count of available items of pool.
+func (p *Pool) Size() int {
+ return p.list.Len()
+}
+
+// Close closes the pool. If `p` has ExpireFunc,
+// then it automatically closes all items using this function before it's closed.
+// Commonly you do not need call this function manually.
+func (p *Pool) Close() {
+ p.closed.Set(true)
+}
+
+// checkExpire removes expired items from pool in every second.
+func (p *Pool) checkExpireItems(ctx context.Context) {
+ if p.closed.Val() {
+ // If p has ExpireFunc,
+ // then it must close all items using this function.
+ if p.ExpireFunc != nil {
+ for {
+ if r := p.list.PopFront(); r != nil {
+ p.ExpireFunc(r.(*poolItem).value)
+ } else {
+ break
+ }
+ }
+ }
+ gtimer.Exit()
+ }
+ // All items do not expire.
+ if p.TTL == 0 {
+ return
+ }
+ // The latest item expire timestamp in milliseconds.
+ var latestExpire int64 = -1
+ // Retrieve the current timestamp in milliseconds, it expires the items
+ // by comparing with this timestamp. It is not accurate comparison for
+ // every item expired, but high performance.
+ var timestampMilli = gtime.TimestampMilli()
+ for {
+ if latestExpire > timestampMilli {
+ break
+ }
+ if r := p.list.PopFront(); r != nil {
+ item := r.(*poolItem)
+ latestExpire = item.expireAt
+ // TODO improve the auto-expiration mechanism of the pool.
+ if item.expireAt > timestampMilli {
+ p.list.PushFront(item)
+ break
+ }
+ if p.ExpireFunc != nil {
+ p.ExpireFunc(item.value)
+ }
+ } else {
+ break
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gqueue/gqueue.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gqueue/gqueue.go
new file mode 100644
index 000000000000..a778709b3678
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gqueue/gqueue.go
@@ -0,0 +1,145 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gqueue provides dynamic/static concurrent-safe queue.
+//
+// Features:
+//
+// 1. FIFO queue(data -> list -> chan);
+//
+// 2. Fast creation and initialization;
+//
+// 3. Support dynamic queue size(unlimited queue size);
+//
+// 4. Blocking when reading data from queue;
+//
+package gqueue
+
+import (
+ "math"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gtype"
+)
+
+// Queue is a concurrent-safe queue built on doubly linked list and channel.
+type Queue struct {
+ limit int // Limit for queue size.
+ list *glist.List // Underlying list structure for data maintaining.
+ closed *gtype.Bool // Whether queue is closed.
+ events chan struct{} // Events for data writing.
+ C chan interface{} // Underlying channel for data reading.
+}
+
+const (
+ defaultQueueSize = 10000 // Size for queue buffer.
+ defaultBatchSize = 10 // Max batch size per-fetching from list.
+)
+
+// New returns an empty queue object.
+// Optional parameter `limit` is used to limit the size of the queue, which is unlimited in default.
+// When `limit` is given, the queue will be static and high performance which is comparable with stdlib channel.
+func New(limit ...int) *Queue {
+ q := &Queue{
+ closed: gtype.NewBool(),
+ }
+ if len(limit) > 0 && limit[0] > 0 {
+ q.limit = limit[0]
+ q.C = make(chan interface{}, limit[0])
+ } else {
+ q.list = glist.New(true)
+ q.events = make(chan struct{}, math.MaxInt32)
+ q.C = make(chan interface{}, defaultQueueSize)
+ go q.asyncLoopFromListToChannel()
+ }
+ return q
+}
+
+// asyncLoopFromListToChannel starts an asynchronous goroutine,
+// which handles the data synchronization from list `q.list` to channel `q.C`.
+func (q *Queue) asyncLoopFromListToChannel() {
+ defer func() {
+ if q.closed.Val() {
+ _ = recover()
+ }
+ }()
+ for !q.closed.Val() {
+ <-q.events
+ for !q.closed.Val() {
+ if length := q.list.Len(); length > 0 {
+ if length > defaultBatchSize {
+ length = defaultBatchSize
+ }
+ for _, v := range q.list.PopFronts(length) {
+ // When q.C is closed, it will panic here, especially q.C is being blocked for writing.
+ // If any error occurs here, it will be caught by recover and be ignored.
+ q.C <- v
+ }
+ } else {
+ break
+ }
+ }
+ // Clear q.events to remain just one event to do the next synchronization check.
+ for i := 0; i < len(q.events)-1; i++ {
+ <-q.events
+ }
+ }
+ // It should be here to close `q.C` if `q` is unlimited size.
+ // It's the sender's responsibility to close channel when it should be closed.
+ close(q.C)
+}
+
+// Push pushes the data `v` into the queue.
+// Note that it would panic if Push is called after the queue is closed.
+func (q *Queue) Push(v interface{}) {
+ if q.limit > 0 {
+ q.C <- v
+ } else {
+ q.list.PushBack(v)
+ if len(q.events) < defaultQueueSize {
+ q.events <- struct{}{}
+ }
+ }
+}
+
+// Pop pops an item from the queue in FIFO way.
+// Note that it would return nil immediately if Pop is called after the queue is closed.
+func (q *Queue) Pop() interface{} {
+ return <-q.C
+}
+
+// Close closes the queue.
+// Notice: It would notify all goroutines return immediately,
+// which are being blocked reading using Pop method.
+func (q *Queue) Close() {
+ q.closed.Set(true)
+ if q.events != nil {
+ close(q.events)
+ }
+ if q.limit > 0 {
+ close(q.C)
+ } else {
+ for i := 0; i < defaultBatchSize; i++ {
+ q.Pop()
+ }
+ }
+}
+
+// Len returns the length of the queue.
+// Note that the result might not be accurate as there's an
+// asynchronous channel reading the list constantly.
+func (q *Queue) Len() (length int) {
+ if q.list != nil {
+ length += q.list.Len()
+ }
+ length += len(q.C)
+ return
+}
+
+// Size is alias of Len.
+func (q *Queue) Size() int {
+ return q.Len()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_any_set.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_any_set.go
new file mode 100644
index 000000000000..b04b05667d39
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_any_set.go
@@ -0,0 +1,509 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gset provides kinds of concurrent-safe/unsafe sets.
+package gset
+
+import (
+ "bytes"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type Set struct {
+ mu rwmutex.RWMutex
+ data map[interface{}]struct{}
+}
+
+// New create and returns a new set, which contains un-repeated items.
+// The parameter `safe` is used to specify whether using set in concurrent-safety,
+// which is false in default.
+func New(safe ...bool) *Set {
+ return NewSet(safe...)
+}
+
+// NewSet create and returns a new set, which contains un-repeated items.
+// Also see New.
+func NewSet(safe ...bool) *Set {
+ return &Set{
+ data: make(map[interface{}]struct{}),
+ mu: rwmutex.Create(safe...),
+ }
+}
+
+// NewFrom returns a new set from `items`.
+// Parameter `items` can be either a variable of any type, or a slice.
+func NewFrom(items interface{}, safe ...bool) *Set {
+ m := make(map[interface{}]struct{})
+ for _, v := range gconv.Interfaces(items) {
+ m[v] = struct{}{}
+ }
+ return &Set{
+ data: m,
+ mu: rwmutex.Create(safe...),
+ }
+}
+
+// Iterator iterates the set readonly with given callback function `f`,
+// if `f` returns true then continue iterating; or false to stop.
+func (set *Set) Iterator(f func(v interface{}) bool) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ if !f(k) {
+ break
+ }
+ }
+}
+
+// Add adds one or multiple items to the set.
+func (set *Set) Add(items ...interface{}) {
+ set.mu.Lock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
+ for _, v := range items {
+ set.data[v] = struct{}{}
+ }
+ set.mu.Unlock()
+}
+
+// AddIfNotExist checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set,
+// or else it does nothing and returns false.
+//
+// Note that, if `item` is nil, it does nothing and returns false.
+func (set *Set) AddIfNotExist(item interface{}) bool {
+ if item == nil {
+ return false
+ }
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ return false
+}
+
+// AddIfNotExistFunc checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exist in the set and
+// function `f` returns true, or else it does nothing and returns false.
+//
+// Note that, if `item` is nil, it does nothing and returns false. The function `f`
+// is executed without writing lock.
+func (set *Set) AddIfNotExistFunc(item interface{}, f func() bool) bool {
+ if item == nil {
+ return false
+ }
+ if !set.Contains(item) {
+ if f() {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// AddIfNotExistFuncLock checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set and
+// function `f` returns true, or else it does nothing and returns false.
+//
+// Note that, if `item` is nil, it does nothing and returns false. The function `f`
+// is executed within writing lock.
+func (set *Set) AddIfNotExistFuncLock(item interface{}, f func() bool) bool {
+ if item == nil {
+ return false
+ }
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
+ if f() {
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Contains checks whether the set contains `item`.
+func (set *Set) Contains(item interface{}) bool {
+ var ok bool
+ set.mu.RLock()
+ if set.data != nil {
+ _, ok = set.data[item]
+ }
+ set.mu.RUnlock()
+ return ok
+}
+
+// Remove deletes `item` from set.
+func (set *Set) Remove(item interface{}) {
+ set.mu.Lock()
+ if set.data != nil {
+ delete(set.data, item)
+ }
+ set.mu.Unlock()
+}
+
+// Size returns the size of the set.
+func (set *Set) Size() int {
+ set.mu.RLock()
+ l := len(set.data)
+ set.mu.RUnlock()
+ return l
+}
+
+// Clear deletes all items of the set.
+func (set *Set) Clear() {
+ set.mu.Lock()
+ set.data = make(map[interface{}]struct{})
+ set.mu.Unlock()
+}
+
+// Slice returns the a of items of the set as slice.
+func (set *Set) Slice() []interface{} {
+ set.mu.RLock()
+ var (
+ i = 0
+ ret = make([]interface{}, len(set.data))
+ )
+ for item := range set.data {
+ ret[i] = item
+ i++
+ }
+ set.mu.RUnlock()
+ return ret
+}
+
+// Join joins items with a string `glue`.
+func (set *Set) Join(glue string) string {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ if len(set.data) == 0 {
+ return ""
+ }
+ var (
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
+ for k, _ := range set.data {
+ buffer.WriteString(gconv.String(k))
+ if i != l-1 {
+ buffer.WriteString(glue)
+ }
+ i++
+ }
+ return buffer.String()
+}
+
+// String returns items as a string, which implements like json.Marshal does.
+func (set *Set) String() string {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ var (
+ s = ""
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
+ buffer.WriteByte('[')
+ for k, _ := range set.data {
+ s = gconv.String(k)
+ if gstr.IsNumeric(s) {
+ buffer.WriteString(s)
+ } else {
+ buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
+ }
+ if i != l-1 {
+ buffer.WriteByte(',')
+ }
+ i++
+ }
+ buffer.WriteByte(']')
+ return buffer.String()
+}
+
+// LockFunc locks writing with callback function `f`.
+func (set *Set) LockFunc(f func(m map[interface{}]struct{})) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ f(set.data)
+}
+
+// RLockFunc locks reading with callback function `f`.
+func (set *Set) RLockFunc(f func(m map[interface{}]struct{})) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ f(set.data)
+}
+
+// Equal checks whether the two sets equal.
+func (set *Set) Equal(other *Set) bool {
+ if set == other {
+ return true
+ }
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ if len(set.data) != len(other.data) {
+ return false
+ }
+ for key := range set.data {
+ if _, ok := other.data[key]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// IsSubsetOf checks whether the current set is a sub-set of `other`.
+func (set *Set) IsSubsetOf(other *Set) bool {
+ if set == other {
+ return true
+ }
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ for key := range set.data {
+ if _, ok := other.data[key]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// Union returns a new set which is the union of `set` and `others`.
+// Which means, all the items in `newSet` are in `set` or in `others`.
+func (set *Set) Union(others ...*Set) (newSet *Set) {
+ newSet = NewSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range set.data {
+ newSet.data[k] = v
+ }
+ if set != other {
+ for k, v := range other.data {
+ newSet.data[k] = v
+ }
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+
+ return
+}
+
+// Diff returns a new set which is the difference set from `set` to `others`.
+// Which means, all the items in `newSet` are in `set` but not in `others`.
+func (set *Set) Diff(others ...*Set) (newSet *Set) {
+ newSet = NewSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set == other {
+ continue
+ }
+ other.mu.RLock()
+ for k, v := range set.data {
+ if _, ok := other.data[k]; !ok {
+ newSet.data[k] = v
+ }
+ }
+ other.mu.RUnlock()
+ }
+ return
+}
+
+// Intersect returns a new set which is the intersection from `set` to `others`.
+// Which means, all the items in `newSet` are in `set` and also in `others`.
+func (set *Set) Intersect(others ...*Set) (newSet *Set) {
+ newSet = NewSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range set.data {
+ if _, ok := other.data[k]; ok {
+ newSet.data[k] = v
+ }
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+ return
+}
+
+// Complement returns a new set which is the complement from `set` to `full`.
+// Which means, all the items in `newSet` are in `full` and not in `set`.
+//
+// It returns the difference between `full` and `set`
+// if the given set `full` is not the full set of `set`.
+func (set *Set) Complement(full *Set) (newSet *Set) {
+ newSet = NewSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ if set != full {
+ full.mu.RLock()
+ defer full.mu.RUnlock()
+ }
+ for k, v := range full.data {
+ if _, ok := set.data[k]; !ok {
+ newSet.data[k] = v
+ }
+ }
+ return
+}
+
+// Merge adds items from `others` sets into `set`.
+func (set *Set) Merge(others ...*Set) *Set {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range other.data {
+ set.data[k] = v
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+ return set
+}
+
+// Sum sums items.
+// Note: The items should be converted to int type,
+// or you'd get a result that you unexpected.
+func (set *Set) Sum() (sum int) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ sum += gconv.Int(k)
+ }
+ return
+}
+
+// Pop randomly pops an item from set.
+func (set *Set) Pop() interface{} {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ for k, _ := range set.data {
+ delete(set.data, k)
+ return k
+ }
+ return nil
+}
+
+// Pops randomly pops `size` items from set.
+// It returns all items if size == -1.
+func (set *Set) Pops(size int) []interface{} {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if size > len(set.data) || size == -1 {
+ size = len(set.data)
+ }
+ if size <= 0 {
+ return nil
+ }
+ index := 0
+ array := make([]interface{}, size)
+ for k, _ := range set.data {
+ delete(set.data, k)
+ array[index] = k
+ index++
+ if index == size {
+ break
+ }
+ }
+ return array
+}
+
+// Walk applies a user supplied function `f` to every item of set.
+func (set *Set) Walk(f func(item interface{}) interface{}) *Set {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ m := make(map[interface{}]struct{}, len(set.data))
+ for k, v := range set.data {
+ m[f(k)] = v
+ }
+ set.data = m
+ return set
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (set Set) MarshalJSON() ([]byte, error) {
+ return json.Marshal(set.Slice())
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (set *Set) UnmarshalJSON(b []byte) error {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
+ var array []interface{}
+ if err := json.UnmarshalUseNumber(b, &array); err != nil {
+ return err
+ }
+ for _, v := range array {
+ set.data[v] = struct{}{}
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for set.
+func (set *Set) UnmarshalValue(value interface{}) (err error) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
+ var array []interface{}
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
+ default:
+ array = gconv.SliceAny(value)
+ }
+ for _, v := range array {
+ set.data[v] = struct{}{}
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_int_set.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_int_set.go
new file mode 100644
index 000000000000..cda8a6711fb0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_int_set.go
@@ -0,0 +1,468 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gset
+
+import (
+ "bytes"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type IntSet struct {
+ mu rwmutex.RWMutex
+ data map[int]struct{}
+}
+
+// NewIntSet create and returns a new set, which contains un-repeated items.
+// The parameter `safe` is used to specify whether using set in concurrent-safety,
+// which is false in default.
+func NewIntSet(safe ...bool) *IntSet {
+ return &IntSet{
+ mu: rwmutex.Create(safe...),
+ data: make(map[int]struct{}),
+ }
+}
+
+// NewIntSetFrom returns a new set from `items`.
+func NewIntSetFrom(items []int, safe ...bool) *IntSet {
+ m := make(map[int]struct{})
+ for _, v := range items {
+ m[v] = struct{}{}
+ }
+ return &IntSet{
+ mu: rwmutex.Create(safe...),
+ data: m,
+ }
+}
+
+// Iterator iterates the set readonly with given callback function `f`,
+// if `f` returns true then continue iterating; or false to stop.
+func (set *IntSet) Iterator(f func(v int) bool) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ if !f(k) {
+ break
+ }
+ }
+}
+
+// Add adds one or multiple items to the set.
+func (set *IntSet) Add(item ...int) {
+ set.mu.Lock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ for _, v := range item {
+ set.data[v] = struct{}{}
+ }
+ set.mu.Unlock()
+}
+
+// AddIfNotExist checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set,
+// or else it does nothing and returns false.
+//
+// Note that, if `item` is nil, it does nothing and returns false.
+func (set *IntSet) AddIfNotExist(item int) bool {
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ return false
+}
+
+// AddIfNotExistFunc checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set and
+// function `f` returns true, or else it does nothing and returns false.
+//
+// Note that, the function `f` is executed without writing lock.
+func (set *IntSet) AddIfNotExistFunc(item int, f func() bool) bool {
+ if !set.Contains(item) {
+ if f() {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// AddIfNotExistFuncLock checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set and
+// function `f` returns true, or else it does nothing and returns false.
+//
+// Note that, the function `f` is executed without writing lock.
+func (set *IntSet) AddIfNotExistFuncLock(item int, f func() bool) bool {
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ if f() {
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Contains checks whether the set contains `item`.
+func (set *IntSet) Contains(item int) bool {
+ var ok bool
+ set.mu.RLock()
+ if set.data != nil {
+ _, ok = set.data[item]
+ }
+ set.mu.RUnlock()
+ return ok
+}
+
+// Remove deletes `item` from set.
+func (set *IntSet) Remove(item int) {
+ set.mu.Lock()
+ if set.data != nil {
+ delete(set.data, item)
+ }
+ set.mu.Unlock()
+}
+
+// Size returns the size of the set.
+func (set *IntSet) Size() int {
+ set.mu.RLock()
+ l := len(set.data)
+ set.mu.RUnlock()
+ return l
+}
+
+// Clear deletes all items of the set.
+func (set *IntSet) Clear() {
+ set.mu.Lock()
+ set.data = make(map[int]struct{})
+ set.mu.Unlock()
+}
+
+// Slice returns the a of items of the set as slice.
+func (set *IntSet) Slice() []int {
+ set.mu.RLock()
+ var (
+ i = 0
+ ret = make([]int, len(set.data))
+ )
+ for k, _ := range set.data {
+ ret[i] = k
+ i++
+ }
+ set.mu.RUnlock()
+ return ret
+}
+
+// Join joins items with a string `glue`.
+func (set *IntSet) Join(glue string) string {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ if len(set.data) == 0 {
+ return ""
+ }
+ var (
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
+ for k, _ := range set.data {
+ buffer.WriteString(gconv.String(k))
+ if i != l-1 {
+ buffer.WriteString(glue)
+ }
+ i++
+ }
+ return buffer.String()
+}
+
+// String returns items as a string, which implements like json.Marshal does.
+func (set *IntSet) String() string {
+ return "[" + set.Join(",") + "]"
+}
+
+// LockFunc locks writing with callback function `f`.
+func (set *IntSet) LockFunc(f func(m map[int]struct{})) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ f(set.data)
+}
+
+// RLockFunc locks reading with callback function `f`.
+func (set *IntSet) RLockFunc(f func(m map[int]struct{})) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ f(set.data)
+}
+
+// Equal checks whether the two sets equal.
+func (set *IntSet) Equal(other *IntSet) bool {
+ if set == other {
+ return true
+ }
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ if len(set.data) != len(other.data) {
+ return false
+ }
+ for key := range set.data {
+ if _, ok := other.data[key]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// IsSubsetOf checks whether the current set is a sub-set of `other`.
+func (set *IntSet) IsSubsetOf(other *IntSet) bool {
+ if set == other {
+ return true
+ }
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ for key := range set.data {
+ if _, ok := other.data[key]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// Union returns a new set which is the union of `set` and `other`.
+// Which means, all the items in `newSet` are in `set` or in `other`.
+func (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) {
+ newSet = NewIntSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range set.data {
+ newSet.data[k] = v
+ }
+ if set != other {
+ for k, v := range other.data {
+ newSet.data[k] = v
+ }
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+
+ return
+}
+
+// Diff returns a new set which is the difference set from `set` to `other`.
+// Which means, all the items in `newSet` are in `set` but not in `other`.
+func (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) {
+ newSet = NewIntSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set == other {
+ continue
+ }
+ other.mu.RLock()
+ for k, v := range set.data {
+ if _, ok := other.data[k]; !ok {
+ newSet.data[k] = v
+ }
+ }
+ other.mu.RUnlock()
+ }
+ return
+}
+
+// Intersect returns a new set which is the intersection from `set` to `other`.
+// Which means, all the items in `newSet` are in `set` and also in `other`.
+func (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) {
+ newSet = NewIntSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range set.data {
+ if _, ok := other.data[k]; ok {
+ newSet.data[k] = v
+ }
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+ return
+}
+
+// Complement returns a new set which is the complement from `set` to `full`.
+// Which means, all the items in `newSet` are in `full` and not in `set`.
+//
+// It returns the difference between `full` and `set`
+// if the given set `full` is not the full set of `set`.
+func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) {
+ newSet = NewIntSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ if set != full {
+ full.mu.RLock()
+ defer full.mu.RUnlock()
+ }
+ for k, v := range full.data {
+ if _, ok := set.data[k]; !ok {
+ newSet.data[k] = v
+ }
+ }
+ return
+}
+
+// Merge adds items from `others` sets into `set`.
+func (set *IntSet) Merge(others ...*IntSet) *IntSet {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range other.data {
+ set.data[k] = v
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+ return set
+}
+
+// Sum sums items.
+// Note: The items should be converted to int type,
+// or you'd get a result that you unexpected.
+func (set *IntSet) Sum() (sum int) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ sum += k
+ }
+ return
+}
+
+// Pop randomly pops an item from set.
+func (set *IntSet) Pop() int {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ for k, _ := range set.data {
+ delete(set.data, k)
+ return k
+ }
+ return 0
+}
+
+// Pops randomly pops `size` items from set.
+// It returns all items if size == -1.
+func (set *IntSet) Pops(size int) []int {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if size > len(set.data) || size == -1 {
+ size = len(set.data)
+ }
+ if size <= 0 {
+ return nil
+ }
+ index := 0
+ array := make([]int, size)
+ for k, _ := range set.data {
+ delete(set.data, k)
+ array[index] = k
+ index++
+ if index == size {
+ break
+ }
+ }
+ return array
+}
+
+// Walk applies a user supplied function `f` to every item of set.
+func (set *IntSet) Walk(f func(item int) int) *IntSet {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ m := make(map[int]struct{}, len(set.data))
+ for k, v := range set.data {
+ m[f(k)] = v
+ }
+ set.data = m
+ return set
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (set IntSet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(set.Slice())
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (set *IntSet) UnmarshalJSON(b []byte) error {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ var array []int
+ if err := json.UnmarshalUseNumber(b, &array); err != nil {
+ return err
+ }
+ for _, v := range array {
+ set.data[v] = struct{}{}
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for set.
+func (set *IntSet) UnmarshalValue(value interface{}) (err error) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ var array []int
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
+ default:
+ array = gconv.SliceInt(value)
+ }
+ for _, v := range array {
+ set.data[v] = struct{}{}
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_str_set.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_str_set.go
new file mode 100644
index 000000000000..9a36f9016cad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gset/gset_str_set.go
@@ -0,0 +1,496 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gset
+
+import (
+ "bytes"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type StrSet struct {
+ mu rwmutex.RWMutex
+ data map[string]struct{}
+}
+
+// NewStrSet create and returns a new set, which contains un-repeated items.
+// The parameter `safe` is used to specify whether using set in concurrent-safety,
+// which is false in default.
+func NewStrSet(safe ...bool) *StrSet {
+ return &StrSet{
+ mu: rwmutex.Create(safe...),
+ data: make(map[string]struct{}),
+ }
+}
+
+// NewStrSetFrom returns a new set from `items`.
+func NewStrSetFrom(items []string, safe ...bool) *StrSet {
+ m := make(map[string]struct{})
+ for _, v := range items {
+ m[v] = struct{}{}
+ }
+ return &StrSet{
+ mu: rwmutex.Create(safe...),
+ data: m,
+ }
+}
+
+// Iterator iterates the set readonly with given callback function `f`,
+// if `f` returns true then continue iterating; or false to stop.
+func (set *StrSet) Iterator(f func(v string) bool) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ if !f(k) {
+ break
+ }
+ }
+}
+
+// Add adds one or multiple items to the set.
+func (set *StrSet) Add(item ...string) {
+ set.mu.Lock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ for _, v := range item {
+ set.data[v] = struct{}{}
+ }
+ set.mu.Unlock()
+}
+
+// AddIfNotExist checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exist in the set,
+// or else it does nothing and returns false.
+func (set *StrSet) AddIfNotExist(item string) bool {
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ return false
+}
+
+// AddIfNotExistFunc checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set and
+// function `f` returns true, or else it does nothing and returns false.
+//
+// Note that, the function `f` is executed without writing lock.
+func (set *StrSet) AddIfNotExistFunc(item string, f func() bool) bool {
+ if !set.Contains(item) {
+ if f() {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// AddIfNotExistFuncLock checks whether item exists in the set,
+// it adds the item to set and returns true if it does not exists in the set and
+// function `f` returns true, or else it does nothing and returns false.
+//
+// Note that, the function `f` is executed without writing lock.
+func (set *StrSet) AddIfNotExistFuncLock(item string, f func() bool) bool {
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ if f() {
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Contains checks whether the set contains `item`.
+func (set *StrSet) Contains(item string) bool {
+ var ok bool
+ set.mu.RLock()
+ if set.data != nil {
+ _, ok = set.data[item]
+ }
+ set.mu.RUnlock()
+ return ok
+}
+
+// ContainsI checks whether a value exists in the set with case-insensitively.
+// Note that it internally iterates the whole set to do the comparison with case-insensitively.
+func (set *StrSet) ContainsI(item string) bool {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ if strings.EqualFold(k, item) {
+ return true
+ }
+ }
+ return false
+}
+
+// Remove deletes `item` from set.
+func (set *StrSet) Remove(item string) {
+ set.mu.Lock()
+ if set.data != nil {
+ delete(set.data, item)
+ }
+ set.mu.Unlock()
+}
+
+// Size returns the size of the set.
+func (set *StrSet) Size() int {
+ set.mu.RLock()
+ l := len(set.data)
+ set.mu.RUnlock()
+ return l
+}
+
+// Clear deletes all items of the set.
+func (set *StrSet) Clear() {
+ set.mu.Lock()
+ set.data = make(map[string]struct{})
+ set.mu.Unlock()
+}
+
+// Slice returns the a of items of the set as slice.
+func (set *StrSet) Slice() []string {
+ set.mu.RLock()
+ var (
+ i = 0
+ ret = make([]string, len(set.data))
+ )
+ for item := range set.data {
+ ret[i] = item
+ i++
+ }
+
+ set.mu.RUnlock()
+ return ret
+}
+
+// Join joins items with a string `glue`.
+func (set *StrSet) Join(glue string) string {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ if len(set.data) == 0 {
+ return ""
+ }
+ var (
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
+ for k, _ := range set.data {
+ buffer.WriteString(k)
+ if i != l-1 {
+ buffer.WriteString(glue)
+ }
+ i++
+ }
+ return buffer.String()
+}
+
+// String returns items as a string, which implements like json.Marshal does.
+func (set *StrSet) String() string {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ var (
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
+ for k, _ := range set.data {
+ buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
+ if i != l-1 {
+ buffer.WriteByte(',')
+ }
+ i++
+ }
+ return buffer.String()
+}
+
+// LockFunc locks writing with callback function `f`.
+func (set *StrSet) LockFunc(f func(m map[string]struct{})) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ f(set.data)
+}
+
+// RLockFunc locks reading with callback function `f`.
+func (set *StrSet) RLockFunc(f func(m map[string]struct{})) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ f(set.data)
+}
+
+// Equal checks whether the two sets equal.
+func (set *StrSet) Equal(other *StrSet) bool {
+ if set == other {
+ return true
+ }
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ if len(set.data) != len(other.data) {
+ return false
+ }
+ for key := range set.data {
+ if _, ok := other.data[key]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// IsSubsetOf checks whether the current set is a sub-set of `other`.
+func (set *StrSet) IsSubsetOf(other *StrSet) bool {
+ if set == other {
+ return true
+ }
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ other.mu.RLock()
+ defer other.mu.RUnlock()
+ for key := range set.data {
+ if _, ok := other.data[key]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// Union returns a new set which is the union of `set` and `other`.
+// Which means, all the items in `newSet` are in `set` or in `other`.
+func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {
+ newSet = NewStrSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range set.data {
+ newSet.data[k] = v
+ }
+ if set != other {
+ for k, v := range other.data {
+ newSet.data[k] = v
+ }
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+
+ return
+}
+
+// Diff returns a new set which is the difference set from `set` to `other`.
+// Which means, all the items in `newSet` are in `set` but not in `other`.
+func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {
+ newSet = NewStrSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set == other {
+ continue
+ }
+ other.mu.RLock()
+ for k, v := range set.data {
+ if _, ok := other.data[k]; !ok {
+ newSet.data[k] = v
+ }
+ }
+ other.mu.RUnlock()
+ }
+ return
+}
+
+// Intersect returns a new set which is the intersection from `set` to `other`.
+// Which means, all the items in `newSet` are in `set` and also in `other`.
+func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {
+ newSet = NewStrSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range set.data {
+ if _, ok := other.data[k]; ok {
+ newSet.data[k] = v
+ }
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+ return
+}
+
+// Complement returns a new set which is the complement from `set` to `full`.
+// Which means, all the items in `newSet` are in `full` and not in `set`.
+//
+// It returns the difference between `full` and `set`
+// if the given set `full` is not the full set of `set`.
+func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) {
+ newSet = NewStrSet()
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ if set != full {
+ full.mu.RLock()
+ defer full.mu.RUnlock()
+ }
+ for k, v := range full.data {
+ if _, ok := set.data[k]; !ok {
+ newSet.data[k] = v
+ }
+ }
+ return
+}
+
+// Merge adds items from `others` sets into `set`.
+func (set *StrSet) Merge(others ...*StrSet) *StrSet {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ for _, other := range others {
+ if set != other {
+ other.mu.RLock()
+ }
+ for k, v := range other.data {
+ set.data[k] = v
+ }
+ if set != other {
+ other.mu.RUnlock()
+ }
+ }
+ return set
+}
+
+// Sum sums items.
+// Note: The items should be converted to int type,
+// or you'd get a result that you unexpected.
+func (set *StrSet) Sum() (sum int) {
+ set.mu.RLock()
+ defer set.mu.RUnlock()
+ for k, _ := range set.data {
+ sum += gconv.Int(k)
+ }
+ return
+}
+
+// Pop randomly pops an item from set.
+func (set *StrSet) Pop() string {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ for k, _ := range set.data {
+ delete(set.data, k)
+ return k
+ }
+ return ""
+}
+
+// Pops randomly pops `size` items from set.
+// It returns all items if size == -1.
+func (set *StrSet) Pops(size int) []string {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if size > len(set.data) || size == -1 {
+ size = len(set.data)
+ }
+ if size <= 0 {
+ return nil
+ }
+ index := 0
+ array := make([]string, size)
+ for k, _ := range set.data {
+ delete(set.data, k)
+ array[index] = k
+ index++
+ if index == size {
+ break
+ }
+ }
+ return array
+}
+
+// Walk applies a user supplied function `f` to every item of set.
+func (set *StrSet) Walk(f func(item string) string) *StrSet {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ m := make(map[string]struct{}, len(set.data))
+ for k, v := range set.data {
+ m[f(k)] = v
+ }
+ set.data = m
+ return set
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (set StrSet) MarshalJSON() ([]byte, error) {
+ return json.Marshal(set.Slice())
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (set *StrSet) UnmarshalJSON(b []byte) error {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ var array []string
+ if err := json.UnmarshalUseNumber(b, &array); err != nil {
+ return err
+ }
+ for _, v := range array {
+ set.data[v] = struct{}{}
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for set.
+func (set *StrSet) UnmarshalValue(value interface{}) (err error) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ var array []string
+ switch value.(type) {
+ case string, []byte:
+ err = json.UnmarshalUseNumber(gconv.Bytes(value), &array)
+ default:
+ array = gconv.SliceStr(value)
+ }
+ for _, v := range array {
+ set.data[v] = struct{}{}
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree.go
new file mode 100644
index 000000000000..2cb7b25ee6ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree.go
@@ -0,0 +1,10 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtree provides concurrent-safe/unsafe tree containers.
+//
+// Some implements are from: https://github.com/emirpasic/gods
+package gtree
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_avltree.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_avltree.go
new file mode 100644
index 000000000000..23c9fa0c8b44
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_avltree.go
@@ -0,0 +1,794 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtree
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// AVLTree holds elements of the AVL tree.
+type AVLTree struct {
+ mu rwmutex.RWMutex
+ root *AVLTreeNode
+ comparator func(v1, v2 interface{}) int
+ size int
+}
+
+// AVLTreeNode is a single element within the tree.
+type AVLTreeNode struct {
+ Key interface{}
+ Value interface{}
+ parent *AVLTreeNode
+ children [2]*AVLTreeNode
+ b int8
+}
+
+// NewAVLTree instantiates an AVL tree with the custom key comparator.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewAVLTree(comparator func(v1, v2 interface{}) int, safe ...bool) *AVLTree {
+ return &AVLTree{
+ mu: rwmutex.Create(safe...),
+ comparator: comparator,
+ }
+}
+
+// NewAVLTreeFrom instantiates an AVL tree with the custom key comparator and data map.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *AVLTree {
+ tree := NewAVLTree(comparator, safe...)
+ for k, v := range data {
+ tree.put(k, v, nil, &tree.root)
+ }
+ return tree
+}
+
+// Clone returns a new tree with a copy of current tree.
+func (tree *AVLTree) Clone() *AVLTree {
+ newTree := NewAVLTree(tree.comparator, tree.mu.IsSafe())
+ newTree.Sets(tree.Map())
+ return newTree
+}
+
+// Set inserts node into the tree.
+func (tree *AVLTree) Set(key interface{}, value interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.put(key, value, nil, &tree.root)
+}
+
+// Sets batch sets key-values to the tree.
+func (tree *AVLTree) Sets(data map[interface{}]interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ for key, value := range data {
+ tree.put(key, value, nil, &tree.root)
+ }
+}
+
+// Search searches the tree with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (tree *AVLTree) Search(key interface{}) (value interface{}, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ if node, found := tree.doSearch(key); found {
+ return node.Value, true
+ }
+ return nil, false
+}
+
+// doSearch searches the tree with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (tree *AVLTree) doSearch(key interface{}) (node *AVLTreeNode, found bool) {
+ node = tree.root
+ for node != nil {
+ cmp := tree.getComparator()(key, node.Key)
+ switch {
+ case cmp == 0:
+ return node, true
+ case cmp < 0:
+ node = node.children[0]
+ case cmp > 0:
+ node = node.children[1]
+ }
+ }
+ return nil, false
+}
+
+// Get searches the node in the tree by `key` and returns its value or nil if key is not found in tree.
+func (tree *AVLTree) Get(key interface{}) (value interface{}) {
+ value, _ = tree.Search(key)
+ return
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of ,
+// it will be executed with mutex.Lock of the hash map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (tree *AVLTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ if node, found := tree.doSearch(key); found {
+ return node.Value
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ tree.put(key, value, nil, &tree.root)
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (tree *AVLTree) GetOrSet(key interface{}, value interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (tree *AVLTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (tree *AVLTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a gvar.Var with the value by given `key`.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *AVLTree) GetVar(key interface{}) *gvar.Var {
+ return gvar.New(tree.Get(key))
+}
+
+// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *AVLTree) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *AVLTree) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *AVLTree) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (tree *AVLTree) SetIfNotExist(key interface{}, value interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (tree *AVLTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (tree *AVLTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Contains checks whether `key` exists in the tree.
+func (tree *AVLTree) Contains(key interface{}) bool {
+ _, ok := tree.Search(key)
+ return ok
+}
+
+// Remove removes the node from the tree by key.
+// Key should adhere to the comparator's type assertion, otherwise method panics.
+func (tree *AVLTree) Remove(key interface{}) (value interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ value, _ = tree.remove(key, &tree.root)
+ return
+}
+
+// Removes batch deletes values of the tree by `keys`.
+func (tree *AVLTree) Removes(keys []interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ for _, key := range keys {
+ tree.remove(key, &tree.root)
+ }
+}
+
+// IsEmpty returns true if tree does not contain any nodes.
+func (tree *AVLTree) IsEmpty() bool {
+ return tree.Size() == 0
+}
+
+// Size returns number of nodes in the tree.
+func (tree *AVLTree) Size() int {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ return tree.size
+}
+
+// Keys returns all keys in asc order.
+func (tree *AVLTree) Keys() []interface{} {
+ keys := make([]interface{}, tree.Size())
+ index := 0
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ keys[index] = key
+ index++
+ return true
+ })
+ return keys
+}
+
+// Values returns all values in asc order based on the key.
+func (tree *AVLTree) Values() []interface{} {
+ values := make([]interface{}, tree.Size())
+ index := 0
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ values[index] = value
+ index++
+ return true
+ })
+ return values
+}
+
+// Left returns the minimum element of the AVL tree
+// or nil if the tree is empty.
+func (tree *AVLTree) Left() *AVLTreeNode {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.bottom(0)
+ if tree.mu.IsSafe() {
+ return &AVLTreeNode{
+ Key: node.Key,
+ Value: node.Value,
+ }
+ }
+ return node
+}
+
+// Right returns the maximum element of the AVL tree
+// or nil if the tree is empty.
+func (tree *AVLTree) Right() *AVLTreeNode {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.bottom(1)
+ if tree.mu.IsSafe() {
+ return &AVLTreeNode{
+ Key: node.Key,
+ Value: node.Value,
+ }
+ }
+ return node
+}
+
+// Floor Finds floor node of the input key, return the floor node or nil if no floor node is found.
+// Second return parameter is true if floor was found, otherwise false.
+//
+// Floor node is defined as the largest node that is smaller than or equal to the given node.
+// A floor node may not be found, either because the tree is empty, or because
+// all nodes in the tree is larger than the given node.
+//
+// Key should adhere to the comparator's type assertion, otherwise method panics.
+func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ n := tree.root
+ for n != nil {
+ c := tree.getComparator()(key, n.Key)
+ switch {
+ case c == 0:
+ return n, true
+ case c < 0:
+ n = n.children[0]
+ case c > 0:
+ floor, found = n, true
+ n = n.children[1]
+ }
+ }
+ if found {
+ return
+ }
+ return nil, false
+}
+
+// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found.
+// Second return parameter is true if ceiling was found, otherwise false.
+//
+// Ceiling node is defined as the smallest node that is larger than or equal to the given node.
+// A ceiling node may not be found, either because the tree is empty, or because
+// all nodes in the tree is smaller than the given node.
+//
+// Key should adhere to the comparator's type assertion, otherwise method panics.
+func (tree *AVLTree) Ceiling(key interface{}) (ceiling *AVLTreeNode, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ n := tree.root
+ for n != nil {
+ c := tree.getComparator()(key, n.Key)
+ switch {
+ case c == 0:
+ return n, true
+ case c > 0:
+ n = n.children[1]
+ case c < 0:
+ ceiling, found = n, true
+ n = n.children[0]
+ }
+ }
+ if found {
+ return
+ }
+ return nil, false
+}
+
+// Clear removes all nodes from the tree.
+func (tree *AVLTree) Clear() {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.root = nil
+ tree.size = 0
+}
+
+// Replace the data of the tree with given `data`.
+func (tree *AVLTree) Replace(data map[interface{}]interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.root = nil
+ tree.size = 0
+ for key, value := range data {
+ tree.put(key, value, nil, &tree.root)
+ }
+}
+
+// String returns a string representation of container
+func (tree *AVLTree) String() string {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ str := ""
+ if tree.size != 0 {
+ output(tree.root, "", true, &str)
+ }
+ return str
+}
+
+// Print prints the tree to stdout.
+func (tree *AVLTree) Print() {
+ fmt.Println(tree.String())
+}
+
+// Map returns all key-value items as map.
+func (tree *AVLTree) Map() map[interface{}]interface{} {
+ m := make(map[interface{}]interface{}, tree.Size())
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ m[key] = value
+ return true
+ })
+ return m
+}
+
+// MapStrAny returns all key-value items as map[string]interface{}.
+func (tree *AVLTree) MapStrAny() map[string]interface{} {
+ m := make(map[string]interface{}, tree.Size())
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ m[gconv.String(key)] = value
+ return true
+ })
+ return m
+}
+
+// Flip exchanges key-value of the tree to value-key.
+// Note that you should guarantee the value is the same type as key,
+// or else the comparator would panic.
+//
+// If the type of value is different with key, you pass the new `comparator`.
+func (tree *AVLTree) Flip(comparator ...func(v1, v2 interface{}) int) {
+ t := (*AVLTree)(nil)
+ if len(comparator) > 0 {
+ t = NewAVLTree(comparator[0], tree.mu.IsSafe())
+ } else {
+ t = NewAVLTree(tree.comparator, tree.mu.IsSafe())
+ }
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ t.put(value, key, nil, &t.root)
+ return true
+ })
+ tree.mu.Lock()
+ tree.root = t.root
+ tree.size = t.size
+ tree.mu.Unlock()
+}
+
+// Iterator is alias of IteratorAsc.
+func (tree *AVLTree) Iterator(f func(key, value interface{}) bool) {
+ tree.IteratorAsc(f)
+}
+
+// IteratorFrom is alias of IteratorAscFrom.
+func (tree *AVLTree) IteratorFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.IteratorAscFrom(key, match, f)
+}
+
+// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *AVLTree) IteratorAsc(f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ tree.doIteratorAsc(tree.bottom(0), f)
+}
+
+// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
+// The parameter `key` specifies the start entry for iterating. The `match` specifies whether
+// starting iterating if the `key` is fully matched, or else using index searching iterating.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *AVLTree) IteratorAscFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, found := tree.doSearch(key)
+ if match {
+ if found {
+ tree.doIteratorAsc(node, f)
+ }
+ } else {
+ tree.doIteratorAsc(node, f)
+ }
+}
+
+func (tree *AVLTree) doIteratorAsc(node *AVLTreeNode, f func(key, value interface{}) bool) {
+ for node != nil {
+ if !f(node.Key, node.Value) {
+ return
+ }
+ node = node.Next()
+ }
+}
+
+// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *AVLTree) IteratorDesc(f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ tree.doIteratorDesc(tree.bottom(1), f)
+}
+
+// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
+// The parameter `key` specifies the start entry for iterating. The `match` specifies whether
+// starting iterating if the `key` is fully matched, or else using index searching iterating.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *AVLTree) IteratorDescFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, found := tree.doSearch(key)
+ if match {
+ if found {
+ tree.doIteratorDesc(node, f)
+ }
+ } else {
+ tree.doIteratorDesc(node, f)
+ }
+}
+
+func (tree *AVLTree) doIteratorDesc(node *AVLTreeNode, f func(key, value interface{}) bool) {
+ for node != nil {
+ if !f(node.Key, node.Value) {
+ return
+ }
+ node = node.Prev()
+ }
+}
+
+func (tree *AVLTree) put(key interface{}, value interface{}, p *AVLTreeNode, qp **AVLTreeNode) bool {
+ q := *qp
+ if q == nil {
+ tree.size++
+ *qp = &AVLTreeNode{Key: key, Value: value, parent: p}
+ return true
+ }
+
+ c := tree.getComparator()(key, q.Key)
+ if c == 0 {
+ q.Key = key
+ q.Value = value
+ return false
+ }
+
+ if c < 0 {
+ c = -1
+ } else {
+ c = 1
+ }
+ a := (c + 1) / 2
+ if tree.put(key, value, q, &q.children[a]) {
+ return putFix(int8(c), qp)
+ }
+ return false
+}
+
+func (tree *AVLTree) remove(key interface{}, qp **AVLTreeNode) (value interface{}, fix bool) {
+ q := *qp
+ if q == nil {
+ return nil, false
+ }
+
+ c := tree.getComparator()(key, q.Key)
+ if c == 0 {
+ tree.size--
+ value = q.Value
+ fix = true
+ if q.children[1] == nil {
+ if q.children[0] != nil {
+ q.children[0].parent = q.parent
+ }
+ *qp = q.children[0]
+ return
+ }
+ if removeMin(&q.children[1], &q.Key, &q.Value) {
+ return value, removeFix(-1, qp)
+ }
+ return
+ }
+
+ if c < 0 {
+ c = -1
+ } else {
+ c = 1
+ }
+ a := (c + 1) / 2
+ value, fix = tree.remove(key, &q.children[a])
+ if fix {
+ return value, removeFix(int8(-c), qp)
+ }
+ return value, false
+}
+
+func removeMin(qp **AVLTreeNode, minKey *interface{}, minVal *interface{}) bool {
+ q := *qp
+ if q.children[0] == nil {
+ *minKey = q.Key
+ *minVal = q.Value
+ if q.children[1] != nil {
+ q.children[1].parent = q.parent
+ }
+ *qp = q.children[1]
+ return true
+ }
+ fix := removeMin(&q.children[0], minKey, minVal)
+ if fix {
+ return removeFix(1, qp)
+ }
+ return false
+}
+
+func putFix(c int8, t **AVLTreeNode) bool {
+ s := *t
+ if s.b == 0 {
+ s.b = c
+ return true
+ }
+
+ if s.b == -c {
+ s.b = 0
+ return false
+ }
+
+ if s.children[(c+1)/2].b == c {
+ s = singleRotate(c, s)
+ } else {
+ s = doubleRotate(c, s)
+ }
+ *t = s
+ return false
+}
+
+func removeFix(c int8, t **AVLTreeNode) bool {
+ s := *t
+ if s.b == 0 {
+ s.b = c
+ return false
+ }
+
+ if s.b == -c {
+ s.b = 0
+ return true
+ }
+
+ a := (c + 1) / 2
+ if s.children[a].b == 0 {
+ s = rotate(c, s)
+ s.b = -c
+ *t = s
+ return false
+ }
+
+ if s.children[a].b == c {
+ s = singleRotate(c, s)
+ } else {
+ s = doubleRotate(c, s)
+ }
+ *t = s
+ return true
+}
+
+func singleRotate(c int8, s *AVLTreeNode) *AVLTreeNode {
+ s.b = 0
+ s = rotate(c, s)
+ s.b = 0
+ return s
+}
+
+func doubleRotate(c int8, s *AVLTreeNode) *AVLTreeNode {
+ a := (c + 1) / 2
+ r := s.children[a]
+ s.children[a] = rotate(-c, s.children[a])
+ p := rotate(c, s)
+
+ switch {
+ default:
+ s.b = 0
+ r.b = 0
+ case p.b == c:
+ s.b = -c
+ r.b = 0
+ case p.b == -c:
+ s.b = 0
+ r.b = c
+ }
+
+ p.b = 0
+ return p
+}
+
+func rotate(c int8, s *AVLTreeNode) *AVLTreeNode {
+ a := (c + 1) / 2
+ r := s.children[a]
+ s.children[a] = r.children[a^1]
+ if s.children[a] != nil {
+ s.children[a].parent = s
+ }
+ r.children[a^1] = s
+ r.parent = s.parent
+ s.parent = r
+ return r
+}
+
+func (tree *AVLTree) bottom(d int) *AVLTreeNode {
+ n := tree.root
+ if n == nil {
+ return nil
+ }
+
+ for c := n.children[d]; c != nil; c = n.children[d] {
+ n = c
+ }
+ return n
+}
+
+// Prev returns the previous element in an inorder
+// walk of the AVL tree.
+func (node *AVLTreeNode) Prev() *AVLTreeNode {
+ return node.walk1(0)
+}
+
+// Next returns the next element in an inorder
+// walk of the AVL tree.
+func (node *AVLTreeNode) Next() *AVLTreeNode {
+ return node.walk1(1)
+}
+
+func (node *AVLTreeNode) walk1(a int) *AVLTreeNode {
+ if node == nil {
+ return nil
+ }
+ n := node
+ if n.children[a] != nil {
+ n = n.children[a]
+ for n.children[a^1] != nil {
+ n = n.children[a^1]
+ }
+ return n
+ }
+
+ p := n.parent
+ for p != nil && p.children[a] == n {
+ n = p
+ p = p.parent
+ }
+ return p
+}
+
+func output(node *AVLTreeNode, prefix string, isTail bool, str *string) {
+ if node.children[1] != nil {
+ newPrefix := prefix
+ if isTail {
+ newPrefix += "│ "
+ } else {
+ newPrefix += " "
+ }
+ output(node.children[1], newPrefix, false, str)
+ }
+ *str += prefix
+ if isTail {
+ *str += "└── "
+ } else {
+ *str += "┌── "
+ }
+ *str += fmt.Sprintf("%v\n", node.Key)
+ if node.children[0] != nil {
+ newPrefix := prefix
+ if isTail {
+ newPrefix += " "
+ } else {
+ newPrefix += "│ "
+ }
+ output(node.children[0], newPrefix, true, str)
+ }
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (tree AVLTree) MarshalJSON() ([]byte, error) {
+ return json.Marshal(tree.MapStrAny())
+}
+
+// getComparator returns the comparator if it's previously set,
+// or else it panics.
+func (tree *AVLTree) getComparator() func(a, b interface{}) int {
+ if tree.comparator == nil {
+ panic("comparator is missing for tree")
+ }
+ return tree.comparator
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_btree.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_btree.go
new file mode 100644
index 000000000000..1123a918547d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_btree.go
@@ -0,0 +1,958 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtree
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// BTree holds elements of the B-tree.
+type BTree struct {
+ mu rwmutex.RWMutex
+ root *BTreeNode
+ comparator func(v1, v2 interface{}) int
+ size int // Total number of keys in the tree
+ m int // order (maximum number of children)
+}
+
+// BTreeNode is a single element within the tree.
+type BTreeNode struct {
+ Parent *BTreeNode
+ Entries []*BTreeEntry // Contained keys in node
+ Children []*BTreeNode // Children nodes
+}
+
+// BTreeEntry represents the key-value pair contained within nodes.
+type BTreeEntry struct {
+ Key interface{}
+ Value interface{}
+}
+
+// NewBTree instantiates a B-tree with `m` (maximum number of children) and a custom key comparator.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+// Note that the `m` must be greater or equal than 3, or else it panics.
+func NewBTree(m int, comparator func(v1, v2 interface{}) int, safe ...bool) *BTree {
+ if m < 3 {
+ panic("Invalid order, should be at least 3")
+ }
+ return &BTree{
+ comparator: comparator,
+ mu: rwmutex.Create(safe...),
+ m: m,
+ }
+}
+
+// NewBTreeFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator and data map.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewBTreeFrom(m int, comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *BTree {
+ tree := NewBTree(m, comparator, safe...)
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+ return tree
+}
+
+// Clone returns a new tree with a copy of current tree.
+func (tree *BTree) Clone() *BTree {
+ newTree := NewBTree(tree.m, tree.comparator, tree.mu.IsSafe())
+ newTree.Sets(tree.Map())
+ return newTree
+}
+
+// Set inserts key-value item into the tree.
+func (tree *BTree) Set(key interface{}, value interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.doSet(key, value)
+}
+
+// doSet inserts key-value pair node into the tree.
+// If key already exists, then its value is updated with the new value.
+func (tree *BTree) doSet(key interface{}, value interface{}) {
+ entry := &BTreeEntry{Key: key, Value: value}
+ if tree.root == nil {
+ tree.root = &BTreeNode{Entries: []*BTreeEntry{entry}, Children: []*BTreeNode{}}
+ tree.size++
+ return
+ }
+
+ if tree.insert(tree.root, entry) {
+ tree.size++
+ }
+}
+
+// Sets batch sets key-values to the tree.
+func (tree *BTree) Sets(data map[interface{}]interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+}
+
+// Get searches the node in the tree by `key` and returns its value or nil if key is not found in tree.
+func (tree *BTree) Get(key interface{}) (value interface{}) {
+ value, _ = tree.Search(key)
+ return
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of ,
+// it will be executed with mutex.Lock of the hash map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (tree *BTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ if entry := tree.doSearch(key); entry != nil {
+ return entry.Value
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ tree.doSet(key, value)
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (tree *BTree) GetOrSet(key interface{}, value interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (tree *BTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (tree *BTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a gvar.Var with the value by given `key`.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *BTree) GetVar(key interface{}) *gvar.Var {
+ return gvar.New(tree.Get(key))
+}
+
+// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *BTree) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *BTree) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *BTree) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (tree *BTree) SetIfNotExist(key interface{}, value interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (tree *BTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (tree *BTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Contains checks whether `key` exists in the tree.
+func (tree *BTree) Contains(key interface{}) bool {
+ _, ok := tree.Search(key)
+ return ok
+}
+
+// doRemove removes the node from the tree by key.
+// Key should adhere to the comparator's type assertion, otherwise method panics.
+func (tree *BTree) doRemove(key interface{}) (value interface{}) {
+ node, index, found := tree.searchRecursively(tree.root, key)
+ if found {
+ value = node.Entries[index].Value
+ tree.delete(node, index)
+ tree.size--
+ }
+ return
+}
+
+// Remove removes the node from the tree by `key`.
+func (tree *BTree) Remove(key interface{}) (value interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ return tree.doRemove(key)
+}
+
+// Removes batch deletes values of the tree by `keys`.
+func (tree *BTree) Removes(keys []interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ for _, key := range keys {
+ tree.doRemove(key)
+ }
+}
+
+// IsEmpty returns true if tree does not contain any nodes
+func (tree *BTree) IsEmpty() bool {
+ return tree.Size() == 0
+}
+
+// Size returns number of nodes in the tree.
+func (tree *BTree) Size() int {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ return tree.size
+}
+
+// Keys returns all keys in asc order.
+func (tree *BTree) Keys() []interface{} {
+ keys := make([]interface{}, tree.Size())
+ index := 0
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ keys[index] = key
+ index++
+ return true
+ })
+ return keys
+}
+
+// Values returns all values in asc order based on the key.
+func (tree *BTree) Values() []interface{} {
+ values := make([]interface{}, tree.Size())
+ index := 0
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ values[index] = value
+ index++
+ return true
+ })
+ return values
+}
+
+// Map returns all key-value items as map.
+func (tree *BTree) Map() map[interface{}]interface{} {
+ m := make(map[interface{}]interface{}, tree.Size())
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ m[key] = value
+ return true
+ })
+ return m
+}
+
+// MapStrAny returns all key-value items as map[string]interface{}.
+func (tree *BTree) MapStrAny() map[string]interface{} {
+ m := make(map[string]interface{}, tree.Size())
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ m[gconv.String(key)] = value
+ return true
+ })
+ return m
+}
+
+// Clear removes all nodes from the tree.
+func (tree *BTree) Clear() {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.root = nil
+ tree.size = 0
+}
+
+// Replace the data of the tree with given `data`.
+func (tree *BTree) Replace(data map[interface{}]interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.root = nil
+ tree.size = 0
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+}
+
+// Height returns the height of the tree.
+func (tree *BTree) Height() int {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ return tree.root.height()
+}
+
+// Left returns the left-most (min) entry or nil if tree is empty.
+func (tree *BTree) Left() *BTreeEntry {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.left(tree.root)
+ if node != nil {
+ return node.Entries[0]
+ }
+ return nil
+}
+
+// Right returns the right-most (max) entry or nil if tree is empty.
+func (tree *BTree) Right() *BTreeEntry {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.right(tree.root)
+ if node != nil {
+ return node.Entries[len(node.Entries)-1]
+ }
+ return nil
+}
+
+// String returns a string representation of container (for debugging purposes)
+func (tree *BTree) String() string {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ var buffer bytes.Buffer
+ if tree.size != 0 {
+ tree.output(&buffer, tree.root, 0, true)
+ }
+ return buffer.String()
+}
+
+// Search searches the tree with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (tree *BTree) Search(key interface{}) (value interface{}, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, index, found := tree.searchRecursively(tree.root, key)
+ if found {
+ return node.Entries[index].Value, true
+ }
+ return nil, false
+}
+
+// Search searches the tree with given `key` without mutex.
+// It returns the entry if found or otherwise nil.
+func (tree *BTree) doSearch(key interface{}) *BTreeEntry {
+ node, index, found := tree.searchRecursively(tree.root, key)
+ if found {
+ return node.Entries[index]
+ }
+ return nil
+}
+
+// Print prints the tree to stdout.
+func (tree *BTree) Print() {
+ fmt.Println(tree.String())
+}
+
+// Iterator is alias of IteratorAsc.
+func (tree *BTree) Iterator(f func(key, value interface{}) bool) {
+ tree.IteratorAsc(f)
+}
+
+// IteratorFrom is alias of IteratorAscFrom.
+func (tree *BTree) IteratorFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.IteratorAscFrom(key, match, f)
+}
+
+// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *BTree) IteratorAsc(f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.left(tree.root)
+ if node == nil {
+ return
+ }
+ tree.doIteratorAsc(node, node.Entries[0], 0, f)
+}
+
+// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
+// The parameter `key` specifies the start entry for iterating. The `match` specifies whether
+// starting iterating if the `key` is fully matched, or else using index searching iterating.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *BTree) IteratorAscFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, index, found := tree.searchRecursively(tree.root, key)
+ if match {
+ if found {
+ tree.doIteratorAsc(node, node.Entries[index], index, f)
+ }
+ } else {
+ if index >= 0 && index < len(node.Entries) {
+ tree.doIteratorAsc(node, node.Entries[index], index, f)
+ }
+ }
+}
+
+func (tree *BTree) doIteratorAsc(node *BTreeNode, entry *BTreeEntry, index int, f func(key, value interface{}) bool) {
+ first := true
+loop:
+ if entry == nil {
+ return
+ }
+ if !f(entry.Key, entry.Value) {
+ return
+ }
+ // Find current entry position in current node
+ if !first {
+ index, _ = tree.search(node, entry.Key)
+ } else {
+ first = false
+ }
+ // Try to go down to the child right of the current entry
+ if index+1 < len(node.Children) {
+ node = node.Children[index+1]
+ // Try to go down to the child left of the current node
+ for len(node.Children) > 0 {
+ node = node.Children[0]
+ }
+ // Return the left-most entry
+ entry = node.Entries[0]
+ goto loop
+ }
+ // Above assures that we have reached a leaf node, so return the next entry in current node (if any)
+ if index+1 < len(node.Entries) {
+ entry = node.Entries[index+1]
+ goto loop
+ }
+ // Reached leaf node and there are no entries to the right of the current entry, so go up to the parent
+ for node.Parent != nil {
+ node = node.Parent
+ // Find next entry position in current node (note: search returns the first equal or bigger than entry)
+ index, _ = tree.search(node, entry.Key)
+ // Check that there is a next entry position in current node
+ if index < len(node.Entries) {
+ entry = node.Entries[index]
+ goto loop
+ }
+ }
+}
+
+// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *BTree) IteratorDesc(f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.right(tree.root)
+ if node == nil {
+ return
+ }
+ index := len(node.Entries) - 1
+ entry := node.Entries[index]
+ tree.doIteratorDesc(node, entry, index, f)
+}
+
+// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
+// The parameter `key` specifies the start entry for iterating. The `match` specifies whether
+// starting iterating if the `key` is fully matched, or else using index searching iterating.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *BTree) IteratorDescFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, index, found := tree.searchRecursively(tree.root, key)
+ if match {
+ if found {
+ tree.doIteratorDesc(node, node.Entries[index], index, f)
+ }
+ } else {
+ if index >= 0 && index < len(node.Entries) {
+ tree.doIteratorDesc(node, node.Entries[index], index, f)
+ }
+ }
+}
+
+// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *BTree) doIteratorDesc(node *BTreeNode, entry *BTreeEntry, index int, f func(key, value interface{}) bool) {
+ first := true
+loop:
+ if entry == nil {
+ return
+ }
+ if !f(entry.Key, entry.Value) {
+ return
+ }
+ // Find current entry position in current node
+ if !first {
+ index, _ = tree.search(node, entry.Key)
+ } else {
+ first = false
+ }
+ // Try to go down to the child left of the current entry
+ if index < len(node.Children) {
+ node = node.Children[index]
+ // Try to go down to the child right of the current node
+ for len(node.Children) > 0 {
+ node = node.Children[len(node.Children)-1]
+ }
+ // Return the right-most entry
+ entry = node.Entries[len(node.Entries)-1]
+ goto loop
+ }
+ // Above assures that we have reached a leaf node, so return the previous entry in current node (if any)
+ if index-1 >= 0 {
+ entry = node.Entries[index-1]
+ goto loop
+ }
+
+ // Reached leaf node and there are no entries to the left of the current entry, so go up to the parent
+ for node.Parent != nil {
+ node = node.Parent
+ // Find previous entry position in current node (note: search returns the first equal or bigger than entry)
+ index, _ = tree.search(node, entry.Key)
+ // Check that there is a previous entry position in current node
+ if index-1 >= 0 {
+ entry = node.Entries[index-1]
+ goto loop
+ }
+ }
+}
+
+func (tree *BTree) output(buffer *bytes.Buffer, node *BTreeNode, level int, isTail bool) {
+ for e := 0; e < len(node.Entries)+1; e++ {
+ if e < len(node.Children) {
+ tree.output(buffer, node.Children[e], level+1, true)
+ }
+ if e < len(node.Entries) {
+ if _, err := buffer.WriteString(strings.Repeat(" ", level)); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ if _, err := buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n"); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ }
+}
+
+func (node *BTreeNode) height() int {
+ h := 0
+ n := node
+ for ; n != nil; n = n.Children[0] {
+ h++
+ if len(n.Children) == 0 {
+ break
+ }
+ }
+ return h
+}
+
+func (tree *BTree) isLeaf(node *BTreeNode) bool {
+ return len(node.Children) == 0
+}
+
+// func (tree *BTree) isFull(node *BTreeNode) bool {
+// return len(node.Entries) == tree.maxEntries()
+// }
+
+func (tree *BTree) shouldSplit(node *BTreeNode) bool {
+ return len(node.Entries) > tree.maxEntries()
+}
+
+func (tree *BTree) maxChildren() int {
+ return tree.m
+}
+
+func (tree *BTree) minChildren() int {
+ return (tree.m + 1) / 2 // ceil(m/2)
+}
+
+func (tree *BTree) maxEntries() int {
+ return tree.maxChildren() - 1
+}
+
+func (tree *BTree) minEntries() int {
+ return tree.minChildren() - 1
+}
+
+func (tree *BTree) middle() int {
+ // "-1" to favor right nodes to have more keys when splitting
+ return (tree.m - 1) / 2
+}
+
+// search does search only within the single node among its entries
+func (tree *BTree) search(node *BTreeNode, key interface{}) (index int, found bool) {
+ low, mid, high := 0, 0, len(node.Entries)-1
+ for low <= high {
+ mid = low + (high-low)/2
+ compare := tree.getComparator()(key, node.Entries[mid].Key)
+ switch {
+ case compare > 0:
+ low = mid + 1
+ case compare < 0:
+ high = mid - 1
+ case compare == 0:
+ return mid, true
+ }
+ }
+ return low, false
+}
+
+// searchRecursively searches recursively down the tree starting at the startNode
+func (tree *BTree) searchRecursively(startNode *BTreeNode, key interface{}) (node *BTreeNode, index int, found bool) {
+ if tree.size == 0 {
+ return nil, -1, false
+ }
+ node = startNode
+ for {
+ index, found = tree.search(node, key)
+ if found {
+ return node, index, true
+ }
+ if tree.isLeaf(node) {
+ return node, index, false
+ }
+ node = node.Children[index]
+ }
+}
+
+func (tree *BTree) insert(node *BTreeNode, entry *BTreeEntry) (inserted bool) {
+ if tree.isLeaf(node) {
+ return tree.insertIntoLeaf(node, entry)
+ }
+ return tree.insertIntoInternal(node, entry)
+}
+
+func (tree *BTree) insertIntoLeaf(node *BTreeNode, entry *BTreeEntry) (inserted bool) {
+ insertPosition, found := tree.search(node, entry.Key)
+ if found {
+ node.Entries[insertPosition] = entry
+ return false
+ }
+ // Insert entry's key in the middle of the node
+ node.Entries = append(node.Entries, nil)
+ copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:])
+ node.Entries[insertPosition] = entry
+ tree.split(node)
+ return true
+}
+
+func (tree *BTree) insertIntoInternal(node *BTreeNode, entry *BTreeEntry) (inserted bool) {
+ insertPosition, found := tree.search(node, entry.Key)
+ if found {
+ node.Entries[insertPosition] = entry
+ return false
+ }
+ return tree.insert(node.Children[insertPosition], entry)
+}
+
+func (tree *BTree) split(node *BTreeNode) {
+ if !tree.shouldSplit(node) {
+ return
+ }
+
+ if node == tree.root {
+ tree.splitRoot()
+ return
+ }
+
+ tree.splitNonRoot(node)
+}
+
+func (tree *BTree) splitNonRoot(node *BTreeNode) {
+ middle := tree.middle()
+ parent := node.Parent
+
+ left := &BTreeNode{Entries: append([]*BTreeEntry(nil), node.Entries[:middle]...), Parent: parent}
+ right := &BTreeNode{Entries: append([]*BTreeEntry(nil), node.Entries[middle+1:]...), Parent: parent}
+
+ // Move children from the node to be split into left and right nodes
+ if !tree.isLeaf(node) {
+ left.Children = append([]*BTreeNode(nil), node.Children[:middle+1]...)
+ right.Children = append([]*BTreeNode(nil), node.Children[middle+1:]...)
+ setParent(left.Children, left)
+ setParent(right.Children, right)
+ }
+
+ insertPosition, _ := tree.search(parent, node.Entries[middle].Key)
+
+ // Insert middle key into parent
+ parent.Entries = append(parent.Entries, nil)
+ copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:])
+ parent.Entries[insertPosition] = node.Entries[middle]
+
+ // Set child left of inserted key in parent to the created left node
+ parent.Children[insertPosition] = left
+
+ // Set child right of inserted key in parent to the created right node
+ parent.Children = append(parent.Children, nil)
+ copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:])
+ parent.Children[insertPosition+1] = right
+
+ tree.split(parent)
+}
+
+func (tree *BTree) splitRoot() {
+ middle := tree.middle()
+ left := &BTreeNode{Entries: append([]*BTreeEntry(nil), tree.root.Entries[:middle]...)}
+ right := &BTreeNode{Entries: append([]*BTreeEntry(nil), tree.root.Entries[middle+1:]...)}
+
+ // Move children from the node to be split into left and right nodes
+ if !tree.isLeaf(tree.root) {
+ left.Children = append([]*BTreeNode(nil), tree.root.Children[:middle+1]...)
+ right.Children = append([]*BTreeNode(nil), tree.root.Children[middle+1:]...)
+ setParent(left.Children, left)
+ setParent(right.Children, right)
+ }
+
+ // Root is a node with one entry and two children (left and right)
+ newRoot := &BTreeNode{
+ Entries: []*BTreeEntry{tree.root.Entries[middle]},
+ Children: []*BTreeNode{left, right},
+ }
+
+ left.Parent = newRoot
+ right.Parent = newRoot
+ tree.root = newRoot
+}
+
+func setParent(nodes []*BTreeNode, parent *BTreeNode) {
+ for _, node := range nodes {
+ node.Parent = parent
+ }
+}
+
+func (tree *BTree) left(node *BTreeNode) *BTreeNode {
+ if tree.size == 0 {
+ return nil
+ }
+ current := node
+ for {
+ if tree.isLeaf(current) {
+ return current
+ }
+ current = current.Children[0]
+ }
+}
+
+func (tree *BTree) right(node *BTreeNode) *BTreeNode {
+ if tree.size == 0 {
+ return nil
+ }
+ current := node
+ for {
+ if tree.isLeaf(current) {
+ return current
+ }
+ current = current.Children[len(current.Children)-1]
+ }
+}
+
+// leftSibling returns the node's left sibling and child index (in parent) if it exists, otherwise (nil,-1)
+// key is any of keys in node (could even be deleted).
+func (tree *BTree) leftSibling(node *BTreeNode, key interface{}) (*BTreeNode, int) {
+ if node.Parent != nil {
+ index, _ := tree.search(node.Parent, key)
+ index--
+ if index >= 0 && index < len(node.Parent.Children) {
+ return node.Parent.Children[index], index
+ }
+ }
+ return nil, -1
+}
+
+// rightSibling returns the node's right sibling and child index (in parent) if it exists, otherwise (nil,-1)
+// key is any of keys in node (could even be deleted).
+func (tree *BTree) rightSibling(node *BTreeNode, key interface{}) (*BTreeNode, int) {
+ if node.Parent != nil {
+ index, _ := tree.search(node.Parent, key)
+ index++
+ if index < len(node.Parent.Children) {
+ return node.Parent.Children[index], index
+ }
+ }
+ return nil, -1
+}
+
+// delete deletes an entry in node at entries' index
+// ref.: https://en.wikipedia.org/wiki/B-tree#Deletion
+func (tree *BTree) delete(node *BTreeNode, index int) {
+ // deleting from a leaf node
+ if tree.isLeaf(node) {
+ deletedKey := node.Entries[index].Key
+ tree.deleteEntry(node, index)
+ tree.reBalance(node, deletedKey)
+ if len(tree.root.Entries) == 0 {
+ tree.root = nil
+ }
+ return
+ }
+
+ // deleting from an internal node
+ leftLargestNode := tree.right(node.Children[index]) // largest node in the left sub-tree (assumed to exist)
+ leftLargestEntryIndex := len(leftLargestNode.Entries) - 1
+ node.Entries[index] = leftLargestNode.Entries[leftLargestEntryIndex]
+ deletedKey := leftLargestNode.Entries[leftLargestEntryIndex].Key
+ tree.deleteEntry(leftLargestNode, leftLargestEntryIndex)
+ tree.reBalance(leftLargestNode, deletedKey)
+}
+
+// reBalance reBalances the tree after deletion if necessary and returns true, otherwise false.
+// Note that we first delete the entry and then call reBalance, thus the passed deleted key as reference.
+func (tree *BTree) reBalance(node *BTreeNode, deletedKey interface{}) {
+ // check if re-balancing is needed
+ if node == nil || len(node.Entries) >= tree.minEntries() {
+ return
+ }
+
+ // try to borrow from left sibling
+ leftSibling, leftSiblingIndex := tree.leftSibling(node, deletedKey)
+ if leftSibling != nil && len(leftSibling.Entries) > tree.minEntries() {
+ // rotate right
+ node.Entries = append([]*BTreeEntry{node.Parent.Entries[leftSiblingIndex]}, node.Entries...) // prepend parent's separator entry to node's entries
+ node.Parent.Entries[leftSiblingIndex] = leftSibling.Entries[len(leftSibling.Entries)-1]
+ tree.deleteEntry(leftSibling, len(leftSibling.Entries)-1)
+ if !tree.isLeaf(leftSibling) {
+ leftSiblingRightMostChild := leftSibling.Children[len(leftSibling.Children)-1]
+ leftSiblingRightMostChild.Parent = node
+ node.Children = append([]*BTreeNode{leftSiblingRightMostChild}, node.Children...)
+ tree.deleteChild(leftSibling, len(leftSibling.Children)-1)
+ }
+ return
+ }
+
+ // try to borrow from right sibling
+ rightSibling, rightSiblingIndex := tree.rightSibling(node, deletedKey)
+ if rightSibling != nil && len(rightSibling.Entries) > tree.minEntries() {
+ // rotate left
+ node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1]) // append parent's separator entry to node's entries
+ node.Parent.Entries[rightSiblingIndex-1] = rightSibling.Entries[0]
+ tree.deleteEntry(rightSibling, 0)
+ if !tree.isLeaf(rightSibling) {
+ rightSiblingLeftMostChild := rightSibling.Children[0]
+ rightSiblingLeftMostChild.Parent = node
+ node.Children = append(node.Children, rightSiblingLeftMostChild)
+ tree.deleteChild(rightSibling, 0)
+ }
+ return
+ }
+
+ // merge with siblings
+ if rightSibling != nil {
+ // merge with right sibling
+ node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1])
+ node.Entries = append(node.Entries, rightSibling.Entries...)
+ deletedKey = node.Parent.Entries[rightSiblingIndex-1].Key
+ tree.deleteEntry(node.Parent, rightSiblingIndex-1)
+ tree.appendChildren(node.Parent.Children[rightSiblingIndex], node)
+ tree.deleteChild(node.Parent, rightSiblingIndex)
+ } else if leftSibling != nil {
+ // merge with left sibling
+ entries := append([]*BTreeEntry(nil), leftSibling.Entries...)
+ entries = append(entries, node.Parent.Entries[leftSiblingIndex])
+ node.Entries = append(entries, node.Entries...)
+ deletedKey = node.Parent.Entries[leftSiblingIndex].Key
+ tree.deleteEntry(node.Parent, leftSiblingIndex)
+ tree.prependChildren(node.Parent.Children[leftSiblingIndex], node)
+ tree.deleteChild(node.Parent, leftSiblingIndex)
+ }
+
+ // make the merged node the root if its parent was the root and the root is empty
+ if node.Parent == tree.root && len(tree.root.Entries) == 0 {
+ tree.root = node
+ node.Parent = nil
+ return
+ }
+
+ // parent might be underflow, so try to reBalance if necessary
+ tree.reBalance(node.Parent, deletedKey)
+}
+
+func (tree *BTree) prependChildren(fromNode *BTreeNode, toNode *BTreeNode) {
+ children := append([]*BTreeNode(nil), fromNode.Children...)
+ toNode.Children = append(children, toNode.Children...)
+ setParent(fromNode.Children, toNode)
+}
+
+func (tree *BTree) appendChildren(fromNode *BTreeNode, toNode *BTreeNode) {
+ toNode.Children = append(toNode.Children, fromNode.Children...)
+ setParent(fromNode.Children, toNode)
+}
+
+func (tree *BTree) deleteEntry(node *BTreeNode, index int) {
+ copy(node.Entries[index:], node.Entries[index+1:])
+ node.Entries[len(node.Entries)-1] = nil
+ node.Entries = node.Entries[:len(node.Entries)-1]
+}
+
+func (tree *BTree) deleteChild(node *BTreeNode, index int) {
+ if index >= len(node.Children) {
+ return
+ }
+ copy(node.Children[index:], node.Children[index+1:])
+ node.Children[len(node.Children)-1] = nil
+ node.Children = node.Children[:len(node.Children)-1]
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (tree BTree) MarshalJSON() ([]byte, error) {
+ return json.Marshal(tree.MapStrAny())
+}
+
+// getComparator returns the comparator if it's previously set,
+// or else it panics.
+func (tree *BTree) getComparator() func(a, b interface{}) int {
+ if tree.comparator == nil {
+ panic("comparator is missing for tree")
+ }
+ return tree.comparator
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_redblacktree.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_redblacktree.go
new file mode 100644
index 000000000000..01d875dcca93
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtree/gtree_redblacktree.go
@@ -0,0 +1,969 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtree
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+type color bool
+
+const (
+ black, red color = true, false
+)
+
+// RedBlackTree holds elements of the red-black tree.
+type RedBlackTree struct {
+ mu rwmutex.RWMutex
+ root *RedBlackTreeNode
+ size int
+ comparator func(v1, v2 interface{}) int
+}
+
+// RedBlackTreeNode is a single element within the tree.
+type RedBlackTreeNode struct {
+ Key interface{}
+ Value interface{}
+ color color
+ left *RedBlackTreeNode
+ right *RedBlackTreeNode
+ parent *RedBlackTreeNode
+}
+
+// NewRedBlackTree instantiates a red-black tree with the custom key comparator.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewRedBlackTree(comparator func(v1, v2 interface{}) int, safe ...bool) *RedBlackTree {
+ return &RedBlackTree{
+ mu: rwmutex.Create(safe...),
+ comparator: comparator,
+ }
+}
+
+// NewRedBlackTreeFrom instantiates a red-black tree with the custom key comparator and `data` map.
+// The parameter `safe` is used to specify whether using tree in concurrent-safety,
+// which is false in default.
+func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *RedBlackTree {
+ tree := NewRedBlackTree(comparator, safe...)
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+ return tree
+}
+
+// SetComparator sets/changes the comparator for sorting.
+func (tree *RedBlackTree) SetComparator(comparator func(a, b interface{}) int) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.comparator = comparator
+ if tree.size > 0 {
+ data := make(map[interface{}]interface{}, tree.size)
+ tree.doIteratorAsc(tree.leftNode(), func(key, value interface{}) bool {
+ data[key] = value
+ return true
+ })
+ // Resort the tree if comparator is changed.
+ tree.root = nil
+ tree.size = 0
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+ }
+}
+
+// Clone returns a new tree with a copy of current tree.
+func (tree *RedBlackTree) Clone() *RedBlackTree {
+ newTree := NewRedBlackTree(tree.comparator, tree.mu.IsSafe())
+ newTree.Sets(tree.Map())
+ return newTree
+}
+
+// Set inserts key-value item into the tree.
+func (tree *RedBlackTree) Set(key interface{}, value interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.doSet(key, value)
+}
+
+// Sets batch sets key-values to the tree.
+func (tree *RedBlackTree) Sets(data map[interface{}]interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+}
+
+// doSet inserts key-value item into the tree without mutex.
+func (tree *RedBlackTree) doSet(key interface{}, value interface{}) {
+ insertedNode := (*RedBlackTreeNode)(nil)
+ if tree.root == nil {
+ // Assert key is of comparator's type for initial tree
+ tree.getComparator()(key, key)
+ tree.root = &RedBlackTreeNode{Key: key, Value: value, color: red}
+ insertedNode = tree.root
+ } else {
+ node := tree.root
+ loop := true
+ for loop {
+ compare := tree.getComparator()(key, node.Key)
+ switch {
+ case compare == 0:
+ // node.Key = key
+ node.Value = value
+ return
+ case compare < 0:
+ if node.left == nil {
+ node.left = &RedBlackTreeNode{Key: key, Value: value, color: red}
+ insertedNode = node.left
+ loop = false
+ } else {
+ node = node.left
+ }
+ case compare > 0:
+ if node.right == nil {
+ node.right = &RedBlackTreeNode{Key: key, Value: value, color: red}
+ insertedNode = node.right
+ loop = false
+ } else {
+ node = node.right
+ }
+ }
+ }
+ insertedNode.parent = node
+ }
+ tree.insertCase1(insertedNode)
+ tree.size++
+}
+
+// Get searches the node in the tree by `key` and returns its value or nil if key is not found in tree.
+func (tree *RedBlackTree) Get(key interface{}) (value interface{}) {
+ value, _ = tree.Search(key)
+ return
+}
+
+// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
+// if not exists, set value to the map with given `key`,
+// or else just return the existing value.
+//
+// When setting value, if `value` is type of ,
+// it will be executed with mutex.Lock of the hash map,
+// and its return value will be set to the map with `key`.
+//
+// It returns value with given `key`.
+func (tree *RedBlackTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ if node, found := tree.doSearch(key); found {
+ return node.Value
+ }
+ if f, ok := value.(func() interface{}); ok {
+ value = f()
+ }
+ if value != nil {
+ tree.doSet(key, value)
+ }
+ return value
+}
+
+// GetOrSet returns the value by key,
+// or sets value with given `value` if it does not exist and then returns this value.
+func (tree *RedBlackTree) GetOrSet(key interface{}, value interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, value)
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFunc returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+func (tree *RedBlackTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, f())
+ } else {
+ return v
+ }
+}
+
+// GetOrSetFuncLock returns the value by key,
+// or sets value with returned value of callback function `f` if it does not exist
+// and then returns this value.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func (tree *RedBlackTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
+ if v, ok := tree.Search(key); !ok {
+ return tree.doSetWithLockCheck(key, f)
+ } else {
+ return v
+ }
+}
+
+// GetVar returns a gvar.Var with the value by given `key`.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *RedBlackTree) GetVar(key interface{}) *gvar.Var {
+ return gvar.New(tree.Get(key))
+}
+
+// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *RedBlackTree) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSet(key, value))
+}
+
+// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *RedBlackTree) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSetFunc(key, f))
+}
+
+// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
+// The returned gvar.Var is un-concurrent safe.
+func (tree *RedBlackTree) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
+ return gvar.New(tree.GetOrSetFuncLock(key, f))
+}
+
+// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (tree *RedBlackTree) SetIfNotExist(key interface{}, value interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, value)
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+func (tree *RedBlackTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, f())
+ return true
+ }
+ return false
+}
+
+// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
+// It returns false if `key` exists, and `value` would be ignored.
+//
+// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
+// it executes function `f` with mutex.Lock of the hash map.
+func (tree *RedBlackTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
+ if !tree.Contains(key) {
+ tree.doSetWithLockCheck(key, f)
+ return true
+ }
+ return false
+}
+
+// Contains checks whether `key` exists in the tree.
+func (tree *RedBlackTree) Contains(key interface{}) bool {
+ _, ok := tree.Search(key)
+ return ok
+}
+
+// doRemove removes the node from the tree by `key` without mutex.
+func (tree *RedBlackTree) doRemove(key interface{}) (value interface{}) {
+ child := (*RedBlackTreeNode)(nil)
+ node, found := tree.doSearch(key)
+ if !found {
+ return
+ }
+ value = node.Value
+ if node.left != nil && node.right != nil {
+ p := node.left.maximumNode()
+ node.Key = p.Key
+ node.Value = p.Value
+ node = p
+ }
+ if node.left == nil || node.right == nil {
+ if node.right == nil {
+ child = node.left
+ } else {
+ child = node.right
+ }
+ if node.color == black {
+ node.color = tree.nodeColor(child)
+ tree.deleteCase1(node)
+ }
+ tree.replaceNode(node, child)
+ if node.parent == nil && child != nil {
+ child.color = black
+ }
+ }
+ tree.size--
+ return
+}
+
+// Remove removes the node from the tree by `key`.
+func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ return tree.doRemove(key)
+}
+
+// Removes batch deletes values of the tree by `keys`.
+func (tree *RedBlackTree) Removes(keys []interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ for _, key := range keys {
+ tree.doRemove(key)
+ }
+}
+
+// IsEmpty returns true if tree does not contain any nodes.
+func (tree *RedBlackTree) IsEmpty() bool {
+ return tree.Size() == 0
+}
+
+// Size returns number of nodes in the tree.
+func (tree *RedBlackTree) Size() int {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ return tree.size
+}
+
+// Keys returns all keys in asc order.
+func (tree *RedBlackTree) Keys() []interface{} {
+ var (
+ keys = make([]interface{}, tree.Size())
+ index = 0
+ )
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ keys[index] = key
+ index++
+ return true
+ })
+ return keys
+}
+
+// Values returns all values in asc order based on the key.
+func (tree *RedBlackTree) Values() []interface{} {
+ var (
+ values = make([]interface{}, tree.Size())
+ index = 0
+ )
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ values[index] = value
+ index++
+ return true
+ })
+ return values
+}
+
+// Map returns all key-value items as map.
+func (tree *RedBlackTree) Map() map[interface{}]interface{} {
+ m := make(map[interface{}]interface{}, tree.Size())
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ m[key] = value
+ return true
+ })
+ return m
+}
+
+// MapStrAny returns all key-value items as map[string]interface{}.
+func (tree *RedBlackTree) MapStrAny() map[string]interface{} {
+ m := make(map[string]interface{}, tree.Size())
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ m[gconv.String(key)] = value
+ return true
+ })
+ return m
+}
+
+// Left returns the left-most (min) node or nil if tree is empty.
+func (tree *RedBlackTree) Left() *RedBlackTreeNode {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.leftNode()
+ if tree.mu.IsSafe() {
+ return &RedBlackTreeNode{
+ Key: node.Key,
+ Value: node.Value,
+ }
+ }
+ return node
+}
+
+// Right returns the right-most (max) node or nil if tree is empty.
+func (tree *RedBlackTree) Right() *RedBlackTreeNode {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node := tree.rightNode()
+ if tree.mu.IsSafe() {
+ return &RedBlackTreeNode{
+ Key: node.Key,
+ Value: node.Value,
+ }
+ }
+ return node
+}
+
+// leftNode returns the left-most (min) node or nil if tree is empty.
+func (tree *RedBlackTree) leftNode() *RedBlackTreeNode {
+ p := (*RedBlackTreeNode)(nil)
+ n := tree.root
+ for n != nil {
+ p = n
+ n = n.left
+ }
+ return p
+}
+
+// rightNode returns the right-most (max) node or nil if tree is empty.
+func (tree *RedBlackTree) rightNode() *RedBlackTreeNode {
+ p := (*RedBlackTreeNode)(nil)
+ n := tree.root
+ for n != nil {
+ p = n
+ n = n.right
+ }
+ return p
+}
+
+// Floor Finds floor node of the input key, return the floor node or nil if no floor node is found.
+// Second return parameter is true if floor was found, otherwise false.
+//
+// Floor node is defined as the largest node that its key is smaller than or equal to the given `key`.
+// A floor node may not be found, either because the tree is empty, or because
+// all nodes in the tree are larger than the given node.
+func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ n := tree.root
+ for n != nil {
+ compare := tree.getComparator()(key, n.Key)
+ switch {
+ case compare == 0:
+ return n, true
+ case compare < 0:
+ n = n.left
+ case compare > 0:
+ floor, found = n, true
+ n = n.right
+ }
+ }
+ if found {
+ return
+ }
+ return nil, false
+}
+
+// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found.
+// Second return parameter is true if ceiling was found, otherwise false.
+//
+// Ceiling node is defined as the smallest node that its key is larger than or equal to the given `key`.
+// A ceiling node may not be found, either because the tree is empty, or because
+// all nodes in the tree are smaller than the given node.
+func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ n := tree.root
+ for n != nil {
+ compare := tree.getComparator()(key, n.Key)
+ switch {
+ case compare == 0:
+ return n, true
+ case compare > 0:
+ n = n.right
+ case compare < 0:
+ ceiling, found = n, true
+ n = n.left
+ }
+ }
+ if found {
+ return
+ }
+ return nil, false
+}
+
+// Iterator is alias of IteratorAsc.
+func (tree *RedBlackTree) Iterator(f func(key, value interface{}) bool) {
+ tree.IteratorAsc(f)
+}
+
+// IteratorFrom is alias of IteratorAscFrom.
+func (tree *RedBlackTree) IteratorFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.IteratorAscFrom(key, match, f)
+}
+
+// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *RedBlackTree) IteratorAsc(f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ tree.doIteratorAsc(tree.leftNode(), f)
+}
+
+// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
+// The parameter `key` specifies the start entry for iterating. The `match` specifies whether
+// starting iterating if the `key` is fully matched, or else using index searching iterating.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *RedBlackTree) IteratorAscFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, found := tree.doSearch(key)
+ if match {
+ if found {
+ tree.doIteratorAsc(node, f)
+ }
+ } else {
+ tree.doIteratorAsc(node, f)
+ }
+}
+
+func (tree *RedBlackTree) doIteratorAsc(node *RedBlackTreeNode, f func(key, value interface{}) bool) {
+loop:
+ if node == nil {
+ return
+ }
+ if !f(node.Key, node.Value) {
+ return
+ }
+ if node.right != nil {
+ node = node.right
+ for node.left != nil {
+ node = node.left
+ }
+ goto loop
+ }
+ if node.parent != nil {
+ old := node
+ for node.parent != nil {
+ node = node.parent
+ if tree.getComparator()(old.Key, node.Key) <= 0 {
+ goto loop
+ }
+ }
+ }
+}
+
+// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *RedBlackTree) IteratorDesc(f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ tree.doIteratorDesc(tree.rightNode(), f)
+}
+
+// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
+// The parameter `key` specifies the start entry for iterating. The `match` specifies whether
+// starting iterating if the `key` is fully matched, or else using index searching iterating.
+// If `f` returns true, then it continues iterating; or false to stop.
+func (tree *RedBlackTree) IteratorDescFrom(key interface{}, match bool, f func(key, value interface{}) bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, found := tree.doSearch(key)
+ if match {
+ if found {
+ tree.doIteratorDesc(node, f)
+ }
+ } else {
+ tree.doIteratorDesc(node, f)
+ }
+}
+
+func (tree *RedBlackTree) doIteratorDesc(node *RedBlackTreeNode, f func(key, value interface{}) bool) {
+loop:
+ if node == nil {
+ return
+ }
+ if !f(node.Key, node.Value) {
+ return
+ }
+ if node.left != nil {
+ node = node.left
+ for node.right != nil {
+ node = node.right
+ }
+ goto loop
+ }
+ if node.parent != nil {
+ old := node
+ for node.parent != nil {
+ node = node.parent
+ if tree.getComparator()(old.Key, node.Key) >= 0 {
+ goto loop
+ }
+ }
+ }
+}
+
+// Clear removes all nodes from the tree.
+func (tree *RedBlackTree) Clear() {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.root = nil
+ tree.size = 0
+}
+
+// Replace the data of the tree with given `data`.
+func (tree *RedBlackTree) Replace(data map[interface{}]interface{}) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ tree.root = nil
+ tree.size = 0
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+}
+
+// String returns a string representation of container.
+func (tree *RedBlackTree) String() string {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ str := ""
+ if tree.size != 0 {
+ tree.output(tree.root, "", true, &str)
+ }
+ return str
+}
+
+// Print prints the tree to stdout.
+func (tree *RedBlackTree) Print() {
+ fmt.Println(tree.String())
+}
+
+// Search searches the tree with given `key`.
+// Second return parameter `found` is true if key was found, otherwise false.
+func (tree *RedBlackTree) Search(key interface{}) (value interface{}, found bool) {
+ tree.mu.RLock()
+ defer tree.mu.RUnlock()
+ node, found := tree.doSearch(key)
+ if found {
+ return node.Value, true
+ }
+ return nil, false
+}
+
+// Flip exchanges key-value of the tree to value-key.
+// Note that you should guarantee the value is the same type as key,
+// or else the comparator would panic.
+//
+// If the type of value is different with key, you pass the new `comparator`.
+func (tree *RedBlackTree) Flip(comparator ...func(v1, v2 interface{}) int) {
+ t := (*RedBlackTree)(nil)
+ if len(comparator) > 0 {
+ t = NewRedBlackTree(comparator[0], tree.mu.IsSafe())
+ } else {
+ t = NewRedBlackTree(tree.comparator, tree.mu.IsSafe())
+ }
+ tree.IteratorAsc(func(key, value interface{}) bool {
+ t.doSet(value, key)
+ return true
+ })
+ tree.mu.Lock()
+ tree.root = t.root
+ tree.size = t.size
+ tree.mu.Unlock()
+}
+
+func (tree *RedBlackTree) output(node *RedBlackTreeNode, prefix string, isTail bool, str *string) {
+ if node.right != nil {
+ newPrefix := prefix
+ if isTail {
+ newPrefix += "│ "
+ } else {
+ newPrefix += " "
+ }
+ tree.output(node.right, newPrefix, false, str)
+ }
+ *str += prefix
+ if isTail {
+ *str += "└── "
+ } else {
+ *str += "┌── "
+ }
+ *str += fmt.Sprintf("%v\n", node.Key)
+ if node.left != nil {
+ newPrefix := prefix
+ if isTail {
+ newPrefix += " "
+ } else {
+ newPrefix += "│ "
+ }
+ tree.output(node.left, newPrefix, true, str)
+ }
+}
+
+// doSearch searches the tree with given `key` without mutex.
+// It returns the node if found or otherwise nil.
+func (tree *RedBlackTree) doSearch(key interface{}) (node *RedBlackTreeNode, found bool) {
+ node = tree.root
+ for node != nil {
+ compare := tree.getComparator()(key, node.Key)
+ switch {
+ case compare == 0:
+ return node, true
+ case compare < 0:
+ node = node.left
+ case compare > 0:
+ node = node.right
+ }
+ }
+ return node, false
+}
+
+func (node *RedBlackTreeNode) grandparent() *RedBlackTreeNode {
+ if node != nil && node.parent != nil {
+ return node.parent.parent
+ }
+ return nil
+}
+
+func (node *RedBlackTreeNode) uncle() *RedBlackTreeNode {
+ if node == nil || node.parent == nil || node.parent.parent == nil {
+ return nil
+ }
+ return node.parent.sibling()
+}
+
+func (node *RedBlackTreeNode) sibling() *RedBlackTreeNode {
+ if node == nil || node.parent == nil {
+ return nil
+ }
+ if node == node.parent.left {
+ return node.parent.right
+ }
+ return node.parent.left
+}
+
+func (tree *RedBlackTree) rotateLeft(node *RedBlackTreeNode) {
+ right := node.right
+ tree.replaceNode(node, right)
+ node.right = right.left
+ if right.left != nil {
+ right.left.parent = node
+ }
+ right.left = node
+ node.parent = right
+}
+
+func (tree *RedBlackTree) rotateRight(node *RedBlackTreeNode) {
+ left := node.left
+ tree.replaceNode(node, left)
+ node.left = left.right
+ if left.right != nil {
+ left.right.parent = node
+ }
+ left.right = node
+ node.parent = left
+}
+
+func (tree *RedBlackTree) replaceNode(old *RedBlackTreeNode, new *RedBlackTreeNode) {
+ if old.parent == nil {
+ tree.root = new
+ } else {
+ if old == old.parent.left {
+ old.parent.left = new
+ } else {
+ old.parent.right = new
+ }
+ }
+ if new != nil {
+ new.parent = old.parent
+ }
+}
+
+func (tree *RedBlackTree) insertCase1(node *RedBlackTreeNode) {
+ if node.parent == nil {
+ node.color = black
+ } else {
+ tree.insertCase2(node)
+ }
+}
+
+func (tree *RedBlackTree) insertCase2(node *RedBlackTreeNode) {
+ if tree.nodeColor(node.parent) == black {
+ return
+ }
+ tree.insertCase3(node)
+}
+
+func (tree *RedBlackTree) insertCase3(node *RedBlackTreeNode) {
+ uncle := node.uncle()
+ if tree.nodeColor(uncle) == red {
+ node.parent.color = black
+ uncle.color = black
+ node.grandparent().color = red
+ tree.insertCase1(node.grandparent())
+ } else {
+ tree.insertCase4(node)
+ }
+}
+
+func (tree *RedBlackTree) insertCase4(node *RedBlackTreeNode) {
+ grandparent := node.grandparent()
+ if node == node.parent.right && node.parent == grandparent.left {
+ tree.rotateLeft(node.parent)
+ node = node.left
+ } else if node == node.parent.left && node.parent == grandparent.right {
+ tree.rotateRight(node.parent)
+ node = node.right
+ }
+ tree.insertCase5(node)
+}
+
+func (tree *RedBlackTree) insertCase5(node *RedBlackTreeNode) {
+ node.parent.color = black
+ grandparent := node.grandparent()
+ grandparent.color = red
+ if node == node.parent.left && node.parent == grandparent.left {
+ tree.rotateRight(grandparent)
+ } else if node == node.parent.right && node.parent == grandparent.right {
+ tree.rotateLeft(grandparent)
+ }
+}
+
+func (node *RedBlackTreeNode) maximumNode() *RedBlackTreeNode {
+ if node == nil {
+ return nil
+ }
+ for node.right != nil {
+ return node.right
+ }
+ return node
+}
+
+func (tree *RedBlackTree) deleteCase1(node *RedBlackTreeNode) {
+ if node.parent == nil {
+ return
+ }
+ tree.deleteCase2(node)
+}
+
+func (tree *RedBlackTree) deleteCase2(node *RedBlackTreeNode) {
+ sibling := node.sibling()
+ if tree.nodeColor(sibling) == red {
+ node.parent.color = red
+ sibling.color = black
+ if node == node.parent.left {
+ tree.rotateLeft(node.parent)
+ } else {
+ tree.rotateRight(node.parent)
+ }
+ }
+ tree.deleteCase3(node)
+}
+
+func (tree *RedBlackTree) deleteCase3(node *RedBlackTreeNode) {
+ sibling := node.sibling()
+ if tree.nodeColor(node.parent) == black &&
+ tree.nodeColor(sibling) == black &&
+ tree.nodeColor(sibling.left) == black &&
+ tree.nodeColor(sibling.right) == black {
+ sibling.color = red
+ tree.deleteCase1(node.parent)
+ } else {
+ tree.deleteCase4(node)
+ }
+}
+
+func (tree *RedBlackTree) deleteCase4(node *RedBlackTreeNode) {
+ sibling := node.sibling()
+ if tree.nodeColor(node.parent) == red &&
+ tree.nodeColor(sibling) == black &&
+ tree.nodeColor(sibling.left) == black &&
+ tree.nodeColor(sibling.right) == black {
+ sibling.color = red
+ node.parent.color = black
+ } else {
+ tree.deleteCase5(node)
+ }
+}
+
+func (tree *RedBlackTree) deleteCase5(node *RedBlackTreeNode) {
+ sibling := node.sibling()
+ if node == node.parent.left &&
+ tree.nodeColor(sibling) == black &&
+ tree.nodeColor(sibling.left) == red &&
+ tree.nodeColor(sibling.right) == black {
+ sibling.color = red
+ sibling.left.color = black
+ tree.rotateRight(sibling)
+ } else if node == node.parent.right &&
+ tree.nodeColor(sibling) == black &&
+ tree.nodeColor(sibling.right) == red &&
+ tree.nodeColor(sibling.left) == black {
+ sibling.color = red
+ sibling.right.color = black
+ tree.rotateLeft(sibling)
+ }
+ tree.deleteCase6(node)
+}
+
+func (tree *RedBlackTree) deleteCase6(node *RedBlackTreeNode) {
+ sibling := node.sibling()
+ sibling.color = tree.nodeColor(node.parent)
+ node.parent.color = black
+ if node == node.parent.left && tree.nodeColor(sibling.right) == red {
+ sibling.right.color = black
+ tree.rotateLeft(node.parent)
+ } else if tree.nodeColor(sibling.left) == red {
+ sibling.left.color = black
+ tree.rotateRight(node.parent)
+ }
+}
+
+func (tree *RedBlackTree) nodeColor(node *RedBlackTreeNode) color {
+ if node == nil {
+ return black
+ }
+ return node.color
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (tree RedBlackTree) MarshalJSON() ([]byte, error) {
+ return json.Marshal(gconv.Map(tree.Map()))
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (tree *RedBlackTree) UnmarshalJSON(b []byte) error {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ if tree.comparator == nil {
+ tree.comparator = gutil.ComparatorString
+ }
+ var data map[string]interface{}
+ if err := json.UnmarshalUseNumber(b, &data); err != nil {
+ return err
+ }
+ for k, v := range data {
+ tree.doSet(k, v)
+ }
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for map.
+func (tree *RedBlackTree) UnmarshalValue(value interface{}) (err error) {
+ tree.mu.Lock()
+ defer tree.mu.Unlock()
+ if tree.comparator == nil {
+ tree.comparator = gutil.ComparatorString
+ }
+ for k, v := range gconv.Map(value) {
+ tree.doSet(k, v)
+ }
+ return
+}
+
+// getComparator returns the comparator if it's previously set,
+// or else it panics.
+func (tree *RedBlackTree) getComparator() func(a, b interface{}) int {
+ if tree.comparator == nil {
+ panic("comparator is missing for tree")
+ }
+ return tree.comparator
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype.go
new file mode 100644
index 000000000000..d6711f2a1684
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype.go
@@ -0,0 +1,14 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtype provides high performance and concurrent-safe basic variable types.
+package gtype
+
+// New is alias of NewInterface.
+// See NewInterface.
+func New(value ...interface{}) *Interface {
+ return NewInterface(value...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_bool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_bool.go
new file mode 100644
index 000000000000..42d0c6a33dc7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_bool.go
@@ -0,0 +1,98 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "bytes"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Bool is a struct for concurrent-safe operation for type bool.
+type Bool struct {
+ value int32
+}
+
+var (
+ bytesTrue = []byte("true")
+ bytesFalse = []byte("false")
+)
+
+// NewBool creates and returns a concurrent-safe object for bool type,
+// with given initial value `value`.
+func NewBool(value ...bool) *Bool {
+ t := &Bool{}
+ if len(value) > 0 {
+ if value[0] {
+ t.value = 1
+ } else {
+ t.value = 0
+ }
+ }
+ return t
+}
+
+// Clone clones and returns a new concurrent-safe object for bool type.
+func (v *Bool) Clone() *Bool {
+ return NewBool(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Bool) Set(value bool) (old bool) {
+ if value {
+ old = atomic.SwapInt32(&v.value, 1) == 1
+ } else {
+ old = atomic.SwapInt32(&v.value, 0) == 1
+ }
+ return
+}
+
+// Val atomically loads and returns t.value.
+func (v *Bool) Val() bool {
+ return atomic.LoadInt32(&v.value) > 0
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Bool) Cas(old, new bool) (swapped bool) {
+ var oldInt32, newInt32 int32
+ if old {
+ oldInt32 = 1
+ }
+ if new {
+ newInt32 = 1
+ }
+ return atomic.CompareAndSwapInt32(&v.value, oldInt32, newInt32)
+}
+
+// String implements String interface for string printing.
+func (v *Bool) String() string {
+ if v.Val() {
+ return "true"
+ }
+ return "false"
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Bool) MarshalJSON() ([]byte, error) {
+ if v.Val() {
+ return bytesTrue, nil
+ }
+ return bytesFalse, nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Bool) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Bool(bytes.Trim(b, `"`)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Bool) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Bool(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_byte.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_byte.go
new file mode 100644
index 000000000000..87e41d29c27b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_byte.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Byte is a struct for concurrent-safe operation for type byte.
+type Byte struct {
+ value int32
+}
+
+// NewByte creates and returns a concurrent-safe object for byte type,
+// with given initial value `value`.
+func NewByte(value ...byte) *Byte {
+ if len(value) > 0 {
+ return &Byte{
+ value: int32(value[0]),
+ }
+ }
+ return &Byte{}
+}
+
+// Clone clones and returns a new concurrent-safe object for byte type.
+func (v *Byte) Clone() *Byte {
+ return NewByte(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Byte) Set(value byte) (old byte) {
+ return byte(atomic.SwapInt32(&v.value, int32(value)))
+}
+
+// Val atomically loads and returns t.value.
+func (v *Byte) Val() byte {
+ return byte(atomic.LoadInt32(&v.value))
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Byte) Add(delta byte) (new byte) {
+ return byte(atomic.AddInt32(&v.value, int32(delta)))
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Byte) Cas(old, new byte) (swapped bool) {
+ return atomic.CompareAndSwapInt32(&v.value, int32(old), int32(new))
+}
+
+// String implements String interface for string printing.
+func (v *Byte) String() string {
+ return strconv.FormatUint(uint64(v.Val()), 10)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Byte) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Byte) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Uint8(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Byte) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Byte(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_bytes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_bytes.go
new file mode 100644
index 000000000000..6b69febfe8fb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_bytes.go
@@ -0,0 +1,85 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "bytes"
+ "encoding/base64"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Bytes is a struct for concurrent-safe operation for type []byte.
+type Bytes struct {
+ value atomic.Value
+}
+
+// NewBytes creates and returns a concurrent-safe object for []byte type,
+// with given initial value `value`.
+func NewBytes(value ...[]byte) *Bytes {
+ t := &Bytes{}
+ if len(value) > 0 {
+ t.value.Store(value[0])
+ }
+ return t
+}
+
+// Clone clones and returns a new concurrent-safe object for []byte type.
+func (v *Bytes) Clone() *Bytes {
+ return NewBytes(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+// Note: The parameter `value` cannot be nil.
+func (v *Bytes) Set(value []byte) (old []byte) {
+ old = v.Val()
+ v.value.Store(value)
+ return
+}
+
+// Val atomically loads and returns t.value.
+func (v *Bytes) Val() []byte {
+ if s := v.value.Load(); s != nil {
+ return s.([]byte)
+ }
+ return nil
+}
+
+// String implements String interface for string printing.
+func (v *Bytes) String() string {
+ return string(v.Val())
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Bytes) MarshalJSON() ([]byte, error) {
+ val := v.Val()
+ dst := make([]byte, base64.StdEncoding.EncodedLen(len(val)))
+ base64.StdEncoding.Encode(dst, val)
+ return []byte(`"` + string(dst) + `"`), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Bytes) UnmarshalJSON(b []byte) error {
+ var (
+ src = make([]byte, base64.StdEncoding.DecodedLen(len(b)))
+ n, err = base64.StdEncoding.Decode(src, bytes.Trim(b, `"`))
+ )
+ if err != nil {
+ err = gerror.Wrap(err, `base64.StdEncoding.Decode failed`)
+ return err
+ }
+ v.Set(src[:n])
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Bytes) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Bytes(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_float32.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_float32.go
new file mode 100644
index 000000000000..961a822bc779
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_float32.go
@@ -0,0 +1,89 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "math"
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Float32 is a struct for concurrent-safe operation for type float32.
+type Float32 struct {
+ value uint32
+}
+
+// NewFloat32 creates and returns a concurrent-safe object for float32 type,
+// with given initial value `value`.
+func NewFloat32(value ...float32) *Float32 {
+ if len(value) > 0 {
+ return &Float32{
+ value: math.Float32bits(value[0]),
+ }
+ }
+ return &Float32{}
+}
+
+// Clone clones and returns a new concurrent-safe object for float32 type.
+func (v *Float32) Clone() *Float32 {
+ return NewFloat32(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Float32) Set(value float32) (old float32) {
+ return math.Float32frombits(atomic.SwapUint32(&v.value, math.Float32bits(value)))
+}
+
+// Val atomically loads and returns t.value.
+func (v *Float32) Val() float32 {
+ return math.Float32frombits(atomic.LoadUint32(&v.value))
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Float32) Add(delta float32) (new float32) {
+ for {
+ old := math.Float32frombits(v.value)
+ new = old + delta
+ if atomic.CompareAndSwapUint32(
+ &v.value,
+ math.Float32bits(old),
+ math.Float32bits(new),
+ ) {
+ break
+ }
+ }
+ return
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Float32) Cas(old, new float32) (swapped bool) {
+ return atomic.CompareAndSwapUint32(&v.value, math.Float32bits(old), math.Float32bits(new))
+}
+
+// String implements String interface for string printing.
+func (v *Float32) String() string {
+ return strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Float32) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Float32) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Float32(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Float32) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Float32(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_float64.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_float64.go
new file mode 100644
index 000000000000..2fc8693555d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_float64.go
@@ -0,0 +1,89 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "math"
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Float64 is a struct for concurrent-safe operation for type float64.
+type Float64 struct {
+ value uint64
+}
+
+// NewFloat64 creates and returns a concurrent-safe object for float64 type,
+// with given initial value `value`.
+func NewFloat64(value ...float64) *Float64 {
+ if len(value) > 0 {
+ return &Float64{
+ value: math.Float64bits(value[0]),
+ }
+ }
+ return &Float64{}
+}
+
+// Clone clones and returns a new concurrent-safe object for float64 type.
+func (v *Float64) Clone() *Float64 {
+ return NewFloat64(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Float64) Set(value float64) (old float64) {
+ return math.Float64frombits(atomic.SwapUint64(&v.value, math.Float64bits(value)))
+}
+
+// Val atomically loads and returns t.value.
+func (v *Float64) Val() float64 {
+ return math.Float64frombits(atomic.LoadUint64(&v.value))
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Float64) Add(delta float64) (new float64) {
+ for {
+ old := math.Float64frombits(v.value)
+ new = old + delta
+ if atomic.CompareAndSwapUint64(
+ &v.value,
+ math.Float64bits(old),
+ math.Float64bits(new),
+ ) {
+ break
+ }
+ }
+ return
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Float64) Cas(old, new float64) (swapped bool) {
+ return atomic.CompareAndSwapUint64(&v.value, math.Float64bits(old), math.Float64bits(new))
+}
+
+// String implements String interface for string printing.
+func (v *Float64) String() string {
+ return strconv.FormatFloat(v.Val(), 'g', -1, 64)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Float64) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatFloat(v.Val(), 'g', -1, 64)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Float64) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Float64(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Float64) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Float64(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int.go
new file mode 100644
index 000000000000..2114b882200f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Int is a struct for concurrent-safe operation for type int.
+type Int struct {
+ value int64
+}
+
+// NewInt creates and returns a concurrent-safe object for int type,
+// with given initial value `value`.
+func NewInt(value ...int) *Int {
+ if len(value) > 0 {
+ return &Int{
+ value: int64(value[0]),
+ }
+ }
+ return &Int{}
+}
+
+// Clone clones and returns a new concurrent-safe object for int type.
+func (v *Int) Clone() *Int {
+ return NewInt(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Int) Set(value int) (old int) {
+ return int(atomic.SwapInt64(&v.value, int64(value)))
+}
+
+// Val atomically loads and returns t.value.
+func (v *Int) Val() int {
+ return int(atomic.LoadInt64(&v.value))
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Int) Add(delta int) (new int) {
+ return int(atomic.AddInt64(&v.value, int64(delta)))
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Int) Cas(old, new int) (swapped bool) {
+ return atomic.CompareAndSwapInt64(&v.value, int64(old), int64(new))
+}
+
+// String implements String interface for string printing.
+func (v *Int) String() string {
+ return strconv.Itoa(v.Val())
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Int) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.Itoa(v.Val())), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Int) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Int(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Int) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Int(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int32.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int32.go
new file mode 100644
index 000000000000..99a3188a0c8a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int32.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Int32 is a struct for concurrent-safe operation for type int32.
+type Int32 struct {
+ value int32
+}
+
+// NewInt32 creates and returns a concurrent-safe object for int32 type,
+// with given initial value `value`.
+func NewInt32(value ...int32) *Int32 {
+ if len(value) > 0 {
+ return &Int32{
+ value: value[0],
+ }
+ }
+ return &Int32{}
+}
+
+// Clone clones and returns a new concurrent-safe object for int32 type.
+func (v *Int32) Clone() *Int32 {
+ return NewInt32(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Int32) Set(value int32) (old int32) {
+ return atomic.SwapInt32(&v.value, value)
+}
+
+// Val atomically loads and returns t.value.
+func (v *Int32) Val() int32 {
+ return atomic.LoadInt32(&v.value)
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Int32) Add(delta int32) (new int32) {
+ return atomic.AddInt32(&v.value, delta)
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Int32) Cas(old, new int32) (swapped bool) {
+ return atomic.CompareAndSwapInt32(&v.value, old, new)
+}
+
+// String implements String interface for string printing.
+func (v *Int32) String() string {
+ return strconv.Itoa(int(v.Val()))
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Int32) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.Itoa(int(v.Val()))), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Int32) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Int32(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Int32) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Int32(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int64.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int64.go
new file mode 100644
index 000000000000..85558acebd80
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_int64.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Int64 is a struct for concurrent-safe operation for type int64.
+type Int64 struct {
+ value int64
+}
+
+// NewInt64 creates and returns a concurrent-safe object for int64 type,
+// with given initial value `value`.
+func NewInt64(value ...int64) *Int64 {
+ if len(value) > 0 {
+ return &Int64{
+ value: value[0],
+ }
+ }
+ return &Int64{}
+}
+
+// Clone clones and returns a new concurrent-safe object for int64 type.
+func (v *Int64) Clone() *Int64 {
+ return NewInt64(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Int64) Set(value int64) (old int64) {
+ return atomic.SwapInt64(&v.value, value)
+}
+
+// Val atomically loads and returns t.value.
+func (v *Int64) Val() int64 {
+ return atomic.LoadInt64(&v.value)
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Int64) Add(delta int64) (new int64) {
+ return atomic.AddInt64(&v.value, delta)
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Int64) Cas(old, new int64) (swapped bool) {
+ return atomic.CompareAndSwapInt64(&v.value, old, new)
+}
+
+// String implements String interface for string printing.
+func (v *Int64) String() string {
+ return strconv.FormatInt(v.Val(), 10)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Int64) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatInt(v.Val(), 10)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Int64) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Int64(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Int64) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Int64(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_interface.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_interface.go
new file mode 100644
index 000000000000..04f95d3c5f6e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_interface.go
@@ -0,0 +1,73 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Interface is a struct for concurrent-safe operation for type interface{}.
+type Interface struct {
+ value atomic.Value
+}
+
+// NewInterface creates and returns a concurrent-safe object for interface{} type,
+// with given initial value `value`.
+func NewInterface(value ...interface{}) *Interface {
+ t := &Interface{}
+ if len(value) > 0 && value[0] != nil {
+ t.value.Store(value[0])
+ }
+ return t
+}
+
+// Clone clones and returns a new concurrent-safe object for interface{} type.
+func (v *Interface) Clone() *Interface {
+ return NewInterface(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+// Note: The parameter `value` cannot be nil.
+func (v *Interface) Set(value interface{}) (old interface{}) {
+ old = v.Val()
+ v.value.Store(value)
+ return
+}
+
+// Val atomically loads and returns t.value.
+func (v *Interface) Val() interface{} {
+ return v.value.Load()
+}
+
+// String implements String interface for string printing.
+func (v *Interface) String() string {
+ return gconv.String(v.Val())
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Interface) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.Val())
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Interface) UnmarshalJSON(b []byte) error {
+ var i interface{}
+ if err := json.UnmarshalUseNumber(b, &i); err != nil {
+ return err
+ }
+ v.Set(i)
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Interface) UnmarshalValue(value interface{}) error {
+ v.Set(value)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_string.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_string.go
new file mode 100644
index 000000000000..f3e442eb2520
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_string.go
@@ -0,0 +1,71 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "bytes"
+ "github.com/gogf/gf/v2/util/gconv"
+ "sync/atomic"
+)
+
+// String is a struct for concurrent-safe operation for type string.
+type String struct {
+ value atomic.Value
+}
+
+// NewString creates and returns a concurrent-safe object for string type,
+// with given initial value `value`.
+func NewString(value ...string) *String {
+ t := &String{}
+ if len(value) > 0 {
+ t.value.Store(value[0])
+ }
+ return t
+}
+
+// Clone clones and returns a new concurrent-safe object for string type.
+func (v *String) Clone() *String {
+ return NewString(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *String) Set(value string) (old string) {
+ old = v.Val()
+ v.value.Store(value)
+ return
+}
+
+// Val atomically loads and returns t.value.
+func (v *String) Val() string {
+ s := v.value.Load()
+ if s != nil {
+ return s.(string)
+ }
+ return ""
+}
+
+// String implements String interface for string printing.
+func (v *String) String() string {
+ return v.Val()
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v String) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + v.Val() + `"`), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *String) UnmarshalJSON(b []byte) error {
+ v.Set(string(bytes.Trim(b, `"`)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *String) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.String(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint.go
new file mode 100644
index 000000000000..763d90f6a57e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Uint is a struct for concurrent-safe operation for type uint.
+type Uint struct {
+ value uint64
+}
+
+// NewUint creates and returns a concurrent-safe object for uint type,
+// with given initial value `value`.
+func NewUint(value ...uint) *Uint {
+ if len(value) > 0 {
+ return &Uint{
+ value: uint64(value[0]),
+ }
+ }
+ return &Uint{}
+}
+
+// Clone clones and returns a new concurrent-safe object for uint type.
+func (v *Uint) Clone() *Uint {
+ return NewUint(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Uint) Set(value uint) (old uint) {
+ return uint(atomic.SwapUint64(&v.value, uint64(value)))
+}
+
+// Val atomically loads and returns t.value.
+func (v *Uint) Val() uint {
+ return uint(atomic.LoadUint64(&v.value))
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Uint) Add(delta uint) (new uint) {
+ return uint(atomic.AddUint64(&v.value, uint64(delta)))
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Uint) Cas(old, new uint) (swapped bool) {
+ return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
+}
+
+// String implements String interface for string printing.
+func (v *Uint) String() string {
+ return strconv.FormatUint(uint64(v.Val()), 10)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Uint) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Uint) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Uint(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Uint) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Uint(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint32.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint32.go
new file mode 100644
index 000000000000..b877b56c45ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint32.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Uint32 is a struct for concurrent-safe operation for type uint32.
+type Uint32 struct {
+ value uint32
+}
+
+// NewUint32 creates and returns a concurrent-safe object for uint32 type,
+// with given initial value `value`.
+func NewUint32(value ...uint32) *Uint32 {
+ if len(value) > 0 {
+ return &Uint32{
+ value: value[0],
+ }
+ }
+ return &Uint32{}
+}
+
+// Clone clones and returns a new concurrent-safe object for uint32 type.
+func (v *Uint32) Clone() *Uint32 {
+ return NewUint32(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Uint32) Set(value uint32) (old uint32) {
+ return atomic.SwapUint32(&v.value, value)
+}
+
+// Val atomically loads and returns t.value.
+func (v *Uint32) Val() uint32 {
+ return atomic.LoadUint32(&v.value)
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Uint32) Add(delta uint32) (new uint32) {
+ return atomic.AddUint32(&v.value, delta)
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Uint32) Cas(old, new uint32) (swapped bool) {
+ return atomic.CompareAndSwapUint32(&v.value, old, new)
+}
+
+// String implements String interface for string printing.
+func (v *Uint32) String() string {
+ return strconv.FormatUint(uint64(v.Val()), 10)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Uint32) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Uint32) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Uint32(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Uint32) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Uint32(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint64.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint64.go
new file mode 100644
index 000000000000..71a7bd20241c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gtype/gtype_uint64.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtype
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Uint64 is a struct for concurrent-safe operation for type uint64.
+type Uint64 struct {
+ value uint64
+}
+
+// NewUint64 creates and returns a concurrent-safe object for uint64 type,
+// with given initial value `value`.
+func NewUint64(value ...uint64) *Uint64 {
+ if len(value) > 0 {
+ return &Uint64{
+ value: value[0],
+ }
+ }
+ return &Uint64{}
+}
+
+// Clone clones and returns a new concurrent-safe object for uint64 type.
+func (v *Uint64) Clone() *Uint64 {
+ return NewUint64(v.Val())
+}
+
+// Set atomically stores `value` into t.value and returns the previous value of t.value.
+func (v *Uint64) Set(value uint64) (old uint64) {
+ return atomic.SwapUint64(&v.value, value)
+}
+
+// Val atomically loads and returns t.value.
+func (v *Uint64) Val() uint64 {
+ return atomic.LoadUint64(&v.value)
+}
+
+// Add atomically adds `delta` to t.value and returns the new value.
+func (v *Uint64) Add(delta uint64) (new uint64) {
+ return atomic.AddUint64(&v.value, delta)
+}
+
+// Cas executes the compare-and-swap operation for value.
+func (v *Uint64) Cas(old, new uint64) (swapped bool) {
+ return atomic.CompareAndSwapUint64(&v.value, old, new)
+}
+
+// String implements String interface for string printing.
+func (v *Uint64) String() string {
+ return strconv.FormatUint(v.Val(), 10)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Uint64) MarshalJSON() ([]byte, error) {
+ return []byte(strconv.FormatUint(v.Val(), 10)), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Uint64) UnmarshalJSON(b []byte) error {
+ v.Set(gconv.Uint64(string(b)))
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for `v`.
+func (v *Uint64) UnmarshalValue(value interface{}) error {
+ v.Set(gconv.Uint64(value))
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar.go
new file mode 100644
index 000000000000..f17afae55aa6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar.go
@@ -0,0 +1,190 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gvar provides an universal variable type, like generics.
+package gvar
+
+import (
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Var is an universal variable type implementer.
+type Var struct {
+ value interface{} // Underlying value.
+ safe bool // Concurrent safe or not.
+}
+
+// New creates and returns a new Var with given `value`.
+// The optional parameter `safe` specifies whether Var is used in concurrent-safety,
+// which is false in default.
+func New(value interface{}, safe ...bool) *Var {
+ if len(safe) > 0 && !safe[0] {
+ return &Var{
+ value: gtype.NewInterface(value),
+ safe: true,
+ }
+ }
+ return &Var{
+ value: value,
+ }
+}
+
+// Clone does a shallow copy of current Var and returns a pointer to this Var.
+func (v *Var) Clone() *Var {
+ return New(v.Val(), v.safe)
+}
+
+// Set sets `value` to `v`, and returns the old value.
+func (v *Var) Set(value interface{}) (old interface{}) {
+ if v.safe {
+ if t, ok := v.value.(*gtype.Interface); ok {
+ old = t.Set(value)
+ return
+ }
+ }
+ old = v.value
+ v.value = value
+ return
+}
+
+// Val returns the current value of `v`.
+func (v *Var) Val() interface{} {
+ if v == nil {
+ return nil
+ }
+ if v.safe {
+ if t, ok := v.value.(*gtype.Interface); ok {
+ return t.Val()
+ }
+ }
+ return v.value
+}
+
+// Interface is alias of Val.
+func (v *Var) Interface() interface{} {
+ return v.Val()
+}
+
+// Bytes converts and returns `v` as []byte.
+func (v *Var) Bytes() []byte {
+ return gconv.Bytes(v.Val())
+}
+
+// String converts and returns `v` as string.
+func (v *Var) String() string {
+ return gconv.String(v.Val())
+}
+
+// Bool converts and returns `v` as bool.
+func (v *Var) Bool() bool {
+ return gconv.Bool(v.Val())
+}
+
+// Int converts and returns `v` as int.
+func (v *Var) Int() int {
+ return gconv.Int(v.Val())
+}
+
+// Int8 converts and returns `v` as int8.
+func (v *Var) Int8() int8 {
+ return gconv.Int8(v.Val())
+}
+
+// Int16 converts and returns `v` as int16.
+func (v *Var) Int16() int16 {
+ return gconv.Int16(v.Val())
+}
+
+// Int32 converts and returns `v` as int32.
+func (v *Var) Int32() int32 {
+ return gconv.Int32(v.Val())
+}
+
+// Int64 converts and returns `v` as int64.
+func (v *Var) Int64() int64 {
+ return gconv.Int64(v.Val())
+}
+
+// Uint converts and returns `v` as uint.
+func (v *Var) Uint() uint {
+ return gconv.Uint(v.Val())
+}
+
+// Uint8 converts and returns `v` as uint8.
+func (v *Var) Uint8() uint8 {
+ return gconv.Uint8(v.Val())
+}
+
+// Uint16 converts and returns `v` as uint16.
+func (v *Var) Uint16() uint16 {
+ return gconv.Uint16(v.Val())
+}
+
+// Uint32 converts and returns `v` as uint32.
+func (v *Var) Uint32() uint32 {
+ return gconv.Uint32(v.Val())
+}
+
+// Uint64 converts and returns `v` as uint64.
+func (v *Var) Uint64() uint64 {
+ return gconv.Uint64(v.Val())
+}
+
+// Float32 converts and returns `v` as float32.
+func (v *Var) Float32() float32 {
+ return gconv.Float32(v.Val())
+}
+
+// Float64 converts and returns `v` as float64.
+func (v *Var) Float64() float64 {
+ return gconv.Float64(v.Val())
+}
+
+// Time converts and returns `v` as time.Time.
+// The parameter `format` specifies the format of the time string using gtime,
+// eg: Y-m-d H:i:s.
+func (v *Var) Time(format ...string) time.Time {
+ return gconv.Time(v.Val(), format...)
+}
+
+// Duration converts and returns `v` as time.Duration.
+// If value of `v` is string, then it uses time.ParseDuration for conversion.
+func (v *Var) Duration() time.Duration {
+ return gconv.Duration(v.Val())
+}
+
+// GTime converts and returns `v` as *gtime.Time.
+// The parameter `format` specifies the format of the time string using gtime,
+// eg: Y-m-d H:i:s.
+func (v *Var) GTime(format ...string) *gtime.Time {
+ return gconv.GTime(v.Val(), format...)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (v Var) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.Val())
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (v *Var) UnmarshalJSON(b []byte) error {
+ var i interface{}
+ if err := json.UnmarshalUseNumber(b, &i); err != nil {
+ return err
+ }
+ v.Set(i)
+ return nil
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for Var.
+func (v *Var) UnmarshalValue(value interface{}) error {
+ v.Set(value)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_is.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_is.go
new file mode 100644
index 000000000000..497996cd9ff4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_is.go
@@ -0,0 +1,51 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvar
+
+import (
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// IsNil checks whether `v` is nil.
+func (v *Var) IsNil() bool {
+ return utils.IsNil(v.Val())
+}
+
+// IsEmpty checks whether `v` is empty.
+func (v *Var) IsEmpty() bool {
+ return utils.IsEmpty(v.Val())
+}
+
+// IsInt checks whether `v` is type of int.
+func (v *Var) IsInt() bool {
+ return utils.IsInt(v.Val())
+}
+
+// IsUint checks whether `v` is type of uint.
+func (v *Var) IsUint() bool {
+ return utils.IsUint(v.Val())
+}
+
+// IsFloat checks whether `v` is type of float.
+func (v *Var) IsFloat() bool {
+ return utils.IsFloat(v.Val())
+}
+
+// IsSlice checks whether `v` is type of slice.
+func (v *Var) IsSlice() bool {
+ return utils.IsSlice(v.Val())
+}
+
+// IsMap checks whether `v` is type of map.
+func (v *Var) IsMap() bool {
+ return utils.IsMap(v.Val())
+}
+
+// IsStruct checks whether `v` is type of struct.
+func (v *Var) IsStruct() bool {
+ return utils.IsStruct(v.Val())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_list.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_list.go
new file mode 100644
index 000000000000..1f24bca88fd4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_list.go
@@ -0,0 +1,25 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvar
+
+import (
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
+// or else it returns an empty slice.
+func (v *Var) ListItemValues(key interface{}) (values []interface{}) {
+ return gutil.ListItemValues(v.Val(), key)
+}
+
+// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
+// or else it returns an empty slice.
+func (v *Var) ListItemValuesUnique(key string) []interface{} {
+ return gutil.ListItemValuesUnique(v.Val(), key)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_map.go
new file mode 100644
index 000000000000..268d9f14042b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_map.go
@@ -0,0 +1,91 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvar
+
+import "github.com/gogf/gf/v2/util/gconv"
+
+// Map converts and returns `v` as map[string]interface{}.
+func (v *Var) Map(tags ...string) map[string]interface{} {
+ return gconv.Map(v.Val(), tags...)
+}
+
+// MapStrAny is like function Map, but implements the interface of MapStrAny.
+func (v *Var) MapStrAny() map[string]interface{} {
+ return v.Map()
+}
+
+// MapStrStr converts and returns `v` as map[string]string.
+func (v *Var) MapStrStr(tags ...string) map[string]string {
+ return gconv.MapStrStr(v.Val(), tags...)
+}
+
+// MapStrVar converts and returns `v` as map[string]Var.
+func (v *Var) MapStrVar(tags ...string) map[string]*Var {
+ m := v.Map(tags...)
+ if len(m) > 0 {
+ vMap := make(map[string]*Var, len(m))
+ for k, v := range m {
+ vMap[k] = New(v)
+ }
+ return vMap
+ }
+ return nil
+}
+
+// MapDeep converts and returns `v` as map[string]interface{} recursively.
+func (v *Var) MapDeep(tags ...string) map[string]interface{} {
+ return gconv.MapDeep(v.Val(), tags...)
+}
+
+// MapStrStrDeep converts and returns `v` as map[string]string recursively.
+func (v *Var) MapStrStrDeep(tags ...string) map[string]string {
+ return gconv.MapStrStrDeep(v.Val(), tags...)
+}
+
+// MapStrVarDeep converts and returns `v` as map[string]*Var recursively.
+func (v *Var) MapStrVarDeep(tags ...string) map[string]*Var {
+ m := v.MapDeep(tags...)
+ if len(m) > 0 {
+ vMap := make(map[string]*Var, len(m))
+ for k, v := range m {
+ vMap[k] = New(v)
+ }
+ return vMap
+ }
+ return nil
+}
+
+// Maps converts and returns `v` as map[string]string.
+// See gconv.Maps.
+func (v *Var) Maps(tags ...string) []map[string]interface{} {
+ return gconv.Maps(v.Val(), tags...)
+}
+
+// MapsDeep converts `value` to []map[string]interface{} recursively.
+// See gconv.MapsDeep.
+func (v *Var) MapsDeep(tags ...string) []map[string]interface{} {
+ return gconv.MapsDeep(v.Val(), tags...)
+}
+
+// MapToMap converts any map type variable `params` to another map type variable `pointer`.
+// See gconv.MapToMap.
+func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err error) {
+ return gconv.MapToMap(v.Val(), pointer, mapping...)
+}
+
+// MapToMaps converts any map type variable `params` to another map type variable `pointer`.
+// See gconv.MapToMaps.
+func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) {
+ return gconv.MapToMaps(v.Val(), pointer, mapping...)
+}
+
+// MapToMapsDeep converts any map type variable `params` to another map type variable
+// `pointer` recursively.
+// See gconv.MapToMapsDeep.
+func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
+ return gconv.MapToMaps(v.Val(), pointer, mapping...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_scan.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_scan.go
new file mode 100644
index 000000000000..469005b5034d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_scan.go
@@ -0,0 +1,19 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvar
+
+import (
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Scan automatically checks the type of `pointer` and converts `params` to `pointer`. It supports `pointer`
+// with type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.
+//
+// See gconv.Scan.
+func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error {
+ return gconv.Scan(v.Val(), pointer, mapping...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_slice.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_slice.go
new file mode 100644
index 000000000000..02a61aa2e267
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_slice.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvar
+
+import "github.com/gogf/gf/v2/util/gconv"
+
+// Ints converts and returns `v` as []int.
+func (v *Var) Ints() []int {
+ return gconv.Ints(v.Val())
+}
+
+// Int64s converts and returns `v` as []int64.
+func (v *Var) Int64s() []int64 {
+ return gconv.Int64s(v.Val())
+}
+
+// Uints converts and returns `v` as []uint.
+func (v *Var) Uints() []uint {
+ return gconv.Uints(v.Val())
+}
+
+// Uint64s converts and returns `v` as []uint64.
+func (v *Var) Uint64s() []uint64 {
+ return gconv.Uint64s(v.Val())
+}
+
+// Floats is alias of Float64s.
+func (v *Var) Floats() []float64 {
+ return gconv.Floats(v.Val())
+}
+
+// Float32s converts and returns `v` as []float32.
+func (v *Var) Float32s() []float32 {
+ return gconv.Float32s(v.Val())
+}
+
+// Float64s converts and returns `v` as []float64.
+func (v *Var) Float64s() []float64 {
+ return gconv.Float64s(v.Val())
+}
+
+// Strings converts and returns `v` as []string.
+func (v *Var) Strings() []string {
+ return gconv.Strings(v.Val())
+}
+
+// Interfaces converts and returns `v` as []interfaces{}.
+func (v *Var) Interfaces() []interface{} {
+ return gconv.Interfaces(v.Val())
+}
+
+// Slice is alias of Interfaces.
+func (v *Var) Slice() []interface{} {
+ return v.Interfaces()
+}
+
+// Array is alias of Interfaces.
+func (v *Var) Array() []interface{} {
+ return v.Interfaces()
+}
+
+// Vars converts and returns `v` as []Var.
+func (v *Var) Vars() []*Var {
+ array := gconv.Interfaces(v.Val())
+ if len(array) == 0 {
+ return nil
+ }
+ vars := make([]*Var, len(array))
+ for k, v := range array {
+ vars[k] = New(v)
+ }
+ return vars
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_struct.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_struct.go
new file mode 100644
index 000000000000..30ca794b48ab
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/container/gvar/gvar_struct.go
@@ -0,0 +1,23 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvar
+
+import (
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Struct maps value of `v` to `pointer`.
+// The parameter `pointer` should be a pointer to a struct instance.
+// The parameter `mapping` is used to specify the key-to-attribute mapping rules.
+func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
+ return gconv.Struct(v.Val(), pointer, mapping...)
+}
+
+// Structs converts and returns `v` as given struct slice.
+func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error {
+ return gconv.Structs(v.Val(), pointer, mapping...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/crypto/gaes/gaes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/crypto/gaes/gaes.go
new file mode 100644
index 000000000000..4e7e5e4f6dc9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/crypto/gaes/gaes.go
@@ -0,0 +1,178 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gaes provides useful API for AES encryption/decryption algorithms.
+package gaes
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+const (
+ // IVDefaultValue is the default value for IV.
+ IVDefaultValue = "I Love Go Frame!"
+)
+
+// Encrypt is alias of EncryptCBC.
+func Encrypt(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {
+ return EncryptCBC(plainText, key, iv...)
+}
+
+// Decrypt is alias of DecryptCBC.
+func Decrypt(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
+ return DecryptCBC(cipherText, key, iv...)
+}
+
+// EncryptCBC encrypts `plainText` using CBC mode.
+// Note that the key must be 16/24/32 bit length.
+// The parameter `iv` initialization vector is unnecessary.
+func EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key)
+ return nil, err
+ }
+ blockSize := block.BlockSize()
+ plainText = PKCS5Padding(plainText, blockSize)
+ ivValue := ([]byte)(nil)
+ if len(iv) > 0 {
+ ivValue = iv[0]
+ } else {
+ ivValue = []byte(IVDefaultValue)
+ }
+ blockMode := cipher.NewCBCEncrypter(block, ivValue)
+ cipherText := make([]byte, len(plainText))
+ blockMode.CryptBlocks(cipherText, plainText)
+
+ return cipherText, nil
+}
+
+// DecryptCBC decrypts `cipherText` using CBC mode.
+// Note that the key must be 16/24/32 bit length.
+// The parameter `iv` initialization vector is unnecessary.
+func DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key)
+ return nil, err
+ }
+ blockSize := block.BlockSize()
+ if len(cipherText) < blockSize {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short")
+ }
+ ivValue := ([]byte)(nil)
+ if len(iv) > 0 {
+ ivValue = iv[0]
+ } else {
+ ivValue = []byte(IVDefaultValue)
+ }
+ if len(cipherText)%blockSize != 0 {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText is not a multiple of the block size")
+ }
+ blockModel := cipher.NewCBCDecrypter(block, ivValue)
+ plainText := make([]byte, len(cipherText))
+ blockModel.CryptBlocks(plainText, cipherText)
+ plainText, e := PKCS5UnPadding(plainText, blockSize)
+ if e != nil {
+ return nil, e
+ }
+ return plainText, nil
+}
+
+func PKCS5Padding(src []byte, blockSize int) []byte {
+ padding := blockSize - len(src)%blockSize
+ padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+ return append(src, padtext...)
+}
+
+func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) {
+ length := len(src)
+ if blockSize <= 0 {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid blocklen")
+ }
+
+ if length%blockSize != 0 || length == 0 {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid data len")
+ }
+
+ unpadding := int(src[length-1])
+ if unpadding > blockSize || unpadding == 0 {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding")
+ }
+
+ padding := src[length-unpadding:]
+ for i := 0; i < unpadding; i++ {
+ if padding[i] != byte(unpadding) {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding")
+ }
+ }
+
+ return src[:(length - unpadding)], nil
+}
+
+// EncryptCFB encrypts `plainText` using CFB mode.
+// Note that the key must be 16/24/32 bit length.
+// The parameter `iv` initialization vector is unnecessary.
+func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key)
+ return nil, err
+ }
+ blockSize := block.BlockSize()
+ plainText, *padding = ZeroPadding(plainText, blockSize)
+ ivValue := ([]byte)(nil)
+ if len(iv) > 0 {
+ ivValue = iv[0]
+ } else {
+ ivValue = []byte(IVDefaultValue)
+ }
+ stream := cipher.NewCFBEncrypter(block, ivValue)
+ cipherText := make([]byte, len(plainText))
+ stream.XORKeyStream(cipherText, plainText)
+ return cipherText, nil
+}
+
+// DecryptCFB decrypts `plainText` using CFB mode.
+// Note that the key must be 16/24/32 bit length.
+// The parameter `iv` initialization vector is unnecessary.
+func DecryptCFB(cipherText []byte, key []byte, unPadding int, iv ...[]byte) ([]byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `aes.NewCipher failed for key "%s"`, key)
+ return nil, err
+ }
+ if len(cipherText) < aes.BlockSize {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short")
+ }
+ ivValue := ([]byte)(nil)
+ if len(iv) > 0 {
+ ivValue = iv[0]
+ } else {
+ ivValue = []byte(IVDefaultValue)
+ }
+ stream := cipher.NewCFBDecrypter(block, ivValue)
+ plainText := make([]byte, len(cipherText))
+ stream.XORKeyStream(plainText, cipherText)
+ plainText = ZeroUnPadding(plainText, unPadding)
+ return plainText, nil
+}
+
+func ZeroPadding(cipherText []byte, blockSize int) ([]byte, int) {
+ padding := blockSize - len(cipherText)%blockSize
+ padText := bytes.Repeat([]byte{byte(0)}, padding)
+ return append(cipherText, padText...), padding
+}
+
+func ZeroUnPadding(plaintext []byte, unPadding int) []byte {
+ length := len(plaintext)
+ return plaintext[:(length - unPadding)]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/crypto/gmd5/gmd5.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/crypto/gmd5/gmd5.go
new file mode 100644
index 000000000000..5b28bdb8066c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/crypto/gmd5/gmd5.go
@@ -0,0 +1,97 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gmd5 provides useful API for MD5 encryption algorithms.
+package gmd5
+
+import (
+ "crypto/md5"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Encrypt encrypts any type of variable using MD5 algorithms.
+// It uses gconv package to convert `v` to its bytes type.
+func Encrypt(data interface{}) (encrypt string, err error) {
+ return EncryptBytes(gconv.Bytes(data))
+}
+
+// MustEncrypt encrypts any type of variable using MD5 algorithms.
+// It uses gconv package to convert `v` to its bytes type.
+// It panics if any error occurs.
+func MustEncrypt(data interface{}) string {
+ result, err := Encrypt(data)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// EncryptBytes encrypts `data` using MD5 algorithms.
+func EncryptBytes(data []byte) (encrypt string, err error) {
+ h := md5.New()
+ if _, err = h.Write(data); err != nil {
+ err = gerror.Wrap(err, `hash.Write failed`)
+ return "", err
+ }
+ return fmt.Sprintf("%x", h.Sum(nil)), nil
+}
+
+// MustEncryptBytes encrypts `data` using MD5 algorithms.
+// It panics if any error occurs.
+func MustEncryptBytes(data []byte) string {
+ result, err := EncryptBytes(data)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// EncryptString encrypts string `data` using MD5 algorithms.
+func EncryptString(data string) (encrypt string, err error) {
+ return EncryptBytes([]byte(data))
+}
+
+// MustEncryptString encrypts string `data` using MD5 algorithms.
+// It panics if any error occurs.
+func MustEncryptString(data string) string {
+ result, err := EncryptString(data)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// EncryptFile encrypts file content of `path` using MD5 algorithms.
+func EncryptFile(path string) (encrypt string, err error) {
+ f, err := os.Open(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Open failed for name "%s"`, path)
+ return "", err
+ }
+ defer f.Close()
+ h := md5.New()
+ _, err = io.Copy(h, f)
+ if err != nil {
+ err = gerror.Wrap(err, `io.Copy failed`)
+ return "", err
+ }
+ return fmt.Sprintf("%x", h.Sum(nil)), nil
+}
+
+// MustEncryptFile encrypts file content of `path` using MD5 algorithms.
+// It panics if any error occurs.
+func MustEncryptFile(path string) string {
+ result, err := EncryptFile(path)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb.go
new file mode 100644
index 000000000000..d054033f0548
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb.go
@@ -0,0 +1,595 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gdb provides ORM features for popular relationship databases.
+package gdb
+
+import (
+ "context"
+ "database/sql"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcache"
+ "github.com/gogf/gf/v2/os/gcmd"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// DB defines the interfaces for ORM operations.
+type DB interface {
+ // ===========================================================================
+ // Model creation.
+ // ===========================================================================
+
+ // Model creates and returns a new ORM model from given schema.
+ // The parameter `table` can be more than one table names, and also alias name, like:
+ // 1. Model names:
+ // Model("user")
+ // Model("user u")
+ // Model("user, user_detail")
+ // Model("user u, user_detail ud")
+ // 2. Model name with alias: Model("user", "u")
+ // Also see Core.Model.
+ Model(tableNameOrStruct ...interface{}) *Model
+
+ // Raw creates and returns a model based on a raw sql not a table.
+ Raw(rawSql string, args ...interface{}) *Model
+
+ // Schema creates and returns a schema.
+ // Also see Core.Schema.
+ Schema(schema string) *Schema
+
+ // With creates and returns an ORM model based on metadata of given object.
+ // Also see Core.With.
+ With(objects ...interface{}) *Model
+
+ // Open creates a raw connection object for database with given node configuration.
+ // Note that it is not recommended using the function manually.
+ // Also see DriverMysql.Open.
+ Open(config *ConfigNode) (*sql.DB, error)
+
+ // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy
+ // of current DB object and with given context in it.
+ // Also see Core.Ctx.
+ Ctx(ctx context.Context) DB
+
+ // Close closes the database and prevents new queries from starting.
+ // Close then waits for all queries that have started processing on the server
+ // to finish.
+ //
+ // It is rare to Close a DB, as the DB handle is meant to be
+ // long-lived and shared between many goroutines.
+ Close(ctx context.Context) error
+
+ // ===========================================================================
+ // Query APIs.
+ // ===========================================================================
+
+ Query(ctx context.Context, sql string, args ...interface{}) (Result, error) // See Core.Query.
+ Exec(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) // See Core.Exec.
+ Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) // See Core.Prepare.
+
+ // ===========================================================================
+ // Common APIs for CURD.
+ // ===========================================================================
+
+ Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Insert.
+ InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.InsertIgnore.
+ InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) // See Core.InsertAndGetId.
+ Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Replace.
+ Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Save.
+ Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Update.
+ Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Delete.
+
+ // ===========================================================================
+ // Internal APIs for CURD, which can be overwritten by custom CURD implements.
+ // ===========================================================================
+
+ DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoGetAll.
+ DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) // See Core.DoInsert.
+ DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoUpdate.
+ DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoDelete.
+ DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoQuery.
+ DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) // See Core.DoExec.
+ DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) // See Core.DoFilter.
+ DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) // See Core.DoCommit.
+ DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) // See Core.DoPrepare.
+
+ // ===========================================================================
+ // Query APIs for convenience purpose.
+ // ===========================================================================
+
+ GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) // See Core.GetAll.
+ GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) // See Core.GetOne.
+ GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) // See Core.GetValue.
+ GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) // See Core.GetArray.
+ GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) // See Core.GetCount.
+ GetScan(ctx context.Context, objPointer interface{}, sql string, args ...interface{}) error // See Core.GetScan.
+ Union(unions ...*Model) *Model // See Core.Union.
+ UnionAll(unions ...*Model) *Model // See Core.UnionAll.
+
+ // ===========================================================================
+ // Master/Slave specification support.
+ // ===========================================================================
+
+ Master(schema ...string) (*sql.DB, error) // See Core.Master.
+ Slave(schema ...string) (*sql.DB, error) // See Core.Slave.
+
+ // ===========================================================================
+ // Ping-Pong.
+ // ===========================================================================
+
+ PingMaster() error // See Core.PingMaster.
+ PingSlave() error // See Core.PingSlave.
+
+ // ===========================================================================
+ // Transaction.
+ // ===========================================================================
+
+ Begin(ctx context.Context) (*TX, error) // See Core.Begin.
+ Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) error // See Core.Transaction.
+
+ // ===========================================================================
+ // Configuration methods.
+ // ===========================================================================
+
+ GetCache() *gcache.Cache // See Core.GetCache.
+ SetDebug(debug bool) // See Core.SetDebug.
+ GetDebug() bool // See Core.GetDebug.
+ GetSchema() string // See Core.GetSchema.
+ GetPrefix() string // See Core.GetPrefix.
+ GetGroup() string // See Core.GetGroup.
+ SetDryRun(enabled bool) // See Core.SetDryRun.
+ GetDryRun() bool // See Core.GetDryRun.
+ SetLogger(logger *glog.Logger) // See Core.SetLogger.
+ GetLogger() *glog.Logger // See Core.GetLogger.
+ GetConfig() *ConfigNode // See Core.GetConfig.
+ SetMaxIdleConnCount(n int) // See Core.SetMaxIdleConnCount.
+ SetMaxOpenConnCount(n int) // See Core.SetMaxOpenConnCount.
+ SetMaxConnLifeTime(d time.Duration) // See Core.SetMaxConnLifeTime.
+
+ // ===========================================================================
+ // Utility methods.
+ // ===========================================================================
+
+ GetCtx() context.Context // See Core.GetCtx.
+ GetCore() *Core // See Core.GetCore
+ GetChars() (charLeft string, charRight string) // See Core.GetChars.
+ Tables(ctx context.Context, schema ...string) (tables []string, err error) // See Core.Tables.
+ TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields.
+ ConvertDataForRecord(ctx context.Context, data interface{}) map[string]interface{} // See Core.ConvertDataForRecord
+ FilteredLink() string // FilteredLink is used for filtering sensitive information in `Link` configuration before output it to tracing server.
+}
+
+// Core is the base struct for database management.
+type Core struct {
+ db DB // DB interface object.
+ ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization.
+ group string // Configuration group name.
+ schema string // Custom schema for this object.
+ debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime.
+ cache *gcache.Cache // Cache manager, SQL result cache only.
+ links *gmap.StrAnyMap // links caches all created links by node.
+ logger *glog.Logger // Logger for logging functionality.
+ config *ConfigNode // Current config node.
+}
+
+// DoCommitInput is the input parameters for function DoCommit.
+type DoCommitInput struct {
+ Db *sql.DB
+ Tx *sql.Tx
+ Stmt *sql.Stmt
+ Link Link
+ Sql string
+ Args []interface{}
+ Type string
+ IsTransaction bool
+}
+
+// DoCommitOutput is the output parameters for function DoCommit.
+type DoCommitOutput struct {
+ Result sql.Result // Result is the result of exec statement.
+ Records []Record // Records is the result of query statement.
+ Stmt *Stmt // Stmt is the Statement object result for Prepare.
+ Tx *TX // Tx is the transaction object result for Begin.
+ RawResult interface{} // RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row.
+}
+
+// Driver is the interface for integrating sql drivers into package gdb.
+type Driver interface {
+ // New creates and returns a database object for specified database server.
+ New(core *Core, node *ConfigNode) (DB, error)
+}
+
+// Link is a common database function wrapper interface.
+type Link interface {
+ Query(sql string, args ...interface{}) (*sql.Rows, error)
+ Exec(sql string, args ...interface{}) (sql.Result, error)
+ Prepare(sql string) (*sql.Stmt, error)
+ QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error)
+ ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error)
+ PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)
+ IsTransaction() bool
+}
+
+// Sql is the sql recording struct.
+type Sql struct {
+ Sql string // SQL string(may contain reserved char '?').
+ Type string // SQL operation type.
+ Args []interface{} // Arguments for this sql.
+ Format string // Formatted sql which contains arguments in the sql.
+ Error error // Execution result.
+ Start int64 // Start execution timestamp in milliseconds.
+ End int64 // End execution timestamp in milliseconds.
+ Group string // Group is the group name of the configuration that the sql is executed from.
+ IsTransaction bool // IsTransaction marks whether this sql is executed in transaction.
+ RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement.
+}
+
+// DoInsertOption is the input struct for function DoInsert.
+type DoInsertOption struct {
+ OnDuplicateStr string
+ OnDuplicateMap map[string]interface{}
+ InsertOption int // Insert operation.
+ BatchCount int // Batch count for batch inserting.
+}
+
+// TableField is the struct for table field.
+type TableField struct {
+ Index int // For ordering purpose as map is unordered.
+ Name string // Field name.
+ Type string // Field type.
+ Null bool // Field can be null or not.
+ Key string // The index information(empty if it's not an index).
+ Default interface{} // Default value for the field.
+ Extra string // Extra information.
+ Comment string // Field comment.
+}
+
+// Counter is the type for update count.
+type Counter struct {
+ Field string
+ Value float64
+}
+
+type (
+ Raw string // Raw is a raw sql that will not be treated as argument but as a direct sql part.
+ Value = *gvar.Var // Value is the field value type.
+ Record map[string]Value // Record is the row record of the table.
+ Result []Record // Result is the row record array.
+ Map = map[string]interface{} // Map is alias of map[string]interface{}, which is the most common usage map type.
+ List = []Map // List is type of map array.
+)
+
+const (
+ defaultModelSafe = false
+ defaultCharset = `utf8`
+ queryTypeNormal = 0
+ queryTypeCount = 1
+ unionTypeNormal = 0
+ unionTypeAll = 1
+ defaultBatchNumber = 10 // Per count for batch insert/replace/save.
+ defaultMaxIdleConnCount = 10 // Max idle connection count in pool.
+ defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit.
+ defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds.
+ ctxTimeoutTypeExec = iota
+ ctxTimeoutTypeQuery
+ ctxTimeoutTypePrepare
+ commandEnvKeyForDryRun = "gf.gdb.dryrun"
+ modelForDaoSuffix = `ForDao`
+ dbRoleSlave = `slave`
+)
+
+const (
+ InsertOptionDefault = 0
+ InsertOptionReplace = 1
+ InsertOptionSave = 2
+ InsertOptionIgnore = 3
+)
+
+const (
+ SqlTypeBegin = "DB.Begin"
+ SqlTypeTXCommit = "TX.Commit"
+ SqlTypeTXRollback = "TX.Rollback"
+ SqlTypeExecContext = "DB.ExecContext"
+ SqlTypeQueryContext = "DB.QueryContext"
+ SqlTypePrepareContext = "DB.PrepareContext"
+ SqlTypeStmtExecContext = "DB.Statement.ExecContext"
+ SqlTypeStmtQueryContext = "DB.Statement.QueryContext"
+ SqlTypeStmtQueryRowContext = "DB.Statement.QueryRowContext"
+)
+
+const (
+ DriverNameMysql = `mysql`
+)
+
+var (
+ // instances is the management map for instances.
+ instances = gmap.NewStrAnyMap(true)
+
+ // driverMap manages all custom registered driver.
+ driverMap = map[string]Driver{
+ DriverNameMysql: &DriverMysql{},
+ }
+
+ // lastOperatorRegPattern is the regular expression pattern for a string
+ // which has operator at its tail.
+ lastOperatorRegPattern = `[<>=]+\s*$`
+
+ // regularFieldNameRegPattern is the regular expression pattern for a string
+ // which is a regular field name of table.
+ regularFieldNameRegPattern = `^[\w\.\-]+$`
+
+ // regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'.
+ // Note that, although some databases allow char '.' in the field name, but it here does not allow '.'
+ // in the field name as it conflicts with "db.table.field" pattern in SOME situations.
+ regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
+
+ // tableFieldsMap caches the table information retrieved from database.
+ tableFieldsMap = gmap.New(true)
+
+ // allDryRun sets dry-run feature for all database connections.
+ // It is commonly used for command options for convenience.
+ allDryRun = false
+)
+
+func init() {
+ // allDryRun is initialized from environment or command options.
+ allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool()
+}
+
+// Register registers custom database driver to gdb.
+func Register(name string, driver Driver) error {
+ driverMap[name] = driver
+ return nil
+}
+
+// New creates and returns an ORM object with given configuration node.
+func New(node ConfigNode) (db DB, err error) {
+ return doNewByNode(node, "")
+}
+
+// NewByGroup creates and returns an ORM object with global configurations.
+// The parameter `name` specifies the configuration group name,
+// which is DefaultGroupName in default.
+func NewByGroup(group ...string) (db DB, err error) {
+ groupName := configs.group
+ if len(group) > 0 && group[0] != "" {
+ groupName = group[0]
+ }
+ configs.RLock()
+ defer configs.RUnlock()
+
+ if len(configs.config) < 1 {
+ return nil, gerror.NewCode(
+ gcode.CodeInvalidConfiguration,
+ "database configuration is empty, please set the database configuration before using",
+ )
+ }
+ if _, ok := configs.config[groupName]; ok {
+ var node *ConfigNode
+ if node, err = getConfigNodeByGroup(groupName, true); err == nil {
+ return doNewByNode(*node, groupName)
+ } else {
+ return nil, err
+ }
+ } else {
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidConfiguration,
+ `database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`,
+ groupName, groupName,
+ )
+ }
+}
+
+// doNewByNode creates and returns an ORM object with given configuration node and group name.
+func doNewByNode(node ConfigNode, group string) (db DB, err error) {
+ c := &Core{
+ group: group,
+ debug: gtype.NewBool(),
+ cache: gcache.New(),
+ links: gmap.NewStrAnyMap(true),
+ logger: glog.New(),
+ config: &node,
+ }
+ if v, ok := driverMap[node.Type]; ok {
+ c.db, err = v.New(c, &node)
+ if err != nil {
+ return nil, err
+ }
+ return c.db, nil
+ }
+ errorMsg := `cannot find database driver for specified database type "%s"`
+ errorMsg += `, did you misspell type name "%s" or forget importing the database driver?`
+ return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type)
+}
+
+// Instance returns an instance for DB operations.
+// The parameter `name` specifies the configuration group name,
+// which is DefaultGroupName in default.
+func Instance(name ...string) (db DB, err error) {
+ group := configs.group
+ if len(name) > 0 && name[0] != "" {
+ group = name[0]
+ }
+ v := instances.GetOrSetFuncLock(group, func() interface{} {
+ db, err = NewByGroup(group)
+ return db
+ })
+ if v != nil {
+ return v.(DB), nil
+ }
+ return
+}
+
+// getConfigNodeByGroup calculates and returns a configuration node of given group. It
+// calculates the value internally using weight algorithm for load balance.
+//
+// The parameter `master` specifies whether retrieving a master node, or else a slave node
+// if master-slave configured.
+func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) {
+ if list, ok := configs.config[group]; ok {
+ // Separates master and slave configuration nodes array.
+ var (
+ masterList = make(ConfigGroup, 0)
+ slaveList = make(ConfigGroup, 0)
+ )
+ for i := 0; i < len(list); i++ {
+ if list[i].Role == dbRoleSlave {
+ slaveList = append(slaveList, list[i])
+ } else {
+ masterList = append(masterList, list[i])
+ }
+ }
+ if len(masterList) < 1 {
+ return nil, gerror.NewCode(
+ gcode.CodeInvalidConfiguration,
+ "at least one master node configuration's need to make sense",
+ )
+ }
+ if len(slaveList) < 1 {
+ slaveList = masterList
+ }
+ if master {
+ return getConfigNodeByWeight(masterList), nil
+ } else {
+ return getConfigNodeByWeight(slaveList), nil
+ }
+ } else {
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidConfiguration,
+ "empty database configuration for item name '%s'",
+ group,
+ )
+ }
+}
+
+// getConfigNodeByWeight calculates the configuration weights and randomly returns a node.
+//
+// Calculation algorithm brief:
+// 1. If we have 2 nodes, and their weights are both 1, then the weight range is [0, 199];
+// 2. Node1 weight range is [0, 99], and node2 weight range is [100, 199], ratio is 1:1;
+// 3. If the random number is 99, it then chooses and returns node1;.
+func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
+ if len(cg) < 2 {
+ return &cg[0]
+ }
+ var total int
+ for i := 0; i < len(cg); i++ {
+ total += cg[i].Weight * 100
+ }
+ // If total is 0 means all the nodes have no weight attribute configured.
+ // It then defaults each node's weight attribute to 1.
+ if total == 0 {
+ for i := 0; i < len(cg); i++ {
+ cg[i].Weight = 1
+ total += cg[i].Weight * 100
+ }
+ }
+ // Exclude the right border value.
+ var (
+ min = 0
+ max = 0
+ random = grand.N(0, total-1)
+ )
+ for i := 0; i < len(cg); i++ {
+ max = min + cg[i].Weight*100
+ // fmt.Printf("r: %d, min: %d, max: %d\n", r, min, max)
+ if random >= min && random < max {
+ return &cg[i]
+ } else {
+ min = max
+ }
+ }
+ return nil
+}
+
+// getSqlDb retrieves and returns an underlying database connection object.
+// The parameter `master` specifies whether retrieves master node connection if
+// master-slave nodes are configured.
+func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
+ // Load balance.
+ var node *ConfigNode
+ if c.group != "" {
+ node, err = getConfigNodeByGroup(c.group, master)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ node = c.config
+ }
+ // Default value checks.
+ if node.Charset == "" {
+ node.Charset = defaultCharset
+ }
+ // Changes the schema.
+ nodeSchema := c.schema
+ if len(schema) > 0 && schema[0] != "" {
+ nodeSchema = schema[0]
+ }
+ if nodeSchema != "" {
+ // Value copy.
+ n := *node
+ n.Name = nodeSchema
+ node = &n
+ }
+ // Cache the underlying connection pool object by node.
+ v := c.links.GetOrSetFuncLock(node.String(), func() interface{} {
+ intlog.Printf(
+ c.db.GetCtx(),
+ `open new connection, master:%#v, config:%#v, node:%#v`,
+ master, c.config, node,
+ )
+ defer func() {
+ if err != nil {
+ intlog.Printf(c.db.GetCtx(), `open new connection failed: %v, %#v`, err, node)
+ } else {
+ intlog.Printf(
+ c.db.GetCtx(),
+ `open new connection success, master:%#v, config:%#v, node:%#v`,
+ master, c.config, node,
+ )
+ }
+ }()
+
+ if sqlDb, err = c.db.Open(node); err != nil {
+ return nil
+ }
+
+ if c.config.MaxIdleConnCount > 0 {
+ sqlDb.SetMaxIdleConns(c.config.MaxIdleConnCount)
+ } else {
+ sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount)
+ }
+ if c.config.MaxOpenConnCount > 0 {
+ sqlDb.SetMaxOpenConns(c.config.MaxOpenConnCount)
+ } else {
+ sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount)
+ }
+ if c.config.MaxConnLifeTime > 0 {
+ sqlDb.SetConnMaxLifetime(c.config.MaxConnLifeTime)
+ } else {
+ sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime)
+ }
+ return sqlDb
+ })
+ if v != nil && sqlDb == nil {
+ sqlDb = v.(*sql.DB)
+ }
+ if node.Debug {
+ c.db.SetDebug(node.Debug)
+ }
+ if node.DryRun {
+ c.db.SetDryRun(node.DryRun)
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core.go
new file mode 100644
index 000000000000..255b67c7766d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core.go
@@ -0,0 +1,702 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gdb
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// GetCore returns the underlying *Core object.
+func (c *Core) GetCore() *Core {
+ return c
+}
+
+// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy
+// of current DB object and with given context in it.
+// Note that this returned DB object can be used only once, so do not assign it to
+// a global or package variable for long using.
+func (c *Core) Ctx(ctx context.Context) DB {
+ if ctx == nil {
+ return c.db
+ }
+ // It makes a shallow copy of current db and changes its context for next chaining operation.
+ var (
+ err error
+ newCore = &Core{}
+ configNode = c.db.GetConfig()
+ )
+ *newCore = *c
+ newCore.ctx = ctx
+ // It creates a new DB object, which is commonly a wrapper for object `Core`.
+ newCore.db, err = driverMap[configNode.Type].New(newCore, configNode)
+ if err != nil {
+ // It is really a serious error here.
+ // Do not let it continue.
+ panic(err)
+ }
+ return newCore.db
+}
+
+// GetCtx returns the context for current DB.
+// It returns `context.Background()` is there's no context previously set.
+func (c *Core) GetCtx() context.Context {
+ if c.ctx != nil {
+ return c.ctx
+ }
+ return context.TODO()
+}
+
+// GetCtxTimeout returns the context and cancel function for specified timeout type.
+func (c *Core) GetCtxTimeout(timeoutType int, ctx context.Context) (context.Context, context.CancelFunc) {
+ if ctx == nil {
+ ctx = c.GetCtx()
+ } else {
+ ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil)
+ }
+ switch timeoutType {
+ case ctxTimeoutTypeExec:
+ if c.db.GetConfig().ExecTimeout > 0 {
+ return context.WithTimeout(ctx, c.db.GetConfig().ExecTimeout)
+ }
+ case ctxTimeoutTypeQuery:
+ if c.db.GetConfig().QueryTimeout > 0 {
+ return context.WithTimeout(ctx, c.db.GetConfig().QueryTimeout)
+ }
+ case ctxTimeoutTypePrepare:
+ if c.db.GetConfig().PrepareTimeout > 0 {
+ return context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout)
+ }
+ default:
+ panic(gerror.NewCodef(gcode.CodeInvalidParameter, "invalid context timeout type: %d", timeoutType))
+ }
+ return ctx, func() {}
+}
+
+// Close closes the database and prevents new queries from starting.
+// Close then waits for all queries that have started processing on the server
+// to finish.
+//
+// It is rare to Close a DB, as the DB handle is meant to be
+// long-lived and shared between many goroutines.
+func (c *Core) Close(ctx context.Context) (err error) {
+ if err = c.cache.Close(ctx); err != nil {
+ return err
+ }
+ c.links.LockFunc(func(m map[string]interface{}) {
+ for k, v := range m {
+ if db, ok := v.(*sql.DB); ok {
+ err = db.Close()
+ if err != nil {
+ err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`)
+ }
+ intlog.Printf(ctx, `close link: %s, err: %v`, k, err)
+ if err != nil {
+ return
+ }
+ delete(m, k)
+ }
+ }
+ })
+ return
+}
+
+// Master creates and returns a connection from master node if master-slave configured.
+// It returns the default connection if master-slave not configured.
+func (c *Core) Master(schema ...string) (*sql.DB, error) {
+ useSchema := ""
+ if len(schema) > 0 && schema[0] != "" {
+ useSchema = schema[0]
+ } else {
+ useSchema = c.schema
+ }
+ return c.getSqlDb(true, useSchema)
+}
+
+// Slave creates and returns a connection from slave node if master-slave configured.
+// It returns the default connection if master-slave not configured.
+func (c *Core) Slave(schema ...string) (*sql.DB, error) {
+ useSchema := ""
+ if len(schema) > 0 && schema[0] != "" {
+ useSchema = schema[0]
+ } else {
+ useSchema = c.schema
+ }
+ return c.getSqlDb(false, useSchema)
+}
+
+// GetAll queries and returns data records from database.
+func (c *Core) GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) {
+ return c.db.DoGetAll(ctx, nil, sql, args...)
+}
+
+// DoGetAll queries and returns data records from database.
+func (c *Core) DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) {
+ return c.db.DoQuery(ctx, link, sql, args...)
+}
+
+// GetOne queries and returns one record from database.
+func (c *Core) GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) {
+ list, err := c.db.GetAll(ctx, sql, args...)
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ return list[0], nil
+ }
+ return nil, nil
+}
+
+// GetArray queries and returns data values as slice from database.
+// Note that if there are multiple columns in the result, it returns just one column values randomly.
+func (c *Core) GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) {
+ all, err := c.db.DoGetAll(ctx, nil, sql, args...)
+ if err != nil {
+ return nil, err
+ }
+ return all.Array(), nil
+}
+
+// GetStruct queries one record from database and converts it to given struct.
+// The parameter `pointer` should be a pointer to struct.
+func (c *Core) GetStruct(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error {
+ one, err := c.db.GetOne(ctx, sql, args...)
+ if err != nil {
+ return err
+ }
+ return one.Struct(pointer)
+}
+
+// GetStructs queries records from database and converts them to given struct.
+// The parameter `pointer` should be type of struct slice: []struct/[]*struct.
+func (c *Core) GetStructs(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error {
+ all, err := c.db.GetAll(ctx, sql, args...)
+ if err != nil {
+ return err
+ }
+ return all.Structs(pointer)
+}
+
+// GetScan queries one or more records from database and converts them to given struct or
+// struct array.
+//
+// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for
+// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
+// for conversion.
+func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error {
+ reflectInfo := utils.OriginTypeAndKind(pointer)
+ if reflectInfo.InputKind != reflect.Ptr {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "params should be type of pointer, but got: %v",
+ reflectInfo.InputKind,
+ )
+ }
+ switch reflectInfo.OriginKind {
+ case reflect.Array, reflect.Slice:
+ return c.db.GetCore().GetStructs(ctx, pointer, sql, args...)
+
+ case reflect.Struct:
+ return c.db.GetCore().GetStruct(ctx, pointer, sql, args...)
+ }
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `in valid parameter type "%v", of which element type should be type of struct/slice`,
+ reflectInfo.InputType,
+ )
+}
+
+// GetValue queries and returns the field value from database.
+// The sql should query only one field from database, or else it returns only one
+// field of the result.
+func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) {
+ one, err := c.db.GetOne(ctx, sql, args...)
+ if err != nil {
+ return gvar.New(nil), err
+ }
+ for _, v := range one {
+ return v, nil
+ }
+ return gvar.New(nil), nil
+}
+
+// GetCount queries and returns the count from database.
+func (c *Core) GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) {
+ // If the query fields do not contains function "COUNT",
+ // it replaces the sql string and adds the "COUNT" function to the fields.
+ if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) {
+ sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql)
+ }
+ value, err := c.db.GetValue(ctx, sql, args...)
+ if err != nil {
+ return 0, err
+ }
+ return value.Int(), nil
+}
+
+// Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement.
+func (c *Core) Union(unions ...*Model) *Model {
+ return c.doUnion(unionTypeNormal, unions...)
+}
+
+// UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement.
+func (c *Core) UnionAll(unions ...*Model) *Model {
+ return c.doUnion(unionTypeAll, unions...)
+}
+
+func (c *Core) doUnion(unionType int, unions ...*Model) *Model {
+ var (
+ unionTypeStr string
+ composedSqlStr string
+ composedArgs = make([]interface{}, 0)
+ )
+ if unionType == unionTypeAll {
+ unionTypeStr = "UNION ALL"
+ } else {
+ unionTypeStr = "UNION"
+ }
+ for _, v := range unions {
+ sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(queryTypeNormal, false)
+ if composedSqlStr == "" {
+ composedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder)
+ } else {
+ composedSqlStr += fmt.Sprintf(` %s (%s)`, unionTypeStr, sqlWithHolder)
+ }
+ composedArgs = append(composedArgs, holderArgs...)
+ }
+ return c.db.Raw(composedSqlStr, composedArgs...)
+}
+
+// PingMaster pings the master node to check authentication or keeps the connection alive.
+func (c *Core) PingMaster() error {
+ if master, err := c.db.Master(); err != nil {
+ return err
+ } else {
+ if err = master.PingContext(c.GetCtx()); err != nil {
+ err = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`)
+ }
+ return err
+ }
+}
+
+// PingSlave pings the slave node to check authentication or keeps the connection alive.
+func (c *Core) PingSlave() error {
+ if slave, err := c.db.Slave(); err != nil {
+ return err
+ } else {
+ if err = slave.PingContext(c.GetCtx()); err != nil {
+ err = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`)
+ }
+ return err
+ }
+}
+
+// Insert does "INSERT INTO ..." statement for the table.
+// If there's already one unique record of the data in the table, it returns error.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `batch` specifies the batch operation count when given data is slice.
+func (c *Core) Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Insert()
+ }
+ return c.Model(table).Ctx(ctx).Data(data).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
+// If there's already one unique record of the data in the table, it ignores the inserting.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `batch` specifies the batch operation count when given data is slice.
+func (c *Core) InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertIgnore()
+ }
+ return c.Model(table).Ctx(ctx).Data(data).InsertIgnore()
+}
+
+// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.
+func (c *Core) InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) {
+ if len(batch) > 0 {
+ return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertAndGetId()
+ }
+ return c.Model(table).Ctx(ctx).Data(data).InsertAndGetId()
+}
+
+// Replace does "REPLACE INTO ..." statement for the table.
+// If there's already one unique record of the data in the table, it deletes the record
+// and inserts a new one.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// If given data is type of slice, it then does batch replacing, and the optional parameter
+// `batch` specifies the batch operation count.
+func (c *Core) Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Replace()
+ }
+ return c.Model(table).Ctx(ctx).Data(data).Replace()
+}
+
+// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table.
+// It updates the record if there's primary or unique index in the saving data,
+// or else it inserts a new record into the table.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// If given data is type of slice, it then does batch saving, and the optional parameter
+// `batch` specifies the batch operation count.
+func (c *Core) Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Save()
+ }
+ return c.Model(table).Ctx(ctx).Data(data).Save()
+}
+
+// DoInsert inserts or updates data forF given table.
+// This function is usually used for custom interface definition, you do not need call it manually.
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `option` values are as follows:
+// 0: insert: just insert, if there's unique/primary key in the data, it returns error;
+// 1: replace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;
+// 2: save: if there's unique/primary key in the data, it updates it or else inserts a new one;
+// 3: ignore: if there's unique/primary key in the data, it ignores the inserting;
+func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) {
+ var (
+ keys []string // Field names.
+ values []string // Value holder string array, like: (?,?,?)
+ params []interface{} // Values that will be committed to underlying database driver.
+ onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement.
+ )
+ // Handle the field names and placeholders.
+ for k := range list[0] {
+ keys = append(keys, k)
+ }
+ // Prepare the batch result pointer.
+ var (
+ charL, charR = c.db.GetChars()
+ batchResult = new(SqlResult)
+ keysStr = charL + strings.Join(keys, charR+","+charL) + charR
+ operation = GetInsertOperationByOption(option.InsertOption)
+ )
+ if option.InsertOption == InsertOptionSave {
+ onDuplicateStr = c.formatOnDuplicate(keys, option)
+ }
+ var (
+ listLength = len(list)
+ valueHolder = make([]string, 0)
+ )
+ for i := 0; i < listLength; i++ {
+ values = values[:0]
+ // Note that the map type is unordered,
+ // so it should use slice+key to retrieve the value.
+ for _, k := range keys {
+ if s, ok := list[i][k].(Raw); ok {
+ values = append(values, gconv.String(s))
+ } else {
+ values = append(values, "?")
+ params = append(params, list[i][k])
+ }
+ }
+ valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")")
+ // Batch package checks: It meets the batch number, or it is the last element.
+ if len(valueHolder) == option.BatchCount || (i == listLength-1 && len(valueHolder) > 0) {
+ var (
+ stdSqlResult sql.Result
+ affectedRows int64
+ )
+ stdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf(
+ "%s INTO %s(%s) VALUES%s %s",
+ operation, c.QuotePrefixTableName(table), keysStr,
+ gstr.Join(valueHolder, ","),
+ onDuplicateStr,
+ ), params...)
+ if err != nil {
+ return stdSqlResult, err
+ }
+ if affectedRows, err = stdSqlResult.RowsAffected(); err != nil {
+ err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`)
+ return stdSqlResult, err
+ } else {
+ batchResult.Result = stdSqlResult
+ batchResult.Affected += affectedRows
+ }
+ params = params[:0]
+ valueHolder = valueHolder[:0]
+ }
+ }
+ return batchResult, nil
+}
+
+func (c *Core) formatOnDuplicate(columns []string, option DoInsertOption) string {
+ var onDuplicateStr string
+ if option.OnDuplicateStr != "" {
+ onDuplicateStr = option.OnDuplicateStr
+ } else if len(option.OnDuplicateMap) > 0 {
+ for k, v := range option.OnDuplicateMap {
+ if len(onDuplicateStr) > 0 {
+ onDuplicateStr += ","
+ }
+ switch v.(type) {
+ case Raw, *Raw:
+ onDuplicateStr += fmt.Sprintf(
+ "%s=%s",
+ c.QuoteWord(k),
+ v,
+ )
+ default:
+ onDuplicateStr += fmt.Sprintf(
+ "%s=VALUES(%s)",
+ c.QuoteWord(k),
+ c.QuoteWord(gconv.String(v)),
+ )
+ }
+ }
+ } else {
+ for _, column := range columns {
+ // If it's SAVE operation, do not automatically update the creating time.
+ if c.isSoftCreatedFieldName(column) {
+ continue
+ }
+ if len(onDuplicateStr) > 0 {
+ onDuplicateStr += ","
+ }
+ onDuplicateStr += fmt.Sprintf(
+ "%s=VALUES(%s)",
+ c.QuoteWord(column),
+ c.QuoteWord(column),
+ )
+ }
+ }
+ return fmt.Sprintf("ON DUPLICATE KEY UPDATE %s", onDuplicateStr)
+}
+
+// Update does "UPDATE ... " statement for the table.
+//
+// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.
+// Eg: "uid=10000", "uid", 10000, g.Map{"uid": 10000, "name":"john"}
+//
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
+// Eg:
+// "uid=10000",
+// "uid", 10000
+// "money>? AND name like ?", 99999, "vip_%"
+// "status IN (?)", g.Slice{1,2,3}
+// "age IN(?,?)", 18, 50
+// User{ Id : 1, UserName : "john"}.
+func (c *Core) Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
+ return c.Model(table).Ctx(ctx).Data(data).Where(condition, args...).Update()
+}
+
+// DoUpdate does "UPDATE ... " statement for the table.
+// This function is usually used for custom interface definition, you do not need to call it manually.
+func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
+ table = c.QuotePrefixTableName(table)
+ var (
+ rv = reflect.ValueOf(data)
+ kind = rv.Kind()
+ )
+ if kind == reflect.Ptr {
+ rv = rv.Elem()
+ kind = rv.Kind()
+ }
+ var (
+ params []interface{}
+ updates = ""
+ )
+ switch kind {
+ case reflect.Map, reflect.Struct:
+ var (
+ fields []string
+ dataMap = c.db.ConvertDataForRecord(ctx, data)
+ counterHandler = func(column string, counter Counter) {
+ if counter.Value != 0 {
+ column = c.QuoteWord(column)
+ var (
+ columnRef = c.QuoteWord(counter.Field)
+ columnVal = counter.Value
+ operator = "+"
+ )
+ if columnVal < 0 {
+ operator = "-"
+ columnVal = -columnVal
+ }
+ fields = append(fields, fmt.Sprintf("%s=%s%s?", column, columnRef, operator))
+ params = append(params, columnVal)
+ }
+ }
+ )
+
+ for k, v := range dataMap {
+ switch value := v.(type) {
+ case *Counter:
+ counterHandler(k, *value)
+
+ case Counter:
+ counterHandler(k, value)
+
+ default:
+ if s, ok := v.(Raw); ok {
+ fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s))
+ } else {
+ fields = append(fields, c.QuoteWord(k)+"=?")
+ params = append(params, v)
+ }
+ }
+ }
+ updates = strings.Join(fields, ",")
+
+ default:
+ updates = gconv.String(data)
+ }
+ if len(updates) == 0 {
+ return nil, gerror.NewCode(gcode.CodeMissingParameter, "data cannot be empty")
+ }
+ if len(params) > 0 {
+ args = append(params, args...)
+ }
+ // If no link passed, it then uses the master link.
+ if link == nil {
+ if link, err = c.MasterLink(); err != nil {
+ return nil, err
+ }
+ }
+ return c.db.DoExec(ctx, link, fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition), args...)
+}
+
+// Delete does "DELETE FROM ... " statement for the table.
+//
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
+// Eg:
+// "uid=10000",
+// "uid", 10000
+// "money>? AND name like ?", 99999, "vip_%"
+// "status IN (?)", g.Slice{1,2,3}
+// "age IN(?,?)", 18, 50
+// User{ Id : 1, UserName : "john"}.
+func (c *Core) Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (result sql.Result, err error) {
+ return c.Model(table).Ctx(ctx).Where(condition, args...).Delete()
+}
+
+// DoDelete does "DELETE FROM ... " statement for the table.
+// This function is usually used for custom interface definition, you do not need call it manually.
+func (c *Core) DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) {
+ if link == nil {
+ if link, err = c.MasterLink(); err != nil {
+ return nil, err
+ }
+ }
+ table = c.QuotePrefixTableName(table)
+ return c.db.DoExec(ctx, link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// It just returns the pointer address.
+//
+// Note that this interface implements mainly for workaround for a json infinite loop bug
+// of Golang version < v1.14.
+func (c Core) MarshalJSON() ([]byte, error) {
+ return []byte(fmt.Sprintf(`%+v`, c)), nil
+}
+
+// writeSqlToLogger outputs the Sql object to logger.
+// It is enabled only if configuration "debug" is true.
+func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {
+ var transactionIdStr string
+ if sql.IsTransaction {
+ if v := ctx.Value(transactionIdForLoggerCtx); v != nil {
+ transactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64))
+ }
+ }
+ s := fmt.Sprintf(
+ "[%3d ms] [%s] [rows:%-3d] %s%s",
+ sql.End-sql.Start, sql.Group, sql.RowsAffected, transactionIdStr, sql.Format,
+ )
+ if sql.Error != nil {
+ s += "\nError: " + sql.Error.Error()
+ c.logger.Error(ctx, s)
+ } else {
+ c.logger.Debug(ctx, s)
+ }
+}
+
+// HasTable determine whether the table name exists in the database.
+func (c *Core) HasTable(name string) (bool, error) {
+ result, err := c.GetCache().GetOrSetFuncLock(
+ c.GetCtx(),
+ fmt.Sprintf(`HasTable: %s`, name),
+ func(ctx context.Context) (interface{}, error) {
+ tableList, err := c.db.Tables(ctx)
+ if err != nil {
+ return false, err
+ }
+ for _, table := range tableList {
+ if table == name {
+ return true, nil
+ }
+ }
+ return false, nil
+ }, 0,
+ )
+ if err != nil {
+ return false, err
+ }
+ return result.Bool(), nil
+}
+
+// isSoftCreatedFieldName checks and returns whether given filed name is an automatic-filled created time.
+func (c *Core) isSoftCreatedFieldName(fieldName string) bool {
+ if fieldName == "" {
+ return false
+ }
+ if config := c.db.GetConfig(); config.CreatedAt != "" {
+ if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) {
+ return true
+ }
+ return gstr.InArray(append([]string{config.CreatedAt}, createdFiledNames...), fieldName)
+ }
+ for _, v := range createdFiledNames {
+ if utils.EqualFoldWithoutChars(fieldName, v) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_config.go
new file mode 100644
index 000000000000..451a14926936
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_config.go
@@ -0,0 +1,236 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/gogf/gf/v2/os/gcache"
+ "github.com/gogf/gf/v2/os/glog"
+)
+
+// Config is the configuration management object.
+type Config map[string]ConfigGroup
+
+// ConfigGroup is a slice of configuration node for specified named group.
+type ConfigGroup []ConfigNode
+
+// ConfigNode is configuration for one node.
+type ConfigNode struct {
+ Host string `json:"host"` // Host of server, ip or domain like: 127.0.0.1, localhost
+ Port string `json:"port"` // Port, it's commonly 3306.
+ User string `json:"user"` // Authentication username.
+ Pass string `json:"pass"` // Authentication password.
+ Name string `json:"name"` // Default used database name.
+ Type string `json:"type"` // Database type: mysql, sqlite, mssql, pgsql, oracle.
+ Link string `json:"link"` // (Optional) Custom link information, when it is used, configuration Host/Port/User/Pass/Name are ignored.
+ Role string `json:"role"` // (Optional, "master" in default) Node role, used for master-slave mode: master, slave.
+ Debug bool `json:"debug"` // (Optional) Debug mode enables debug information logging and output.
+ Prefix string `json:"prefix"` // (Optional) Table prefix.
+ DryRun bool `json:"dryRun"` // (Optional) Dry run, which does SELECT but no INSERT/UPDATE/DELETE statements.
+ Weight int `json:"weight"` // (Optional) Weight for load balance calculating, it's useless if there's just one node.
+ Charset string `json:"charset"` // (Optional, "utf8mb4" in default) Custom charset when operating on database.
+ Timezone string `json:"timezone"` // (Optional) Sets the time zone for displaying and interpreting time stamps.
+ MaxIdleConnCount int `json:"maxIdle"` // (Optional) Max idle connection configuration for underlying connection pool.
+ MaxOpenConnCount int `json:"maxOpen"` // (Optional) Max open connection configuration for underlying connection pool.
+ MaxConnLifeTime time.Duration `json:"maxLifeTime"` // (Optional) Max amount of time a connection may be idle before being closed.
+ QueryTimeout time.Duration `json:"queryTimeout"` // (Optional) Max query time for per dql.
+ ExecTimeout time.Duration `json:"execTimeout"` // (Optional) Max exec time for dml.
+ TranTimeout time.Duration `json:"tranTimeout"` // (Optional) Max exec time time for a transaction.
+ PrepareTimeout time.Duration `json:"prepareTimeout"` // (Optional) Max exec time time for prepare operation.
+ CreatedAt string `json:"createdAt"` // (Optional) The filed name of table for automatic-filled created datetime.
+ UpdatedAt string `json:"updatedAt"` // (Optional) The filed name of table for automatic-filled updated datetime.
+ DeletedAt string `json:"deletedAt"` // (Optional) The filed name of table for automatic-filled updated datetime.
+ TimeMaintainDisabled bool `json:"timeMaintainDisabled"` // (Optional) Disable the automatic time maintaining feature.
+}
+
+const (
+ DefaultGroupName = "default" // Default group name.
+)
+
+// configs is internal used configuration object.
+var configs struct {
+ sync.RWMutex
+ config Config // All configurations.
+ group string // Default configuration group.
+}
+
+func init() {
+ configs.config = make(Config)
+ configs.group = DefaultGroupName
+}
+
+// SetConfig sets the global configuration for package.
+// It will overwrite the old configuration of package.
+func SetConfig(config Config) {
+ defer instances.Clear()
+ configs.Lock()
+ defer configs.Unlock()
+ configs.config = config
+}
+
+// SetConfigGroup sets the configuration for given group.
+func SetConfigGroup(group string, nodes ConfigGroup) {
+ defer instances.Clear()
+ configs.Lock()
+ defer configs.Unlock()
+ configs.config[group] = nodes
+}
+
+// AddConfigNode adds one node configuration to configuration of given group.
+func AddConfigNode(group string, node ConfigNode) {
+ defer instances.Clear()
+ configs.Lock()
+ defer configs.Unlock()
+ configs.config[group] = append(configs.config[group], node)
+}
+
+// AddDefaultConfigNode adds one node configuration to configuration of default group.
+func AddDefaultConfigNode(node ConfigNode) {
+ AddConfigNode(DefaultGroupName, node)
+}
+
+// AddDefaultConfigGroup adds multiple node configurations to configuration of default group.
+func AddDefaultConfigGroup(nodes ConfigGroup) {
+ SetConfigGroup(DefaultGroupName, nodes)
+}
+
+// GetConfig retrieves and returns the configuration of given group.
+func GetConfig(group string) ConfigGroup {
+ configs.RLock()
+ defer configs.RUnlock()
+ return configs.config[group]
+}
+
+// SetDefaultGroup sets the group name for default configuration.
+func SetDefaultGroup(name string) {
+ defer instances.Clear()
+ configs.Lock()
+ defer configs.Unlock()
+ configs.group = name
+}
+
+// GetDefaultGroup returns the { name of default configuration.
+func GetDefaultGroup() string {
+ defer instances.Clear()
+ configs.RLock()
+ defer configs.RUnlock()
+ return configs.group
+}
+
+// IsConfigured checks and returns whether the database configured.
+// It returns true if any configuration exists.
+func IsConfigured() bool {
+ configs.RLock()
+ defer configs.RUnlock()
+ return len(configs.config) > 0
+}
+
+// SetLogger sets the logger for orm.
+func (c *Core) SetLogger(logger *glog.Logger) {
+ c.logger = logger
+}
+
+// GetLogger returns the (logger) of the orm.
+func (c *Core) GetLogger() *glog.Logger {
+ return c.logger
+}
+
+// SetMaxIdleConnCount sets the maximum number of connections in the idle
+// connection pool.
+//
+// If MaxOpenConns is greater than 0 but less than the new MaxIdleConns,
+// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.
+//
+// If n <= 0, no idle connections are retained.
+//
+// The default max idle connections is currently 2. This may change in
+// a future release.
+func (c *Core) SetMaxIdleConnCount(n int) {
+ c.config.MaxIdleConnCount = n
+}
+
+// SetMaxOpenConnCount sets the maximum number of open connections to the database.
+//
+// If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than
+// MaxIdleConns, then MaxIdleConns will be reduced to match the new
+// MaxOpenConns limit.
+//
+// If n <= 0, then there is no limit on the number of open connections.
+// The default is 0 (unlimited).
+func (c *Core) SetMaxOpenConnCount(n int) {
+ c.config.MaxOpenConnCount = n
+}
+
+// SetMaxConnLifeTime sets the maximum amount of time a connection may be reused.
+//
+// Expired connections may be closed lazily before reuse.
+//
+// If d <= 0, connections are not closed due to a connection's age.
+func (c *Core) SetMaxConnLifeTime(d time.Duration) {
+ c.config.MaxConnLifeTime = d
+}
+
+// String returns the node as string.
+func (node *ConfigNode) String() string {
+ return fmt.Sprintf(
+ `%s@%s:%s,%s,%s,%s,%s,%v,%d-%d-%d#%s`,
+ node.User, node.Host, node.Port,
+ node.Name, node.Type, node.Role, node.Charset, node.Debug,
+ node.MaxIdleConnCount,
+ node.MaxOpenConnCount,
+ node.MaxConnLifeTime,
+ node.Link,
+ )
+}
+
+// GetConfig returns the current used node configuration.
+func (c *Core) GetConfig() *ConfigNode {
+ return c.config
+}
+
+// SetDebug enables/disables the debug mode.
+func (c *Core) SetDebug(debug bool) {
+ c.debug.Set(debug)
+}
+
+// GetDebug returns the debug value.
+func (c *Core) GetDebug() bool {
+ return c.debug.Val()
+}
+
+// GetCache returns the internal cache object.
+func (c *Core) GetCache() *gcache.Cache {
+ return c.cache
+}
+
+// GetGroup returns the group string configured.
+func (c *Core) GetGroup() string {
+ return c.group
+}
+
+// SetDryRun enables/disables the DryRun feature.
+func (c *Core) SetDryRun(enabled bool) {
+ c.config.DryRun = enabled
+}
+
+// GetDryRun returns the DryRun value.
+func (c *Core) GetDryRun() bool {
+ return c.config.DryRun || allDryRun
+}
+
+// GetPrefix returns the table prefix string configured.
+func (c *Core) GetPrefix() string {
+ return c.config.Prefix
+}
+
+// GetSchema returns the schema configured.
+func (c *Core) GetSchema() string {
+ return c.schema
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_link.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_link.go
new file mode 100644
index 000000000000..06ea3190b27a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_link.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+)
+
+// dbLink is used to implement interface Link for DB.
+type dbLink struct {
+ *sql.DB
+}
+
+// txLink is used to implement interface Link for TX.
+type txLink struct {
+ *sql.Tx
+}
+
+// IsTransaction returns if current Link is a transaction.
+func (*dbLink) IsTransaction() bool {
+ return false
+}
+
+// IsTransaction returns if current Link is a transaction.
+func (*txLink) IsTransaction() bool {
+ return true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_structure.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_structure.go
new file mode 100644
index 000000000000..ca60f6906533
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_structure.go
@@ -0,0 +1,253 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "context"
+ "reflect"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/encoding/gbinary"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// ConvertDataForRecord is a very important function, which does converting for any data that
+// will be inserted into table/collection as a record.
+//
+// The parameter `value` should be type of *map/map/*struct/struct.
+// It supports embedded struct definition for struct.
+func (c *Core) ConvertDataForRecord(ctx context.Context, value interface{}) map[string]interface{} {
+ var data = DataToMapDeep(value)
+ for k, v := range data {
+ data[k] = c.ConvertDataForRecordValue(ctx, v)
+ }
+ return data
+}
+
+func (c *Core) ConvertDataForRecordValue(ctx context.Context, value interface{}) interface{} {
+ var (
+ rvValue = reflect.ValueOf(value)
+ rvKind = rvValue.Kind()
+ )
+ for rvKind == reflect.Ptr {
+ rvValue = rvValue.Elem()
+ rvKind = rvValue.Kind()
+ }
+ switch rvKind {
+ case reflect.Slice, reflect.Array, reflect.Map:
+ // It should ignore the bytes type.
+ if _, ok := value.([]byte); !ok {
+ // Convert the value to JSON.
+ value, _ = json.Marshal(value)
+ }
+
+ case reflect.Struct:
+ switch r := value.(type) {
+ // If the time is zero, it then updates it to nil,
+ // which will insert/update the value to database as "null".
+ case time.Time:
+ if r.IsZero() {
+ value = nil
+ }
+
+ case gtime.Time:
+ if r.IsZero() {
+ value = nil
+ }
+
+ case *gtime.Time:
+ if r.IsZero() {
+ value = nil
+ }
+
+ case *time.Time:
+ // Nothing to do.
+
+ case Counter, *Counter:
+ // Nothing to do.
+
+ default:
+ // Use string conversion in default.
+ if s, ok := value.(iString); ok {
+ value = s.String()
+ } else {
+ // Convert the value to JSON.
+ value, _ = json.Marshal(value)
+ }
+ }
+ }
+ return value
+}
+
+// convertFieldValueToLocalValue automatically checks and converts field value from database type
+// to golang variable type as underlying value of Value.
+func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType string) interface{} {
+ // If there's no type retrieved, it returns the `fieldValue` directly
+ // to use its original data type, as `fieldValue` is type of interface{}.
+ if fieldType == "" {
+ return fieldValue
+ }
+ typeName, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
+ typeName = strings.ToLower(typeName)
+ switch typeName {
+ case
+ "binary",
+ "varbinary",
+ "blob",
+ "tinyblob",
+ "mediumblob",
+ "longblob":
+ return gconv.Bytes(fieldValue)
+
+ case
+ "int",
+ "tinyint",
+ "small_int",
+ "smallint",
+ "medium_int",
+ "mediumint",
+ "serial":
+ if gstr.ContainsI(fieldType, "unsigned") {
+ gconv.Uint(gconv.String(fieldValue))
+ }
+ return gconv.Int(gconv.String(fieldValue))
+
+ case
+ "int8", // For pgsql, int8 = bigint.
+ "big_int",
+ "bigint",
+ "bigserial":
+ if gstr.ContainsI(fieldType, "unsigned") {
+ gconv.Uint64(gconv.String(fieldValue))
+ }
+ return gconv.Int64(gconv.String(fieldValue))
+
+ case "real":
+ return gconv.Float32(gconv.String(fieldValue))
+
+ case
+ "float",
+ "double",
+ "decimal",
+ "money",
+ "numeric",
+ "smallmoney":
+ return gconv.Float64(gconv.String(fieldValue))
+
+ case "bit":
+ s := gconv.String(fieldValue)
+ // mssql is true|false string.
+ if strings.EqualFold(s, "true") {
+ return 1
+ }
+ if strings.EqualFold(s, "false") {
+ return 0
+ }
+ return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue))
+
+ case "bool":
+ return gconv.Bool(fieldValue)
+
+ case "date":
+ // Date without time.
+ if t, ok := fieldValue.(time.Time); ok {
+ return gtime.NewFromTime(t).Format("Y-m-d")
+ }
+ t, _ := gtime.StrToTime(gconv.String(fieldValue))
+ return t.Format("Y-m-d")
+
+ case
+ "datetime",
+ "timestamp",
+ "timestamptz":
+ if t, ok := fieldValue.(time.Time); ok {
+ return gtime.NewFromTime(t)
+ }
+ t, _ := gtime.StrToTime(gconv.String(fieldValue))
+ return t
+
+ default:
+ // Auto-detect field type, using key match.
+ switch {
+ case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"):
+ return gconv.String(fieldValue)
+
+ case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
+ return gconv.Float64(gconv.String(fieldValue))
+
+ case strings.Contains(typeName, "bool"):
+ return gconv.Bool(gconv.String(fieldValue))
+
+ case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
+ return fieldValue
+
+ case strings.Contains(typeName, "int"):
+ return gconv.Int(gconv.String(fieldValue))
+
+ case strings.Contains(typeName, "time"):
+ s := gconv.String(fieldValue)
+ t, err := gtime.StrToTime(s)
+ if err != nil {
+ return s
+ }
+ return t
+
+ case strings.Contains(typeName, "date"):
+ s := gconv.String(fieldValue)
+ t, err := gtime.StrToTime(s)
+ if err != nil {
+ return s
+ }
+ return t
+
+ default:
+ return gconv.String(fieldValue)
+ }
+ }
+}
+
+// mappingAndFilterData automatically mappings the map key to table field and removes
+// all key-value pairs that are not the field of given table.
+func (c *Core) mappingAndFilterData(schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) {
+ fieldsMap, err := c.TableFields(c.guessPrimaryTableName(table), schema)
+ if err != nil {
+ return nil, err
+ }
+ fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
+ for k := range fieldsMap {
+ fieldsKeyMap[k] = nil
+ }
+ // Automatic data key to table field name mapping.
+ var foundKey string
+ for dataKey, dataValue := range data {
+ if _, ok := fieldsKeyMap[dataKey]; !ok {
+ foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey)
+ if foundKey != "" {
+ if _, ok = data[foundKey]; !ok {
+ data[foundKey] = dataValue
+ }
+ delete(data, dataKey)
+ }
+ }
+ }
+ // Data filtering.
+ // It deletes all key-value pairs that has incorrect field name.
+ if filter {
+ for dataKey := range data {
+ if _, ok := fieldsMap[dataKey]; !ok {
+ delete(data, dataKey)
+ }
+ }
+ }
+ return data, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_trace.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_trace.go
new file mode 100644
index 000000000000..020fe928a8b6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_trace.go
@@ -0,0 +1,86 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gdb
+
+import (
+ "context"
+ "fmt"
+
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/semconv/v1.4.0"
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2/net/gtrace"
+)
+
+const (
+ traceInstrumentName = "github.com/gogf/gf/v2/database/gdb"
+ traceAttrDbType = "db.type"
+ traceAttrDbHost = "db.host"
+ traceAttrDbPort = "db.port"
+ traceAttrDbName = "db.name"
+ traceAttrDbUser = "db.user"
+ traceAttrDbLink = "db.link"
+ traceAttrDbGroup = "db.group"
+ traceEventDbExecution = "db.execution"
+ traceEventDbExecutionSql = "db.execution.sql"
+ traceEventDbExecutionCost = "db.execution.cost"
+ traceEventDbExecutionRows = "db.execution.rows"
+ traceEventDbExecutionTxID = "db.execution.txid"
+ traceEventDbExecutionType = "db.execution.type"
+)
+
+// addSqlToTracing adds sql information to tracer if it's enabled.
+func (c *Core) traceSpanEnd(ctx context.Context, span trace.Span, sql *Sql) {
+ if gtrace.IsUsingDefaultProvider() || !gtrace.IsTracingInternal() {
+ return
+ }
+ if sql.Error != nil {
+ span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, sql.Error))
+ }
+ labels := make([]attribute.KeyValue, 0)
+ labels = append(labels, gtrace.CommonLabels()...)
+ labels = append(labels,
+ attribute.String(traceAttrDbType, c.db.GetConfig().Type),
+ semconv.DBStatementKey.String(sql.Format),
+ )
+ if c.db.GetConfig().Host != "" {
+ labels = append(labels, attribute.String(traceAttrDbHost, c.db.GetConfig().Host))
+ }
+ if c.db.GetConfig().Port != "" {
+ labels = append(labels, attribute.String(traceAttrDbPort, c.db.GetConfig().Port))
+ }
+ if c.db.GetConfig().Name != "" {
+ labels = append(labels, attribute.String(traceAttrDbName, c.db.GetConfig().Name))
+ }
+ if c.db.GetConfig().User != "" {
+ labels = append(labels, attribute.String(traceAttrDbUser, c.db.GetConfig().User))
+ }
+ if filteredLink := c.db.FilteredLink(); filteredLink != "" {
+ labels = append(labels, attribute.String(traceAttrDbLink, c.db.FilteredLink()))
+ }
+ if group := c.db.GetGroup(); group != "" {
+ labels = append(labels, attribute.String(traceAttrDbGroup, group))
+ }
+ span.SetAttributes(labels...)
+ events := []attribute.KeyValue{
+ attribute.String(traceEventDbExecutionSql, sql.Format),
+ attribute.String(traceEventDbExecutionCost, fmt.Sprintf(`%d ms`, sql.End-sql.Start)),
+ attribute.String(traceEventDbExecutionRows, fmt.Sprintf(`%d`, sql.RowsAffected)),
+ }
+ if sql.IsTransaction {
+ if v := ctx.Value(transactionIdForLoggerCtx); v != nil {
+ events = append(events, attribute.String(
+ traceEventDbExecutionTxID, fmt.Sprintf(`%d`, v.(uint64)),
+ ))
+ }
+ }
+ events = append(events, attribute.String(traceEventDbExecutionType, sql.Type))
+ span.AddEvent(traceEventDbExecution, trace.WithAttributes(events...))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_transaction.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_transaction.go
new file mode 100644
index 000000000000..7dcad387396d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_transaction.go
@@ -0,0 +1,500 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "context"
+ "database/sql"
+ "reflect"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// TX is the struct for transaction management.
+type TX struct {
+ db DB // db is the current gdb database manager.
+ tx *sql.Tx // tx is the raw and underlying transaction manager.
+ ctx context.Context // ctx is the context for this transaction only.
+ master *sql.DB // master is the raw and underlying database manager.
+ transactionId string // transactionId is a unique id generated by this object for this transaction.
+ transactionCount int // transactionCount marks the times that Begins.
+ isClosed bool // isClosed marks this transaction has already been committed or rolled back.
+}
+
+const (
+ transactionPointerPrefix = "transaction"
+ contextTransactionKeyPrefix = "TransactionObjectForGroup_"
+ transactionIdForLoggerCtx = "TransactionId"
+)
+
+var transactionIdGenerator = gtype.NewUint64()
+
+// Begin starts and returns the transaction object.
+// You should call Commit or Rollback functions of the transaction object
+// if you no longer use the transaction. Commit or Rollback functions will also
+// close the transaction automatically.
+func (c *Core) Begin(ctx context.Context) (tx *TX, err error) {
+ return c.doBeginCtx(ctx)
+}
+
+func (c *Core) doBeginCtx(ctx context.Context) (*TX, error) {
+ master, err := c.db.Master()
+ if err != nil {
+ return nil, err
+ }
+ var out DoCommitOutput
+ out, err = c.db.DoCommit(ctx, DoCommitInput{
+ Db: master,
+ Sql: "BEGIN",
+ Type: SqlTypeBegin,
+ IsTransaction: true,
+ })
+ return out.Tx, err
+}
+
+// Transaction wraps the transaction logic using function `f`.
+// It rollbacks the transaction and returns the error from function `f` if
+// it returns non-nil error. It commits the transaction and returns nil if
+// function `f` returns nil.
+//
+// Note that, you should not Commit or Rollback the transaction in function `f`
+// as it is automatically handled by this function.
+func (c *Core) Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) (err error) {
+ var tx *TX
+ if ctx == nil {
+ ctx = c.GetCtx()
+ }
+ // Check transaction object from context.
+ tx = TXFromCtx(ctx, c.db.GetGroup())
+ if tx != nil {
+ return tx.Transaction(ctx, f)
+ }
+ tx, err = c.doBeginCtx(ctx)
+ if err != nil {
+ return err
+ }
+ // Inject transaction object into context.
+ tx.ctx = WithTX(tx.ctx, tx)
+ defer func() {
+ if err == nil {
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.Newf("%+v", exception)
+ }
+ }
+ }
+ if err != nil {
+ if e := tx.Rollback(); e != nil {
+ err = e
+ }
+ } else {
+ if e := tx.Commit(); e != nil {
+ err = e
+ }
+ }
+ }()
+ err = f(tx.ctx, tx)
+ return
+}
+
+// WithTX injects given transaction object into context and returns a new context.
+func WithTX(ctx context.Context, tx *TX) context.Context {
+ if tx == nil {
+ return ctx
+ }
+ // Check repeat injection from given.
+ group := tx.db.GetGroup()
+ if ctxTx := TXFromCtx(ctx, group); ctxTx != nil && ctxTx.db.GetGroup() == group {
+ return ctx
+ }
+ dbCtx := tx.db.GetCtx()
+ if ctxTx := TXFromCtx(dbCtx, group); ctxTx != nil && ctxTx.db.GetGroup() == group {
+ return dbCtx
+ }
+ // Inject transaction object and id into context.
+ ctx = context.WithValue(ctx, transactionKeyForContext(group), tx)
+ return ctx
+}
+
+// TXFromCtx retrieves and returns transaction object from context.
+// It is usually used in nested transaction feature, and it returns nil if it is not set previously.
+func TXFromCtx(ctx context.Context, group string) *TX {
+ if ctx == nil {
+ return nil
+ }
+ v := ctx.Value(transactionKeyForContext(group))
+ if v != nil {
+ tx := v.(*TX)
+ if tx.IsClosed() {
+ return nil
+ }
+ tx.ctx = ctx
+ return tx
+ }
+ return nil
+}
+
+// transactionKeyForContext forms and returns a string for storing transaction object of certain database group into context.
+func transactionKeyForContext(group string) string {
+ return contextTransactionKeyPrefix + group
+}
+
+// transactionKeyForNestedPoint forms and returns the transaction key at current save point.
+func (tx *TX) transactionKeyForNestedPoint() string {
+ return tx.db.GetCore().QuoteWord(transactionPointerPrefix + gconv.String(tx.transactionCount))
+}
+
+// Ctx sets the context for current transaction.
+func (tx *TX) Ctx(ctx context.Context) *TX {
+ tx.ctx = ctx
+ return tx
+}
+
+// Commit commits current transaction.
+// Note that it releases previous saved transaction point if it's in a nested transaction procedure,
+// or else it commits the hole transaction.
+func (tx *TX) Commit() error {
+ if tx.transactionCount > 0 {
+ tx.transactionCount--
+ _, err := tx.Exec("RELEASE SAVEPOINT " + tx.transactionKeyForNestedPoint())
+ return err
+ }
+ _, err := tx.db.DoCommit(tx.ctx, DoCommitInput{
+ Tx: tx.tx,
+ Sql: "COMMIT",
+ Type: SqlTypeTXCommit,
+ IsTransaction: true,
+ })
+ if err == nil {
+ tx.isClosed = true
+ }
+ return err
+}
+
+// Rollback aborts current transaction.
+// Note that it aborts current transaction if it's in a nested transaction procedure,
+// or else it aborts the hole transaction.
+func (tx *TX) Rollback() error {
+ if tx.transactionCount > 0 {
+ tx.transactionCount--
+ _, err := tx.Exec("ROLLBACK TO SAVEPOINT " + tx.transactionKeyForNestedPoint())
+ return err
+ }
+ _, err := tx.db.DoCommit(tx.ctx, DoCommitInput{
+ Tx: tx.tx,
+ Sql: "ROLLBACK",
+ Type: SqlTypeTXRollback,
+ IsTransaction: true,
+ })
+ if err == nil {
+ tx.isClosed = true
+ }
+ return err
+}
+
+// IsClosed checks and returns this transaction has already been committed or rolled back.
+func (tx *TX) IsClosed() bool {
+ return tx.isClosed
+}
+
+// Begin starts a nested transaction procedure.
+func (tx *TX) Begin() error {
+ _, err := tx.Exec("SAVEPOINT " + tx.transactionKeyForNestedPoint())
+ if err != nil {
+ return err
+ }
+ tx.transactionCount++
+ return nil
+}
+
+// SavePoint performs `SAVEPOINT xxx` SQL statement that saves transaction at current point.
+// The parameter `point` specifies the point name that will be saved to server.
+func (tx *TX) SavePoint(point string) error {
+ _, err := tx.Exec("SAVEPOINT " + tx.db.GetCore().QuoteWord(point))
+ return err
+}
+
+// RollbackTo performs `ROLLBACK TO SAVEPOINT xxx` SQL statement that rollbacks to specified saved transaction.
+// The parameter `point` specifies the point name that was saved previously.
+func (tx *TX) RollbackTo(point string) error {
+ _, err := tx.Exec("ROLLBACK TO SAVEPOINT " + tx.db.GetCore().QuoteWord(point))
+ return err
+}
+
+// Transaction wraps the transaction logic using function `f`.
+// It rollbacks the transaction and returns the error from function `f` if
+// it returns non-nil error. It commits the transaction and returns nil if
+// function `f` returns nil.
+//
+// Note that, you should not Commit or Rollback the transaction in function `f`
+// as it is automatically handled by this function.
+func (tx *TX) Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) (err error) {
+ if ctx != nil {
+ tx.ctx = ctx
+ }
+ // Check transaction object from context.
+ if TXFromCtx(tx.ctx, tx.db.GetGroup()) == nil {
+ // Inject transaction object into context.
+ tx.ctx = WithTX(tx.ctx, tx)
+ }
+ err = tx.Begin()
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err == nil {
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.Newf("%+v", exception)
+ }
+ }
+ }
+ if err != nil {
+ if e := tx.Rollback(); e != nil {
+ err = e
+ }
+ } else {
+ if e := tx.Commit(); e != nil {
+ err = e
+ }
+ }
+ }()
+ err = f(tx.ctx, tx)
+ return
+}
+
+// Query does query operation on transaction.
+// See Core.Query.
+func (tx *TX) Query(sql string, args ...interface{}) (result Result, err error) {
+ return tx.db.DoQuery(tx.ctx, &txLink{tx.tx}, sql, args...)
+}
+
+// Exec does none query operation on transaction.
+// See Core.Exec.
+func (tx *TX) Exec(sql string, args ...interface{}) (sql.Result, error) {
+ return tx.db.DoExec(tx.ctx, &txLink{tx.tx}, sql, args...)
+}
+
+// Prepare creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the
+// returned statement.
+// The caller must call the statement's Close method
+// when the statement is no longer needed.
+func (tx *TX) Prepare(sql string) (*Stmt, error) {
+ return tx.db.DoPrepare(tx.ctx, &txLink{tx.tx}, sql)
+}
+
+// GetAll queries and returns data records from database.
+func (tx *TX) GetAll(sql string, args ...interface{}) (Result, error) {
+ return tx.Query(sql, args...)
+}
+
+// GetOne queries and returns one record from database.
+func (tx *TX) GetOne(sql string, args ...interface{}) (Record, error) {
+ list, err := tx.GetAll(sql, args...)
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ return list[0], nil
+ }
+ return nil, nil
+}
+
+// GetStruct queries one record from database and converts it to given struct.
+// The parameter `pointer` should be a pointer to struct.
+func (tx *TX) GetStruct(obj interface{}, sql string, args ...interface{}) error {
+ one, err := tx.GetOne(sql, args...)
+ if err != nil {
+ return err
+ }
+ return one.Struct(obj)
+}
+
+// GetStructs queries records from database and converts them to given struct.
+// The parameter `pointer` should be type of struct slice: []struct/[]*struct.
+func (tx *TX) GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error {
+ all, err := tx.GetAll(sql, args...)
+ if err != nil {
+ return err
+ }
+ return all.Structs(objPointerSlice)
+}
+
+// GetScan queries one or more records from database and converts them to given struct or
+// struct array.
+//
+// If parameter `pointer` is type of struct pointer, it calls GetStruct internally for
+// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
+// for conversion.
+func (tx *TX) GetScan(pointer interface{}, sql string, args ...interface{}) error {
+ reflectInfo := utils.OriginTypeAndKind(pointer)
+ if reflectInfo.InputKind != reflect.Ptr {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "params should be type of pointer, but got: %v",
+ reflectInfo.InputKind,
+ )
+ }
+ switch reflectInfo.OriginKind {
+ case reflect.Array, reflect.Slice:
+ return tx.GetStructs(pointer, sql, args...)
+
+ case reflect.Struct:
+ return tx.GetStruct(pointer, sql, args...)
+ }
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `in valid parameter type "%v", of which element type should be type of struct/slice`,
+ reflectInfo.InputType,
+ )
+}
+
+// GetValue queries and returns the field value from database.
+// The sql should query only one field from database, or else it returns only one
+// field of the result.
+func (tx *TX) GetValue(sql string, args ...interface{}) (Value, error) {
+ one, err := tx.GetOne(sql, args...)
+ if err != nil {
+ return nil, err
+ }
+ for _, v := range one {
+ return v, nil
+ }
+ return nil, nil
+}
+
+// GetCount queries and returns the count from database.
+func (tx *TX) GetCount(sql string, args ...interface{}) (int, error) {
+ if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) {
+ sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql)
+ }
+ value, err := tx.GetValue(sql, args...)
+ if err != nil {
+ return 0, err
+ }
+ return value.Int(), nil
+}
+
+// Insert does "INSERT INTO ..." statement for the table.
+// If there's already one unique record of the data in the table, it returns error.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `batch` specifies the batch operation count when given data is slice.
+func (tx *TX) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Insert()
+ }
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Insert()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for the table.
+// If there's already one unique record of the data in the table, it ignores the inserting.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `batch` specifies the batch operation count when given data is slice.
+func (tx *TX) InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).InsertIgnore()
+ }
+ return tx.Model(table).Ctx(tx.ctx).Data(data).InsertIgnore()
+}
+
+// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.
+func (tx *TX) InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) {
+ if len(batch) > 0 {
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).InsertAndGetId()
+ }
+ return tx.Model(table).Ctx(tx.ctx).Data(data).InsertAndGetId()
+}
+
+// Replace does "REPLACE INTO ..." statement for the table.
+// If there's already one unique record of the data in the table, it deletes the record
+// and inserts a new one.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// If given data is type of slice, it then does batch replacing, and the optional parameter
+// `batch` specifies the batch operation count.
+func (tx *TX) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Replace()
+ }
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Replace()
+}
+
+// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table.
+// It updates the record if there's primary or unique index in the saving data,
+// or else it inserts a new record into the table.
+//
+// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
+// Eg:
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+//
+// If given data is type of slice, it then does batch saving, and the optional parameter
+// `batch` specifies the batch operation count.
+func (tx *TX) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
+ if len(batch) > 0 {
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Batch(batch[0]).Save()
+ }
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Save()
+}
+
+// Update does "UPDATE ... " statement for the table.
+//
+// The parameter `data` can be type of string/map/gmap/struct/*struct, etc.
+// Eg: "uid=10000", "uid", 10000, g.Map{"uid": 10000, "name":"john"}
+//
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
+// Eg:
+// "uid=10000",
+// "uid", 10000
+// "money>? AND name like ?", 99999, "vip_%"
+// "status IN (?)", g.Slice{1,2,3}
+// "age IN(?,?)", 18, 50
+// User{ Id : 1, UserName : "john"}.
+func (tx *TX) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
+ return tx.Model(table).Ctx(tx.ctx).Data(data).Where(condition, args...).Update()
+}
+
+// Delete does "DELETE FROM ... " statement for the table.
+//
+// The parameter `condition` can be type of string/map/gmap/slice/struct/*struct, etc.
+// It is commonly used with parameter `args`.
+// Eg:
+// "uid=10000",
+// "uid", 10000
+// "money>? AND name like ?", 99999, "vip_%"
+// "status IN (?)", g.Slice{1,2,3}
+// "age IN(?,?)", 18, 50
+// User{ Id : 1, UserName : "john"}.
+func (tx *TX) Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) {
+ return tx.Model(table).Ctx(tx.ctx).Where(condition, args...).Delete()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_underlying.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_underlying.go
new file mode 100644
index 000000000000..60a255c9a815
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_underlying.go
@@ -0,0 +1,378 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gdb
+
+import (
+ "context"
+ "database/sql"
+
+ "github.com/gogf/gf/v2"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/util/guid"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// Query commits one query SQL to underlying driver and returns the execution result.
+// It is most commonly used for data querying.
+func (c *Core) Query(ctx context.Context, sql string, args ...interface{}) (result Result, err error) {
+ return c.db.DoQuery(ctx, nil, sql, args...)
+}
+
+// DoQuery commits the sql string and its arguments to underlying driver
+// through given link object and returns the execution result.
+func (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) {
+ // Transaction checks.
+ if link == nil {
+ if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
+ // Firstly, check and retrieve transaction link from context.
+ link = &txLink{tx.tx}
+ } else if link, err = c.SlaveLink(); err != nil {
+ // Or else it creates one from master node.
+ return nil, err
+ }
+ } else if !link.IsTransaction() {
+ // If current link is not transaction link, it checks and retrieves transaction from context.
+ if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
+ link = &txLink{tx.tx}
+ }
+ }
+
+ if c.GetConfig().QueryTimeout > 0 {
+ ctx, _ = context.WithTimeout(ctx, c.GetConfig().QueryTimeout)
+ }
+
+ // Sql filtering.
+ sql, args = formatSql(sql, args)
+ sql, args, err = c.db.DoFilter(ctx, link, sql, args)
+ if err != nil {
+ return nil, err
+ }
+ // Link execution.
+ var out DoCommitOutput
+ out, err = c.db.DoCommit(ctx, DoCommitInput{
+ Link: link,
+ Sql: sql,
+ Args: args,
+ Stmt: nil,
+ Type: SqlTypeQueryContext,
+ IsTransaction: link.IsTransaction(),
+ })
+ return out.Records, err
+}
+
+// Exec commits one query SQL to underlying driver and returns the execution result.
+// It is most commonly used for data inserting and updating.
+func (c *Core) Exec(ctx context.Context, sql string, args ...interface{}) (result sql.Result, err error) {
+ return c.db.DoExec(ctx, nil, sql, args...)
+}
+
+// DoExec commits the sql string and its arguments to underlying driver
+// through given link object and returns the execution result.
+func (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) {
+ // Transaction checks.
+ if link == nil {
+ if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
+ // Firstly, check and retrieve transaction link from context.
+ link = &txLink{tx.tx}
+ } else if link, err = c.MasterLink(); err != nil {
+ // Or else it creates one from master node.
+ return nil, err
+ }
+ } else if !link.IsTransaction() {
+ // If current link is not transaction link, it checks and retrieves transaction from context.
+ if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
+ link = &txLink{tx.tx}
+ }
+ }
+
+ if c.GetConfig().ExecTimeout > 0 {
+ var cancelFunc context.CancelFunc
+ ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().ExecTimeout)
+ defer cancelFunc()
+ }
+
+ // Sql filtering.
+ sql, args = formatSql(sql, args)
+ sql, args, err = c.db.DoFilter(ctx, link, sql, args)
+ if err != nil {
+ return nil, err
+ }
+ // Link execution.
+ var out DoCommitOutput
+ out, err = c.db.DoCommit(ctx, DoCommitInput{
+ Link: link,
+ Sql: sql,
+ Args: args,
+ Stmt: nil,
+ Type: SqlTypeExecContext,
+ IsTransaction: link.IsTransaction(),
+ })
+ return out.Result, err
+}
+
+// DoFilter is a hook function, which filters the sql and its arguments before it's committed to underlying driver.
+// The parameter `link` specifies the current database connection operation object. You can modify the sql
+// string `sql` and its arguments `args` as you wish before they're committed to driver.
+func (c *Core) DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) {
+ return sql, args, nil
+}
+
+// DoCommit commits current sql and arguments to underlying sql driver.
+func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) {
+ var (
+ sqlTx *sql.Tx
+ sqlStmt *sql.Stmt
+ sqlRows *sql.Rows
+ sqlResult sql.Result
+ stmtSqlRows *sql.Rows
+ stmtSqlRow *sql.Row
+ rowsAffected int64
+ cancelFuncForTimeout context.CancelFunc
+ timestampMilli1 = gtime.TimestampMilli()
+ )
+
+ // Trace span start.
+ tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
+ ctx, span := tr.Start(ctx, in.Type, trace.WithSpanKind(trace.SpanKindInternal))
+ defer span.End()
+
+ // Execution cased by type.
+ switch in.Type {
+ case SqlTypeBegin:
+ if sqlTx, err = in.Db.Begin(); err == nil {
+ out.Tx = &TX{
+ db: c.db,
+ tx: sqlTx,
+ ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)),
+ master: in.Db,
+ transactionId: guid.S(),
+ }
+ ctx = out.Tx.ctx
+ }
+ out.RawResult = sqlTx
+
+ case SqlTypeTXCommit:
+ err = in.Tx.Commit()
+
+ case SqlTypeTXRollback:
+ err = in.Tx.Rollback()
+
+ case SqlTypeExecContext:
+ if c.db.GetDryRun() {
+ sqlResult = new(SqlResult)
+ } else {
+ sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...)
+ }
+ out.RawResult = sqlResult
+
+ case SqlTypeQueryContext:
+ sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...)
+ out.RawResult = sqlRows
+
+ case SqlTypePrepareContext:
+ sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql)
+ out.RawResult = sqlStmt
+
+ case SqlTypeStmtExecContext:
+ ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctxTimeoutTypeExec, ctx)
+ defer cancelFuncForTimeout()
+ if c.db.GetDryRun() {
+ sqlResult = new(SqlResult)
+ } else {
+ sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...)
+ }
+ out.RawResult = sqlResult
+
+ case SqlTypeStmtQueryContext:
+ ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctxTimeoutTypeQuery, ctx)
+ defer cancelFuncForTimeout()
+ stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...)
+ out.RawResult = stmtSqlRows
+
+ case SqlTypeStmtQueryRowContext:
+ ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctxTimeoutTypeQuery, ctx)
+ defer cancelFuncForTimeout()
+ stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...)
+ out.RawResult = stmtSqlRow
+
+ default:
+ panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type))
+ }
+ // Result handling.
+ switch {
+ case sqlResult != nil:
+ rowsAffected, err = sqlResult.RowsAffected()
+ out.Result = sqlResult
+
+ case sqlRows != nil:
+ out.Records, err = c.RowsToResult(ctx, sqlRows)
+ rowsAffected = int64(len(out.Records))
+
+ case sqlStmt != nil:
+ out.Stmt = &Stmt{
+ Stmt: sqlStmt,
+ core: c,
+ link: in.Link,
+ sql: in.Sql,
+ }
+ }
+ var (
+ timestampMilli2 = gtime.TimestampMilli()
+ sqlObj = &Sql{
+ Sql: in.Sql,
+ Type: in.Type,
+ Args: in.Args,
+ Format: FormatSqlWithArgs(in.Sql, in.Args),
+ Error: err,
+ Start: timestampMilli1,
+ End: timestampMilli2,
+ Group: c.db.GetGroup(),
+ RowsAffected: rowsAffected,
+ IsTransaction: in.IsTransaction,
+ }
+ )
+
+ // Tracing.
+ c.traceSpanEnd(ctx, span, sqlObj)
+
+ // Logging.
+ if c.db.GetDebug() {
+ c.writeSqlToLogger(ctx, sqlObj)
+ }
+ if err != nil && err != sql.ErrNoRows {
+ err = gerror.NewCodef(
+ gcode.CodeDbOperationError,
+ "%s, %s\n",
+ err.Error(),
+ FormatSqlWithArgs(in.Sql, in.Args),
+ )
+ }
+ return out, err
+}
+
+// Prepare creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the
+// returned statement.
+// The caller must call the statement's Close method
+// when the statement is no longer needed.
+//
+// The parameter `execOnMaster` specifies whether executing the sql on master node,
+// or else it executes the sql on slave node if master-slave configured.
+func (c *Core) Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) {
+ var (
+ err error
+ link Link
+ )
+ if len(execOnMaster) > 0 && execOnMaster[0] {
+ if link, err = c.MasterLink(); err != nil {
+ return nil, err
+ }
+ } else {
+ if link, err = c.SlaveLink(); err != nil {
+ return nil, err
+ }
+ }
+ return c.db.DoPrepare(ctx, link, sql)
+}
+
+// DoPrepare calls prepare function on given link object and returns the statement object.
+func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (stmt *Stmt, err error) {
+ // Transaction checks.
+ if link == nil {
+ if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
+ // Firstly, check and retrieve transaction link from context.
+ link = &txLink{tx.tx}
+ } else {
+ // Or else it creates one from master node.
+ var err error
+ if link, err = c.MasterLink(); err != nil {
+ return nil, err
+ }
+ }
+ } else if !link.IsTransaction() {
+ // If current link is not transaction link, it checks and retrieves transaction from context.
+ if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil {
+ link = &txLink{tx.tx}
+ }
+ }
+
+ if c.GetConfig().PrepareTimeout > 0 {
+ // DO NOT USE cancel function in prepare statement.
+ ctx, _ = context.WithTimeout(ctx, c.GetConfig().PrepareTimeout)
+ }
+
+ // Link execution.
+ var out DoCommitOutput
+ out, err = c.db.DoCommit(ctx, DoCommitInput{
+ Link: link,
+ Sql: sql,
+ Type: SqlTypePrepareContext,
+ IsTransaction: link.IsTransaction(),
+ })
+ return out.Stmt, err
+}
+
+// RowsToResult converts underlying data record type sql.Rows to Result type.
+func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) {
+ if rows == nil {
+ return nil, nil
+ }
+ defer func() {
+ if err := rows.Close(); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }()
+ if !rows.Next() {
+ return nil, nil
+ }
+ // Column names and types.
+ columns, err := rows.ColumnTypes()
+ if err != nil {
+ return nil, err
+ }
+
+ var (
+ columnTypes = make([]string, len(columns))
+ columnNames = make([]string, len(columns))
+ )
+ for k, v := range columns {
+ columnTypes[k] = v.DatabaseTypeName()
+ columnNames[k] = v.Name()
+ }
+ var (
+ values = make([]interface{}, len(columnNames))
+ result = make(Result, 0)
+ scanArgs = make([]interface{}, len(values))
+ )
+ for i := range values {
+ scanArgs[i] = &values[i]
+ }
+ for {
+ if err = rows.Scan(scanArgs...); err != nil {
+ return result, err
+ }
+ record := Record{}
+ for i, value := range values {
+ if value == nil {
+ record[columnNames[i]] = gvar.New(nil)
+ } else {
+ record[columnNames[i]] = gvar.New(c.convertFieldValueToLocalValue(value, columnTypes[i]))
+ }
+ }
+ result = append(result, record)
+ if !rows.Next() {
+ break
+ }
+ }
+ return result, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_utility.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_utility.go
new file mode 100644
index 000000000000..0e0ff4403e34
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_core_utility.go
@@ -0,0 +1,157 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gdb
+
+import (
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// MasterLink acts like function Master but with additional `schema` parameter specifying
+// the schema for the connection. It is defined for internal usage.
+// Also see Master.
+func (c *Core) MasterLink(schema ...string) (Link, error) {
+ db, err := c.db.Master(schema...)
+ if err != nil {
+ return nil, err
+ }
+ return &dbLink{db}, nil
+}
+
+// SlaveLink acts like function Slave but with additional `schema` parameter specifying
+// the schema for the connection. It is defined for internal usage.
+// Also see Slave.
+func (c *Core) SlaveLink(schema ...string) (Link, error) {
+ db, err := c.db.Slave(schema...)
+ if err != nil {
+ return nil, err
+ }
+ return &dbLink{db}, nil
+}
+
+// QuoteWord checks given string `s` a word,
+// if true it quotes `s` with security chars of the database
+// and returns the quoted string; or else it returns `s` without any change.
+//
+// The meaning of a `word` can be considered as a column name.
+func (c *Core) QuoteWord(s string) string {
+ s = gstr.Trim(s)
+ if s == "" {
+ return s
+ }
+ charLeft, charRight := c.db.GetChars()
+ return doQuoteWord(s, charLeft, charRight)
+}
+
+// QuoteString quotes string with quote chars. Strings like:
+// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
+//
+// The meaning of a `string` can be considered as part of a statement string including columns.
+func (c *Core) QuoteString(s string) string {
+ charLeft, charRight := c.db.GetChars()
+ return doQuoteString(s, charLeft, charRight)
+}
+
+// QuotePrefixTableName adds prefix string and quotes chars for the table.
+// It handles table string like:
+// "user", "user u",
+// "user,user_detail",
+// "user u, user_detail ut",
+// "user as u, user_detail as ut".
+//
+// Note that, this will automatically checks the table prefix whether already added,
+// if true it does nothing to the table name, or else adds the prefix to the table name.
+func (c *Core) QuotePrefixTableName(table string) string {
+ charLeft, charRight := c.db.GetChars()
+ return doHandleTableName(table, c.db.GetPrefix(), charLeft, charRight)
+}
+
+// GetChars returns the security char for current database.
+// It does nothing in default.
+func (c *Core) GetChars() (charLeft string, charRight string) {
+ return "", ""
+}
+
+// Tables retrieves and returns the tables of current schema.
+// It's mainly used in cli tool chain for automatically generating the models.
+//
+// It does nothing in default.
+func (c *Core) Tables(schema ...string) (tables []string, err error) {
+ return
+}
+
+// TableFields retrieves and returns the fields' information of specified table of current schema.
+//
+// Note that it returns a map containing the field name and its corresponding fields.
+// As a map is unsorted, the TableField struct has an "Index" field marks its sequence in the fields.
+//
+// It's using cache feature to enhance the performance, which is never expired util the process restarts.
+//
+// It does nothing in default.
+func (c *Core) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
+ // It does nothing if given table is empty, especially in sub-query.
+ if table == "" {
+ return map[string]*TableField{}, nil
+ }
+ return c.db.TableFields(c.GetCtx(), table, schema...)
+}
+
+// HasField determine whether the field exists in the table.
+func (c *Core) HasField(table, field string, schema ...string) (bool, error) {
+ table = c.guessPrimaryTableName(table)
+ tableFields, err := c.TableFields(table, schema...)
+ if err != nil {
+ return false, err
+ }
+ if len(tableFields) == 0 {
+ return false, gerror.NewCodef(
+ gcode.CodeNotFound,
+ `empty table fields for table "%s"`, table,
+ )
+ }
+ fieldsArray := make([]string, len(tableFields))
+ for k, v := range tableFields {
+ fieldsArray[v.Index] = k
+ }
+ charLeft, charRight := c.db.GetChars()
+ field = gstr.Trim(field, charLeft+charRight)
+ for _, f := range fieldsArray {
+ if f == field {
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+// guessPrimaryTableName parses and returns the primary table name.
+func (c *Core) guessPrimaryTableName(tableStr string) string {
+ if tableStr == "" {
+ return ""
+ }
+ var (
+ guessedTableName = ""
+ array1 = gstr.SplitAndTrim(tableStr, ",")
+ array2 = gstr.SplitAndTrim(array1[0], " ")
+ array3 = gstr.SplitAndTrim(array2[0], ".")
+ )
+ if len(array3) >= 2 {
+ guessedTableName = array3[1]
+ } else {
+ guessedTableName = array3[0]
+ }
+ charL, charR := c.db.GetChars()
+ if charL != "" || charR != "" {
+ guessedTableName = gstr.Trim(guessedTableName, charL+charR)
+ }
+ if !gregex.IsMatchString(regularFieldNameRegPattern, guessedTableName) {
+ return ""
+ }
+ return guessedTableName
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_driver_mysql.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_driver_mysql.go
new file mode 100644
index 000000000000..cbfff2434662
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_driver_mysql.go
@@ -0,0 +1,177 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "net/url"
+
+ _ "github.com/go-sql-driver/mysql"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// DriverMysql is the driver for mysql database.
+type DriverMysql struct {
+ *Core
+}
+
+// New creates and returns a database object for mysql.
+// It implements the interface of gdb.Driver for extra database driver installation.
+func (d *DriverMysql) New(core *Core, node *ConfigNode) (DB, error) {
+ return &DriverMysql{
+ Core: core,
+ }, nil
+}
+
+// Open creates and returns an underlying sql.DB object for mysql.
+// Note that it converts time.Time argument to local timezone in default.
+func (d *DriverMysql) Open(config *ConfigNode) (db *sql.DB, err error) {
+ var (
+ source string
+ underlyingDriverName = "mysql"
+ )
+ if config.Link != "" {
+ source = config.Link
+ // Custom changing the schema in runtime.
+ if config.Name != "" {
+ source, _ = gregex.ReplaceString(`/([\w\.\-]+)+`, "/"+config.Name, source)
+ }
+ } else {
+ source = fmt.Sprintf(
+ "%s:%s@tcp(%s:%s)/%s?charset=%s",
+ config.User, config.Pass, config.Host, config.Port, config.Name, config.Charset,
+ )
+ if config.Timezone != "" {
+ source = fmt.Sprintf("%s&loc=%s", source, url.QueryEscape(config.Timezone))
+ }
+ }
+ intlog.Printf(d.GetCtx(), "Open: %s", source)
+ if db, err = sql.Open(underlyingDriverName, source); err != nil {
+ err = gerror.WrapCodef(
+ gcode.CodeDbOperationError, err,
+ `sql.Open failed for driver "%s" by source "%s"`, underlyingDriverName, source,
+ )
+ return nil, err
+ }
+ return
+}
+
+// FilteredLink retrieves and returns filtered `linkInfo` that can be using for
+// logging or tracing purpose.
+func (d *DriverMysql) FilteredLink() string {
+ linkInfo := d.GetConfig().Link
+ if linkInfo == "" {
+ return ""
+ }
+ s, _ := gregex.ReplaceString(
+ `(.+?):(.+)@tcp(.+)`,
+ `$1:xxx@tcp$3`,
+ linkInfo,
+ )
+ return s
+}
+
+// GetChars returns the security char for this type of database.
+func (d *DriverMysql) GetChars() (charLeft string, charRight string) {
+ return "`", "`"
+}
+
+// DoFilter handles the sql before posts it to database.
+func (d *DriverMysql) DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) {
+ return d.Core.DoFilter(ctx, link, sql, args)
+}
+
+// Tables retrieves and returns the tables of current schema.
+// It's mainly used in cli tool chain for automatically generating the models.
+func (d *DriverMysql) Tables(ctx context.Context, schema ...string) (tables []string, err error) {
+ var result Result
+ link, err := d.SlaveLink(schema...)
+ if err != nil {
+ return nil, err
+ }
+ result, err = d.DoGetAll(ctx, link, `SHOW TABLES`)
+ if err != nil {
+ return
+ }
+ for _, m := range result {
+ for _, v := range m {
+ tables = append(tables, v.String())
+ }
+ }
+ return
+}
+
+// TableFields retrieves and returns the fields' information of specified table of current
+// schema.
+//
+// The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection
+// as its link to proceed necessary sql query.
+//
+// Note that it returns a map containing the field name and its corresponding fields.
+// As a map is unsorted, the TableField struct has a "Index" field marks its sequence in
+// the fields.
+//
+// It's using cache feature to enhance the performance, which is never expired util the
+// process restarts.
+func (d *DriverMysql) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*TableField, err error) {
+ charL, charR := d.GetChars()
+ table = gstr.Trim(table, charL+charR)
+ if gstr.Contains(table, " ") {
+ return nil, gerror.NewCode(
+ gcode.CodeInvalidParameter,
+ "function TableFields supports only single table operations",
+ )
+ }
+ useSchema := d.schema
+ if len(schema) > 0 && schema[0] != "" {
+ useSchema = schema[0]
+ }
+ v := tableFieldsMap.GetOrSetFuncLock(
+ fmt.Sprintf(`mysql_table_fields_%s_%s@group:%s`, table, useSchema, d.GetGroup()),
+ func() interface{} {
+ var (
+ result Result
+ link Link
+ )
+ if link, err = d.SlaveLink(useSchema); err != nil {
+ return nil
+ }
+ result, err = d.DoGetAll(
+ ctx, link,
+ fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, d.QuoteWord(table)),
+ )
+ if err != nil {
+ return nil
+ }
+ fields = make(map[string]*TableField)
+ for i, m := range result {
+ fields[m["Field"].String()] = &TableField{
+ Index: i,
+ Name: m["Field"].String(),
+ Type: m["Type"].String(),
+ Null: m["Null"].Bool(),
+ Key: m["Key"].String(),
+ Default: m["Default"].Val(),
+ Extra: m["Extra"].String(),
+ Comment: m["Comment"].String(),
+ }
+ }
+ return fields
+ },
+ )
+ if v != nil {
+ fields = v.(map[string]*TableField)
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_func.go
new file mode 100644
index 000000000000..4c20d26a7d5a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_func.go
@@ -0,0 +1,840 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "regexp"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gmeta"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// iString is the type assert api for String.
+type iString interface {
+ String() string
+}
+
+// iIterator is the type assert api for Iterator.
+type iIterator interface {
+ Iterator(f func(key, value interface{}) bool)
+}
+
+// iInterfaces is the type assert api for Interfaces.
+type iInterfaces interface {
+ Interfaces() []interface{}
+}
+
+// iMapStrAny is the interface support for converting struct parameter to map.
+type iMapStrAny interface {
+ MapStrAny() map[string]interface{}
+}
+
+// iTableName is the interface for retrieving table name fro struct.
+type iTableName interface {
+ TableName() string
+}
+
+const (
+ OrmTagForStruct = "orm"
+ OrmTagForTable = "table"
+ OrmTagForWith = "with"
+ OrmTagForWithWhere = "where"
+ OrmTagForWithOrder = "order"
+ OrmTagForDo = "do"
+)
+
+var (
+ // quoteWordReg is the regular expression object for a word check.
+ quoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
+
+ // Priority tags for struct converting for orm field mapping.
+ structTagPriority = append([]string{OrmTagForStruct}, gconv.StructTagPriority...)
+)
+
+// isDoStruct checks and returns whether given type is a DO struct.
+func isDoStruct(object interface{}) bool {
+ // It checks by struct name like "XxxForDao", to be compatible with old version.
+ // TODO remove this compatible codes in future.
+ reflectType := reflect.TypeOf(object)
+ if gstr.HasSuffix(reflectType.String(), modelForDaoSuffix) {
+ return true
+ }
+ // It checks by struct meta for DO struct in version.
+ if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {
+ match, _ := gregex.MatchString(
+ fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForDo),
+ ormTag.String(),
+ )
+ if len(match) > 1 {
+ return gconv.Bool(match[1])
+ }
+ }
+ return false
+}
+
+// getTableNameFromOrmTag retrieves and returns the table name from struct object.
+func getTableNameFromOrmTag(object interface{}) string {
+ var tableName string
+ // Use the interface value.
+ if r, ok := object.(iTableName); ok {
+ tableName = r.TableName()
+ }
+ // User meta data tag "orm".
+ if tableName == "" {
+ if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {
+ match, _ := gregex.MatchString(
+ fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForTable),
+ ormTag.String(),
+ )
+ if len(match) > 1 {
+ tableName = match[1]
+ }
+ }
+ }
+ // Use the struct name of snake case.
+ if tableName == "" {
+ if t, err := gstructs.StructType(object); err != nil {
+ panic(err)
+ } else {
+ tableName = gstr.CaseSnakeFirstUpper(
+ gstr.StrEx(t.String(), "."),
+ )
+ }
+ }
+ return tableName
+}
+
+// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
+// or else it returns an empty slice.
+//
+// The parameter `list` supports types like:
+// []map[string]interface{}
+// []map[string]sub-map
+// []struct
+// []struct:sub-struct
+// Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.
+// See gutil.ListItemValues.
+func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) {
+ return gutil.ListItemValues(list, key, subKey...)
+}
+
+// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
+// or else it returns an empty slice.
+// See gutil.ListItemValuesUnique.
+func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} {
+ return gutil.ListItemValuesUnique(list, key, subKey...)
+}
+
+// GetInsertOperationByOption returns proper insert option with given parameter `option`.
+func GetInsertOperationByOption(option int) string {
+ var operator string
+ switch option {
+ case InsertOptionReplace:
+ operator = "REPLACE"
+ case InsertOptionIgnore:
+ operator = "INSERT IGNORE"
+ default:
+ operator = "INSERT"
+ }
+ return operator
+}
+
+// DataToMapDeep converts `value` to map type recursively(if attribute struct is embedded).
+// The parameter `value` should be type of *map/map/*struct/struct.
+// It supports embedded struct definition for struct.
+func DataToMapDeep(value interface{}) map[string]interface{} {
+ m := gconv.Map(value, structTagPriority...)
+ for k, v := range m {
+ switch v.(type) {
+ case time.Time, *time.Time, gtime.Time, *gtime.Time:
+ m[k] = v
+
+ default:
+ // Use string conversion in default.
+ if s, ok := v.(iString); ok {
+ m[k] = s.String()
+ } else {
+ m[k] = v
+ }
+ }
+ }
+ return m
+}
+
+// doHandleTableName adds prefix string and quote chars for the table. It handles table string like:
+// "user", "user u", "user,user_detail", "user u, user_detail ut", "user as u, user_detail as ut",
+// "user.user u", "`user`.`user` u".
+//
+// Note that, this will automatically checks the table prefix whether already added, if true it does
+// nothing to the table name, or else adds the prefix to the table name.
+func doHandleTableName(table, prefix, charLeft, charRight string) string {
+ var (
+ index = 0
+ chars = charLeft + charRight
+ array1 = gstr.SplitAndTrim(table, ",")
+ )
+ for k1, v1 := range array1 {
+ array2 := gstr.SplitAndTrim(v1, " ")
+ // Trim the security chars.
+ array2[0] = gstr.Trim(array2[0], chars)
+ // Check whether it has database name.
+ array3 := gstr.Split(gstr.Trim(array2[0]), ".")
+ for k, v := range array3 {
+ array3[k] = gstr.Trim(v, chars)
+ }
+ index = len(array3) - 1
+ // If the table name already has the prefix, skips the prefix adding.
+ if len(array3[index]) <= len(prefix) || array3[index][:len(prefix)] != prefix {
+ array3[index] = prefix + array3[index]
+ }
+ array2[0] = gstr.Join(array3, ".")
+ // Add the security chars.
+ array2[0] = doQuoteString(array2[0], charLeft, charRight)
+ array1[k1] = gstr.Join(array2, " ")
+ }
+ return gstr.Join(array1, ",")
+}
+
+// doQuoteWord checks given string `s` a word, if true quotes it with `charLeft` and `charRight`
+// and returns the quoted string; or else returns `s` without any change.
+func doQuoteWord(s, charLeft, charRight string) string {
+ if quoteWordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
+ return charLeft + s + charRight
+ }
+ return s
+}
+
+// doQuoteString quotes string with quote chars.
+// For example, if quote char is '`':
+// "null" => "NULL"
+// "user" => "`user`"
+// "user u" => "`user` u"
+// "user,user_detail" => "`user`,`user_detail`"
+// "user u, user_detail ut" => "`user` u,`user_detail` ut"
+// "user.user u, user.user_detail ut" => "`user`.`user` u,`user`.`user_detail` ut"
+// "u.id, u.name, u.age" => "`u`.`id`,`u`.`name`,`u`.`age`"
+// "u.id asc" => "`u`.`id` asc".
+func doQuoteString(s, charLeft, charRight string) string {
+ array1 := gstr.SplitAndTrim(s, ",")
+ for k1, v1 := range array1 {
+ array2 := gstr.SplitAndTrim(v1, " ")
+ array3 := gstr.Split(gstr.Trim(array2[0]), ".")
+ if len(array3) == 1 {
+ if strings.EqualFold(array3[0], "NULL") {
+ array3[0] = doQuoteWord(array3[0], "", "")
+ } else {
+ array3[0] = doQuoteWord(array3[0], charLeft, charRight)
+ }
+ } else if len(array3) >= 2 {
+ array3[0] = doQuoteWord(array3[0], charLeft, charRight)
+ // Note:
+ // mysql: u.uid
+ // mssql double dots: Database..Table
+ array3[len(array3)-1] = doQuoteWord(array3[len(array3)-1], charLeft, charRight)
+ }
+ array2[0] = gstr.Join(array3, ".")
+ array1[k1] = gstr.Join(array2, " ")
+ }
+ return gstr.Join(array1, ",")
+}
+
+func getFieldsFromStructOrMap(structOrMap interface{}) (fields []string) {
+ fields = []string{}
+ if utils.IsStruct(structOrMap) {
+ structFields, _ := gstructs.Fields(gstructs.FieldsInput{
+ Pointer: structOrMap,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ for _, structField := range structFields {
+ if tag := structField.Tag(OrmTagForStruct); tag != "" && gregex.IsMatchString(regularFieldNameRegPattern, tag) {
+ fields = append(fields, tag)
+ } else {
+ fields = append(fields, structField.Name())
+ }
+ }
+ } else {
+ fields = gutil.Keys(structOrMap)
+ }
+ return
+}
+
+// GetPrimaryKeyCondition returns a new where condition by primary field name.
+// The optional parameter `where` is like follows:
+// 123 => primary=123
+// []int{1, 2, 3} => primary IN(1,2,3)
+// "john" => primary='john'
+// []string{"john", "smith"} => primary IN('john','smith')
+// g.Map{"id": g.Slice{1,2,3}} => id IN(1,2,3)
+// g.Map{"id": 1, "name": "john"} => id=1 AND name='john'
+// etc.
+//
+// Note that it returns the given `where` parameter directly if the `primary` is empty
+// or length of `where` > 1.
+func GetPrimaryKeyCondition(primary string, where ...interface{}) (newWhereCondition []interface{}) {
+ if len(where) == 0 {
+ return nil
+ }
+ if primary == "" {
+ return where
+ }
+ if len(where) == 1 {
+ var (
+ rv = reflect.ValueOf(where[0])
+ kind = rv.Kind()
+ )
+ if kind == reflect.Ptr {
+ rv = rv.Elem()
+ kind = rv.Kind()
+ }
+ switch kind {
+ case reflect.Map, reflect.Struct:
+ // Ignore the parameter `primary`.
+ break
+
+ default:
+ return []interface{}{map[string]interface{}{
+ primary: where[0],
+ }}
+ }
+ }
+ return where
+}
+
+// formatSql formats the sql string and its arguments before executing.
+// The internal handleArguments function might be called twice during the SQL procedure,
+// but do not worry about it, it's safe and efficient.
+func formatSql(sql string, args []interface{}) (newSql string, newArgs []interface{}) {
+ // DO NOT do this as there may be multiple lines and comments in the sql.
+ // sql = gstr.Trim(sql)
+ // sql = gstr.Replace(sql, "\n", " ")
+ // sql, _ = gregex.ReplaceString(`\s{2,}`, ` `, sql)
+ return handleArguments(sql, args)
+}
+
+type formatWhereHolderInput struct {
+ ModelWhereHolder
+ OmitNil bool
+ OmitEmpty bool
+ Schema string
+ Table string // Table is used for fields mapping and filtering internally.
+}
+
+func isKeyValueCanBeOmitEmpty(omitEmpty bool, whereType string, key, value interface{}) bool {
+ if !omitEmpty {
+ return false
+ }
+ // Eg:
+ // Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
+ // Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
+ // OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
+ // OmitEmpty().Where("name", "").All() -> SELECT xxx FROM xxx
+ // OmitEmpty().Where("1").All() -> SELECT xxx FROM xxx WHERE 1
+ switch whereType {
+ case whereHolderTypeNoArgs:
+ return false
+
+ case whereHolderTypeIn:
+ return gutil.IsEmpty(value)
+
+ default:
+ if gstr.Count(gconv.String(key), "?") == 0 && gutil.IsEmpty(value) {
+ return true
+ }
+ }
+ return false
+}
+
+// formatWhereHolder formats where statement and its arguments for `Where` and `Having` statements.
+func formatWhereHolder(db DB, in formatWhereHolderInput) (newWhere string, newArgs []interface{}) {
+ var (
+ buffer = bytes.NewBuffer(nil)
+ reflectInfo = utils.OriginValueAndKind(in.Where)
+ )
+ switch reflectInfo.OriginKind {
+ case reflect.Array, reflect.Slice:
+ newArgs = formatWhereInterfaces(db, gconv.Interfaces(in.Where), buffer, newArgs)
+
+ case reflect.Map:
+ for key, value := range DataToMapDeep(in.Where) {
+ if in.OmitNil && empty.IsNil(value) {
+ continue
+ }
+ if in.OmitEmpty && empty.IsEmpty(value) {
+ continue
+ }
+ newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
+ Db: db,
+ Buffer: buffer,
+ Args: newArgs,
+ Key: key,
+ Value: value,
+ Prefix: in.Prefix,
+ Type: in.Type,
+ })
+ }
+
+ case reflect.Struct:
+ // If the `where` parameter is DO struct, it then adds `OmitNil` option for this condition,
+ // which will filter all nil parameters in `where`.
+ if isDoStruct(in.Where) {
+ in.OmitNil = true
+ }
+ // If `where` struct implements `iIterator` interface,
+ // it then uses its Iterate function to iterate its key-value pairs.
+ // For example, ListMap and TreeMap are ordered map,
+ // which implement `iIterator` interface and are index-friendly for where conditions.
+ if iterator, ok := in.Where.(iIterator); ok {
+ iterator.Iterator(func(key, value interface{}) bool {
+ ketStr := gconv.String(key)
+ if in.OmitNil && empty.IsNil(value) {
+ return true
+ }
+ if in.OmitEmpty && empty.IsEmpty(value) {
+ return true
+ }
+ newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
+ Db: db,
+ Buffer: buffer,
+ Args: newArgs,
+ Key: ketStr,
+ Value: value,
+ OmitEmpty: in.OmitEmpty,
+ Prefix: in.Prefix,
+ Type: in.Type,
+ })
+ return true
+ })
+ break
+ }
+ // Automatically mapping and filtering the struct attribute.
+ var (
+ reflectType = reflectInfo.OriginValue.Type()
+ structField reflect.StructField
+ data = DataToMapDeep(in.Where)
+ )
+ // If `Prefix` is given, it checks and retrieves the table name.
+ if in.Prefix != "" {
+ hasTable, _ := db.GetCore().HasTable(in.Prefix)
+ if hasTable {
+ in.Table = in.Prefix
+ } else {
+ ormTagTableName := getTableNameFromOrmTag(in.Where)
+ if ormTagTableName != "" {
+ in.Table = ormTagTableName
+ }
+ }
+ }
+ // Mapping and filtering fields if `Table` is given.
+ if in.Table != "" {
+ data, _ = db.GetCore().mappingAndFilterData(in.Schema, in.Table, data, true)
+ }
+ // Put the struct attributes in sequence in Where statement.
+ for i := 0; i < reflectType.NumField(); i++ {
+ structField = reflectType.Field(i)
+ foundKey, foundValue := gutil.MapPossibleItemByKey(data, structField.Name)
+ if foundKey != "" {
+ if in.OmitNil && empty.IsNil(foundValue) {
+ continue
+ }
+ if in.OmitEmpty && empty.IsEmpty(foundValue) {
+ continue
+ }
+ newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
+ Db: db,
+ Buffer: buffer,
+ Args: newArgs,
+ Key: foundKey,
+ Value: foundValue,
+ OmitEmpty: in.OmitEmpty,
+ Prefix: in.Prefix,
+ Type: in.Type,
+ })
+ }
+ }
+
+ default:
+ // Where filter.
+ var omitEmptyCheckValue interface{}
+ if len(in.Args) == 1 {
+ omitEmptyCheckValue = in.Args[0]
+ } else {
+ omitEmptyCheckValue = in.Args
+ }
+ if isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, in.Where, omitEmptyCheckValue) {
+ return
+ }
+ // Usually a string.
+ whereStr := gconv.String(in.Where)
+ // Is `whereStr` a field name which composed as a key-value condition?
+ // Eg:
+ // Where("id", 1)
+ // Where("id", g.Slice{1,2,3})
+ if gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, whereStr) && len(in.Args) == 1 {
+ newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
+ Db: db,
+ Buffer: buffer,
+ Args: newArgs,
+ Key: whereStr,
+ Value: in.Args[0],
+ OmitEmpty: in.OmitEmpty,
+ Prefix: in.Prefix,
+ Type: in.Type,
+ })
+ in.Args = in.Args[:0]
+ break
+ }
+ // If the first part is column name, it automatically adds prefix to the column.
+ if in.Prefix != "" {
+ array := gstr.Split(whereStr, " ")
+ if ok, _ := db.GetCore().HasField(in.Table, array[0]); ok {
+ whereStr = in.Prefix + "." + whereStr
+ }
+ }
+ // Regular string and parameter place holder handling.
+ // Eg:
+ // Where("id in(?) and name=?", g.Slice{1,2,3}, "john")
+ i := 0
+ for {
+ if i >= len(in.Args) {
+ break
+ }
+ // Sub query, which is always used along with a string condition.
+ if model, ok := in.Args[i].(*Model); ok {
+ index := -1
+ whereStr, _ = gregex.ReplaceStringFunc(`(\?)`, whereStr, func(s string) string {
+ index++
+ if i+len(newArgs) == index {
+ sqlWithHolder, holderArgs := model.getFormattedSqlAndArgs(queryTypeNormal, false)
+ newArgs = append(newArgs, holderArgs...)
+ // Automatically adding the brackets.
+ return "(" + sqlWithHolder + ")"
+ }
+ return s
+ })
+ in.Args = gutil.SliceDelete(in.Args, i)
+ continue
+ }
+ i++
+ }
+ buffer.WriteString(whereStr)
+ }
+
+ if buffer.Len() == 0 {
+ return "", in.Args
+ }
+ if len(in.Args) > 0 {
+ newArgs = append(newArgs, in.Args...)
+ }
+ newWhere = buffer.String()
+ if len(newArgs) > 0 {
+ if gstr.Pos(newWhere, "?") == -1 {
+ if gregex.IsMatchString(lastOperatorRegPattern, newWhere) {
+ // Eg: Where/And/Or("uid>=", 1)
+ newWhere += "?"
+ } else if gregex.IsMatchString(regularFieldNameRegPattern, newWhere) {
+ newWhere = db.GetCore().QuoteString(newWhere)
+ if len(newArgs) > 0 {
+ if utils.IsArray(newArgs[0]) {
+ // Eg:
+ // Where("id", []int{1,2,3})
+ // Where("user.id", []int{1,2,3})
+ newWhere += " IN (?)"
+ } else if empty.IsNil(newArgs[0]) {
+ // Eg:
+ // Where("id", nil)
+ // Where("user.id", nil)
+ newWhere += " IS NULL"
+ newArgs = nil
+ } else {
+ // Eg:
+ // Where/And/Or("uid", 1)
+ // Where/And/Or("user.uid", 1)
+ newWhere += "=?"
+ }
+ }
+ }
+ }
+ }
+ return handleArguments(newWhere, newArgs)
+}
+
+// formatWhereInterfaces formats `where` as []interface{}.
+func formatWhereInterfaces(db DB, where []interface{}, buffer *bytes.Buffer, newArgs []interface{}) []interface{} {
+ if len(where) == 0 {
+ return newArgs
+ }
+ if len(where)%2 != 0 {
+ buffer.WriteString(gstr.Join(gconv.Strings(where), ""))
+ return newArgs
+ }
+ var str string
+ for i := 0; i < len(where); i += 2 {
+ str = gconv.String(where[i])
+ if buffer.Len() > 0 {
+ buffer.WriteString(" AND " + db.GetCore().QuoteWord(str) + "=?")
+ } else {
+ buffer.WriteString(db.GetCore().QuoteWord(str) + "=?")
+ }
+ if s, ok := where[i+1].(Raw); ok {
+ buffer.WriteString(gconv.String(s))
+ } else {
+ newArgs = append(newArgs, where[i+1])
+ }
+ }
+ return newArgs
+}
+
+type formatWhereKeyValueInput struct {
+ Db DB // Db is the underlying DB object for current operation.
+ Buffer *bytes.Buffer // Buffer is the sql statement string without Args for current operation.
+ Args []interface{} // Args is the full arguments of current operation.
+ Key string // The field name, eg: "id", "name", etc.
+ Value interface{} // The field value, can be any types.
+ Type string // The value in Where type.
+ OmitEmpty bool // Ignores current condition key if `value` is empty.
+ Prefix string // Field prefix, eg: "user", "order", etc.
+}
+
+// formatWhereKeyValue handles each key-value pair of the parameter map.
+func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) {
+ var (
+ quotedKey = in.Db.GetCore().QuoteWord(in.Key)
+ holderCount = gstr.Count(quotedKey, "?")
+ )
+ if isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, quotedKey, in.Value) {
+ return in.Args
+ }
+ if in.Prefix != "" && !gstr.Contains(quotedKey, ".") {
+ quotedKey = in.Prefix + "." + quotedKey
+ }
+ if in.Buffer.Len() > 0 {
+ in.Buffer.WriteString(" AND ")
+ }
+ // If the value is type of slice, and there's only one '?' holder in
+ // the key string, it automatically adds '?' holder chars according to its arguments count
+ // and converts it to "IN" statement.
+ var (
+ reflectValue = reflect.ValueOf(in.Value)
+ reflectKind = reflectValue.Kind()
+ )
+ switch reflectKind {
+ // Slice argument.
+ case reflect.Slice, reflect.Array:
+ if holderCount == 0 {
+ in.Buffer.WriteString(quotedKey + " IN(?)")
+ in.Args = append(in.Args, in.Value)
+ } else {
+ if holderCount != reflectValue.Len() {
+ in.Buffer.WriteString(quotedKey)
+ in.Args = append(in.Args, in.Value)
+ } else {
+ in.Buffer.WriteString(quotedKey)
+ in.Args = append(in.Args, gconv.Interfaces(in.Value)...)
+ }
+ }
+
+ default:
+ if in.Value == nil || empty.IsNil(reflectValue) {
+ if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
+ // The key is a single field name.
+ in.Buffer.WriteString(quotedKey + " IS NULL")
+ } else {
+ // The key may have operation chars.
+ in.Buffer.WriteString(quotedKey)
+ }
+ } else {
+ // It also supports "LIKE" statement, which we consider it an operator.
+ quotedKey = gstr.Trim(quotedKey)
+ if gstr.Pos(quotedKey, "?") == -1 {
+ like := " LIKE"
+ if len(quotedKey) > len(like) && gstr.Equal(quotedKey[len(quotedKey)-len(like):], like) {
+ // Eg: Where(g.Map{"name like": "john%"})
+ in.Buffer.WriteString(quotedKey + " ?")
+ } else if gregex.IsMatchString(lastOperatorRegPattern, quotedKey) {
+ // Eg: Where(g.Map{"age > ": 16})
+ in.Buffer.WriteString(quotedKey + " ?")
+ } else if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
+ // The key is a regular field name.
+ in.Buffer.WriteString(quotedKey + "=?")
+ } else {
+ // The key is not a regular field name.
+ // Eg: Where(g.Map{"age > 16": nil})
+ // Issue: https://github.com/gogf/gf/issues/765
+ if empty.IsEmpty(in.Value) {
+ in.Buffer.WriteString(quotedKey)
+ break
+ } else {
+ in.Buffer.WriteString(quotedKey + "=?")
+ }
+ }
+ } else {
+ in.Buffer.WriteString(quotedKey)
+ }
+ if s, ok := in.Value.(Raw); ok {
+ in.Buffer.WriteString(gconv.String(s))
+ } else {
+ in.Args = append(in.Args, in.Value)
+ }
+ }
+ }
+ return in.Args
+}
+
+// handleArguments is an important function, which handles the sql and all its arguments
+// before committing them to underlying driver.
+func handleArguments(sql string, args []interface{}) (newSql string, newArgs []interface{}) {
+ newSql = sql
+ // insertHolderCount is used to calculate the inserting position for the '?' holder.
+ insertHolderCount := 0
+ // Handles the slice arguments.
+ if len(args) > 0 {
+ for index, arg := range args {
+ reflectInfo := utils.OriginValueAndKind(arg)
+ switch reflectInfo.OriginKind {
+ case reflect.Slice, reflect.Array:
+ // It does not split the type of []byte.
+ // Eg: table.Where("name = ?", []byte("john"))
+ if _, ok := arg.([]byte); ok {
+ newArgs = append(newArgs, arg)
+ continue
+ }
+
+ if reflectInfo.OriginValue.Len() == 0 {
+ // Empty slice argument, it converts the sql to a false sql.
+ // Eg:
+ // Query("select * from xxx where id in(?)", g.Slice{}) -> select * from xxx where 0=1
+ // Where("id in(?)", g.Slice{}) -> WHERE 0=1
+ if gstr.Contains(newSql, "?") {
+ whereKeyWord := " WHERE "
+ if p := gstr.PosI(newSql, whereKeyWord); p == -1 {
+ return "0=1", []interface{}{}
+ } else {
+ return gstr.SubStr(newSql, 0, p+len(whereKeyWord)) + "0=1", []interface{}{}
+ }
+ }
+ } else {
+ for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
+ newArgs = append(newArgs, reflectInfo.OriginValue.Index(i).Interface())
+ }
+ }
+
+ // If the '?' holder count equals the length of the slice,
+ // it does not implement the arguments splitting logic.
+ // Eg: db.Query("SELECT ?+?", g.Slice{1, 2})
+ if len(args) == 1 && gstr.Count(newSql, "?") == reflectInfo.OriginValue.Len() {
+ break
+ }
+ // counter is used to finding the inserting position for the '?' holder.
+ var (
+ counter = 0
+ replaced = false
+ )
+ newSql, _ = gregex.ReplaceStringFunc(`\?`, newSql, func(s string) string {
+ if replaced {
+ return s
+ }
+ counter++
+ if counter == index+insertHolderCount+1 {
+ replaced = true
+ insertHolderCount += reflectInfo.OriginValue.Len() - 1
+ return "?" + strings.Repeat(",?", reflectInfo.OriginValue.Len()-1)
+ }
+ return s
+ })
+
+ // Special struct handling.
+ case reflect.Struct:
+ switch v := arg.(type) {
+ // The underlying driver supports time.Time/*time.Time types.
+ case time.Time, *time.Time:
+ newArgs = append(newArgs, arg)
+ continue
+
+ // Special handling for gtime.Time/*gtime.Time.
+ //
+ // DO NOT use its underlying gtime.Time.Time as its argument,
+ // because the std time.Time will be converted to certain timezone
+ // according to underlying driver. And the underlying driver also
+ // converts the time.Time to string automatically as the following does.
+ case gtime.Time:
+ newArgs = append(newArgs, v.String())
+ continue
+
+ case *gtime.Time:
+ newArgs = append(newArgs, v.String())
+ continue
+
+ default:
+ // It converts the struct to string in default
+ // if it has implemented the String interface.
+ if v, ok := arg.(iString); ok {
+ newArgs = append(newArgs, v.String())
+ continue
+ }
+ }
+ newArgs = append(newArgs, arg)
+
+ default:
+ newArgs = append(newArgs, arg)
+ }
+ }
+ }
+ return
+}
+
+// FormatSqlWithArgs binds the arguments to the sql string and returns a complete
+// sql string, just for debugging.
+func FormatSqlWithArgs(sql string, args []interface{}) string {
+ index := -1
+ newQuery, _ := gregex.ReplaceStringFunc(
+ `(\?|:v\d+|\$\d+|@p\d+)`,
+ sql,
+ func(s string) string {
+ index++
+ if len(args) > index {
+ if args[index] == nil {
+ return "null"
+ }
+ // Parameters of type Raw do not require special treatment
+ if v, ok := args[index].(Raw); ok {
+ return gconv.String(v)
+ }
+ reflectInfo := utils.OriginValueAndKind(args[index])
+ if reflectInfo.OriginKind == reflect.Ptr &&
+ (reflectInfo.OriginValue.IsNil() || !reflectInfo.OriginValue.IsValid()) {
+ return "null"
+ }
+ switch reflectInfo.OriginKind {
+ case reflect.String, reflect.Map, reflect.Slice, reflect.Array:
+ return `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`
+
+ case reflect.Struct:
+ if t, ok := args[index].(time.Time); ok {
+ return `'` + t.Format(`2006-01-02 15:04:05`) + `'`
+ }
+ return `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`
+ }
+ return gconv.String(args[index])
+ }
+ return s
+ })
+ return newQuery
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model.go
new file mode 100644
index 000000000000..b1c1e819689c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model.go
@@ -0,0 +1,325 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Model is core struct implementing the DAO for ORM.
+type Model struct {
+ db DB // Underlying DB interface.
+ tx *TX // Underlying TX interface.
+ rawSql string // rawSql is the raw SQL string which marks a raw SQL based Model not a table based Model.
+ schema string // Custom database schema.
+ linkType int // Mark for operation on master or slave.
+ tablesInit string // Table names when model initialization.
+ tables string // Operation table names, which can be more than one table names and aliases, like: "user", "user u", "user u, user_detail ud".
+ fields string // Operation fields, multiple fields joined using char ','.
+ fieldsEx string // Excluded operation fields, multiple fields joined using char ','.
+ withArray []interface{} // Arguments for With feature.
+ withAll bool // Enable model association operations on all objects that have "with" tag in the struct.
+ extraArgs []interface{} // Extra custom arguments for sql, which are prepended to the arguments before sql committed to underlying driver.
+ whereHolder []ModelWhereHolder // Condition strings for where operation.
+ groupBy string // Used for "group by" statement.
+ orderBy string // Used for "order by" statement.
+ having []interface{} // Used for "having..." statement.
+ start int // Used for "select ... start, limit ..." statement.
+ limit int // Used for "select ... start, limit ..." statement.
+ option int // Option for extra operation features.
+ offset int // Offset statement for some databases grammar.
+ data interface{} // Data for operation, which can be type of map/[]map/struct/*struct/string, etc.
+ batch int // Batch number for batch Insert/Replace/Save operations.
+ filter bool // Filter data and where key-value pairs according to the fields of the table.
+ distinct string // Force the query to only return distinct results.
+ lockInfo string // Lock for update or in shared lock.
+ cacheEnabled bool // Enable sql result cache feature, which is mainly for indicating cache duration(especially 0) usage.
+ cacheOption CacheOption // Cache option for query statement.
+ unscoped bool // Disables soft deleting features when select/delete operations.
+ safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model.
+ onDuplicate interface{} // onDuplicate is used for ON "DUPLICATE KEY UPDATE" statement.
+ onDuplicateEx interface{} // onDuplicateEx is used for excluding some columns ON "DUPLICATE KEY UPDATE" statement.
+}
+
+// ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
+type ModelHandler func(m *Model) *Model
+
+// ChunkHandler is a function that is used in function Chunk, which handles given Result and error.
+// It returns true if it wants to continue chunking, or else it returns false to stop chunking.
+type ChunkHandler func(result Result, err error) bool
+
+// ModelWhereHolder is the holder for where condition preparing.
+type ModelWhereHolder struct {
+ Type string // Type of this holder.
+ Operator int // Operator for this holder.
+ Where interface{} // Where parameter, which can commonly be type of string/map/struct.
+ Args []interface{} // Arguments for where parameter.
+ Prefix string // Field prefix, eg: "user.", "order.".
+}
+
+const (
+ linkTypeMaster = 1
+ linkTypeSlave = 2
+ defaultFields = "*"
+ whereHolderOperatorWhere = 1
+ whereHolderOperatorAnd = 2
+ whereHolderOperatorOr = 3
+ whereHolderTypeDefault = "Default"
+ whereHolderTypeNoArgs = "NoArgs"
+ whereHolderTypeIn = "In"
+)
+
+// Model creates and returns a new ORM model from given schema.
+// The parameter `tableNameQueryOrStruct` can be more than one table names, and also alias name, like:
+// 1. Model names:
+// db.Model("user")
+// db.Model("user u")
+// db.Model("user, user_detail")
+// db.Model("user u, user_detail ud")
+// 2. Model name with alias:
+// db.Model("user", "u")
+// 3. Model name with sub-query:
+// db.Model("? AS a, ? AS b", subQuery1, subQuery2)
+func (c *Core) Model(tableNameQueryOrStruct ...interface{}) *Model {
+ var (
+ tableStr string
+ tableName string
+ extraArgs []interface{}
+ )
+ // Model creation with sub-query.
+ if len(tableNameQueryOrStruct) > 1 {
+ conditionStr := gconv.String(tableNameQueryOrStruct[0])
+ if gstr.Contains(conditionStr, "?") {
+ whereHolder := ModelWhereHolder{
+ Where: conditionStr,
+ Args: tableNameQueryOrStruct[1:],
+ }
+ tableStr, extraArgs = formatWhereHolder(c.db, formatWhereHolderInput{
+ ModelWhereHolder: whereHolder,
+ OmitNil: false,
+ OmitEmpty: false,
+ Schema: "",
+ Table: "",
+ })
+ }
+ }
+ // Normal model creation.
+ if tableStr == "" {
+ tableNames := make([]string, len(tableNameQueryOrStruct))
+ for k, v := range tableNameQueryOrStruct {
+ if s, ok := v.(string); ok {
+ tableNames[k] = s
+ } else if tableName = getTableNameFromOrmTag(v); tableName != "" {
+ tableNames[k] = tableName
+ }
+ }
+ if len(tableNames) > 1 {
+ tableStr = fmt.Sprintf(
+ `%s AS %s`, c.QuotePrefixTableName(tableNames[0]), c.QuoteWord(tableNames[1]),
+ )
+ } else if len(tableNames) == 1 {
+ tableStr = c.QuotePrefixTableName(tableNames[0])
+ }
+ }
+ m := &Model{
+ db: c.db,
+ schema: c.schema,
+ tablesInit: tableStr,
+ tables: tableStr,
+ fields: defaultFields,
+ start: -1,
+ offset: -1,
+ filter: true,
+ extraArgs: extraArgs,
+ }
+ if defaultModelSafe {
+ m.safe = true
+ }
+ return m
+}
+
+// Raw creates and returns a model based on a raw sql not a table.
+// Example:
+// db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
+func (c *Core) Raw(rawSql string, args ...interface{}) *Model {
+ model := c.Model()
+ model.rawSql = rawSql
+ model.extraArgs = args
+ return model
+}
+
+// Raw sets current model as a raw sql model.
+// Example:
+// db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
+// See Core.Raw.
+func (m *Model) Raw(rawSql string, args ...interface{}) *Model {
+ model := m.db.Raw(rawSql, args...)
+ model.db = m.db
+ model.tx = m.tx
+ return model
+}
+
+func (tx *TX) Raw(rawSql string, args ...interface{}) *Model {
+ return tx.Model().Raw(rawSql, args...)
+}
+
+// With creates and returns an ORM model based on metadata of given object.
+func (c *Core) With(objects ...interface{}) *Model {
+ return c.db.Model().With(objects...)
+}
+
+// Model acts like Core.Model except it operates on transaction.
+// See Core.Model.
+func (tx *TX) Model(tableNameQueryOrStruct ...interface{}) *Model {
+ model := tx.db.Model(tableNameQueryOrStruct...)
+ model.db = tx.db
+ model.tx = tx
+ return model
+}
+
+// With acts like Core.With except it operates on transaction.
+// See Core.With.
+func (tx *TX) With(object interface{}) *Model {
+ return tx.Model().With(object)
+}
+
+// Ctx sets the context for current operation.
+func (m *Model) Ctx(ctx context.Context) *Model {
+ if ctx == nil {
+ return m
+ }
+ model := m.getModel()
+ model.db = model.db.Ctx(ctx)
+ if m.tx != nil {
+ model.tx = model.tx.Ctx(ctx)
+ }
+ return model
+}
+
+// GetCtx returns the context for current Model.
+// It returns `context.Background()` is there's no context previously set.
+func (m *Model) GetCtx() context.Context {
+ if m.tx != nil && m.tx.ctx != nil {
+ return m.tx.ctx
+ }
+ return m.db.GetCtx()
+}
+
+// As sets an alias name for current table.
+func (m *Model) As(as string) *Model {
+ if m.tables != "" {
+ model := m.getModel()
+ split := " JOIN "
+ if gstr.ContainsI(model.tables, split) {
+ // For join table.
+ array := gstr.Split(model.tables, split)
+ array[len(array)-1], _ = gregex.ReplaceString(`(.+) ON`, fmt.Sprintf(`$1 AS %s ON`, as), array[len(array)-1])
+ model.tables = gstr.Join(array, split)
+ } else {
+ // For base table.
+ model.tables = gstr.TrimRight(model.tables) + " AS " + as
+ }
+ return model
+ }
+ return m
+}
+
+// DB sets/changes the db object for current operation.
+func (m *Model) DB(db DB) *Model {
+ model := m.getModel()
+ model.db = db
+ return model
+}
+
+// TX sets/changes the transaction for current operation.
+func (m *Model) TX(tx *TX) *Model {
+ model := m.getModel()
+ model.db = tx.db
+ model.tx = tx
+ return model
+}
+
+// Schema sets the schema for current operation.
+func (m *Model) Schema(schema string) *Model {
+ model := m.getModel()
+ model.schema = schema
+ return model
+}
+
+// Clone creates and returns a new model which is a clone of current model.
+// Note that it uses deep-copy for the clone.
+func (m *Model) Clone() *Model {
+ newModel := (*Model)(nil)
+ if m.tx != nil {
+ newModel = m.tx.Model(m.tablesInit)
+ } else {
+ newModel = m.db.Model(m.tablesInit)
+ }
+ *newModel = *m
+ // Shallow copy slice attributes.
+ if n := len(m.extraArgs); n > 0 {
+ newModel.extraArgs = make([]interface{}, n)
+ copy(newModel.extraArgs, m.extraArgs)
+ }
+ if n := len(m.whereHolder); n > 0 {
+ newModel.whereHolder = make([]ModelWhereHolder, n)
+ copy(newModel.whereHolder, m.whereHolder)
+ }
+ if n := len(m.withArray); n > 0 {
+ newModel.withArray = make([]interface{}, n)
+ copy(newModel.withArray, m.withArray)
+ }
+ return newModel
+}
+
+// Master marks the following operation on master node.
+func (m *Model) Master() *Model {
+ model := m.getModel()
+ model.linkType = linkTypeMaster
+ return model
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (m *Model) Slave() *Model {
+ model := m.getModel()
+ model.linkType = linkTypeSlave
+ return model
+}
+
+// Safe marks this model safe or unsafe. If safe is true, it clones and returns a new model object
+// whenever the operation done, or else it changes the attribute of current model.
+func (m *Model) Safe(safe ...bool) *Model {
+ if len(safe) > 0 {
+ m.safe = safe[0]
+ } else {
+ m.safe = true
+ }
+ return m
+}
+
+// Args sets custom arguments for model operation.
+func (m *Model) Args(args ...interface{}) *Model {
+ model := m.getModel()
+ model.extraArgs = append(model.extraArgs, args)
+ return model
+}
+
+// Handler calls each of `handlers` on current Model and returns a new Model.
+// ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
+func (m *Model) Handler(handlers ...ModelHandler) *Model {
+ model := m.getModel()
+ for _, handler := range handlers {
+ model = handler(model)
+ }
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_cache.go
new file mode 100644
index 000000000000..e9f66aa52a16
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_cache.go
@@ -0,0 +1,55 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "time"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+type CacheOption struct {
+ // Duration is the TTL for the cache.
+ // If the parameter `Duration` < 0, which means it clear the cache with given `Name`.
+ // If the parameter `Duration` = 0, which means it never expires.
+ // If the parameter `Duration` > 0, which means it expires after `Duration`.
+ Duration time.Duration
+
+ // Name is an optional unique name for the cache.
+ // The Name is used to bind a name to the cache, which means you can later control the cache
+ // like changing the `duration` or clearing the cache with specified Name.
+ Name string
+
+ // Force caches the query result whatever the result is nil or not.
+ // It is used to avoid Cache Penetration.
+ Force bool
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// Note that, the cache feature is disabled if the model is performing select statement
+// on a transaction.
+func (m *Model) Cache(option CacheOption) *Model {
+ model := m.getModel()
+ model.cacheOption = option
+ model.cacheEnabled = true
+ return model
+}
+
+// checkAndRemoveCache checks and removes the cache in insert/update/delete statement if
+// cache feature is enabled.
+func (m *Model) checkAndRemoveCache() {
+ if m.cacheEnabled && m.cacheOption.Duration < 0 && len(m.cacheOption.Name) > 0 {
+ ctx := m.GetCtx()
+ _, err := m.db.GetCache().Remove(ctx, m.cacheOption.Name)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_delete.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_delete.go
new file mode 100644
index 000000000000..334338f6ff03
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_delete.go
@@ -0,0 +1,51 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+ "fmt"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Delete does "DELETE FROM ... " statement for the model.
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) {
+ if len(where) > 0 {
+ return m.Where(where[0], where[1:]...).Delete()
+ }
+ defer func() {
+ if err == nil {
+ m.checkAndRemoveCache()
+ }
+ }()
+ var (
+ fieldNameDelete = m.getSoftFieldNameDeleted()
+ conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false, false)
+ )
+ // Soft deleting.
+ if !m.unscoped && fieldNameDelete != "" {
+ return m.db.DoUpdate(
+ m.GetCtx(),
+ m.getLink(true),
+ m.tables,
+ fmt.Sprintf(`%s=?`, m.db.GetCore().QuoteString(fieldNameDelete)),
+ conditionWhere+conditionExtra,
+ append([]interface{}{gtime.Now().String()}, conditionArgs...),
+ )
+ }
+ conditionStr := conditionWhere + conditionExtra
+ if !gstr.ContainsI(conditionStr, " WHERE ") {
+ return nil, gerror.NewCode(gcode.CodeMissingParameter, "there should be WHERE condition statement for DELETE operation")
+ }
+ return m.db.DoDelete(m.GetCtx(), m.getLink(true), m.tables, conditionStr, conditionArgs...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_fields.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_fields.go
new file mode 100644
index 000000000000..9d2cd34a8012
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_fields.go
@@ -0,0 +1,251 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Fields appends `fieldNamesOrMapStruct` to the operation fields of the model, multiple fields joined using char ','.
+// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.
+//
+// Eg:
+// Fields("id", "name", "age")
+// Fields([]string{"id", "name", "age"})
+// Fields(map[string]interface{}{"id":1, "name":"john", "age":18})
+// Fields(User{ Id: 1, Name: "john", Age: 18}).
+func (m *Model) Fields(fieldNamesOrMapStruct ...interface{}) *Model {
+ length := len(fieldNamesOrMapStruct)
+ if length == 0 {
+ return m
+ }
+ switch {
+ // String slice.
+ case length >= 2:
+ return m.appendFieldsByStr(gstr.Join(
+ m.mappingAndFilterToTableFields(gconv.Strings(fieldNamesOrMapStruct), true),
+ ",",
+ ))
+
+ // It needs type asserting.
+ case length == 1:
+ structOrMap := fieldNamesOrMapStruct[0]
+ switch r := structOrMap.(type) {
+ case string:
+ return m.appendFieldsByStr(gstr.Join(
+ m.mappingAndFilterToTableFields([]string{r}, false), ",",
+ ))
+
+ case []string:
+ return m.appendFieldsByStr(gstr.Join(
+ m.mappingAndFilterToTableFields(r, true), ",",
+ ))
+
+ default:
+ return m.appendFieldsByStr(gstr.Join(
+ m.mappingAndFilterToTableFields(getFieldsFromStructOrMap(structOrMap), true), ",",
+ ))
+ }
+ }
+ return m
+}
+
+// FieldsPrefix performs as function Fields but add extra prefix for each field.
+func (m *Model) FieldsPrefix(prefix string, fieldNamesOrMapStruct ...interface{}) *Model {
+ model := m.Fields(fieldNamesOrMapStruct...)
+ array := gstr.SplitAndTrim(model.fields, ",")
+ gstr.PrefixArray(array, prefix+".")
+ model.fields = gstr.Join(array, ",")
+ return model
+}
+
+// FieldsEx appends `fieldNamesOrMapStruct` to the excluded operation fields of the model,
+// multiple fields joined using char ','.
+// Note that this function supports only single table operations.
+// The parameter `fieldNamesOrMapStruct` can be type of string/map/*map/struct/*struct.
+//
+// Also see Fields.
+func (m *Model) FieldsEx(fieldNamesOrMapStruct ...interface{}) *Model {
+ length := len(fieldNamesOrMapStruct)
+ if length == 0 {
+ return m
+ }
+ model := m.getModel()
+ switch {
+ case length >= 2:
+ model.fieldsEx = gstr.Join(
+ m.mappingAndFilterToTableFields(gconv.Strings(fieldNamesOrMapStruct), true),
+ ",",
+ )
+ return model
+ case length == 1:
+ switch r := fieldNamesOrMapStruct[0].(type) {
+ case string:
+ model.fieldsEx = gstr.Join(m.mappingAndFilterToTableFields([]string{r}, false), ",")
+ case []string:
+ model.fieldsEx = gstr.Join(m.mappingAndFilterToTableFields(r, true), ",")
+ default:
+ model.fieldsEx = gstr.Join(m.mappingAndFilterToTableFields(getFieldsFromStructOrMap(r), true), ",")
+ }
+ return model
+ }
+ return m
+}
+
+// FieldsExPrefix performs as function FieldsEx but add extra prefix for each field.
+func (m *Model) FieldsExPrefix(prefix string, fieldNamesOrMapStruct ...interface{}) *Model {
+ model := m.FieldsEx(fieldNamesOrMapStruct...)
+ array := gstr.SplitAndTrim(model.fieldsEx, ",")
+ gstr.PrefixArray(array, prefix+".")
+ model.fieldsEx = gstr.Join(array, ",")
+ return model
+}
+
+// FieldCount formats and appends commonly used field `COUNT(column)` to the select fields of model.
+func (m *Model) FieldCount(column string, as ...string) *Model {
+ asStr := ""
+ if len(as) > 0 && as[0] != "" {
+ asStr = fmt.Sprintf(` AS %s`, m.db.GetCore().QuoteWord(as[0]))
+ }
+ return m.appendFieldsByStr(fmt.Sprintf(`COUNT(%s)%s`, m.QuoteWord(column), asStr))
+}
+
+// FieldSum formats and appends commonly used field `SUM(column)` to the select fields of model.
+func (m *Model) FieldSum(column string, as ...string) *Model {
+ asStr := ""
+ if len(as) > 0 && as[0] != "" {
+ asStr = fmt.Sprintf(` AS %s`, m.db.GetCore().QuoteWord(as[0]))
+ }
+ return m.appendFieldsByStr(fmt.Sprintf(`SUM(%s)%s`, m.QuoteWord(column), asStr))
+}
+
+// FieldMin formats and appends commonly used field `MIN(column)` to the select fields of model.
+func (m *Model) FieldMin(column string, as ...string) *Model {
+ asStr := ""
+ if len(as) > 0 && as[0] != "" {
+ asStr = fmt.Sprintf(` AS %s`, m.db.GetCore().QuoteWord(as[0]))
+ }
+ return m.appendFieldsByStr(fmt.Sprintf(`MIN(%s)%s`, m.QuoteWord(column), asStr))
+}
+
+// FieldMax formats and appends commonly used field `MAX(column)` to the select fields of model.
+func (m *Model) FieldMax(column string, as ...string) *Model {
+ asStr := ""
+ if len(as) > 0 && as[0] != "" {
+ asStr = fmt.Sprintf(` AS %s`, m.db.GetCore().QuoteWord(as[0]))
+ }
+ return m.appendFieldsByStr(fmt.Sprintf(`MAX(%s)%s`, m.QuoteWord(column), asStr))
+}
+
+// FieldAvg formats and appends commonly used field `AVG(column)` to the select fields of model.
+func (m *Model) FieldAvg(column string, as ...string) *Model {
+ asStr := ""
+ if len(as) > 0 && as[0] != "" {
+ asStr = fmt.Sprintf(` AS %s`, m.db.GetCore().QuoteWord(as[0]))
+ }
+ return m.appendFieldsByStr(fmt.Sprintf(`AVG(%s)%s`, m.QuoteWord(column), asStr))
+}
+
+func (m *Model) appendFieldsByStr(fields string) *Model {
+ if fields != "" {
+ model := m.getModel()
+ if model.fields == defaultFields {
+ model.fields = ""
+ }
+ if model.fields != "" {
+ model.fields += ","
+ }
+ model.fields += fields
+ return model
+ }
+ return m
+}
+
+func (m *Model) appendFieldsExByStr(fieldsEx string) *Model {
+ if fieldsEx != "" {
+ model := m.getModel()
+ if model.fieldsEx != "" {
+ model.fieldsEx += ","
+ }
+ model.fieldsEx += fieldsEx
+ return model
+ }
+ return m
+}
+
+// GetFieldsStr retrieves and returns all fields from the table, joined with char ','.
+// The optional parameter `prefix` specifies the prefix for each field, eg: GetFieldsStr("u.").
+func (m *Model) GetFieldsStr(prefix ...string) string {
+ prefixStr := ""
+ if len(prefix) > 0 {
+ prefixStr = prefix[0]
+ }
+ tableFields, err := m.TableFields(m.tablesInit)
+ if err != nil {
+ panic(err)
+ }
+ if len(tableFields) == 0 {
+ panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables))
+ }
+ fieldsArray := make([]string, len(tableFields))
+ for k, v := range tableFields {
+ fieldsArray[v.Index] = k
+ }
+ newFields := ""
+ for _, k := range fieldsArray {
+ if len(newFields) > 0 {
+ newFields += ","
+ }
+ newFields += prefixStr + k
+ }
+ newFields = m.db.GetCore().QuoteString(newFields)
+ return newFields
+}
+
+// GetFieldsExStr retrieves and returns fields which are not in parameter `fields` from the table,
+// joined with char ','.
+// The parameter `fields` specifies the fields that are excluded.
+// The optional parameter `prefix` specifies the prefix for each field, eg: FieldsExStr("id", "u.").
+func (m *Model) GetFieldsExStr(fields string, prefix ...string) string {
+ prefixStr := ""
+ if len(prefix) > 0 {
+ prefixStr = prefix[0]
+ }
+ tableFields, err := m.TableFields(m.tablesInit)
+ if err != nil {
+ panic(err)
+ }
+ if len(tableFields) == 0 {
+ panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables))
+ }
+ fieldsExSet := gset.NewStrSetFrom(gstr.SplitAndTrim(fields, ","))
+ fieldsArray := make([]string, len(tableFields))
+ for k, v := range tableFields {
+ fieldsArray[v.Index] = k
+ }
+ newFields := ""
+ for _, k := range fieldsArray {
+ if fieldsExSet.Contains(k) {
+ continue
+ }
+ if len(newFields) > 0 {
+ newFields += ","
+ }
+ newFields += prefixStr + k
+ }
+ newFields = m.db.GetCore().QuoteString(newFields)
+ return newFields
+}
+
+// HasField determine whether the field exists in the table.
+func (m *Model) HasField(field string) (bool, error) {
+ return m.db.GetCore().HasField(m.tablesInit, field)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_insert.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_insert.go
new file mode 100644
index 000000000000..09787ec93223
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_insert.go
@@ -0,0 +1,414 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+ "reflect"
+
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// Batch sets the batch operation number for the model.
+func (m *Model) Batch(batch int) *Model {
+ model := m.getModel()
+ model.batch = batch
+ return model
+}
+
+// Data sets the operation data for the model.
+// The parameter `data` can be type of string/map/gmap/slice/struct/*struct, etc.
+// Note that, it uses shallow value copying for `data` if `data` is type of map/slice
+// to avoid changing it inside function.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data("uid=? AND name=?", 10000, "john")
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}).
+func (m *Model) Data(data ...interface{}) *Model {
+ model := m.getModel()
+ if len(data) > 1 {
+ if s := gconv.String(data[0]); gstr.Contains(s, "?") {
+ model.data = s
+ model.extraArgs = data[1:]
+ } else {
+ m := make(map[string]interface{})
+ for i := 0; i < len(data); i += 2 {
+ m[gconv.String(data[i])] = data[i+1]
+ }
+ model.data = m
+ }
+ } else {
+ switch value := data[0].(type) {
+ case Result:
+ model.data = value.List()
+
+ case Record:
+ model.data = value.Map()
+
+ case List:
+ list := make(List, len(value))
+ for k, v := range value {
+ list[k] = gutil.MapCopy(v)
+ }
+ model.data = list
+
+ case Map:
+ model.data = gutil.MapCopy(value)
+
+ default:
+ reflectInfo := utils.OriginValueAndKind(value)
+ switch reflectInfo.OriginKind {
+ case reflect.Slice, reflect.Array:
+ if reflectInfo.OriginValue.Len() > 0 {
+ // If the `data` parameter is a DO struct,
+ // it then adds `OmitNilData` option for this condition,
+ // which will filter all nil parameters in `data`.
+ if isDoStruct(reflectInfo.OriginValue.Index(0).Interface()) {
+ model = model.OmitNilData()
+ model.option |= optionOmitNilDataInternal
+ }
+ }
+ list := make(List, reflectInfo.OriginValue.Len())
+ for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
+ list[i] = m.db.ConvertDataForRecord(m.GetCtx(), reflectInfo.OriginValue.Index(i).Interface())
+ }
+ model.data = list
+
+ case reflect.Struct:
+ // If the `data` parameter is a DO struct,
+ // it then adds `OmitNilData` option for this condition,
+ // which will filter all nil parameters in `data`.
+ if isDoStruct(value) {
+ model = model.OmitNilData()
+ }
+ if v, ok := data[0].(iInterfaces); ok {
+ var (
+ array = v.Interfaces()
+ list = make(List, len(array))
+ )
+ for i := 0; i < len(array); i++ {
+ list[i] = m.db.ConvertDataForRecord(m.GetCtx(), array[i])
+ }
+ model.data = list
+ } else {
+ model.data = m.db.ConvertDataForRecord(m.GetCtx(), data[0])
+ }
+
+ case reflect.Map:
+ model.data = m.db.ConvertDataForRecord(m.GetCtx(), data[0])
+
+ default:
+ model.data = data[0]
+ }
+ }
+ }
+ return model
+}
+
+// OnDuplicate sets the operations when columns conflicts occurs.
+// In MySQL, this is used for "ON DUPLICATE KEY UPDATE" statement.
+// The parameter `onDuplicate` can be type of string/Raw/*Raw/map/slice.
+// Example:
+// OnDuplicate("nickname, age")
+// OnDuplicate("nickname", "age")
+// OnDuplicate(g.Map{
+// "nickname": gdb.Raw("CONCAT('name_', VALUES(`nickname`))"),
+// })
+// OnDuplicate(g.Map{
+// "nickname": "passport",
+// }).
+func (m *Model) OnDuplicate(onDuplicate ...interface{}) *Model {
+ model := m.getModel()
+ if len(onDuplicate) > 1 {
+ model.onDuplicate = onDuplicate
+ } else {
+ model.onDuplicate = onDuplicate[0]
+ }
+ return model
+}
+
+// OnDuplicateEx sets the excluding columns for operations when columns conflicts occurs.
+// In MySQL, this is used for "ON DUPLICATE KEY UPDATE" statement.
+// The parameter `onDuplicateEx` can be type of string/map/slice.
+// Example:
+// OnDuplicateEx("passport, password")
+// OnDuplicateEx("passport", "password")
+// OnDuplicateEx(g.Map{
+// "passport": "",
+// "password": "",
+// }).
+func (m *Model) OnDuplicateEx(onDuplicateEx ...interface{}) *Model {
+ model := m.getModel()
+ if len(onDuplicateEx) > 1 {
+ model.onDuplicateEx = onDuplicateEx
+ } else {
+ model.onDuplicateEx = onDuplicateEx[0]
+ }
+ return model
+}
+
+// Insert does "INSERT INTO ..." statement for the model.
+// The optional parameter `data` is the same as the parameter of Model.Data function,
+// see Model.Data.
+func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) {
+ if len(data) > 0 {
+ return m.Data(data...).Insert()
+ }
+ return m.doInsertWithOption(InsertOptionDefault)
+}
+
+// InsertAndGetId performs action Insert and returns the last insert id that automatically generated.
+func (m *Model) InsertAndGetId(data ...interface{}) (lastInsertId int64, err error) {
+ if len(data) > 0 {
+ return m.Data(data...).InsertAndGetId()
+ }
+ result, err := m.doInsertWithOption(InsertOptionDefault)
+ if err != nil {
+ return 0, err
+ }
+ return result.LastInsertId()
+}
+
+// InsertIgnore does "INSERT IGNORE INTO ..." statement for the model.
+// The optional parameter `data` is the same as the parameter of Model.Data function,
+// see Model.Data.
+func (m *Model) InsertIgnore(data ...interface{}) (result sql.Result, err error) {
+ if len(data) > 0 {
+ return m.Data(data...).InsertIgnore()
+ }
+ return m.doInsertWithOption(InsertOptionIgnore)
+}
+
+// Replace does "REPLACE INTO ..." statement for the model.
+// The optional parameter `data` is the same as the parameter of Model.Data function,
+// see Model.Data.
+func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
+ if len(data) > 0 {
+ return m.Data(data...).Replace()
+ }
+ return m.doInsertWithOption(InsertOptionReplace)
+}
+
+// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model.
+// The optional parameter `data` is the same as the parameter of Model.Data function,
+// see Model.Data.
+//
+// It updates the record if there's primary or unique index in the saving data,
+// or else it inserts a new record into the table.
+func (m *Model) Save(data ...interface{}) (result sql.Result, err error) {
+ if len(data) > 0 {
+ return m.Data(data...).Save()
+ }
+ return m.doInsertWithOption(InsertOptionSave)
+}
+
+// doInsertWithOption inserts data with option parameter.
+func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err error) {
+ defer func() {
+ if err == nil {
+ m.checkAndRemoveCache()
+ }
+ }()
+ if m.data == nil {
+ return nil, gerror.NewCode(gcode.CodeMissingParameter, "inserting into table with empty data")
+ }
+ var (
+ list List
+ nowString = gtime.Now().String()
+ fieldNameCreate = m.getSoftFieldNameCreated()
+ fieldNameUpdate = m.getSoftFieldNameUpdated()
+ )
+ newData, err := m.filterDataForInsertOrUpdate(m.data)
+ if err != nil {
+ return nil, err
+ }
+ // It converts any data to List type for inserting.
+ switch value := newData.(type) {
+ case Result:
+ list = value.List()
+
+ case Record:
+ list = List{value.Map()}
+
+ case List:
+ list = value
+ for i, v := range list {
+ list[i] = m.db.ConvertDataForRecord(m.GetCtx(), v)
+ }
+
+ case Map:
+ list = List{m.db.ConvertDataForRecord(m.GetCtx(), value)}
+
+ default:
+ reflectInfo := utils.OriginValueAndKind(newData)
+ switch reflectInfo.OriginKind {
+ // If it's slice type, it then converts it to List type.
+ case reflect.Slice, reflect.Array:
+ list = make(List, reflectInfo.OriginValue.Len())
+ for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
+ list[i] = m.db.ConvertDataForRecord(m.GetCtx(), reflectInfo.OriginValue.Index(i).Interface())
+ }
+
+ case reflect.Map:
+ list = List{m.db.ConvertDataForRecord(m.GetCtx(), value)}
+
+ case reflect.Struct:
+ if v, ok := value.(iInterfaces); ok {
+ array := v.Interfaces()
+ list = make(List, len(array))
+ for i := 0; i < len(array); i++ {
+ list[i] = m.db.ConvertDataForRecord(m.GetCtx(), array[i])
+ }
+ } else {
+ list = List{m.db.ConvertDataForRecord(m.GetCtx(), value)}
+ }
+
+ default:
+ return result, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "unsupported data list type: %v",
+ reflectInfo.InputValue.Type(),
+ )
+ }
+ }
+
+ if len(list) < 1 {
+ return result, gerror.NewCode(gcode.CodeMissingParameter, "data list cannot be empty")
+ }
+
+ // Automatic handling for creating/updating time.
+ if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") {
+ for k, v := range list {
+ if fieldNameCreate != "" {
+ v[fieldNameCreate] = nowString
+ }
+ if fieldNameUpdate != "" {
+ v[fieldNameUpdate] = nowString
+ }
+ list[k] = v
+ }
+ }
+ // Format DoInsertOption, especially for "ON DUPLICATE KEY UPDATE" statement.
+ columnNames := make([]string, 0, len(list[0]))
+ for k := range list[0] {
+ columnNames = append(columnNames, k)
+ }
+ doInsertOption, err := m.formatDoInsertOption(insertOption, columnNames)
+ if err != nil {
+ return result, err
+ }
+ return m.db.DoInsert(m.GetCtx(), m.getLink(true), m.tables, list, doInsertOption)
+}
+
+func (m *Model) formatDoInsertOption(insertOption int, columnNames []string) (option DoInsertOption, err error) {
+ option = DoInsertOption{
+ InsertOption: insertOption,
+ BatchCount: m.getBatch(),
+ }
+ if insertOption == InsertOptionSave {
+ onDuplicateExKeys, err := m.formatOnDuplicateExKeys(m.onDuplicateEx)
+ if err != nil {
+ return option, err
+ }
+ onDuplicateExKeySet := gset.NewStrSetFrom(onDuplicateExKeys)
+ if m.onDuplicate != nil {
+ switch m.onDuplicate.(type) {
+ case Raw, *Raw:
+ option.OnDuplicateStr = gconv.String(m.onDuplicate)
+
+ default:
+ reflectInfo := utils.OriginValueAndKind(m.onDuplicate)
+ switch reflectInfo.OriginKind {
+ case reflect.String:
+ option.OnDuplicateMap = make(map[string]interface{})
+ for _, v := range gstr.SplitAndTrim(reflectInfo.OriginValue.String(), ",") {
+ if onDuplicateExKeySet.Contains(v) {
+ continue
+ }
+ option.OnDuplicateMap[v] = v
+ }
+
+ case reflect.Map:
+ option.OnDuplicateMap = make(map[string]interface{})
+ for k, v := range gconv.Map(m.onDuplicate) {
+ if onDuplicateExKeySet.Contains(k) {
+ continue
+ }
+ option.OnDuplicateMap[k] = v
+ }
+
+ case reflect.Slice, reflect.Array:
+ option.OnDuplicateMap = make(map[string]interface{})
+ for _, v := range gconv.Strings(m.onDuplicate) {
+ if onDuplicateExKeySet.Contains(v) {
+ continue
+ }
+ option.OnDuplicateMap[v] = v
+ }
+
+ default:
+ return option, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `unsupported OnDuplicate parameter type "%s"`,
+ reflect.TypeOf(m.onDuplicate),
+ )
+ }
+ }
+ } else if onDuplicateExKeySet.Size() > 0 {
+ option.OnDuplicateMap = make(map[string]interface{})
+ for _, v := range columnNames {
+ if onDuplicateExKeySet.Contains(v) {
+ continue
+ }
+ option.OnDuplicateMap[v] = v
+ }
+ }
+ }
+ return
+}
+
+func (m *Model) formatOnDuplicateExKeys(onDuplicateEx interface{}) ([]string, error) {
+ if onDuplicateEx == nil {
+ return nil, nil
+ }
+
+ reflectInfo := utils.OriginValueAndKind(onDuplicateEx)
+ switch reflectInfo.OriginKind {
+ case reflect.String:
+ return gstr.SplitAndTrim(reflectInfo.OriginValue.String(), ","), nil
+
+ case reflect.Map:
+ return gutil.Keys(onDuplicateEx), nil
+
+ case reflect.Slice, reflect.Array:
+ return gconv.Strings(onDuplicateEx), nil
+
+ default:
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `unsupported OnDuplicateEx parameter type "%s"`,
+ reflect.TypeOf(onDuplicateEx),
+ )
+ }
+}
+
+func (m *Model) getBatch() int {
+ batch := defaultBatchNumber
+ if m.batch > 0 {
+ batch = m.batch
+ }
+ return batch
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_join.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_join.go
new file mode 100644
index 000000000000..237397b5fb74
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_join.go
@@ -0,0 +1,148 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// isSubQuery checks and returns whether given string a sub-query sql string.
+func isSubQuery(s string) bool {
+ s = gstr.TrimLeft(s, "()")
+ if p := gstr.Pos(s, " "); p != -1 {
+ if gstr.Equal(s[:p], "select") {
+ return true
+ }
+ }
+ return false
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter `table` can be joined table and its joined condition,
+// and also with its alias name.
+//
+// Eg:
+// Model("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Model("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+// Model("user", "u").LeftJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid").
+func (m *Model) LeftJoin(table ...string) *Model {
+ return m.doJoin("LEFT", table...)
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter `table` can be joined table and its joined condition,
+// and also with its alias name.
+//
+// Eg:
+// Model("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Model("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+// Model("user", "u").RightJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid").
+func (m *Model) RightJoin(table ...string) *Model {
+ return m.doJoin("RIGHT", table...)
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter `table` can be joined table and its joined condition,
+// and also with its alias name。
+//
+// Eg:
+// Model("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Model("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+// Model("user", "u").InnerJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid").
+func (m *Model) InnerJoin(table ...string) *Model {
+ return m.doJoin("INNER", table...)
+}
+
+// LeftJoinOnField performs as LeftJoin, but it joins both tables with the same field name.
+//
+// Eg:
+// Model("order").LeftJoinOnField("user", "user_id")
+// Model("order").LeftJoinOnField("product", "product_id").
+func (m *Model) LeftJoinOnField(table, field string) *Model {
+ return m.doJoin("LEFT", table, fmt.Sprintf(
+ `%s.%s=%s.%s`,
+ m.tables,
+ m.db.GetCore().QuoteWord(field),
+ m.db.GetCore().QuoteWord(table),
+ m.db.GetCore().QuoteWord(field),
+ ))
+}
+
+// RightJoinOnField performs as RightJoin, but it joins both tables with the same field name.
+//
+// Eg:
+// Model("order").InnerJoinOnField("user", "user_id")
+// Model("order").InnerJoinOnField("product", "product_id").
+func (m *Model) RightJoinOnField(table, field string) *Model {
+ return m.doJoin("RIGHT", table, fmt.Sprintf(
+ `%s.%s=%s.%s`,
+ m.tables,
+ m.db.GetCore().QuoteWord(field),
+ m.db.GetCore().QuoteWord(table),
+ m.db.GetCore().QuoteWord(field),
+ ))
+}
+
+// InnerJoinOnField performs as InnerJoin, but it joins both tables with the same field name.
+//
+// Eg:
+// Model("order").InnerJoinOnField("user", "user_id")
+// Model("order").InnerJoinOnField("product", "product_id").
+func (m *Model) InnerJoinOnField(table, field string) *Model {
+ return m.doJoin("INNER", table, fmt.Sprintf(
+ `%s.%s=%s.%s`,
+ m.tables,
+ m.db.GetCore().QuoteWord(field),
+ m.db.GetCore().QuoteWord(table),
+ m.db.GetCore().QuoteWord(field),
+ ))
+}
+
+// doJoin does "LEFT/RIGHT/INNER JOIN ... ON ..." statement on the model.
+// The parameter `table` can be joined table and its joined condition,
+// and also with its alias name.
+//
+// Eg:
+// Model("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Model("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+// Model("user", "u").InnerJoin("SELECT xxx FROM xxx AS a", "a.uid=u.uid")
+// Related issues:
+// https://github.com/gogf/gf/issues/1024
+func (m *Model) doJoin(operator string, table ...string) *Model {
+ var (
+ model = m.getModel()
+ joinStr = ""
+ )
+ if len(table) > 0 {
+ if isSubQuery(table[0]) {
+ joinStr = gstr.Trim(table[0])
+ if joinStr[0] != '(' {
+ joinStr = "(" + joinStr + ")"
+ }
+ } else {
+ joinStr = m.db.GetCore().QuotePrefixTableName(table[0])
+ }
+ }
+ if len(table) > 2 {
+ model.tables += fmt.Sprintf(
+ " %s JOIN %s AS %s ON (%s)",
+ operator, joinStr, m.db.GetCore().QuoteWord(table[1]), table[2],
+ )
+ } else if len(table) == 2 {
+ model.tables += fmt.Sprintf(
+ " %s JOIN %s ON (%s)",
+ operator, joinStr, table[1],
+ )
+ } else if len(table) == 1 {
+ model.tables += fmt.Sprintf(
+ " %s JOIN %s", operator, joinStr,
+ )
+ }
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_lock.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_lock.go
new file mode 100644
index 000000000000..a207a126e8dc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_lock.go
@@ -0,0 +1,21 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+// LockUpdate sets the lock for update for current operation.
+func (m *Model) LockUpdate() *Model {
+ model := m.getModel()
+ model.lockInfo = "FOR UPDATE"
+ return model
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (m *Model) LockShared() *Model {
+ model := m.getModel()
+ model.lockInfo = "LOCK IN SHARE MODE"
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_option.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_option.go
new file mode 100644
index 000000000000..f7520b3e94f1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_option.go
@@ -0,0 +1,72 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+const (
+ optionOmitNil = optionOmitNilWhere | optionOmitNilData
+ optionOmitEmpty = optionOmitEmptyWhere | optionOmitEmptyData
+ optionOmitNilDataInternal = optionOmitNilData | optionOmitNilDataList // this option is used internally only for ForDao feature.
+ optionOmitEmptyWhere = 1 << iota // 8
+ optionOmitEmptyData // 16
+ optionOmitNilWhere // 32
+ optionOmitNilData // 64
+ optionOmitNilDataList // 128
+)
+
+// OmitEmpty sets optionOmitEmpty option for the model, which automatically filers
+// the data and where parameters for `empty` values.
+func (m *Model) OmitEmpty() *Model {
+ model := m.getModel()
+ model.option = model.option | optionOmitEmpty
+ return model
+}
+
+// OmitEmptyWhere sets optionOmitEmptyWhere option for the model, which automatically filers
+// the Where/Having parameters for `empty` values.
+//
+// Eg:
+// Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
+// Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
+// OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
+// OmitEmpty().("name", "").All() -> SELECT xxx FROM xxx.
+func (m *Model) OmitEmptyWhere() *Model {
+ model := m.getModel()
+ model.option = model.option | optionOmitEmptyWhere
+ return model
+}
+
+// OmitEmptyData sets optionOmitEmptyData option for the model, which automatically filers
+// the Data parameters for `empty` values.
+func (m *Model) OmitEmptyData() *Model {
+ model := m.getModel()
+ model.option = model.option | optionOmitEmptyData
+ return model
+}
+
+// OmitNil sets optionOmitNil option for the model, which automatically filers
+// the data and where parameters for `nil` values.
+func (m *Model) OmitNil() *Model {
+ model := m.getModel()
+ model.option = model.option | optionOmitNil
+ return model
+}
+
+// OmitNilWhere sets optionOmitNilWhere option for the model, which automatically filers
+// the Where/Having parameters for `nil` values.
+func (m *Model) OmitNilWhere() *Model {
+ model := m.getModel()
+ model.option = model.option | optionOmitNilWhere
+ return model
+}
+
+// OmitNilData sets optionOmitNilData option for the model, which automatically filers
+// the Data parameters for `nil` values.
+func (m *Model) OmitNilData() *Model {
+ model := m.getModel()
+ model.option = model.option | optionOmitNilData
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_order_group.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_order_group.go
new file mode 100644
index 000000000000..bf8fbbc0174c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_order_group.go
@@ -0,0 +1,63 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import "strings"
+
+// Order sets the "ORDER BY" statement for the model.
+//
+// Eg:
+// Order("id desc")
+// Order("id", "desc")
+// Order("id desc,name asc").
+func (m *Model) Order(orderBy ...string) *Model {
+ if len(orderBy) == 0 {
+ return m
+ }
+ model := m.getModel()
+ if model.orderBy != "" {
+ model.orderBy += ","
+ }
+ model.orderBy = model.db.GetCore().QuoteString(strings.Join(orderBy, " "))
+ return model
+}
+
+// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
+func (m *Model) OrderAsc(column string) *Model {
+ if len(column) == 0 {
+ return m
+ }
+ return m.Order(column + " ASC")
+}
+
+// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
+func (m *Model) OrderDesc(column string) *Model {
+ if len(column) == 0 {
+ return m
+ }
+ return m.Order(column + " DESC")
+}
+
+// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
+func (m *Model) OrderRandom() *Model {
+ model := m.getModel()
+ model.orderBy = "RAND()"
+ return model
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (m *Model) Group(groupBy ...string) *Model {
+ if len(groupBy) == 0 {
+ return m
+ }
+ model := m.getModel()
+ if model.groupBy != "" {
+ model.groupBy += ","
+ }
+ model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ","))
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_select.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_select.go
new file mode 100644
index 000000000000..2fcc84b2d183
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_select.go
@@ -0,0 +1,749 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/crypto/gmd5"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as slice type.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *Model) All(where ...interface{}) (Result, error) {
+ return m.doGetAll(false, where...)
+}
+
+// doGetAll does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as slice type.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *Model) doGetAll(limit1 bool, where ...interface{}) (Result, error) {
+ if len(where) > 0 {
+ return m.Where(where[0], where[1:]...).All()
+ }
+ sqlWithHolder, holderArgs := m.getFormattedSqlAndArgs(queryTypeNormal, limit1)
+ return m.doGetAllBySql(sqlWithHolder, holderArgs...)
+}
+
+// getFieldsFiltered checks the fields and fieldsEx attributes, filters and returns the fields that will
+// really be committed to underlying database driver.
+func (m *Model) getFieldsFiltered() string {
+ if m.fieldsEx == "" {
+ // No filtering.
+ if !gstr.Contains(m.fields, ".") && !gstr.Contains(m.fields, " ") {
+ return m.db.GetCore().QuoteString(m.fields)
+ }
+ return m.fields
+ }
+ var (
+ fieldsArray []string
+ fieldsExSet = gset.NewStrSetFrom(gstr.SplitAndTrim(m.fieldsEx, ","))
+ )
+ if m.fields != "*" {
+ // Filter custom fields with fieldEx.
+ fieldsArray = make([]string, 0, 8)
+ for _, v := range gstr.SplitAndTrim(m.fields, ",") {
+ fieldsArray = append(fieldsArray, v[gstr.PosR(v, "-")+1:])
+ }
+ } else {
+ if gstr.Contains(m.tables, " ") {
+ panic("function FieldsEx supports only single table operations")
+ }
+ // Filter table fields with fieldEx.
+ tableFields, err := m.TableFields(m.tablesInit)
+ if err != nil {
+ panic(err)
+ }
+ if len(tableFields) == 0 {
+ panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables))
+ }
+ fieldsArray = make([]string, len(tableFields))
+ for k, v := range tableFields {
+ fieldsArray[v.Index] = k
+ }
+ }
+ newFields := ""
+ for _, k := range fieldsArray {
+ if fieldsExSet.Contains(k) {
+ continue
+ }
+ if len(newFields) > 0 {
+ newFields += ","
+ }
+ newFields += m.db.GetCore().QuoteWord(k)
+ }
+ return newFields
+}
+
+// Chunk iterates the query result with given `size` and `handler` function.
+func (m *Model) Chunk(size int, handler ChunkHandler) {
+ page := m.start
+ if page <= 0 {
+ page = 1
+ }
+ model := m
+ for {
+ model = model.Page(page, size)
+ data, err := model.All()
+ if err != nil {
+ handler(nil, err)
+ break
+ }
+ if len(data) == 0 {
+ break
+ }
+ if handler(data, err) == false {
+ break
+ }
+ if len(data) < size {
+ break
+ }
+ page++
+ }
+}
+
+// One retrieves one record from table and returns the result as map type.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *Model) One(where ...interface{}) (Record, error) {
+ if len(where) > 0 {
+ return m.Where(where[0], where[1:]...).One()
+ }
+ all, err := m.doGetAll(true)
+ if err != nil {
+ return nil, err
+ }
+ if len(all) > 0 {
+ return all[0], nil
+ }
+ return nil, nil
+}
+
+// Value retrieves a specified record value from table and returns the result as interface type.
+// It returns nil if there's no record found with the given conditions from table.
+//
+// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
+// and fieldsAndWhere[1:] is treated as where condition fields.
+// Also see Model.Fields and Model.Where functions.
+func (m *Model) Value(fieldsAndWhere ...interface{}) (Value, error) {
+ if len(fieldsAndWhere) > 0 {
+ if len(fieldsAndWhere) > 2 {
+ return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Value()
+ } else if len(fieldsAndWhere) == 2 {
+ return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Value()
+ } else {
+ return m.Fields(gconv.String(fieldsAndWhere[0])).Value()
+ }
+ }
+ one, err := m.One()
+ if err != nil {
+ return gvar.New(nil), err
+ }
+ for _, v := range one {
+ return v, nil
+ }
+ return gvar.New(nil), nil
+}
+
+// Array queries and returns data values as slice from database.
+// Note that if there are multiple columns in the result, it returns just one column values randomly.
+//
+// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
+// and fieldsAndWhere[1:] is treated as where condition fields.
+// Also see Model.Fields and Model.Where functions.
+func (m *Model) Array(fieldsAndWhere ...interface{}) ([]Value, error) {
+ if len(fieldsAndWhere) > 0 {
+ if len(fieldsAndWhere) > 2 {
+ return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Array()
+ } else if len(fieldsAndWhere) == 2 {
+ return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Array()
+ } else {
+ return m.Fields(gconv.String(fieldsAndWhere[0])).Array()
+ }
+ }
+ all, err := m.All()
+ if err != nil {
+ return nil, err
+ }
+ return all.Array(), nil
+}
+
+// Struct retrieves one record from table and converts it into given struct.
+// The parameter `pointer` should be type of *struct/**struct. If type **struct is given,
+// it can create the struct internally during converting.
+//
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+//
+// Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has
+// default value and there's no record retrieved with the given conditions from table.
+//
+// Example:
+// user := new(User)
+// err := db.Model("user").Where("id", 1).Scan(user)
+//
+// user := (*User)(nil)
+// err := db.Model("user").Where("id", 1).Scan(&user).
+func (m *Model) doStruct(pointer interface{}, where ...interface{}) error {
+ model := m
+ // Auto selecting fields by struct attributes.
+ if model.fieldsEx == "" && (model.fields == "" || model.fields == "*") {
+ if v, ok := pointer.(reflect.Value); ok {
+ model = m.Fields(v.Interface())
+ } else {
+ model = m.Fields(pointer)
+ }
+ }
+ one, err := model.One(where...)
+ if err != nil {
+ return err
+ }
+ if err = one.Struct(pointer); err != nil {
+ return err
+ }
+ return model.doWithScanStruct(pointer)
+}
+
+// Structs retrieves records from table and converts them into given struct slice.
+// The parameter `pointer` should be type of *[]struct/*[]*struct. It can create and fill the struct
+// slice internally during converting.
+//
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+//
+// Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has
+// default value and there's no record retrieved with the given conditions from table.
+//
+// Example:
+// users := ([]User)(nil)
+// err := db.Model("user").Scan(&users)
+//
+// users := ([]*User)(nil)
+// err := db.Model("user").Scan(&users).
+func (m *Model) doStructs(pointer interface{}, where ...interface{}) error {
+ model := m
+ // Auto selecting fields by struct attributes.
+ if model.fieldsEx == "" && (model.fields == "" || model.fields == "*") {
+ if v, ok := pointer.(reflect.Value); ok {
+ model = m.Fields(
+ reflect.New(
+ v.Type().Elem(),
+ ).Interface(),
+ )
+ } else {
+ model = m.Fields(
+ reflect.New(
+ reflect.ValueOf(pointer).Elem().Type().Elem(),
+ ).Interface(),
+ )
+ }
+ }
+ all, err := model.All(where...)
+ if err != nil {
+ return err
+ }
+ if err = all.Structs(pointer); err != nil {
+ return err
+ }
+ return model.doWithScanStructs(pointer)
+}
+
+// Scan automatically calls Struct or Structs function according to the type of parameter `pointer`.
+// It calls function doStruct if `pointer` is type of *struct/**struct.
+// It calls function doStructs if `pointer` is type of *[]struct/*[]*struct.
+//
+// The optional parameter `where` is the same as the parameter of Model.Where function, see Model.Where.
+//
+// Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has
+// default value and there's no record retrieved with the given conditions from table.
+//
+// Example:
+// user := new(User)
+// err := db.Model("user").Where("id", 1).Scan(user)
+//
+// user := (*User)(nil)
+// err := db.Model("user").Where("id", 1).Scan(&user)
+//
+// users := ([]User)(nil)
+// err := db.Model("user").Scan(&users)
+//
+// users := ([]*User)(nil)
+// err := db.Model("user").Scan(&users).
+func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
+ reflectInfo := utils.OriginTypeAndKind(pointer)
+ if reflectInfo.InputKind != reflect.Ptr {
+ return gerror.NewCode(
+ gcode.CodeInvalidParameter,
+ `the parameter "pointer" for function Scan should type of pointer`,
+ )
+ }
+ switch reflectInfo.OriginKind {
+ case reflect.Slice, reflect.Array:
+ return m.doStructs(pointer, where...)
+
+ case reflect.Struct, reflect.Invalid:
+ return m.doStruct(pointer, where...)
+
+ default:
+ return gerror.NewCode(
+ gcode.CodeInvalidParameter,
+ `element of parameter "pointer" for function Scan should type of struct/*struct/[]struct/[]*struct`,
+ )
+ }
+}
+
+// ScanList converts `r` to struct slice which contains other complex struct attributes.
+// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
+//
+// See Result.ScanList.
+func (m *Model) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
+ var result Result
+ out, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)
+ if err != nil {
+ return err
+ }
+ if m.fields != defaultFields || m.fieldsEx != "" {
+ // There are custom fields.
+ result, err = m.All()
+ } else {
+ // Filter fields using temporary created struct using reflect.New.
+ result, err = m.Fields(reflect.New(out.BindToAttrType).Interface()).All()
+ }
+ if err != nil {
+ return err
+ }
+ var (
+ relationAttrName string
+ relationFields string
+ )
+ switch len(relationAttrNameAndFields) {
+ case 2:
+ relationAttrName = relationAttrNameAndFields[0]
+ relationFields = relationAttrNameAndFields[1]
+ case 1:
+ relationFields = relationAttrNameAndFields[0]
+ }
+ return doScanList(doScanListInput{
+ Model: m,
+ Result: result,
+ StructSlicePointer: structSlicePointer,
+ StructSliceValue: out.SliceReflectValue,
+ BindToAttrName: bindToAttrName,
+ RelationAttrName: relationAttrName,
+ RelationFields: relationFields,
+ })
+}
+
+// Count does "SELECT COUNT(x) FROM ..." statement for the model.
+// The optional parameter `where` is the same as the parameter of Model.Where function,
+// see Model.Where.
+func (m *Model) Count(where ...interface{}) (int, error) {
+ if len(where) > 0 {
+ return m.Where(where[0], where[1:]...).Count()
+ }
+ var (
+ sqlWithHolder, holderArgs = m.getFormattedSqlAndArgs(queryTypeCount, false)
+ list, err = m.doGetAllBySql(sqlWithHolder, holderArgs...)
+ )
+ if err != nil {
+ return 0, err
+ }
+ if len(list) > 0 {
+ for _, v := range list[0] {
+ return v.Int(), nil
+ }
+ }
+ return 0, nil
+}
+
+// CountColumn does "SELECT COUNT(x) FROM ..." statement for the model.
+func (m *Model) CountColumn(column string) (int, error) {
+ if len(column) == 0 {
+ return 0, nil
+ }
+ return m.Fields(column).Count()
+}
+
+// Min does "SELECT MIN(x) FROM ..." statement for the model.
+func (m *Model) Min(column string) (float64, error) {
+ if len(column) == 0 {
+ return 0, nil
+ }
+ value, err := m.Fields(fmt.Sprintf(`MIN(%s)`, m.QuoteWord(column))).Value()
+ if err != nil {
+ return 0, err
+ }
+ return value.Float64(), err
+}
+
+// Max does "SELECT MAX(x) FROM ..." statement for the model.
+func (m *Model) Max(column string) (float64, error) {
+ if len(column) == 0 {
+ return 0, nil
+ }
+ value, err := m.Fields(fmt.Sprintf(`MAX(%s)`, m.QuoteWord(column))).Value()
+ if err != nil {
+ return 0, err
+ }
+ return value.Float64(), err
+}
+
+// Avg does "SELECT AVG(x) FROM ..." statement for the model.
+func (m *Model) Avg(column string) (float64, error) {
+ if len(column) == 0 {
+ return 0, nil
+ }
+ value, err := m.Fields(fmt.Sprintf(`AVG(%s)`, m.QuoteWord(column))).Value()
+ if err != nil {
+ return 0, err
+ }
+ return value.Float64(), err
+}
+
+// Sum does "SELECT SUM(x) FROM ..." statement for the model.
+func (m *Model) Sum(column string) (float64, error) {
+ if len(column) == 0 {
+ return 0, nil
+ }
+ value, err := m.Fields(fmt.Sprintf(`SUM(%s)`, m.QuoteWord(column))).Value()
+ if err != nil {
+ return 0, err
+ }
+ return value.Float64(), err
+}
+
+// Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement for the model.
+func (m *Model) Union(unions ...*Model) *Model {
+ return m.db.Union(unions...)
+}
+
+// UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement for the model.
+func (m *Model) UnionAll(unions ...*Model) *Model {
+ return m.db.UnionAll(unions...)
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter `limit` can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (m *Model) Limit(limit ...int) *Model {
+ model := m.getModel()
+ switch len(limit) {
+ case 1:
+ model.limit = limit[0]
+ case 2:
+ model.start = limit[0]
+ model.limit = limit[1]
+ }
+ return model
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (m *Model) Offset(offset int) *Model {
+ model := m.getModel()
+ model.offset = offset
+ return model
+}
+
+// Distinct forces the query to only return distinct results.
+func (m *Model) Distinct() *Model {
+ model := m.getModel()
+ model.distinct = "DISTINCT "
+ return model
+}
+
+// Page sets the paging number for the model.
+// The parameter `page` is started from 1 for paging.
+// Note that, it differs that the Limit function starts from 0 for "LIMIT" statement.
+func (m *Model) Page(page, limit int) *Model {
+ model := m.getModel()
+ if page <= 0 {
+ page = 1
+ }
+ model.start = (page - 1) * limit
+ model.limit = limit
+ return model
+}
+
+// Having sets the having statement for the model.
+// The parameters of this function usage are as the same as function Where.
+// See Where.
+func (m *Model) Having(having interface{}, args ...interface{}) *Model {
+ model := m.getModel()
+ model.having = []interface{}{
+ having, args,
+ }
+ return model
+}
+
+// doGetAllBySql does the select statement on the database.
+func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, err error) {
+ var (
+ ok bool
+ ctx = m.GetCtx()
+ cacheKey = ""
+ cacheObj = m.db.GetCache()
+ )
+ // Retrieve from cache.
+ if m.cacheEnabled && m.tx == nil {
+ cacheKey = m.cacheOption.Name
+ if len(cacheKey) == 0 {
+ cacheKey = fmt.Sprintf(
+ `GCache@Schema(%s):%s`,
+ m.db.GetSchema(),
+ gmd5.MustEncryptString(sql+", @PARAMS:"+gconv.String(args)),
+ )
+ }
+ if v, _ := cacheObj.Get(ctx, cacheKey); !v.IsNil() {
+ if result, ok = v.Val().(Result); ok {
+ // In-memory cache.
+ return result, nil
+ }
+ // Other cache, it needs conversion.
+ if err = json.UnmarshalUseNumber(v.Bytes(), &result); err != nil {
+ return nil, err
+ } else {
+ return result, nil
+ }
+ }
+ }
+ result, err = m.db.DoGetAll(
+ m.GetCtx(), m.getLink(false), sql, m.mergeArguments(args)...,
+ )
+ // Cache the result.
+ if cacheKey != "" && err == nil {
+ if m.cacheOption.Duration < 0 {
+ if _, err = cacheObj.Remove(ctx, cacheKey); err != nil {
+ intlog.Errorf(m.GetCtx(), `%+v`, err)
+ }
+ } else {
+ // In case of Cache Penetration.
+ if result.IsEmpty() && m.cacheOption.Force {
+ result = Result{}
+ }
+ if err = cacheObj.Set(ctx, cacheKey, result, m.cacheOption.Duration); err != nil {
+ intlog.Errorf(m.GetCtx(), `%+v`, err)
+ }
+ }
+ }
+ return result, err
+}
+
+func (m *Model) getFormattedSqlAndArgs(queryType int, limit1 bool) (sqlWithHolder string, holderArgs []interface{}) {
+ switch queryType {
+ case queryTypeCount:
+ countFields := "COUNT(1)"
+ if m.fields != "" && m.fields != "*" {
+ // DO NOT quote the m.fields here, in case of fields like:
+ // DISTINCT t.user_id uid
+ countFields = fmt.Sprintf(`COUNT(%s%s)`, m.distinct, m.fields)
+ }
+ // Raw SQL Model.
+ if m.rawSql != "" {
+ sqlWithHolder = fmt.Sprintf("SELECT %s FROM (%s) AS T", countFields, m.rawSql)
+ return sqlWithHolder, nil
+ }
+ conditionWhere, conditionExtra, conditionArgs := m.formatCondition(false, true)
+ sqlWithHolder = fmt.Sprintf("SELECT %s FROM %s%s", countFields, m.tables, conditionWhere+conditionExtra)
+ if len(m.groupBy) > 0 {
+ sqlWithHolder = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", sqlWithHolder)
+ }
+ return sqlWithHolder, conditionArgs
+
+ default:
+ conditionWhere, conditionExtra, conditionArgs := m.formatCondition(limit1, false)
+ // Raw SQL Model, especially for UNION/UNION ALL featured SQL.
+ if m.rawSql != "" {
+ sqlWithHolder = fmt.Sprintf(
+ "%s%s",
+ m.rawSql,
+ conditionWhere+conditionExtra,
+ )
+ return sqlWithHolder, conditionArgs
+ }
+ // DO NOT quote the m.fields where, in case of fields like:
+ // DISTINCT t.user_id uid
+ sqlWithHolder = fmt.Sprintf(
+ "SELECT %s%s FROM %s%s",
+ m.distinct,
+ m.getFieldsFiltered(),
+ m.tables,
+ conditionWhere+conditionExtra,
+ )
+ return sqlWithHolder, conditionArgs
+ }
+}
+
+// formatCondition formats where arguments of the model and returns a new condition sql and its arguments.
+// Note that this function does not change any attribute value of the `m`.
+//
+// The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
+func (m *Model) formatCondition(limit1 bool, isCountStatement bool) (conditionWhere string, conditionExtra string, conditionArgs []interface{}) {
+ autoPrefix := ""
+ if gstr.Contains(m.tables, " JOIN ") {
+ autoPrefix = m.db.GetCore().QuoteWord(
+ m.db.GetCore().guessPrimaryTableName(m.tablesInit),
+ )
+ }
+ var (
+ tableForMappingAndFiltering = m.tables
+ )
+ if len(m.whereHolder) > 0 {
+ for _, holder := range m.whereHolder {
+ tableForMappingAndFiltering = m.tables
+ if holder.Prefix == "" {
+ holder.Prefix = autoPrefix
+ }
+
+ switch holder.Operator {
+ case whereHolderOperatorWhere:
+ if conditionWhere == "" {
+ newWhere, newArgs := formatWhereHolder(m.db, formatWhereHolderInput{
+ ModelWhereHolder: holder,
+ OmitNil: m.option&optionOmitNilWhere > 0,
+ OmitEmpty: m.option&optionOmitEmptyWhere > 0,
+ Schema: m.schema,
+ Table: tableForMappingAndFiltering,
+ })
+ if len(newWhere) > 0 {
+ conditionWhere = newWhere
+ conditionArgs = newArgs
+ }
+ continue
+ }
+ fallthrough
+
+ case whereHolderOperatorAnd:
+ newWhere, newArgs := formatWhereHolder(m.db, formatWhereHolderInput{
+ ModelWhereHolder: holder,
+ OmitNil: m.option&optionOmitNilWhere > 0,
+ OmitEmpty: m.option&optionOmitEmptyWhere > 0,
+ Schema: m.schema,
+ Table: tableForMappingAndFiltering,
+ })
+ if len(newWhere) > 0 {
+ if len(conditionWhere) == 0 {
+ conditionWhere = newWhere
+ } else if conditionWhere[0] == '(' {
+ conditionWhere = fmt.Sprintf(`%s AND (%s)`, conditionWhere, newWhere)
+ } else {
+ conditionWhere = fmt.Sprintf(`(%s) AND (%s)`, conditionWhere, newWhere)
+ }
+ conditionArgs = append(conditionArgs, newArgs...)
+ }
+
+ case whereHolderOperatorOr:
+ newWhere, newArgs := formatWhereHolder(m.db, formatWhereHolderInput{
+ ModelWhereHolder: holder,
+ OmitNil: m.option&optionOmitNilWhere > 0,
+ OmitEmpty: m.option&optionOmitEmptyWhere > 0,
+ Schema: m.schema,
+ Table: tableForMappingAndFiltering,
+ })
+ if len(newWhere) > 0 {
+ if len(conditionWhere) == 0 {
+ conditionWhere = newWhere
+ } else if conditionWhere[0] == '(' {
+ conditionWhere = fmt.Sprintf(`%s OR (%s)`, conditionWhere, newWhere)
+ } else {
+ conditionWhere = fmt.Sprintf(`(%s) OR (%s)`, conditionWhere, newWhere)
+ }
+ conditionArgs = append(conditionArgs, newArgs...)
+ }
+ }
+ }
+ }
+ // Soft deletion.
+ softDeletingCondition := m.getConditionForSoftDeleting()
+ if m.rawSql != "" && conditionWhere != "" {
+ if gstr.ContainsI(m.rawSql, " WHERE ") {
+ conditionWhere = " AND " + conditionWhere
+ } else {
+ conditionWhere = " WHERE " + conditionWhere
+ }
+ } else if !m.unscoped && softDeletingCondition != "" {
+ if conditionWhere == "" {
+ conditionWhere = fmt.Sprintf(` WHERE %s`, softDeletingCondition)
+ } else {
+ conditionWhere = fmt.Sprintf(` WHERE (%s) AND %s`, conditionWhere, softDeletingCondition)
+ }
+ } else {
+ if conditionWhere != "" {
+ conditionWhere = " WHERE " + conditionWhere
+ }
+ }
+
+ // GROUP BY.
+ if m.groupBy != "" {
+ conditionExtra += " GROUP BY " + m.groupBy
+ }
+ // HAVING.
+ if len(m.having) > 0 {
+ havingHolder := ModelWhereHolder{
+ Where: m.having[0],
+ Args: gconv.Interfaces(m.having[1]),
+ Prefix: autoPrefix,
+ }
+ havingStr, havingArgs := formatWhereHolder(m.db, formatWhereHolderInput{
+ ModelWhereHolder: havingHolder,
+ OmitNil: m.option&optionOmitNilWhere > 0,
+ OmitEmpty: m.option&optionOmitEmptyWhere > 0,
+ Schema: m.schema,
+ Table: m.tables,
+ })
+ if len(havingStr) > 0 {
+ conditionExtra += " HAVING " + havingStr
+ conditionArgs = append(conditionArgs, havingArgs...)
+ }
+ }
+ // ORDER BY.
+ if m.orderBy != "" {
+ conditionExtra += " ORDER BY " + m.orderBy
+ }
+ // LIMIT.
+ if !isCountStatement {
+ if m.limit != 0 {
+ if m.start >= 0 {
+ conditionExtra += fmt.Sprintf(" LIMIT %d,%d", m.start, m.limit)
+ } else {
+ conditionExtra += fmt.Sprintf(" LIMIT %d", m.limit)
+ }
+ } else if limit1 {
+ conditionExtra += " LIMIT 1"
+ }
+
+ if m.offset >= 0 {
+ conditionExtra += fmt.Sprintf(" OFFSET %d", m.offset)
+ }
+ }
+
+ if m.lockInfo != "" {
+ conditionExtra += " " + m.lockInfo
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_time.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_time.go
new file mode 100644
index 000000000000..34ff115663a1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_time.go
@@ -0,0 +1,174 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+var (
+ createdFiledNames = []string{"created_at", "create_at"} // Default filed names of table for automatic-filled created datetime.
+ updatedFiledNames = []string{"updated_at", "update_at"} // Default filed names of table for automatic-filled updated datetime.
+ deletedFiledNames = []string{"deleted_at", "delete_at"} // Default filed names of table for automatic-filled deleted datetime.
+)
+
+// Unscoped disables the auto-update time feature for insert, update and delete options.
+func (m *Model) Unscoped() *Model {
+ model := m.getModel()
+ model.unscoped = true
+ return model
+}
+
+// getSoftFieldNameCreate checks and returns the field name for record creating time.
+// If there's no field name for storing creating time, it returns an empty string.
+// It checks the key with or without cases or chars '-'/'_'/'.'/' '.
+func (m *Model) getSoftFieldNameCreated(table ...string) string {
+ // It checks whether this feature disabled.
+ if m.db.GetConfig().TimeMaintainDisabled {
+ return ""
+ }
+ tableName := ""
+ if len(table) > 0 {
+ tableName = table[0]
+ } else {
+ tableName = m.tablesInit
+ }
+ config := m.db.GetConfig()
+ if config.CreatedAt != "" {
+ return m.getSoftFieldName(tableName, []string{config.CreatedAt})
+ }
+ return m.getSoftFieldName(tableName, createdFiledNames)
+}
+
+// getSoftFieldNameUpdate checks and returns the field name for record updating time.
+// If there's no field name for storing updating time, it returns an empty string.
+// It checks the key with or without cases or chars '-'/'_'/'.'/' '.
+func (m *Model) getSoftFieldNameUpdated(table ...string) (field string) {
+ // It checks whether this feature disabled.
+ if m.db.GetConfig().TimeMaintainDisabled {
+ return ""
+ }
+ tableName := ""
+ if len(table) > 0 {
+ tableName = table[0]
+ } else {
+ tableName = m.tablesInit
+ }
+ config := m.db.GetConfig()
+ if config.UpdatedAt != "" {
+ return m.getSoftFieldName(tableName, []string{config.UpdatedAt})
+ }
+ return m.getSoftFieldName(tableName, updatedFiledNames)
+}
+
+// getSoftFieldNameDelete checks and returns the field name for record deleting time.
+// If there's no field name for storing deleting time, it returns an empty string.
+// It checks the key with or without cases or chars '-'/'_'/'.'/' '.
+func (m *Model) getSoftFieldNameDeleted(table ...string) (field string) {
+ // It checks whether this feature disabled.
+ if m.db.GetConfig().TimeMaintainDisabled {
+ return ""
+ }
+ tableName := ""
+ if len(table) > 0 {
+ tableName = table[0]
+ } else {
+ tableName = m.tablesInit
+ }
+ config := m.db.GetConfig()
+ if config.UpdatedAt != "" {
+ return m.getSoftFieldName(tableName, []string{config.DeletedAt})
+ }
+ return m.getSoftFieldName(tableName, deletedFiledNames)
+}
+
+// getSoftFieldName retrieves and returns the field name of the table for possible key.
+func (m *Model) getSoftFieldName(table string, keys []string) (field string) {
+ // Ignore the error from TableFields.
+ fieldsMap, _ := m.TableFields(table)
+ if len(fieldsMap) > 0 {
+ for _, key := range keys {
+ field, _ = gutil.MapPossibleItemByKey(
+ gconv.Map(fieldsMap), key,
+ )
+ if field != "" {
+ return
+ }
+ }
+ }
+ return
+}
+
+// getConditionForSoftDeleting retrieves and returns the condition string for soft deleting.
+// It supports multiple tables string like:
+// "user u, user_detail ud"
+// "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid)"
+// "user LEFT JOIN user_detail ON(user_detail.uid=user.uid)"
+// "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid) LEFT JOIN user_stats us ON(us.uid=u.uid)".
+func (m *Model) getConditionForSoftDeleting() string {
+ if m.unscoped {
+ return ""
+ }
+ conditionArray := garray.NewStrArray()
+ if gstr.Contains(m.tables, " JOIN ") {
+ // Base table.
+ match, _ := gregex.MatchString(`(.+?) [A-Z]+ JOIN`, m.tables)
+ conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
+ // Multiple joined tables, exclude the sub query sql which contains char '(' and ')'.
+ matches, _ := gregex.MatchAllString(`JOIN ([^()]+?) ON`, m.tables)
+ for _, match := range matches {
+ conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
+ }
+ }
+ if conditionArray.Len() == 0 && gstr.Contains(m.tables, ",") {
+ // Multiple base tables.
+ for _, s := range gstr.SplitAndTrim(m.tables, ",") {
+ conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(s))
+ }
+ }
+ conditionArray.FilterEmpty()
+ if conditionArray.Len() > 0 {
+ return conditionArray.Join(" AND ")
+ }
+ // Only one table.
+ if fieldName := m.getSoftFieldNameDeleted(); fieldName != "" {
+ return fmt.Sprintf(`%s IS NULL`, m.db.GetCore().QuoteWord(fieldName))
+ }
+ return ""
+}
+
+// getConditionOfTableStringForSoftDeleting does something as its name describes.
+func (m *Model) getConditionOfTableStringForSoftDeleting(s string) string {
+ var (
+ field = ""
+ table = ""
+ array1 = gstr.SplitAndTrim(s, " ")
+ array2 = gstr.SplitAndTrim(array1[0], ".")
+ )
+ if len(array2) >= 2 {
+ table = array2[1]
+ } else {
+ table = array2[0]
+ }
+ field = m.getSoftFieldNameDeleted(table)
+ if field == "" {
+ return ""
+ }
+ if len(array1) >= 3 {
+ return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(array1[2]), m.db.GetCore().QuoteWord(field))
+ }
+ if len(array1) >= 2 {
+ return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(array1[1]), m.db.GetCore().QuoteWord(field))
+ }
+ return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(table), m.db.GetCore().QuoteWord(field))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_transaction.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_transaction.go
new file mode 100644
index 000000000000..6aaf933bf7fa
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_transaction.go
@@ -0,0 +1,28 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "context"
+)
+
+// Transaction wraps the transaction logic using function `f`.
+// It rollbacks the transaction and returns the error from function `f` if
+// it returns non-nil error. It commits the transaction and returns nil if
+// function `f` returns nil.
+//
+// Note that, you should not Commit or Rollback the transaction in function `f`
+// as it is automatically handled by this function.
+func (m *Model) Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) (err error) {
+ if ctx == nil {
+ ctx = m.GetCtx()
+ }
+ if m.tx != nil {
+ return m.tx.Transaction(ctx, f)
+ }
+ return m.db.Transaction(ctx, f)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_update.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_update.go
new file mode 100644
index 000000000000..c6fe04c6f0e1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_update.go
@@ -0,0 +1,103 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+ "fmt"
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Update does "UPDATE ... " statement for the model.
+//
+// If the optional parameter `dataAndWhere` is given, the dataAndWhere[0] is the updated data field,
+// and dataAndWhere[1:] is treated as where condition fields.
+// Also see Model.Data and Model.Where functions.
+func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
+ if len(dataAndWhere) > 0 {
+ if len(dataAndWhere) > 2 {
+ return m.Data(dataAndWhere[0]).Where(dataAndWhere[1], dataAndWhere[2:]...).Update()
+ } else if len(dataAndWhere) == 2 {
+ return m.Data(dataAndWhere[0]).Where(dataAndWhere[1]).Update()
+ } else {
+ return m.Data(dataAndWhere[0]).Update()
+ }
+ }
+ defer func() {
+ if err == nil {
+ m.checkAndRemoveCache()
+ }
+ }()
+ if m.data == nil {
+ return nil, gerror.NewCode(gcode.CodeMissingParameter, "updating table with empty data")
+ }
+ var (
+ updateData = m.data
+ fieldNameUpdate = m.getSoftFieldNameUpdated()
+ conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false, false)
+ )
+ // Automatically update the record updating time.
+ if !m.unscoped && fieldNameUpdate != "" {
+ reflectInfo := utils.OriginTypeAndKind(m.data)
+ switch reflectInfo.OriginKind {
+ case reflect.Map, reflect.Struct:
+ dataMap := m.db.ConvertDataForRecord(m.GetCtx(), m.data)
+ if fieldNameUpdate != "" {
+ dataMap[fieldNameUpdate] = gtime.Now().String()
+ }
+ updateData = dataMap
+
+ default:
+ updates := gconv.String(m.data)
+ if fieldNameUpdate != "" && !gstr.Contains(updates, fieldNameUpdate) {
+ updates += fmt.Sprintf(`,%s='%s'`, fieldNameUpdate, gtime.Now().String())
+ }
+ updateData = updates
+ }
+ }
+ newData, err := m.filterDataForInsertOrUpdate(updateData)
+ if err != nil {
+ return nil, err
+ }
+ conditionStr := conditionWhere + conditionExtra
+ if !gstr.ContainsI(conditionStr, " WHERE ") {
+ return nil, gerror.NewCode(gcode.CodeMissingParameter, "there should be WHERE condition statement for UPDATE operation")
+ }
+ return m.db.DoUpdate(
+ m.GetCtx(),
+ m.getLink(true),
+ m.tables,
+ newData,
+ conditionStr,
+ m.mergeArguments(conditionArgs)...,
+ )
+}
+
+// Increment increments a column's value by a given amount.
+// The parameter `amount` can be type of float or integer.
+func (m *Model) Increment(column string, amount interface{}) (sql.Result, error) {
+ return m.getModel().Data(column, &Counter{
+ Field: column,
+ Value: gconv.Float64(amount),
+ }).Update()
+}
+
+// Decrement decrements a column's value by a given amount.
+// The parameter `amount` can be type of float or integer.
+func (m *Model) Decrement(column string, amount interface{}) (sql.Result, error) {
+ return m.getModel().Data(column, &Counter{
+ Field: column,
+ Value: -gconv.Float64(amount),
+ }).Update()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_utility.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_utility.go
new file mode 100644
index 000000000000..2559217e8581
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_utility.go
@@ -0,0 +1,253 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "time"
+
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// QuoteWord checks given string `s` a word,
+// if true it quotes `s` with security chars of the database
+// and returns the quoted string; or else it returns `s` without any change.
+//
+// The meaning of a `word` can be considered as a column name.
+func (m *Model) QuoteWord(s string) string {
+ return m.db.GetCore().QuoteWord(s)
+}
+
+// TableFields retrieves and returns the fields' information of specified table of current
+// schema.
+//
+// Also see DriverMysql.TableFields.
+func (m *Model) TableFields(tableStr string, schema ...string) (fields map[string]*TableField, err error) {
+ var (
+ table = m.db.GetCore().guessPrimaryTableName(tableStr)
+ useSchema = m.schema
+ )
+ if len(schema) > 0 && schema[0] != "" {
+ useSchema = schema[0]
+ }
+ return m.db.GetCore().TableFields(table, useSchema)
+}
+
+// getModel creates and returns a cloned model of current model if `safe` is true, or else it returns
+// the current model.
+func (m *Model) getModel() *Model {
+ if !m.safe {
+ return m
+ } else {
+ return m.Clone()
+ }
+}
+
+// mappingAndFilterToTableFields mappings and changes given field name to really table field name.
+// Eg:
+// ID -> id
+// NICK_Name -> nickname.
+func (m *Model) mappingAndFilterToTableFields(fields []string, filter bool) []string {
+ fieldsMap, _ := m.TableFields(m.tablesInit)
+ if len(fieldsMap) == 0 {
+ return fields
+ }
+ var (
+ inputFieldsArray = gstr.SplitAndTrim(gstr.Join(fields, ","), ",")
+ outputFieldsArray = make([]string, 0, len(inputFieldsArray))
+ )
+ fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
+ for k := range fieldsMap {
+ fieldsKeyMap[k] = nil
+ }
+ for _, field := range inputFieldsArray {
+ if _, ok := fieldsKeyMap[field]; !ok {
+ if !gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, field) {
+ // Eg: user.id, user.name
+ outputFieldsArray = append(outputFieldsArray, field)
+ continue
+ } else {
+ // Eg: id, name
+ if foundKey, _ := gutil.MapPossibleItemByKey(fieldsKeyMap, field); foundKey != "" {
+ outputFieldsArray = append(outputFieldsArray, foundKey)
+ } else if !filter {
+ outputFieldsArray = append(outputFieldsArray, field)
+ }
+ }
+ } else {
+ outputFieldsArray = append(outputFieldsArray, field)
+ }
+ }
+ return outputFieldsArray
+}
+
+// filterDataForInsertOrUpdate does filter feature with data for inserting/updating operations.
+// Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
+func (m *Model) filterDataForInsertOrUpdate(data interface{}) (interface{}, error) {
+ var err error
+ switch value := data.(type) {
+ case List:
+ var omitEmpty bool
+ if m.option&optionOmitNilDataList > 0 {
+ omitEmpty = true
+ }
+ for k, item := range value {
+ value[k], err = m.doMappingAndFilterForInsertOrUpdateDataMap(item, omitEmpty)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return value, nil
+
+ case Map:
+ return m.doMappingAndFilterForInsertOrUpdateDataMap(value, true)
+
+ default:
+ return data, nil
+ }
+}
+
+// doMappingAndFilterForInsertOrUpdateDataMap does the filter features for map.
+// Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
+func (m *Model) doMappingAndFilterForInsertOrUpdateDataMap(data Map, allowOmitEmpty bool) (Map, error) {
+ var err error
+ data, err = m.db.GetCore().mappingAndFilterData(
+ m.schema, m.tablesInit, data, m.filter,
+ )
+ if err != nil {
+ return nil, err
+ }
+ // Remove key-value pairs of which the value is nil.
+ if allowOmitEmpty && m.option&optionOmitNilData > 0 {
+ tempMap := make(Map, len(data))
+ for k, v := range data {
+ if empty.IsNil(v) {
+ continue
+ }
+ tempMap[k] = v
+ }
+ data = tempMap
+ }
+
+ // Remove key-value pairs of which the value is empty.
+ if allowOmitEmpty && m.option&optionOmitEmptyData > 0 {
+ tempMap := make(Map, len(data))
+ for k, v := range data {
+ if empty.IsEmpty(v) {
+ continue
+ }
+ // Special type filtering.
+ switch r := v.(type) {
+ case time.Time:
+ if r.IsZero() {
+ continue
+ }
+ case *time.Time:
+ if r.IsZero() {
+ continue
+ }
+ case gtime.Time:
+ if r.IsZero() {
+ continue
+ }
+ case *gtime.Time:
+ if r.IsZero() {
+ continue
+ }
+ }
+ tempMap[k] = v
+ }
+ data = tempMap
+ }
+
+ if len(m.fields) > 0 && m.fields != "*" {
+ // Keep specified fields.
+ var (
+ set = gset.NewStrSetFrom(gstr.SplitAndTrim(m.fields, ","))
+ charL, charR = m.db.GetChars()
+ chars = charL + charR
+ )
+ set.Walk(func(item string) string {
+ return gstr.Trim(item, chars)
+ })
+ for k := range data {
+ k = gstr.Trim(k, chars)
+ if !set.Contains(k) {
+ delete(data, k)
+ }
+ }
+ } else if len(m.fieldsEx) > 0 {
+ // Filter specified fields.
+ for _, v := range gstr.SplitAndTrim(m.fieldsEx, ",") {
+ delete(data, v)
+ }
+ }
+ return data, nil
+}
+
+// getLink returns the underlying database link object with configured `linkType` attribute.
+// The parameter `master` specifies whether using the master node if master-slave configured.
+func (m *Model) getLink(master bool) Link {
+ if m.tx != nil {
+ return &txLink{m.tx.tx}
+ }
+ linkType := m.linkType
+ if linkType == 0 {
+ if master {
+ linkType = linkTypeMaster
+ } else {
+ linkType = linkTypeSlave
+ }
+ }
+ switch linkType {
+ case linkTypeMaster:
+ link, err := m.db.GetCore().MasterLink(m.schema)
+ if err != nil {
+ panic(err)
+ }
+ return link
+ case linkTypeSlave:
+ link, err := m.db.GetCore().SlaveLink(m.schema)
+ if err != nil {
+ panic(err)
+ }
+ return link
+ }
+ return nil
+}
+
+// getPrimaryKey retrieves and returns the primary key name of the model table.
+// It parses m.tables to retrieve the primary table name, supporting m.tables like:
+// "user", "user u", "user as u, user_detail as ud".
+func (m *Model) getPrimaryKey() string {
+ table := gstr.SplitAndTrim(m.tablesInit, " ")[0]
+ tableFields, err := m.TableFields(table)
+ if err != nil {
+ return ""
+ }
+ for name, field := range tableFields {
+ if gstr.ContainsI(field.Key, "pri") {
+ return name
+ }
+ }
+ return ""
+}
+
+// mergeArguments creates and returns new arguments by merging `m.extraArgs` and given `args`.
+func (m *Model) mergeArguments(args []interface{}) []interface{} {
+ if len(m.extraArgs) > 0 {
+ newArgs := make([]interface{}, len(m.extraArgs)+len(args))
+ copy(newArgs, m.extraArgs)
+ copy(newArgs[len(m.extraArgs):], args)
+ return newArgs
+ }
+ return args
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_where.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_where.go
new file mode 100644
index 000000000000..0b168eb642e3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_where.go
@@ -0,0 +1,159 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// doWhereType sets the condition statement for the model. The parameter `where` can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+func (m *Model) doWhereType(t string, where interface{}, args ...interface{}) *Model {
+ model := m.getModel()
+ if model.whereHolder == nil {
+ model.whereHolder = make([]ModelWhereHolder, 0)
+ }
+ if t == "" {
+ if len(args) == 0 {
+ t = whereHolderTypeNoArgs
+ } else {
+ t = whereHolderTypeDefault
+ }
+ }
+ model.whereHolder = append(model.whereHolder, ModelWhereHolder{
+ Type: t,
+ Operator: whereHolderOperatorWhere,
+ Where: where,
+ Args: args,
+ })
+ return model
+}
+
+// doWherefType builds condition string using fmt.Sprintf and arguments.
+// Note that if the number of `args` is more than the placeholder in `format`,
+// the extra `args` will be used as the where condition arguments of the Model.
+func (m *Model) doWherefType(t string, format string, args ...interface{}) *Model {
+ var (
+ placeHolderCount = gstr.Count(format, "?")
+ conditionStr = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...)
+ )
+ return m.doWhereType(t, conditionStr, args[len(args)-placeHolderCount:]...)
+}
+
+// Where sets the condition statement for the model. The parameter `where` can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"}).
+func (m *Model) Where(where interface{}, args ...interface{}) *Model {
+ return m.doWhereType(``, where, args...)
+}
+
+// Wheref builds condition string using fmt.Sprintf and arguments.
+// Note that if the number of `args` is more than the placeholder in `format`,
+// the extra `args` will be used as the where condition arguments of the Model.
+// Eg:
+// Wheref(`amount and status=%s`, "paid", 100) => WHERE `amount`<100 and status='paid'
+// Wheref(`amount<%d and status=%s`, 100, "paid") => WHERE `amount`<100 and status='paid'
+func (m *Model) Wheref(format string, args ...interface{}) *Model {
+ return m.doWherefType(``, format, args...)
+}
+
+// WherePri does the same logic as Model.Where except that if the parameter `where`
+// is a single condition like int/string/float/slice, it treats the condition as the primary
+// key value. That is, if primary key is "id" and given `where` parameter as "123", the
+// WherePri function treats the condition as "id=123", but Model.Where treats the condition
+// as string "123".
+func (m *Model) WherePri(where interface{}, args ...interface{}) *Model {
+ if len(args) > 0 {
+ return m.Where(where, args...)
+ }
+ newWhere := GetPrimaryKeyCondition(m.getPrimaryKey(), where)
+ return m.Where(newWhere[0], newWhere[1:]...)
+}
+
+// WhereLT builds `column < value` statement.
+func (m *Model) WhereLT(column string, value interface{}) *Model {
+ return m.Wheref(`%s < ?`, m.QuoteWord(column), value)
+}
+
+// WhereLTE builds `column <= value` statement.
+func (m *Model) WhereLTE(column string, value interface{}) *Model {
+ return m.Wheref(`%s <= ?`, m.QuoteWord(column), value)
+}
+
+// WhereGT builds `column > value` statement.
+func (m *Model) WhereGT(column string, value interface{}) *Model {
+ return m.Wheref(`%s > ?`, m.QuoteWord(column), value)
+}
+
+// WhereGTE builds `column >= value` statement.
+func (m *Model) WhereGTE(column string, value interface{}) *Model {
+ return m.Wheref(`%s >= ?`, m.QuoteWord(column), value)
+}
+
+// WhereBetween builds `column BETWEEN min AND max` statement.
+func (m *Model) WhereBetween(column string, min, max interface{}) *Model {
+ return m.Wheref(`%s BETWEEN ? AND ?`, m.QuoteWord(column), min, max)
+}
+
+// WhereLike builds `column LIKE like` statement.
+func (m *Model) WhereLike(column string, like string) *Model {
+ return m.Wheref(`%s LIKE ?`, m.QuoteWord(column), like)
+}
+
+// WhereIn builds `column IN (in)` statement.
+func (m *Model) WhereIn(column string, in interface{}) *Model {
+ return m.doWherefType(whereHolderTypeIn, `%s IN (?)`, m.QuoteWord(column), in)
+}
+
+// WhereNull builds `columns[0] IS NULL AND columns[1] IS NULL ...` statement.
+func (m *Model) WhereNull(columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.Wheref(`%s IS NULL`, m.QuoteWord(column))
+ }
+ return model
+}
+
+// WhereNotBetween builds `column NOT BETWEEN min AND max` statement.
+func (m *Model) WhereNotBetween(column string, min, max interface{}) *Model {
+ return m.Wheref(`%s NOT BETWEEN ? AND ?`, m.QuoteWord(column), min, max)
+}
+
+// WhereNotLike builds `column NOT LIKE like` statement.
+func (m *Model) WhereNotLike(column string, like interface{}) *Model {
+ return m.Wheref(`%s NOT LIKE ?`, m.QuoteWord(column), like)
+}
+
+// WhereNot builds `column != value` statement.
+func (m *Model) WhereNot(column string, value interface{}) *Model {
+ return m.Wheref(`%s != ?`, m.QuoteWord(column), value)
+}
+
+// WhereNotIn builds `column NOT IN (in)` statement.
+func (m *Model) WhereNotIn(column string, in interface{}) *Model {
+ return m.doWherefType(whereHolderTypeIn, `%s NOT IN (?)`, m.QuoteWord(column), in)
+}
+
+// WhereNotNull builds `columns[0] IS NOT NULL AND columns[1] IS NOT NULL ...` statement.
+func (m *Model) WhereNotNull(columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.Wheref(`%s IS NOT NULL`, m.QuoteWord(column))
+ }
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_where_prefix.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_where_prefix.go
new file mode 100644
index 000000000000..382a0b1a797f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_where_prefix.go
@@ -0,0 +1,99 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+// WherePrefix performs as Where, but it adds prefix to each field in where statement.
+// Eg:
+// WherePrefix("order", "status", "paid") => WHERE `order`.`status`='paid'
+// WherePrefix("order", struct{Status:"paid", "channel":"bank"}) => WHERE `order`.`status`='paid' AND `order`.`channel`='bank'
+func (m *Model) WherePrefix(prefix string, where interface{}, args ...interface{}) *Model {
+ model := m.getModel()
+ if model.whereHolder == nil {
+ model.whereHolder = make([]ModelWhereHolder, 0)
+ }
+ model.whereHolder = append(model.whereHolder, ModelWhereHolder{
+ Type: whereHolderTypeDefault,
+ Operator: whereHolderOperatorWhere,
+ Where: where,
+ Args: args,
+ Prefix: prefix,
+ })
+ return model
+}
+
+// WherePrefixLT builds `prefix.column < value` statement.
+func (m *Model) WherePrefixLT(prefix string, column string, value interface{}) *Model {
+ return m.Wheref(`%s.%s < ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WherePrefixLTE builds `prefix.column <= value` statement.
+func (m *Model) WherePrefixLTE(prefix string, column string, value interface{}) *Model {
+ return m.Wheref(`%s.%s <= ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WherePrefixGT builds `prefix.column > value` statement.
+func (m *Model) WherePrefixGT(prefix string, column string, value interface{}) *Model {
+ return m.Wheref(`%s.%s > ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WherePrefixGTE builds `prefix.column >= value` statement.
+func (m *Model) WherePrefixGTE(prefix string, column string, value interface{}) *Model {
+ return m.Wheref(`%s.%s >= ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WherePrefixBetween builds `prefix.column BETWEEN min AND max` statement.
+func (m *Model) WherePrefixBetween(prefix string, column string, min, max interface{}) *Model {
+ return m.Wheref(`%s.%s BETWEEN ? AND ?`, m.QuoteWord(prefix), m.QuoteWord(column), min, max)
+}
+
+// WherePrefixLike builds `prefix.column LIKE like` statement.
+func (m *Model) WherePrefixLike(prefix string, column string, like interface{}) *Model {
+ return m.Wheref(`%s.%s LIKE ?`, m.QuoteWord(prefix), m.QuoteWord(column), like)
+}
+
+// WherePrefixIn builds `prefix.column IN (in)` statement.
+func (m *Model) WherePrefixIn(prefix string, column string, in interface{}) *Model {
+ return m.doWherefType(whereHolderTypeIn, `%s.%s IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in)
+}
+
+// WherePrefixNull builds `prefix.columns[0] IS NULL AND prefix.columns[1] IS NULL ...` statement.
+func (m *Model) WherePrefixNull(prefix string, columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.Wheref(`%s.%s IS NULL`, m.QuoteWord(prefix), m.QuoteWord(column))
+ }
+ return model
+}
+
+// WherePrefixNotBetween builds `prefix.column NOT BETWEEN min AND max` statement.
+func (m *Model) WherePrefixNotBetween(prefix string, column string, min, max interface{}) *Model {
+ return m.Wheref(`%s.%s NOT BETWEEN ? AND ?`, m.QuoteWord(prefix), m.QuoteWord(column), min, max)
+}
+
+// WherePrefixNotLike builds `prefix.column NOT LIKE like` statement.
+func (m *Model) WherePrefixNotLike(prefix string, column string, like interface{}) *Model {
+ return m.Wheref(`%s.%s NOT LIKE ?`, m.QuoteWord(prefix), m.QuoteWord(column), like)
+}
+
+// WherePrefixNot builds `prefix.column != value` statement.
+func (m *Model) WherePrefixNot(prefix string, column string, value interface{}) *Model {
+ return m.Wheref(`%s.%s != ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WherePrefixNotIn builds `prefix.column NOT IN (in)` statement.
+func (m *Model) WherePrefixNotIn(prefix string, column string, in interface{}) *Model {
+ return m.doWherefType(whereHolderTypeIn, `%s.%s NOT IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in)
+}
+
+// WherePrefixNotNull builds `prefix.columns[0] IS NOT NULL AND prefix.columns[1] IS NOT NULL ...` statement.
+func (m *Model) WherePrefixNotNull(prefix string, columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.Wheref(`%s.%s IS NOT NULL`, m.QuoteWord(prefix), m.QuoteWord(column))
+ }
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_whereor.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_whereor.go
new file mode 100644
index 000000000000..3d288459e8f8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_whereor.go
@@ -0,0 +1,118 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// WhereOr adds "OR" condition to the where statement.
+func (m *Model) doWhereOrType(t string, where interface{}, args ...interface{}) *Model {
+ model := m.getModel()
+ if model.whereHolder == nil {
+ model.whereHolder = make([]ModelWhereHolder, 0)
+ }
+ model.whereHolder = append(model.whereHolder, ModelWhereHolder{
+ Type: t,
+ Operator: whereHolderOperatorOr,
+ Where: where,
+ Args: args,
+ })
+ return model
+}
+
+// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments.
+func (m *Model) doWhereOrfType(t string, format string, args ...interface{}) *Model {
+ var (
+ placeHolderCount = gstr.Count(format, "?")
+ conditionStr = fmt.Sprintf(format, args[:len(args)-placeHolderCount]...)
+ )
+ return m.doWhereOrType(t, conditionStr, args[len(args)-placeHolderCount:]...)
+}
+
+// WhereOr adds "OR" condition to the where statement.
+func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model {
+ return m.doWhereOrType(``, where, args...)
+}
+
+// WhereOrf builds `OR` condition string using fmt.Sprintf and arguments.
+// Eg:
+// WhereOrf(`amount and status=%s`, "paid", 100) => WHERE xxx OR `amount`<100 and status='paid'
+// WhereOrf(`amount<%d and status=%s`, 100, "paid") => WHERE xxx OR `amount`<100 and status='paid'
+func (m *Model) WhereOrf(format string, args ...interface{}) *Model {
+ return m.doWhereOrfType(``, format, args...)
+}
+
+// WhereOrLT builds `column < value` statement in `OR` conditions..
+func (m *Model) WhereOrLT(column string, value interface{}) *Model {
+ return m.WhereOrf(`%s < ?`, column, value)
+}
+
+// WhereOrLTE builds `column <= value` statement in `OR` conditions..
+func (m *Model) WhereOrLTE(column string, value interface{}) *Model {
+ return m.WhereOrf(`%s <= ?`, column, value)
+}
+
+// WhereOrGT builds `column > value` statement in `OR` conditions..
+func (m *Model) WhereOrGT(column string, value interface{}) *Model {
+ return m.WhereOrf(`%s > ?`, column, value)
+}
+
+// WhereOrGTE builds `column >= value` statement in `OR` conditions..
+func (m *Model) WhereOrGTE(column string, value interface{}) *Model {
+ return m.WhereOrf(`%s >= ?`, column, value)
+}
+
+// WhereOrBetween builds `column BETWEEN min AND max` statement in `OR` conditions.
+func (m *Model) WhereOrBetween(column string, min, max interface{}) *Model {
+ return m.WhereOrf(`%s BETWEEN ? AND ?`, m.QuoteWord(column), min, max)
+}
+
+// WhereOrLike builds `column LIKE like` statement in `OR` conditions.
+func (m *Model) WhereOrLike(column string, like interface{}) *Model {
+ return m.WhereOrf(`%s LIKE ?`, m.QuoteWord(column), like)
+}
+
+// WhereOrIn builds `column IN (in)` statement in `OR` conditions.
+func (m *Model) WhereOrIn(column string, in interface{}) *Model {
+ return m.doWhereOrfType(whereHolderTypeIn, `%s IN (?)`, m.QuoteWord(column), in)
+}
+
+// WhereOrNull builds `columns[0] IS NULL OR columns[1] IS NULL ...` statement in `OR` conditions.
+func (m *Model) WhereOrNull(columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.WhereOrf(`%s IS NULL`, m.QuoteWord(column))
+ }
+ return model
+}
+
+// WhereOrNotBetween builds `column NOT BETWEEN min AND max` statement in `OR` conditions.
+func (m *Model) WhereOrNotBetween(column string, min, max interface{}) *Model {
+ return m.WhereOrf(`%s NOT BETWEEN ? AND ?`, m.QuoteWord(column), min, max)
+}
+
+// WhereOrNotLike builds `column NOT LIKE like` statement in `OR` conditions.
+func (m *Model) WhereOrNotLike(column string, like interface{}) *Model {
+ return m.WhereOrf(`%s NOT LIKE ?`, m.QuoteWord(column), like)
+}
+
+// WhereOrNotIn builds `column NOT IN (in)` statement.
+func (m *Model) WhereOrNotIn(column string, in interface{}) *Model {
+ return m.doWhereOrfType(whereHolderTypeIn, `%s NOT IN (?)`, m.QuoteWord(column), in)
+}
+
+// WhereOrNotNull builds `columns[0] IS NOT NULL OR columns[1] IS NOT NULL ...` statement in `OR` conditions.
+func (m *Model) WhereOrNotNull(columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.WhereOrf(`%s IS NOT NULL`, m.QuoteWord(column))
+ }
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_whereor_prefix.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_whereor_prefix.go
new file mode 100644
index 000000000000..7230895cb494
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_whereor_prefix.go
@@ -0,0 +1,94 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+// WhereOrPrefix performs as WhereOr, but it adds prefix to each field in where statement.
+// Eg:
+// WhereOrPrefix("order", "status", "paid") => WHERE xxx OR (`order`.`status`='paid')
+// WhereOrPrefix("order", struct{Status:"paid", "channel":"bank"}) => WHERE xxx OR (`order`.`status`='paid' AND `order`.`channel`='bank')
+func (m *Model) WhereOrPrefix(prefix string, where interface{}, args ...interface{}) *Model {
+ model := m.getModel()
+ if model.whereHolder == nil {
+ model.whereHolder = make([]ModelWhereHolder, 0)
+ }
+ model.whereHolder = append(model.whereHolder, ModelWhereHolder{
+ Type: whereHolderTypeDefault,
+ Operator: whereHolderOperatorOr,
+ Where: where,
+ Args: args,
+ Prefix: prefix,
+ })
+ return model
+}
+
+// WhereOrPrefixLT builds `prefix.column < value` statement in `OR` conditions..
+func (m *Model) WhereOrPrefixLT(prefix string, column string, value interface{}) *Model {
+ return m.WhereOrf(`%s.%s < ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WhereOrPrefixLTE builds `prefix.column <= value` statement in `OR` conditions..
+func (m *Model) WhereOrPrefixLTE(prefix string, column string, value interface{}) *Model {
+ return m.WhereOrf(`%s.%s <= ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WhereOrPrefixGT builds `prefix.column > value` statement in `OR` conditions..
+func (m *Model) WhereOrPrefixGT(prefix string, column string, value interface{}) *Model {
+ return m.WhereOrf(`%s.%s > ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WhereOrPrefixGTE builds `prefix.column >= value` statement in `OR` conditions..
+func (m *Model) WhereOrPrefixGTE(prefix string, column string, value interface{}) *Model {
+ return m.WhereOrf(`%s.%s >= ?`, m.QuoteWord(prefix), m.QuoteWord(column), value)
+}
+
+// WhereOrPrefixBetween builds `prefix.column BETWEEN min AND max` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixBetween(prefix string, column string, min, max interface{}) *Model {
+ return m.WhereOrf(`%s.%s BETWEEN ? AND ?`, m.QuoteWord(prefix), m.QuoteWord(column), min, max)
+}
+
+// WhereOrPrefixLike builds `prefix.column LIKE like` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixLike(prefix string, column string, like interface{}) *Model {
+ return m.WhereOrf(`%s.%s LIKE ?`, m.QuoteWord(prefix), m.QuoteWord(column), like)
+}
+
+// WhereOrPrefixIn builds `prefix.column IN (in)` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixIn(prefix string, column string, in interface{}) *Model {
+ return m.doWhereOrfType(whereHolderTypeIn, `%s.%s IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in)
+}
+
+// WhereOrPrefixNull builds `prefix.columns[0] IS NULL OR prefix.columns[1] IS NULL ...` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixNull(prefix string, columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.WhereOrf(`%s.%s IS NULL`, m.QuoteWord(prefix), m.QuoteWord(column))
+ }
+ return model
+}
+
+// WhereOrPrefixNotBetween builds `prefix.column NOT BETWEEN min AND max` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixNotBetween(prefix string, column string, min, max interface{}) *Model {
+ return m.WhereOrf(`%s.%s NOT BETWEEN ? AND ?`, m.QuoteWord(prefix), m.QuoteWord(column), min, max)
+}
+
+// WhereOrPrefixNotLike builds `prefix.column NOT LIKE like` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixNotLike(prefix string, column string, like interface{}) *Model {
+ return m.WhereOrf(`%s.%s NOT LIKE ?`, m.QuoteWord(prefix), m.QuoteWord(column), like)
+}
+
+// WhereOrPrefixNotIn builds `prefix.column NOT IN (in)` statement.
+func (m *Model) WhereOrPrefixNotIn(prefix string, column string, in interface{}) *Model {
+ return m.doWhereOrfType(whereHolderTypeIn, `%s.%s NOT IN (?)`, m.QuoteWord(prefix), m.QuoteWord(column), in)
+}
+
+// WhereOrPrefixNotNull builds `prefix.columns[0] IS NOT NULL OR prefix.columns[1] IS NOT NULL ...` statement in `OR` conditions.
+func (m *Model) WhereOrPrefixNotNull(prefix string, columns ...string) *Model {
+ model := m
+ for _, column := range columns {
+ model = m.WhereOrf(`%s.%s IS NOT NULL`, m.QuoteWord(prefix), m.QuoteWord(column))
+ }
+ return model
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_with.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_with.go
new file mode 100644
index 000000000000..e5846e8836c7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_model_with.go
@@ -0,0 +1,317 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// With creates and returns an ORM model based on metadata of given object.
+// It also enables model association operations feature on given `object`.
+// It can be called multiple times to add one or more objects to model and enable
+// their mode association operations feature.
+// For example, if given struct definition:
+// type User struct {
+// gmeta.Meta `orm:"table:user"`
+// Id int `json:"id"`
+// Name string `json:"name"`
+// UserDetail *UserDetail `orm:"with:uid=id"`
+// UserScores []*UserScores `orm:"with:uid=id"`
+// }
+// We can enable model association operations on attribute `UserDetail` and `UserScores` by:
+// db.With(User{}.UserDetail).With(User{}.UserDetail).Scan(xxx)
+// Or:
+// db.With(UserDetail{}).With(UserDetail{}).Scan(xxx)
+// Or:
+// db.With(UserDetail{}, UserDetail{}).Scan(xxx)
+func (m *Model) With(objects ...interface{}) *Model {
+ model := m.getModel()
+ for _, object := range objects {
+ if m.tables == "" {
+ m.tablesInit = m.db.GetCore().QuotePrefixTableName(
+ getTableNameFromOrmTag(object),
+ )
+ m.tables = m.tablesInit
+ return model
+ }
+ model.withArray = append(model.withArray, object)
+ }
+ return model
+}
+
+// WithAll enables model association operations on all objects that have "with" tag in the struct.
+func (m *Model) WithAll() *Model {
+ model := m.getModel()
+ model.withAll = true
+ return model
+}
+
+// doWithScanStruct handles model association operations feature for single struct.
+func (m *Model) doWithScanStruct(pointer interface{}) error {
+ var (
+ err error
+ allowedTypeStrArray = make([]string, 0)
+ )
+ currentStructFieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{
+ Pointer: pointer,
+ PriorityTagArray: nil,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ if err != nil {
+ return err
+ }
+ // It checks the with array and automatically calls the ScanList to complete association querying.
+ if !m.withAll {
+ for _, field := range currentStructFieldMap {
+ for _, withItem := range m.withArray {
+ withItemReflectValueType, err := gstructs.StructType(withItem)
+ if err != nil {
+ return err
+ }
+ var (
+ fieldTypeStr = gstr.TrimAll(field.Type().String(), "*[]")
+ withItemReflectValueTypeStr = gstr.TrimAll(withItemReflectValueType.String(), "*[]")
+ )
+ // It does select operation if the field type is in the specified "with" type array.
+ if gstr.Compare(fieldTypeStr, withItemReflectValueTypeStr) == 0 {
+ allowedTypeStrArray = append(allowedTypeStrArray, fieldTypeStr)
+ }
+ }
+ }
+ }
+ for _, field := range currentStructFieldMap {
+ var (
+ fieldTypeStr = gstr.TrimAll(field.Type().String(), "*[]")
+ parsedTagOutput = m.parseWithTagInFieldStruct(field)
+ )
+ if parsedTagOutput.With == "" {
+ continue
+ }
+ // It just handlers "with" type attribute struct, so it ignores other struct types.
+ if !m.withAll && !gstr.InArray(allowedTypeStrArray, fieldTypeStr) {
+ continue
+ }
+ array := gstr.SplitAndTrim(parsedTagOutput.With, "=")
+ if len(array) == 1 {
+ // It also supports using only one column name
+ // if both tables associates using the same column name.
+ array = append(array, parsedTagOutput.With)
+ }
+ var (
+ model *Model
+ fieldKeys []string
+ relatedSourceName = array[0]
+ relatedTargetName = array[1]
+ relatedTargetValue interface{}
+ )
+ // Find the value of related attribute from `pointer`.
+ for attributeName, attributeValue := range currentStructFieldMap {
+ if utils.EqualFoldWithoutChars(attributeName, relatedTargetName) {
+ relatedTargetValue = attributeValue.Value.Interface()
+ break
+ }
+ }
+ if relatedTargetValue == nil {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find the target related value of name "%s" in with tag "%s" for attribute "%s.%s"`,
+ relatedTargetName, parsedTagOutput.With, reflect.TypeOf(pointer).Elem(), field.Name(),
+ )
+ }
+ bindToReflectValue := field.Value
+ if bindToReflectValue.Kind() != reflect.Ptr && bindToReflectValue.CanAddr() {
+ bindToReflectValue = bindToReflectValue.Addr()
+ }
+
+ // It automatically retrieves struct field names from current attribute struct/slice.
+ if structType, err := gstructs.StructType(field.Value); err != nil {
+ return err
+ } else {
+ fieldKeys = structType.FieldKeys()
+ }
+
+ // Recursively with feature checks.
+ model = m.db.With(field.Value)
+ if m.withAll {
+ model = model.WithAll()
+ } else {
+ model = model.With(m.withArray...)
+ }
+ if parsedTagOutput.Where != "" {
+ model = model.Where(parsedTagOutput.Where)
+ }
+ if parsedTagOutput.Order != "" {
+ model = model.Order(parsedTagOutput.Order)
+ }
+ // With cache feature.
+ if m.cacheEnabled && m.cacheOption.Name == "" {
+ model = model.Cache(m.cacheOption)
+ }
+ err = model.Fields(fieldKeys).
+ Where(relatedSourceName, relatedTargetValue).
+ Scan(bindToReflectValue)
+ // It ignores sql.ErrNoRows in with feature.
+ if err != nil && err != sql.ErrNoRows {
+ return err
+ }
+ }
+ return nil
+}
+
+// doWithScanStructs handles model association operations feature for struct slice.
+// Also see doWithScanStruct.
+func (m *Model) doWithScanStructs(pointer interface{}) error {
+ if v, ok := pointer.(reflect.Value); ok {
+ pointer = v.Interface()
+ }
+
+ var (
+ err error
+ allowedTypeStrArray = make([]string, 0)
+ )
+ currentStructFieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{
+ Pointer: pointer,
+ PriorityTagArray: nil,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ if err != nil {
+ return err
+ }
+ // It checks the with array and automatically calls the ScanList to complete association querying.
+ if !m.withAll {
+ for _, field := range currentStructFieldMap {
+ for _, withItem := range m.withArray {
+ withItemReflectValueType, err := gstructs.StructType(withItem)
+ if err != nil {
+ return err
+ }
+ var (
+ fieldTypeStr = gstr.TrimAll(field.Type().String(), "*[]")
+ withItemReflectValueTypeStr = gstr.TrimAll(withItemReflectValueType.String(), "*[]")
+ )
+ // It does select operation if the field type is in the specified with type array.
+ if gstr.Compare(fieldTypeStr, withItemReflectValueTypeStr) == 0 {
+ allowedTypeStrArray = append(allowedTypeStrArray, fieldTypeStr)
+ }
+ }
+ }
+ }
+
+ for fieldName, field := range currentStructFieldMap {
+ var (
+ fieldTypeStr = gstr.TrimAll(field.Type().String(), "*[]")
+ parsedTagOutput = m.parseWithTagInFieldStruct(field)
+ )
+ if parsedTagOutput.With == "" {
+ continue
+ }
+ if !m.withAll && !gstr.InArray(allowedTypeStrArray, fieldTypeStr) {
+ continue
+ }
+ array := gstr.SplitAndTrim(parsedTagOutput.With, "=")
+ if len(array) == 1 {
+ // It supports using only one column name
+ // if both tables associates using the same column name.
+ array = append(array, parsedTagOutput.With)
+ }
+ var (
+ model *Model
+ fieldKeys []string
+ relatedSourceName = array[0]
+ relatedTargetName = array[1]
+ relatedTargetValue interface{}
+ )
+ // Find the value slice of related attribute from `pointer`.
+ for attributeName := range currentStructFieldMap {
+ if utils.EqualFoldWithoutChars(attributeName, relatedTargetName) {
+ relatedTargetValue = ListItemValuesUnique(pointer, attributeName)
+ break
+ }
+ }
+ if relatedTargetValue == nil {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find the related value for attribute name "%s" of with tag "%s"`,
+ relatedTargetName, parsedTagOutput.With,
+ )
+ }
+ // If related value is empty, it does nothing but just returns.
+ if gutil.IsEmpty(relatedTargetValue) {
+ return nil
+ }
+ // It automatically retrieves struct field names from current attribute struct/slice.
+ if structType, err := gstructs.StructType(field.Value); err != nil {
+ return err
+ } else {
+ fieldKeys = structType.FieldKeys()
+ }
+ // Recursively with feature checks.
+ model = m.db.With(field.Value)
+ if m.withAll {
+ model = model.WithAll()
+ } else {
+ model = model.With(m.withArray...)
+ }
+ if parsedTagOutput.Where != "" {
+ model = model.Where(parsedTagOutput.Where)
+ }
+ if parsedTagOutput.Order != "" {
+ model = model.Order(parsedTagOutput.Order)
+ }
+ // With cache feature.
+ if m.cacheEnabled && m.cacheOption.Name == "" {
+ model = model.Cache(m.cacheOption)
+ }
+ err = model.Fields(fieldKeys).
+ Where(relatedSourceName, relatedTargetValue).
+ ScanList(pointer, fieldName, parsedTagOutput.With)
+ // It ignores sql.ErrNoRows in with feature.
+ if err != nil && err != sql.ErrNoRows {
+ return err
+ }
+ }
+ return nil
+}
+
+type parseWithTagInFieldStructOutput struct {
+ With string
+ Where string
+ Order string
+}
+
+func (m *Model) parseWithTagInFieldStruct(field gstructs.Field) (output parseWithTagInFieldStructOutput) {
+ var (
+ ormTag = field.Tag(OrmTagForStruct)
+ data = make(map[string]string)
+ array []string
+ key string
+ )
+ for _, v := range gstr.SplitAndTrim(ormTag, " ") {
+ array = gstr.Split(v, ":")
+ if len(array) == 2 {
+ key = array[0]
+ data[key] = gstr.Trim(array[1])
+ } else {
+ data[key] += " " + gstr.Trim(v)
+ }
+ }
+ for k, v := range data {
+ data[k] = gstr.TrimRight(v, ",")
+ }
+ output.With = data[OrmTagForWith]
+ output.Where = data[OrmTagForWithWhere]
+ output.Order = data[OrmTagForWithOrder]
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_result.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_result.go
new file mode 100644
index 000000000000..f7c91013b9e0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_result.go
@@ -0,0 +1,70 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// SqlResult is execution result for sql operations.
+// It also supports batch operation result for rowsAffected.
+type SqlResult struct {
+ Result sql.Result
+ Affected int64
+}
+
+// MustGetAffected returns the affected rows count, if any error occurs, it panics.
+func (r *SqlResult) MustGetAffected() int64 {
+ rows, err := r.RowsAffected()
+ if err != nil {
+ err = gerror.Wrap(err, `sql.Result.RowsAffected failed`)
+ panic(err)
+ }
+ return rows
+}
+
+// MustGetInsertId returns the last insert id, if any error occurs, it panics.
+func (r *SqlResult) MustGetInsertId() int64 {
+ id, err := r.LastInsertId()
+ if err != nil {
+ err = gerror.Wrap(err, `sql.Result.LastInsertId failed`)
+ panic(err)
+ }
+ return id
+}
+
+// RowsAffected returns the number of rows affected by an
+// update, insert, or delete. Not every database or database
+// driver may support this.
+// Also, See sql.Result.
+func (r *SqlResult) RowsAffected() (int64, error) {
+ if r.Result == nil {
+ return 0, nil
+ }
+ if r.Affected > 0 {
+ return r.Affected, nil
+ }
+ if r.Result == nil {
+ return 0, nil
+ }
+ return r.Result.RowsAffected()
+}
+
+// LastInsertId returns the integer generated by the database
+// in response to a command. Typically, this will be from an
+// "auto increment" column when inserting a new row. Not all
+// databases support this feature, and the syntax of such
+// statements varies.
+// Also, See sql.Result.
+func (r *SqlResult) LastInsertId() (int64, error) {
+ if r.Result == nil {
+ return 0, nil
+ }
+ return r.Result.LastInsertId()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_schema.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_schema.go
new file mode 100644
index 000000000000..75012e3dcb3d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_schema.go
@@ -0,0 +1,30 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+// Schema is a schema object from which it can then create a Model.
+type Schema struct {
+ DB
+}
+
+// Schema creates and returns a schema.
+func (c *Core) Schema(schema string) *Schema {
+ // Do not change the schema of the original db,
+ // it here creates a new db and changes its schema.
+ db, err := NewByGroup(c.GetGroup())
+ if err != nil {
+ panic(err)
+ }
+ core := db.GetCore()
+ // Different schema share some same objects.
+ core.logger = c.logger
+ core.cache = c.cache
+ core.schema = schema
+ return &Schema{
+ DB: db,
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_statement.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_statement.go
new file mode 100644
index 000000000000..89ffb752e103
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_statement.go
@@ -0,0 +1,118 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "context"
+ "database/sql"
+)
+
+// Stmt is a prepared statement.
+// A Stmt is safe for concurrent use by multiple goroutines.
+//
+// If a Stmt is prepared on a Tx or Conn, it will be bound to a single
+// underlying connection forever. If the Tx or Conn closes, the Stmt will
+// become unusable and all operations will return an error.
+// If a Stmt is prepared on a DB, it will remain usable for the lifetime of the
+// DB. When the Stmt needs to execute on a new underlying connection, it will
+// prepare itself on the new connection automatically.
+type Stmt struct {
+ *sql.Stmt
+ core *Core
+ link Link
+ sql string
+}
+
+// ExecContext executes a prepared statement with the given arguments and
+// returns a Result summarizing the effect of the statement.
+func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) {
+ out, err := s.core.db.DoCommit(ctx, DoCommitInput{
+ Stmt: s.Stmt,
+ Link: s.link,
+ Sql: s.sql,
+ Args: args,
+ Type: SqlTypeStmtExecContext,
+ IsTransaction: s.link.IsTransaction(),
+ })
+ return out.Result, err
+}
+
+// QueryContext executes a prepared query statement with the given arguments
+// and returns the query results as a *Rows.
+func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*sql.Rows, error) {
+ out, err := s.core.db.DoCommit(ctx, DoCommitInput{
+ Stmt: s.Stmt,
+ Link: s.link,
+ Sql: s.sql,
+ Args: args,
+ Type: SqlTypeStmtQueryContext,
+ IsTransaction: s.link.IsTransaction(),
+ })
+ if err != nil {
+ return nil, err
+ }
+ if out.RawResult != nil {
+ return out.RawResult.(*sql.Rows), err
+ }
+ return nil, nil
+}
+
+// QueryRowContext executes a prepared query statement with the given arguments.
+// If an error occurs during the execution of the statement, that error will
+// be returned by a call to Scan on the returned *Row, which is always non-nil.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
+func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *sql.Row {
+ out, err := s.core.db.DoCommit(ctx, DoCommitInput{
+ Stmt: s.Stmt,
+ Link: s.link,
+ Sql: s.sql,
+ Args: args,
+ Type: SqlTypeStmtQueryContext,
+ IsTransaction: s.link.IsTransaction(),
+ })
+ if err != nil {
+ panic(err)
+ }
+ if out.RawResult != nil {
+ return out.RawResult.(*sql.Row)
+ }
+ return nil
+}
+
+// Exec executes a prepared statement with the given arguments and
+// returns a Result summarizing the effect of the statement.
+func (s *Stmt) Exec(args ...interface{}) (sql.Result, error) {
+ return s.ExecContext(context.Background(), args...)
+}
+
+// Query executes a prepared query statement with the given arguments
+// and returns the query results as a *Rows.
+func (s *Stmt) Query(args ...interface{}) (*sql.Rows, error) {
+ return s.QueryContext(context.Background(), args...)
+}
+
+// QueryRow executes a prepared query statement with the given arguments.
+// If an error occurs during the execution of the statement, that error will
+// be returned by a call to Scan on the returned *Row, which is always non-nil.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
+//
+// Example usage:
+//
+// var name string
+// err := nameByUseridStmt.QueryRow(id).Scan(&name)
+func (s *Stmt) QueryRow(args ...interface{}) *sql.Row {
+ return s.QueryRowContext(context.Background(), args...)
+}
+
+// Close closes the statement.
+func (s *Stmt) Close() error {
+ return s.Stmt.Close()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_record.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_record.go
new file mode 100644
index 000000000000..2b14c5375732
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_record.go
@@ -0,0 +1,62 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Json converts `r` to JSON format content.
+func (r Record) Json() string {
+ content, _ := gjson.New(r.Map()).ToJsonString()
+ return content
+}
+
+// Xml converts `r` to XML format content.
+func (r Record) Xml(rootTag ...string) string {
+ content, _ := gjson.New(r.Map()).ToXmlString(rootTag...)
+ return content
+}
+
+// Map converts `r` to map[string]interface{}.
+func (r Record) Map() Map {
+ m := make(map[string]interface{})
+ for k, v := range r {
+ m[k] = v.Val()
+ }
+ return m
+}
+
+// GMap converts `r` to a gmap.
+func (r Record) GMap() *gmap.StrAnyMap {
+ return gmap.NewStrAnyMapFrom(r.Map())
+}
+
+// Struct converts `r` to a struct.
+// Note that the parameter `pointer` should be type of *struct/**struct.
+//
+// Note that it returns sql.ErrNoRows if `r` is empty.
+func (r Record) Struct(pointer interface{}) error {
+ // If the record is empty, it returns error.
+ if r.IsEmpty() {
+ if !empty.IsNil(pointer, true) {
+ return sql.ErrNoRows
+ }
+ return nil
+ }
+ return gconv.StructTag(r, pointer, OrmTagForStruct)
+}
+
+// IsEmpty checks and returns whether `r` is empty.
+func (r Record) IsEmpty() bool {
+ return len(r) == 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_result.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_result.go
new file mode 100644
index 000000000000..062381a480ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_result.go
@@ -0,0 +1,195 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "math"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// IsEmpty checks and returns whether `r` is empty.
+func (r Result) IsEmpty() bool {
+ return r.Len() == 0
+}
+
+// Len returns the length of result list.
+func (r Result) Len() int {
+ return len(r)
+}
+
+// Size is alias of function Len.
+func (r Result) Size() int {
+ return r.Len()
+}
+
+// Chunk splits a Result into multiple Results,
+// the size of each array is determined by `size`.
+// The last chunk may contain less than size elements.
+func (r Result) Chunk(size int) []Result {
+ if size < 1 {
+ return nil
+ }
+ length := len(r)
+ chunks := int(math.Ceil(float64(length) / float64(size)))
+ var n []Result
+ for i, end := 0, 0; chunks > 0; chunks-- {
+ end = (i + 1) * size
+ if end > length {
+ end = length
+ }
+ n = append(n, r[i*size:end])
+ i++
+ }
+ return n
+}
+
+// Json converts `r` to JSON format content.
+func (r Result) Json() string {
+ content, _ := gjson.New(r.List()).ToJsonString()
+ return content
+}
+
+// Xml converts `r` to XML format content.
+func (r Result) Xml(rootTag ...string) string {
+ content, _ := gjson.New(r.List()).ToXmlString(rootTag...)
+ return content
+}
+
+// List converts `r` to a List.
+func (r Result) List() List {
+ list := make(List, len(r))
+ for k, v := range r {
+ list[k] = v.Map()
+ }
+ return list
+}
+
+// Array retrieves and returns specified column values as slice.
+// The parameter `field` is optional is the column field is only one.
+// The default `field` is the first field name of the first item in `Result` if parameter `field` is not given.
+func (r Result) Array(field ...string) []Value {
+ array := make([]Value, len(r))
+ if len(r) == 0 {
+ return array
+ }
+ key := ""
+ if len(field) > 0 && field[0] != "" {
+ key = field[0]
+ } else {
+ for k := range r[0] {
+ key = k
+ break
+ }
+ }
+ for k, v := range r {
+ array[k] = v[key]
+ }
+ return array
+}
+
+// MapKeyValue converts `r` to a map[string]Value of which key is specified by `key`.
+// Note that the item value may be type of slice.
+func (r Result) MapKeyValue(key string) map[string]Value {
+ var (
+ s = ""
+ m = make(map[string]Value)
+ tempMap = make(map[string][]interface{})
+ hasMultiValues bool
+ )
+ for _, item := range r {
+ if k, ok := item[key]; ok {
+ s = k.String()
+ tempMap[s] = append(tempMap[s], item)
+ if len(tempMap[s]) > 1 {
+ hasMultiValues = true
+ }
+ }
+ }
+ for k, v := range tempMap {
+ if hasMultiValues {
+ m[k] = gvar.New(v)
+ } else {
+ m[k] = gvar.New(v[0])
+ }
+ }
+ return m
+}
+
+// MapKeyStr converts `r` to a map[string]Map of which key is specified by `key`.
+func (r Result) MapKeyStr(key string) map[string]Map {
+ m := make(map[string]Map)
+ for _, item := range r {
+ if v, ok := item[key]; ok {
+ m[v.String()] = item.Map()
+ }
+ }
+ return m
+}
+
+// MapKeyInt converts `r` to a map[int]Map of which key is specified by `key`.
+func (r Result) MapKeyInt(key string) map[int]Map {
+ m := make(map[int]Map)
+ for _, item := range r {
+ if v, ok := item[key]; ok {
+ m[v.Int()] = item.Map()
+ }
+ }
+ return m
+}
+
+// MapKeyUint converts `r` to a map[uint]Map of which key is specified by `key`.
+func (r Result) MapKeyUint(key string) map[uint]Map {
+ m := make(map[uint]Map)
+ for _, item := range r {
+ if v, ok := item[key]; ok {
+ m[v.Uint()] = item.Map()
+ }
+ }
+ return m
+}
+
+// RecordKeyStr converts `r` to a map[string]Record of which key is specified by `key`.
+func (r Result) RecordKeyStr(key string) map[string]Record {
+ m := make(map[string]Record)
+ for _, item := range r {
+ if v, ok := item[key]; ok {
+ m[v.String()] = item
+ }
+ }
+ return m
+}
+
+// RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`.
+func (r Result) RecordKeyInt(key string) map[int]Record {
+ m := make(map[int]Record)
+ for _, item := range r {
+ if v, ok := item[key]; ok {
+ m[v.Int()] = item
+ }
+ }
+ return m
+}
+
+// RecordKeyUint converts `r` to a map[uint]Record of which key is specified by `key`.
+func (r Result) RecordKeyUint(key string) map[uint]Record {
+ m := make(map[uint]Record)
+ for _, item := range r {
+ if v, ok := item[key]; ok {
+ m[v.Uint()] = item
+ }
+ }
+ return m
+}
+
+// Structs converts `r` to struct slice.
+// Note that the parameter `pointer` should be type of *[]struct/*[]*struct.
+func (r Result) Structs(pointer interface{}) (err error) {
+ return gconv.StructsTag(r, pointer, OrmTagForStruct)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_result_scanlist.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_result_scanlist.go
new file mode 100644
index 000000000000..0824f5894ebf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gdb/gdb_type_result_scanlist.go
@@ -0,0 +1,505 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdb
+
+import (
+ "database/sql"
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// ScanList converts `r` to struct slice which contains other complex struct attributes.
+// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
+//
+// Usage example 1: Normal attribute struct relation:
+// type EntityUser struct {
+// Uid int
+// Name string
+// }
+// type EntityUserDetail struct {
+// Uid int
+// Address string
+// }
+// type EntityUserScores struct {
+// Id int
+// Uid int
+// Score int
+// Course string
+// }
+// type Entity struct {
+// User *EntityUser
+// UserDetail *EntityUserDetail
+// UserScores []*EntityUserScores
+// }
+// var users []*Entity
+// ScanList(&users, "User")
+// ScanList(&users, "User", "uid")
+// ScanList(&users, "UserDetail", "User", "uid:Uid")
+// ScanList(&users, "UserScores", "User", "uid:Uid")
+// ScanList(&users, "UserScores", "User", "uid")
+//
+//
+// Usage example 2: Embedded attribute struct relation:
+// type EntityUser struct {
+// Uid int
+// Name string
+// }
+// type EntityUserDetail struct {
+// Uid int
+// Address string
+// }
+// type EntityUserScores struct {
+// Id int
+// Uid int
+// Score int
+// }
+// type Entity struct {
+// EntityUser
+// UserDetail EntityUserDetail
+// UserScores []EntityUserScores
+// }
+//
+// var users []*Entity
+// ScanList(&users)
+// ScanList(&users, "UserDetail", "uid")
+// ScanList(&users, "UserScores", "uid")
+//
+//
+// The parameters "User/UserDetail/UserScores" in the example codes specify the target attribute struct
+// that current result will be bound to.
+//
+// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
+// struct attribute name - not the attribute name of the bound to target. In the example codes, it's attribute
+// name "Uid" of "User" of entity "Entity". It automatically calculates the HasOne/HasMany relationship with
+// given `relation` parameter.
+//
+// See the example or unit testing cases for clear understanding for this function.
+func (r Result) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
+ out, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)
+ if err != nil {
+ return err
+ }
+
+ var (
+ relationAttrName string
+ relationFields string
+ )
+ switch len(relationAttrNameAndFields) {
+ case 2:
+ relationAttrName = relationAttrNameAndFields[0]
+ relationFields = relationAttrNameAndFields[1]
+ case 1:
+ relationFields = relationAttrNameAndFields[0]
+ }
+ return doScanList(doScanListInput{
+ Model: nil,
+ Result: r,
+ StructSlicePointer: structSlicePointer,
+ StructSliceValue: out.SliceReflectValue,
+ BindToAttrName: bindToAttrName,
+ RelationAttrName: relationAttrName,
+ RelationFields: relationFields,
+ })
+}
+
+type checkGetSliceElementInfoForScanListOutput struct {
+ SliceReflectValue reflect.Value
+ BindToAttrType reflect.Type
+}
+
+func checkGetSliceElementInfoForScanList(structSlicePointer interface{}, bindToAttrName string) (out *checkGetSliceElementInfoForScanListOutput, err error) {
+ // Necessary checks for parameters.
+ if structSlicePointer == nil {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, `structSlicePointer cannot be nil`)
+ }
+ if bindToAttrName == "" {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
+ }
+ var (
+ reflectType reflect.Type
+ reflectValue = reflect.ValueOf(structSlicePointer)
+ reflectKind = reflectValue.Kind()
+ )
+ if reflectKind == reflect.Interface {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ if reflectKind != reflect.Ptr {
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "structSlicePointer should be type of *[]struct/*[]*struct, but got: %s",
+ reflect.TypeOf(structSlicePointer).String(),
+ )
+ }
+ out = &checkGetSliceElementInfoForScanListOutput{
+ SliceReflectValue: reflectValue.Elem(),
+ }
+ // Find the element struct type of the slice.
+ reflectType = reflectValue.Type().Elem().Elem()
+ reflectKind = reflectType.Kind()
+ for reflectKind == reflect.Ptr {
+ reflectType = reflectType.Elem()
+ reflectKind = reflectType.Kind()
+ }
+ if reflectKind != reflect.Struct {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "structSlicePointer should be type of *[]struct/*[]*struct, but got: %s",
+ reflect.TypeOf(structSlicePointer).String(),
+ )
+ return
+ }
+ // Find the target field by given name.
+ structField, ok := reflectType.FieldByName(bindToAttrName)
+ if !ok {
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `field "%s" not found in element of "%s"`,
+ bindToAttrName,
+ reflect.TypeOf(structSlicePointer).String(),
+ )
+ }
+ // Find the attribute struct type for ORM fields filtering.
+ reflectType = structField.Type
+ reflectKind = reflectType.Kind()
+ for reflectKind == reflect.Ptr {
+ reflectType = reflectType.Elem()
+ reflectKind = reflectType.Kind()
+ }
+ if reflectKind == reflect.Slice || reflectKind == reflect.Array {
+ reflectType = reflectType.Elem()
+ reflectKind = reflectType.Kind()
+ }
+ out.BindToAttrType = reflectType
+ return
+}
+
+type doScanListInput struct {
+ Model *Model
+ Result Result
+ StructSlicePointer interface{}
+ StructSliceValue reflect.Value
+ BindToAttrName string
+ RelationAttrName string
+ RelationFields string
+}
+
+// doScanList converts `result` to struct slice which contains other complex struct attributes recursively.
+// The parameter `model` is used for recursively scanning purpose, which means, it can scan the attribute struct/structs recursively,
+// but it needs the Model for database accessing.
+// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
+func doScanList(in doScanListInput) (err error) {
+ if in.Result.IsEmpty() {
+ return nil
+ }
+ if in.BindToAttrName == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
+ }
+
+ length := len(in.Result)
+ if length == 0 {
+ // The pointed slice is not empty.
+ if in.StructSliceValue.Len() > 0 {
+ // It here checks if it has struct item, which is already initialized.
+ // It then returns error to warn the developer its empty and no conversion.
+ if v := in.StructSliceValue.Index(0); v.Kind() != reflect.Ptr {
+ return sql.ErrNoRows
+ }
+ }
+ // Do nothing for empty struct slice.
+ return nil
+ }
+ var (
+ arrayValue reflect.Value // Like: []*Entity
+ arrayItemType reflect.Type // Like: *Entity
+ reflectType = reflect.TypeOf(in.StructSlicePointer)
+ )
+ if in.StructSliceValue.Len() > 0 {
+ arrayValue = in.StructSliceValue
+ } else {
+ arrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)
+ }
+
+ // Slice element item.
+ arrayItemType = arrayValue.Index(0).Type()
+
+ // Relation variables.
+ var (
+ relationDataMap map[string]Value
+ relationFromFieldName string // Eg: relationKV: id:uid -> id
+ relationBindToFieldName string // Eg: relationKV: id:uid -> uid
+ )
+ if len(in.RelationFields) > 0 {
+ // The relation key string of table filed name and attribute name
+ // can be joined with char '=' or ':'.
+ array := gstr.SplitAndTrim(in.RelationFields, "=")
+ if len(array) == 1 {
+ // Compatible with old splitting char ':'.
+ array = gstr.SplitAndTrim(in.RelationFields, ":")
+ }
+ if len(array) == 1 {
+ // The relation names are the same.
+ array = []string{in.RelationFields, in.RelationFields}
+ }
+ if len(array) == 2 {
+ // Defined table field to relation attribute name.
+ // Like:
+ // uid:Uid
+ // uid:UserId
+ relationFromFieldName = array[0]
+ relationBindToFieldName = array[1]
+ if key, _ := gutil.MapPossibleItemByKey(in.Result[0].Map(), relationFromFieldName); key == "" {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find possible related table field name "%s" from given relation fields "%s"`,
+ relationFromFieldName,
+ in.RelationFields,
+ )
+ } else {
+ relationFromFieldName = key
+ }
+ } else {
+ return gerror.NewCode(
+ gcode.CodeInvalidParameter,
+ `parameter relationKV should be format of "ResultFieldName:BindToAttrName"`,
+ )
+ }
+ if relationFromFieldName != "" {
+ // Note that the value might be type of slice.
+ relationDataMap = in.Result.MapKeyValue(relationFromFieldName)
+ }
+ if len(relationDataMap) == 0 {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find the relation data map, maybe invalid relation fields given "%v"`,
+ in.RelationFields,
+ )
+ }
+ }
+ // Bind to target attribute.
+ var (
+ ok bool
+ bindToAttrValue reflect.Value
+ bindToAttrKind reflect.Kind
+ bindToAttrType reflect.Type
+ bindToAttrField reflect.StructField
+ )
+ if arrayItemType.Kind() == reflect.Ptr {
+ if bindToAttrField, ok = arrayItemType.Elem().FieldByName(in.BindToAttrName); !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
+ in.BindToAttrName,
+ )
+ }
+ } else {
+ if bindToAttrField, ok = arrayItemType.FieldByName(in.BindToAttrName); !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
+ in.BindToAttrName,
+ )
+ }
+ }
+ bindToAttrType = bindToAttrField.Type
+ bindToAttrKind = bindToAttrType.Kind()
+
+ // Bind to relation conditions.
+ var (
+ relationFromAttrValue reflect.Value
+ relationFromAttrField reflect.Value
+ relationBindToFieldNameChecked bool
+ )
+ for i := 0; i < arrayValue.Len(); i++ {
+ arrayElemValue := arrayValue.Index(i)
+ // The FieldByName should be called on non-pointer reflect.Value.
+ if arrayElemValue.Kind() == reflect.Ptr {
+ // Like: []*Entity
+ arrayElemValue = arrayElemValue.Elem()
+ if !arrayElemValue.IsValid() {
+ // The element is nil, then create one and set it to the slice.
+ // The "reflect.New(itemType.Elem())" creates a new element and returns the address of it.
+ // For example:
+ // reflect.New(itemType.Elem()) => *Entity
+ // reflect.New(itemType.Elem()).Elem() => Entity
+ arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
+ arrayValue.Index(i).Set(arrayElemValue.Addr())
+ }
+ } else {
+ // Like: []Entity
+ }
+ bindToAttrValue = arrayElemValue.FieldByName(in.BindToAttrName)
+ if in.RelationAttrName != "" {
+ // Attribute value of current slice element.
+ relationFromAttrValue = arrayElemValue.FieldByName(in.RelationAttrName)
+ if relationFromAttrValue.Kind() == reflect.Ptr {
+ relationFromAttrValue = relationFromAttrValue.Elem()
+ }
+ } else {
+ // Current slice element.
+ relationFromAttrValue = arrayElemValue
+ }
+ if len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
+ }
+ // Check and find possible bind to attribute name.
+ if in.RelationFields != "" && !relationBindToFieldNameChecked {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if !relationFromAttrField.IsValid() {
+ filedMap, _ := gstructs.FieldMap(gstructs.FieldMapInput{
+ Pointer: relationFromAttrValue,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ if key, _ := gutil.MapPossibleItemByKey(gconv.Map(filedMap), relationBindToFieldName); key == "" {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find possible related attribute name "%s" from given relation fields "%s"`,
+ relationBindToFieldName,
+ in.RelationFields,
+ )
+ } else {
+ relationBindToFieldName = key
+ }
+ }
+ relationBindToFieldNameChecked = true
+ }
+ switch bindToAttrKind {
+ case reflect.Array, reflect.Slice:
+ if len(relationDataMap) > 0 {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if relationFromAttrField.IsValid() {
+ results := make(Result, 0)
+ for _, v := range relationDataMap[gconv.String(relationFromAttrField.Interface())].Slice() {
+ results = append(results, v.(Record))
+ }
+ if err = results.Structs(bindToAttrValue.Addr()); err != nil {
+ return err
+ }
+ // Recursively Scan.
+ if in.Model != nil {
+ if err = in.Model.doWithScanStructs(bindToAttrValue.Addr()); err != nil {
+ return nil
+ }
+ }
+ } else {
+ // Maybe the attribute does not exist yet.
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
+ }
+ } else {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `relationKey should not be empty as field "%s" is slice`,
+ in.BindToAttrName,
+ )
+ }
+
+ case reflect.Ptr:
+ var element reflect.Value
+ if bindToAttrValue.IsNil() {
+ element = reflect.New(bindToAttrType.Elem()).Elem()
+ } else {
+ element = bindToAttrValue.Elem()
+ }
+ if len(relationDataMap) > 0 {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if relationFromAttrField.IsValid() {
+ v := relationDataMap[gconv.String(relationFromAttrField.Interface())]
+ if v == nil {
+ // There's no relational data.
+ continue
+ }
+ if v.IsSlice() {
+ if err = v.Slice()[0].(Record).Struct(element); err != nil {
+ return err
+ }
+ } else {
+ if err = v.Val().(Record).Struct(element); err != nil {
+ return err
+ }
+ }
+ } else {
+ // Maybe the attribute does not exist yet.
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
+ }
+ } else {
+ if i >= len(in.Result) {
+ // There's no relational data.
+ continue
+ }
+ v := in.Result[i]
+ if v == nil {
+ // There's no relational data.
+ continue
+ }
+ if err = v.Struct(element); err != nil {
+ return err
+ }
+ }
+ // Recursively Scan.
+ if in.Model != nil {
+ if err = in.Model.doWithScanStruct(element); err != nil {
+ return err
+ }
+ }
+ bindToAttrValue.Set(element.Addr())
+
+ case reflect.Struct:
+ if len(relationDataMap) > 0 {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if relationFromAttrField.IsValid() {
+ relationDataItem := relationDataMap[gconv.String(relationFromAttrField.Interface())]
+ if relationDataItem == nil {
+ // There's no relational data.
+ continue
+ }
+ if relationDataItem.IsSlice() {
+ if err = relationDataItem.Slice()[0].(Record).Struct(bindToAttrValue); err != nil {
+ return err
+ }
+ } else {
+ if err = relationDataItem.Val().(Record).Struct(bindToAttrValue); err != nil {
+ return err
+ }
+ }
+ } else {
+ // Maybe the attribute does not exist yet.
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
+ }
+ } else {
+ if i >= len(in.Result) {
+ // There's no relational data.
+ continue
+ }
+ relationDataItem := in.Result[i]
+ if relationDataItem == nil {
+ // There's no relational data.
+ continue
+ }
+ if err = relationDataItem.Struct(bindToAttrValue); err != nil {
+ return err
+ }
+ }
+ // Recursively Scan.
+ if in.Model != nil {
+ if err = in.Model.doWithScanStruct(bindToAttrValue); err != nil {
+ return err
+ }
+ }
+
+ default:
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())
+ }
+ }
+ reflect.ValueOf(in.StructSlicePointer).Elem().Set(arrayValue)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis.go
new file mode 100644
index 000000000000..0d510c6ca3a8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis.go
@@ -0,0 +1,34 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gredis provides convenient client for redis server.
+//
+// Redis Client.
+//
+// Redis Commands Official: https://redis.io/commands
+//
+// Redis Chinese Documentation: http://redisdoc.com/
+package gredis
+
+// New creates and returns a redis client.
+// It creates a default redis adapter of go-redis.
+func New(config ...*Config) (*Redis, error) {
+ if len(config) > 0 && config[0] != nil {
+ // Redis client with go redis implements adapter from given configuration.
+ return &Redis{adapter: NewAdapterGoRedis(config[0])}, nil
+ }
+ // Redis client with go redis implements adapter from package configuration.
+ if configFromGlobal, ok := GetConfig(); ok {
+ return &Redis{adapter: NewAdapterGoRedis(configFromGlobal)}, nil
+ }
+ // Redis client with empty adapter.
+ return &Redis{}, nil
+}
+
+// NewWithAdapter creates and returns a redis client with given adapter.
+func NewWithAdapter(adapter Adapter) *Redis {
+ return &Redis{adapter: adapter}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter.go
new file mode 100644
index 000000000000..b4598bd727e2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter.go
@@ -0,0 +1,36 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// Adapter is an interface for universal redis operations.
+type Adapter interface {
+ // Conn retrieves and returns a connection object for continuous operations.
+ // Note that you should call Close function manually if you do not use this connection any further.
+ Conn(ctx context.Context) (conn Conn, err error)
+
+ // Close closes current redis client, closes its connection pool and releases all its related resources.
+ Close(ctx context.Context) (err error)
+}
+
+// Conn is an interface of a connection from universal redis client.
+type Conn interface {
+ // Do send a command to the server and returns the received reply.
+ // It uses json.Marshal for struct/slice/map type values before committing them to redis.
+ Do(ctx context.Context, command string, args ...interface{}) (result *gvar.Var, err error)
+
+ // Receive receives a single reply as gvar.Var from the Redis server.
+ Receive(ctx context.Context) (result *gvar.Var, err error)
+
+ // Close puts the connection back to connection pool.
+ Close(ctx context.Context) (err error)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter_goredis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter_goredis.go
new file mode 100644
index 000000000000..28ac0ebf17ac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter_goredis.go
@@ -0,0 +1,101 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+ "time"
+
+ "github.com/go-redis/redis/v8"
+ "github.com/gogf/gf/v2/errors/gerror"
+
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// AdapterGoRedis is an implement of Adapter using go-redis.
+type AdapterGoRedis struct {
+ client redis.UniversalClient
+ config *Config
+}
+
+const (
+ defaultPoolMaxIdle = 10
+ defaultPoolMaxActive = 100
+ defaultPoolIdleTimeout = 10 * time.Second
+ defaultPoolWaitTimeout = 10 * time.Second
+ defaultPoolMaxLifeTime = 30 * time.Second
+ defaultMaxRetries = -1
+)
+
+// NewAdapterGoRedis creates and returns a redis adapter using go-redis.
+func NewAdapterGoRedis(config *Config) *AdapterGoRedis {
+ fillWithDefaultConfiguration(config)
+ client := redis.NewUniversalClient(&redis.UniversalOptions{
+ Addrs: gstr.SplitAndTrim(config.Address, ","),
+ Password: config.Pass,
+ DB: config.Db,
+ MaxRetries: defaultMaxRetries,
+ MinIdleConns: config.MinIdle,
+ MaxConnAge: config.MaxConnLifetime,
+ IdleTimeout: config.IdleTimeout,
+ PoolTimeout: config.WaitTimeout,
+ DialTimeout: config.DialTimeout,
+ ReadTimeout: config.ReadTimeout,
+ WriteTimeout: config.WriteTimeout,
+ MasterName: config.MasterName,
+ TLSConfig: config.TLSConfig,
+ })
+ return &AdapterGoRedis{
+ client: client,
+ config: config,
+ }
+}
+
+// Close closes the redis connection pool, which will release all connections reserved by this pool.
+// It is commonly not necessary to call Close manually.
+func (r *AdapterGoRedis) Close(ctx context.Context) (err error) {
+ if err = r.client.Close(); err != nil {
+ err = gerror.Wrap(err, `Redis Client Close failed`)
+ }
+ return
+}
+
+// Conn retrieves and returns a connection object for continuous operations.
+// Note that you should call Close function manually if you do not use this connection any further.
+func (r *AdapterGoRedis) Conn(ctx context.Context) (Conn, error) {
+ return &localAdapterGoRedisConn{
+ redis: r,
+ }, nil
+}
+
+func fillWithDefaultConfiguration(config *Config) {
+ // The MaxIdle is the most important attribute of the connection pool.
+ // Only if this attribute is set, the created connections from client
+ // can not exceed the limit of the server.
+ if config.MaxIdle == 0 {
+ config.MaxIdle = defaultPoolMaxIdle
+ }
+ // This value SHOULD NOT exceed the connection limit of redis server.
+ if config.MaxActive == 0 {
+ config.MaxActive = defaultPoolMaxActive
+ }
+ if config.IdleTimeout == 0 {
+ config.IdleTimeout = defaultPoolIdleTimeout
+ }
+ if config.WaitTimeout == 0 {
+ config.WaitTimeout = defaultPoolWaitTimeout
+ }
+ if config.MaxConnLifetime == 0 {
+ config.MaxConnLifetime = defaultPoolMaxLifeTime
+ }
+ if config.WriteTimeout == 0 {
+ config.WriteTimeout = -1
+ }
+ if config.ReadTimeout == 0 {
+ config.ReadTimeout = -1
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter_goredis_conn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter_goredis_conn.go
new file mode 100644
index 000000000000..fe0df51b2c71
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_adapter_goredis_conn.go
@@ -0,0 +1,118 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+
+ "github.com/go-redis/redis/v8"
+ "github.com/gogf/gf/v2/errors/gerror"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type localAdapterGoRedisConn struct {
+ ps *redis.PubSub
+ redis *AdapterGoRedis
+}
+
+// Do send a command to the server and returns the received reply.
+// It uses json.Marshal for struct/slice/map type values before committing them to redis.
+func (c *localAdapterGoRedisConn) Do(ctx context.Context, command string, args ...interface{}) (reply *gvar.Var, err error) {
+ argStrSlice := gconv.Strings(args)
+ switch gstr.ToLower(command) {
+ case `subscribe`:
+ c.ps = c.redis.client.Subscribe(ctx, argStrSlice...)
+
+ case `psubscribe`:
+ c.ps = c.redis.client.PSubscribe(ctx, argStrSlice...)
+
+ case `unsubscribe`:
+ if c.ps != nil {
+ err = c.ps.Unsubscribe(ctx, argStrSlice...)
+ if err != nil {
+ err = gerror.Wrapf(err, `Redis PubSub Unsubscribe failed with arguments "%v"`, argStrSlice)
+ }
+ }
+
+ case `punsubscribe`:
+ if c.ps != nil {
+ err = c.ps.PUnsubscribe(ctx, argStrSlice...)
+ if err != nil {
+ err = gerror.Wrapf(err, `Redis PubSub PUnsubscribe failed with arguments "%v"`, argStrSlice)
+ }
+ }
+
+ default:
+ arguments := make([]interface{}, len(args)+1)
+ copy(arguments, []interface{}{command})
+ copy(arguments[1:], args)
+ reply, err = c.resultToVar(c.redis.client.Do(ctx, arguments...).Result())
+ if err != nil {
+ err = gerror.Wrapf(err, `Redis Client Do failed with arguments "%v"`, arguments)
+ }
+ }
+ return
+}
+
+// resultToVar converts redis operation result to gvar.Var.
+func (c *localAdapterGoRedisConn) resultToVar(result interface{}, err error) (*gvar.Var, error) {
+ if err == redis.Nil {
+ err = nil
+ }
+ if err == nil {
+ switch v := result.(type) {
+ case []byte:
+ return gvar.New(string(v)), err
+
+ case []interface{}:
+ return gvar.New(gconv.Strings(v)), err
+
+ case *redis.Message:
+ result = &Message{
+ Channel: v.Channel,
+ Pattern: v.Pattern,
+ Payload: v.Payload,
+ PayloadSlice: v.PayloadSlice,
+ }
+
+ case *redis.Subscription:
+ result = &Subscription{
+ Kind: v.Kind,
+ Channel: v.Channel,
+ Count: v.Count,
+ }
+ }
+ }
+
+ return gvar.New(result), err
+}
+
+// Receive receives a single reply as gvar.Var from the Redis server.
+func (c *localAdapterGoRedisConn) Receive(ctx context.Context) (*gvar.Var, error) {
+ if c.ps != nil {
+ v, err := c.resultToVar(c.ps.Receive(ctx))
+ if err != nil {
+ err = gerror.Wrapf(err, `Redis PubSub Receive failed`)
+ }
+ return v, err
+ }
+ return nil, nil
+}
+
+// Close closes current PubSub or puts the connection back to connection pool.
+func (c *localAdapterGoRedisConn) Close(ctx context.Context) (err error) {
+ if c.ps != nil {
+ err = c.ps.Close()
+ if err != nil {
+ err = gerror.Wrapf(err, `Redis PubSub Close failed`)
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_config.go
new file mode 100644
index 000000000000..d381332ffb44
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_config.go
@@ -0,0 +1,132 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+ "crypto/tls"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Config is redis configuration.
+type Config struct {
+ Address string `json:"address"` // It supports single and cluster redis server. Multiple addresses joined with char ','. Eg: 192.168.1.1:6379, 192.168.1.2:6379.
+ Db int `json:"db"` // Redis db.
+ Pass string `json:"pass"` // Password for AUTH.
+ MinIdle int `json:"minIdle"` // Minimum number of connections allowed to be idle (default is 0)
+ MaxIdle int `json:"maxIdle"` // Maximum number of connections allowed to be idle (default is 10)
+ MaxActive int `json:"maxActive"` // Maximum number of connections limit (default is 0 means no limit).
+ MaxConnLifetime time.Duration `json:"maxConnLifetime"` // Maximum lifetime of the connection (default is 30 seconds, not allowed to be set to 0)
+ IdleTimeout time.Duration `json:"idleTimeout"` // Maximum idle time for connection (default is 10 seconds, not allowed to be set to 0)
+ WaitTimeout time.Duration `json:"waitTimeout"` // Timed out duration waiting to get a connection from the connection pool.
+ DialTimeout time.Duration `json:"dialTimeout"` // Dial connection timeout for TCP.
+ ReadTimeout time.Duration `json:"readTimeout"` // Read timeout for TCP. DO NOT set it if not necessary.
+ WriteTimeout time.Duration `json:"writeTimeout"` // Write timeout for TCP.
+ MasterName string `json:"masterName"` // Used in Redis Sentinel mode.
+ TLS bool `json:"tls"` // Specifies whether TLS should be used when connecting to the server.
+ TLSSkipVerify bool `json:"tlsSkipVerify"` // Disables server name verification when connecting over TLS.
+ TLSConfig *tls.Config `json:"-"` // TLS Config to use. When set TLS will be negotiated.
+}
+
+const (
+ DefaultGroupName = "default" // Default configuration group name.
+)
+
+var (
+ // Configuration groups.
+ localConfigMap = gmap.NewStrAnyMap(true)
+)
+
+// SetConfig sets the global configuration for specified group.
+// If `name` is not passed, it sets configuration for the default group name.
+func SetConfig(config *Config, name ...string) {
+ group := DefaultGroupName
+ if len(name) > 0 {
+ group = name[0]
+ }
+ localConfigMap.Set(group, config)
+
+ intlog.Printf(context.TODO(), `SetConfig for group "%s": %+v`, group, config)
+}
+
+// SetConfigByMap sets the global configuration for specified group with map.
+// If `name` is not passed, it sets configuration for the default group name.
+func SetConfigByMap(m map[string]interface{}, name ...string) error {
+ group := DefaultGroupName
+ if len(name) > 0 {
+ group = name[0]
+ }
+ config, err := ConfigFromMap(m)
+ if err != nil {
+ return err
+ }
+ localConfigMap.Set(group, config)
+ return nil
+}
+
+// ConfigFromMap parses and returns config from given map.
+func ConfigFromMap(m map[string]interface{}) (config *Config, err error) {
+ config = &Config{}
+ if err = gconv.Scan(m, config); err != nil {
+ err = gerror.NewCodef(gcode.CodeInvalidConfiguration, `invalid redis configuration: %#v`, m)
+ }
+ if config.DialTimeout < time.Second {
+ config.DialTimeout = config.DialTimeout * time.Second
+ }
+ if config.WaitTimeout < time.Second {
+ config.WaitTimeout = config.WaitTimeout * time.Second
+ }
+ if config.WriteTimeout < time.Second {
+ config.WriteTimeout = config.WriteTimeout * time.Second
+ }
+ if config.ReadTimeout < time.Second {
+ config.ReadTimeout = config.ReadTimeout * time.Second
+ }
+ if config.IdleTimeout < time.Second {
+ config.IdleTimeout = config.IdleTimeout * time.Second
+ }
+ if config.MaxConnLifetime < time.Second {
+ config.MaxConnLifetime = config.MaxConnLifetime * time.Second
+ }
+ return
+}
+
+// GetConfig returns the global configuration with specified group name.
+// If `name` is not passed, it returns configuration of the default group name.
+func GetConfig(name ...string) (config *Config, ok bool) {
+ group := DefaultGroupName
+ if len(name) > 0 {
+ group = name[0]
+ }
+ if v := localConfigMap.Get(group); v != nil {
+ return v.(*Config), true
+ }
+ return &Config{}, false
+}
+
+// RemoveConfig removes the global configuration with specified group.
+// If `name` is not passed, it removes configuration of the default group name.
+func RemoveConfig(name ...string) {
+ group := DefaultGroupName
+ if len(name) > 0 {
+ group = name[0]
+ }
+ localConfigMap.Remove(group)
+
+ intlog.Printf(context.TODO(), `RemoveConfig: %s`, group)
+}
+
+// ClearConfig removes all configurations of redis.
+func ClearConfig() {
+ localConfigMap.Clear()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_instance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_instance.go
new file mode 100644
index 000000000000..fbe61eff271a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_instance.go
@@ -0,0 +1,43 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+var (
+ localInstances = gmap.NewStrAnyMap(true)
+)
+
+// Instance returns an instance of redis client with specified group.
+// The `name` param is unnecessary, if `name` is not passed,
+// it returns a redis instance with default configuration group.
+func Instance(name ...string) *Redis {
+ group := DefaultGroupName
+ if len(name) > 0 && name[0] != "" {
+ group = name[0]
+ }
+ v := localInstances.GetOrSetFuncLock(group, func() interface{} {
+ if config, ok := GetConfig(group); ok {
+ r, err := New(config)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ return nil
+ }
+ return r
+ }
+ return nil
+ })
+ if v != nil {
+ return v.(*Redis)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_message.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_message.go
new file mode 100644
index 000000000000..29ef66ee81ab
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_message.go
@@ -0,0 +1,15 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+// Message received as result of a PUBLISH command issued by another client.
+type Message struct {
+ Channel string
+ Pattern string
+ Payload string
+ PayloadSlice []string
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis.go
new file mode 100644
index 000000000000..389a9d4db779
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis.go
@@ -0,0 +1,107 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// Redis client.
+type Redis struct {
+ adapter Adapter
+}
+
+const (
+ errorNilRedis = `the Redis object is nil`
+)
+
+// SetAdapter sets custom adapter for current redis client.
+func (r *Redis) SetAdapter(adapter Adapter) {
+ if r == nil {
+ return
+ }
+ r.adapter = adapter
+}
+
+// GetAdapter returns the adapter that is set in current redis client.
+func (r *Redis) GetAdapter() Adapter {
+ if r == nil {
+ return nil
+ }
+ return r.adapter
+}
+
+// Conn retrieves and returns a connection object for continuous operations.
+// Note that you should call Close function manually if you do not use this connection any further.
+func (r *Redis) Conn(ctx context.Context) (*RedisConn, error) {
+ if r == nil {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, errorNilRedis)
+ }
+ if r.adapter == nil {
+ return nil, gerror.NewCodef(
+ gcode.CodeMissingConfiguration,
+ `redis adapter not initialized, missing configuration or adapter register?`,
+ )
+ }
+ conn, err := r.adapter.Conn(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return &RedisConn{
+ conn: conn,
+ redis: r,
+ }, nil
+}
+
+// Do send a command to the server and returns the received reply.
+// It uses json.Marshal for struct/slice/map type values before committing them to redis.
+func (r *Redis) Do(ctx context.Context, command string, args ...interface{}) (*gvar.Var, error) {
+ if r == nil {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, errorNilRedis)
+ }
+ conn, err := r.Conn(ctx)
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ if closeErr := conn.Close(ctx); closeErr != nil {
+ intlog.Errorf(ctx, `%+v`, closeErr)
+ }
+ }()
+ return conn.Do(ctx, command, args...)
+}
+
+// MustConn performs as function Conn, but it panics if any error occurs internally.
+func (r *Redis) MustConn(ctx context.Context) *RedisConn {
+ c, err := r.Conn(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return c
+}
+
+// MustDo performs as function Do, but it panics if any error occurs internally.
+func (r *Redis) MustDo(ctx context.Context, command string, args ...interface{}) *gvar.Var {
+ v, err := r.Do(ctx, command, args...)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// Close closes current redis client, closes its connection pool and releases all its related resources.
+func (r *Redis) Close(ctx context.Context) error {
+ if r == nil {
+ return gerror.NewCode(gcode.CodeInvalidParameter, errorNilRedis)
+ }
+ return r.adapter.Close(ctx)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis_conn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis_conn.go
new file mode 100644
index 000000000000..2bef863e3c59
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis_conn.go
@@ -0,0 +1,80 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+ "reflect"
+
+ "github.com/gogf/gf/v2"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gtime"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// RedisConn is a connection of redis client.
+type RedisConn struct {
+ conn Conn
+ redis *Redis
+}
+
+// Do send a command to the server and returns the received reply.
+// It uses json.Marshal for struct/slice/map type values before committing them to redis.
+func (c *RedisConn) Do(ctx context.Context, command string, args ...interface{}) (reply *gvar.Var, err error) {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ for k, v := range args {
+ var (
+ reflectInfo = utils.OriginTypeAndKind(v)
+ )
+ switch reflectInfo.OriginKind {
+ case
+ reflect.Struct,
+ reflect.Map,
+ reflect.Slice,
+ reflect.Array:
+ // Ignore slice type of: []byte.
+ if _, ok := v.([]byte); !ok {
+ if args[k], err = json.Marshal(v); err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+
+ // Trace span start.
+ tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
+ _, span := tr.Start(ctx, "Redis."+command, trace.WithSpanKind(trace.SpanKindInternal))
+ defer span.End()
+
+ timestampMilli1 := gtime.TimestampMilli()
+ reply, err = c.conn.Do(ctx, command, args...)
+ timestampMilli2 := gtime.TimestampMilli()
+
+ // Trace span end.
+ c.traceSpanEnd(ctx, span, &traceItem{
+ err: err,
+ command: command,
+ args: args,
+ costMilli: timestampMilli2 - timestampMilli1,
+ })
+ return
+}
+
+// Receive receives a single reply as gvar.Var from the Redis server.
+func (c *RedisConn) Receive(ctx context.Context) (*gvar.Var, error) {
+ return c.conn.Receive(ctx)
+}
+
+// Close puts the connection back to connection pool.
+func (c *RedisConn) Close(ctx context.Context) error {
+ return c.conn.Close(ctx)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis_trace.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis_trace.go
new file mode 100644
index 000000000000..68af5bb121b0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_redis_trace.go
@@ -0,0 +1,66 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import (
+ "context"
+ "fmt"
+
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/net/gtrace"
+)
+
+// traceItem holds the information for redis trace.
+type traceItem struct {
+ err error
+ command string
+ args []interface{}
+ costMilli int64
+}
+
+const (
+ traceInstrumentName = "github.com/gogf/gf/v2/database/gredis"
+ traceAttrRedisAddress = "redis.address"
+ traceAttrRedisDb = "redis.db"
+ traceEventRedisExecution = "redis.execution"
+ traceEventRedisExecutionCommand = "redis.execution.command"
+ traceEventRedisExecutionCost = "redis.execution.cost"
+ traceEventRedisExecutionArguments = "redis.execution.arguments"
+)
+
+// traceSpanEnd checks and adds redis trace information to OpenTelemetry.
+func (c *RedisConn) traceSpanEnd(ctx context.Context, span trace.Span, item *traceItem) {
+ if gtrace.IsUsingDefaultProvider() || !gtrace.IsTracingInternal() {
+ return
+ }
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ if item.err != nil {
+ span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, item.err))
+ }
+
+ span.SetAttributes(gtrace.CommonLabels()...)
+
+ if adapter, ok := c.redis.GetAdapter().(*AdapterGoRedis); ok {
+ span.SetAttributes(
+ attribute.String(traceAttrRedisAddress, adapter.config.Address),
+ attribute.Int(traceAttrRedisDb, adapter.config.Db),
+ )
+ }
+
+ jsonBytes, _ := json.Marshal(item.args)
+ span.AddEvent(traceEventRedisExecution, trace.WithAttributes(
+ attribute.String(traceEventRedisExecutionCommand, item.command),
+ attribute.String(traceEventRedisExecutionCost, fmt.Sprintf(`%d ms`, item.costMilli)),
+ attribute.String(traceEventRedisExecutionArguments, string(jsonBytes)),
+ ))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_subscription.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_subscription.go
new file mode 100644
index 000000000000..41060158fd77
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/database/gredis/gredis_subscription.go
@@ -0,0 +1,21 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gredis
+
+import "fmt"
+
+// Subscription received after a successful subscription to channel.
+type Subscription struct {
+ Kind string // Can be "subscribe", "unsubscribe", "psubscribe" or "punsubscribe".
+ Channel string // Channel name we have subscribed to.
+ Count int // Number of channels we are currently subscribed to.
+}
+
+// String converts current object to a readable string.
+func (m *Subscription) String() string {
+ return fmt.Sprintf("%s: %s", m.Kind, m.Channel)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug.go
new file mode 100644
index 000000000000..7ff8e3db957a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gdebug contains facilities for programs to debug themselves while they are running.
+package gdebug
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_caller.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_caller.go
new file mode 100644
index 000000000000..5f145502e411
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_caller.go
@@ -0,0 +1,192 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdebug
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strings"
+)
+
+const (
+ maxCallerDepth = 1000
+ stackFilterKey = "/debug/gdebug/gdebug"
+)
+
+var (
+ goRootForFilter = runtime.GOROOT() // goRootForFilter is used for stack filtering purpose.
+ binaryVersion = "" // The version of current running binary(uint64 hex).
+ binaryVersionMd5 = "" // The version of current running binary(MD5).
+ selfPath = "" // Current running binary absolute path.
+)
+
+func init() {
+ if goRootForFilter != "" {
+ goRootForFilter = strings.Replace(goRootForFilter, "\\", "/", -1)
+ }
+ // Initialize internal package variable: selfPath.
+ selfPath, _ = exec.LookPath(os.Args[0])
+ if selfPath != "" {
+ selfPath, _ = filepath.Abs(selfPath)
+ }
+ if selfPath == "" {
+ selfPath, _ = filepath.Abs(os.Args[0])
+ }
+}
+
+// Caller returns the function name and the absolute file path along with its line
+// number of the caller.
+func Caller(skip ...int) (function string, path string, line int) {
+ return CallerWithFilter(nil, skip...)
+}
+
+// CallerWithFilter returns the function name and the absolute file path along with
+// its line number of the caller.
+//
+// The parameter `filters` is used to filter the path of the caller.
+func CallerWithFilter(filters []string, skip ...int) (function string, path string, line int) {
+ var (
+ number = 0
+ ok = true
+ )
+ if len(skip) > 0 {
+ number = skip[0]
+ }
+ pc, file, line, start := callerFromIndex(filters)
+ if start != -1 {
+ for i := start + number; i < maxCallerDepth; i++ {
+ if i != start {
+ pc, file, line, ok = runtime.Caller(i)
+ }
+ if ok {
+ if filterFileByFilters(file, filters) {
+ continue
+ }
+ function = ""
+ if fn := runtime.FuncForPC(pc); fn == nil {
+ function = "unknown"
+ } else {
+ function = fn.Name()
+ }
+ return function, file, line
+ } else {
+ break
+ }
+ }
+ }
+ return "", "", -1
+}
+
+// callerFromIndex returns the caller position and according information exclusive of the
+// debug package.
+//
+// VERY NOTE THAT, the returned index value should be `index - 1` as the caller's start point.
+func callerFromIndex(filters []string) (pc uintptr, file string, line int, index int) {
+ var ok bool
+ for index = 0; index < maxCallerDepth; index++ {
+ if pc, file, line, ok = runtime.Caller(index); ok {
+ if filterFileByFilters(file, filters) {
+ continue
+ }
+ if index > 0 {
+ index--
+ }
+ return
+ }
+ }
+ return 0, "", -1, -1
+}
+
+func filterFileByFilters(file string, filters []string) (filtered bool) {
+ // Filter empty file.
+ if file == "" {
+ return true
+ }
+ // Filter gdebug package callings.
+ if strings.Contains(file, stackFilterKey) {
+ return true
+ }
+ for _, filter := range filters {
+ if filter != "" && strings.Contains(file, filter) {
+ return true
+ }
+ }
+ // GOROOT filter.
+ if goRootForFilter != "" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter {
+ return true
+ }
+ return false
+}
+
+// CallerPackage returns the package name of the caller.
+func CallerPackage() string {
+ function, _, _ := Caller()
+ indexSplit := strings.LastIndexByte(function, '/')
+ if indexSplit == -1 {
+ return function[:strings.IndexByte(function, '.')]
+ } else {
+ leftPart := function[:indexSplit+1]
+ rightPart := function[indexSplit+1:]
+ indexDot := strings.IndexByte(function, '.')
+ rightPart = rightPart[:indexDot-1]
+ return leftPart + rightPart
+ }
+}
+
+// CallerFunction returns the function name of the caller.
+func CallerFunction() string {
+ function, _, _ := Caller()
+ function = function[strings.LastIndexByte(function, '/')+1:]
+ function = function[strings.IndexByte(function, '.')+1:]
+ return function
+}
+
+// CallerFilePath returns the file path of the caller.
+func CallerFilePath() string {
+ _, path, _ := Caller()
+ return path
+}
+
+// CallerDirectory returns the directory of the caller.
+func CallerDirectory() string {
+ _, path, _ := Caller()
+ return filepath.Dir(path)
+}
+
+// CallerFileLine returns the file path along with the line number of the caller.
+func CallerFileLine() string {
+ _, path, line := Caller()
+ return fmt.Sprintf(`%s:%d`, path, line)
+}
+
+// CallerFileLineShort returns the file name along with the line number of the caller.
+func CallerFileLineShort() string {
+ _, path, line := Caller()
+ return fmt.Sprintf(`%s:%d`, filepath.Base(path), line)
+}
+
+// FuncPath returns the complete function path of given `f`.
+func FuncPath(f interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+}
+
+// FuncName returns the function name of given `f`.
+func FuncName(f interface{}) string {
+ path := FuncPath(f)
+ if path == "" {
+ return ""
+ }
+ index := strings.LastIndexByte(path, '/')
+ if index < 0 {
+ index = strings.LastIndexByte(path, '\\')
+ }
+ return path[index+1:]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_grid.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_grid.go
new file mode 100644
index 000000000000..f43023d87cf5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_grid.go
@@ -0,0 +1,29 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdebug
+
+import (
+ "regexp"
+ "runtime"
+ "strconv"
+)
+
+var (
+ // gridRegex is the regular expression object for parsing goroutine id from stack information.
+ gridRegex = regexp.MustCompile(`^\w+\s+(\d+)\s+`)
+)
+
+// GoroutineId retrieves and returns the current goroutine id from stack information.
+// Be very aware that, it is with low performance as it uses runtime.Stack function.
+// It is commonly used for debugging purpose.
+func GoroutineId() int {
+ buf := make([]byte, 26)
+ runtime.Stack(buf, false)
+ match := gridRegex.FindSubmatch(buf)
+ id, _ := strconv.Atoi(string(match[1]))
+ return id
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_stack.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_stack.go
new file mode 100644
index 000000000000..0bfc6030c98c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_stack.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdebug
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+)
+
+// PrintStack prints to standard error the stack trace returned by runtime.Stack.
+func PrintStack(skip ...int) {
+ fmt.Print(Stack(skip...))
+}
+
+// Stack returns a formatted stack trace of the goroutine that calls it.
+// It calls runtime.Stack with a large enough buffer to capture the entire trace.
+func Stack(skip ...int) string {
+ return StackWithFilter(nil, skip...)
+}
+
+// StackWithFilter returns a formatted stack trace of the goroutine that calls it.
+// It calls runtime.Stack with a large enough buffer to capture the entire trace.
+//
+// The parameter `filter` is used to filter the path of the caller.
+func StackWithFilter(filters []string, skip ...int) string {
+ return StackWithFilters(filters, skip...)
+}
+
+// StackWithFilters returns a formatted stack trace of the goroutine that calls it.
+// It calls runtime.Stack with a large enough buffer to capture the entire trace.
+//
+// The parameter `filters` is a slice of strings, which are used to filter the path of the
+// caller.
+//
+// TODO Improve the performance using debug.Stack.
+func StackWithFilters(filters []string, skip ...int) string {
+ number := 0
+ if len(skip) > 0 {
+ number = skip[0]
+ }
+ var (
+ name = ""
+ space = " "
+ index = 1
+ buffer = bytes.NewBuffer(nil)
+ ok = true
+ pc, file, line, start = callerFromIndex(filters)
+ )
+ for i := start + number; i < maxCallerDepth; i++ {
+ if i != start {
+ pc, file, line, ok = runtime.Caller(i)
+ }
+ if ok {
+ if filterFileByFilters(file, filters) {
+ continue
+ }
+ if fn := runtime.FuncForPC(pc); fn == nil {
+ name = "unknown"
+ } else {
+ name = fn.Name()
+ }
+ if index > 9 {
+ space = " "
+ }
+ buffer.WriteString(fmt.Sprintf("%d.%s%s\n %s:%d\n", index, space, name, file, line))
+ index++
+ } else {
+ break
+ }
+ }
+ return buffer.String()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_testdata.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_testdata.go
new file mode 100644
index 000000000000..c87f24b138f9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_testdata.go
@@ -0,0 +1,36 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdebug
+
+import (
+ "io/ioutil"
+ "path/filepath"
+)
+
+// TestDataPath retrieves and returns the testdata path of current package,
+// which is used for unit testing cases only.
+// The optional parameter `names` specifies the sub-folders/sub-files,
+// which will be joined with current system separator and returned with the path.
+func TestDataPath(names ...string) string {
+ path := CallerDirectory() + string(filepath.Separator) + "testdata"
+ for _, name := range names {
+ path += string(filepath.Separator) + name
+ }
+ return path
+}
+
+// TestDataContent retrieves and returns the file content for specified testdata path of current package
+func TestDataContent(names ...string) string {
+ path := TestDataPath(names...)
+ if path != "" {
+ data, err := ioutil.ReadFile(path)
+ if err == nil {
+ return string(data)
+ }
+ }
+ return ""
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_version.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_version.go
new file mode 100644
index 000000000000..5c883f68dc13
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/debug/gdebug/gdebug_version.go
@@ -0,0 +1,58 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gdebug
+
+import (
+ "crypto/md5"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+
+ "github.com/gogf/gf/v2/encoding/ghash"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// BinVersion returns the version of current running binary.
+// It uses ghash.BKDRHash+BASE36 algorithm to calculate the unique version of the binary.
+func BinVersion() string {
+ if binaryVersion == "" {
+ binaryContent, _ := ioutil.ReadFile(selfPath)
+ binaryVersion = strconv.FormatInt(
+ int64(ghash.BKDR(binaryContent)),
+ 36,
+ )
+ }
+ return binaryVersion
+}
+
+// BinVersionMd5 returns the version of current running binary.
+// It uses MD5 algorithm to calculate the unique version of the binary.
+func BinVersionMd5() string {
+ if binaryVersionMd5 == "" {
+ binaryVersionMd5, _ = md5File(selfPath)
+ }
+ return binaryVersionMd5
+}
+
+// md5File encrypts file content of `path` using MD5 algorithms.
+func md5File(path string) (encrypt string, err error) {
+ f, err := os.Open(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Open failed for name "%s"`, path)
+ return "", err
+ }
+ defer f.Close()
+ h := md5.New()
+ _, err = io.Copy(h, f)
+ if err != nil {
+ err = gerror.Wrap(err, `io.Copy failed`)
+ return "", err
+ }
+ return fmt.Sprintf("%x", h.Sum(nil)), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbase64/gbase64.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbase64/gbase64.go
new file mode 100644
index 000000000000..566d68c5a03d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbase64/gbase64.go
@@ -0,0 +1,124 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gbase64 provides useful API for BASE64 encoding/decoding algorithm.
+package gbase64
+
+import (
+ "encoding/base64"
+ "io/ioutil"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Encode encodes bytes with BASE64 algorithm.
+func Encode(src []byte) []byte {
+ dst := make([]byte, base64.StdEncoding.EncodedLen(len(src)))
+ base64.StdEncoding.Encode(dst, src)
+ return dst
+}
+
+// EncodeString encodes string with BASE64 algorithm.
+func EncodeString(src string) string {
+ return EncodeToString([]byte(src))
+}
+
+// EncodeToString encodes bytes to string with BASE64 algorithm.
+func EncodeToString(src []byte) string {
+ return string(Encode(src))
+}
+
+// EncodeFile encodes file content of `path` using BASE64 algorithms.
+func EncodeFile(path string) ([]byte, error) {
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `ioutil.ReadFile failed for filename "%s"`, path)
+ return nil, err
+ }
+ return Encode(content), nil
+}
+
+// MustEncodeFile encodes file content of `path` using BASE64 algorithms.
+// It panics if any error occurs.
+func MustEncodeFile(path string) []byte {
+ result, err := EncodeFile(path)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// EncodeFileToString encodes file content of `path` to string using BASE64 algorithms.
+func EncodeFileToString(path string) (string, error) {
+ content, err := EncodeFile(path)
+ if err != nil {
+ return "", err
+ }
+ return string(content), nil
+}
+
+// MustEncodeFileToString encodes file content of `path` to string using BASE64 algorithms.
+// It panics if any error occurs.
+func MustEncodeFileToString(path string) string {
+ result, err := EncodeFileToString(path)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// Decode decodes bytes with BASE64 algorithm.
+func Decode(data []byte) ([]byte, error) {
+ var (
+ src = make([]byte, base64.StdEncoding.DecodedLen(len(data)))
+ n, err = base64.StdEncoding.Decode(src, data)
+ )
+ if err != nil {
+ err = gerror.Wrap(err, `base64.StdEncoding.Decode failed`)
+ }
+ return src[:n], err
+}
+
+// MustDecode decodes bytes with BASE64 algorithm.
+// It panics if any error occurs.
+func MustDecode(data []byte) []byte {
+ result, err := Decode(data)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// DecodeString decodes string with BASE64 algorithm.
+func DecodeString(data string) ([]byte, error) {
+ return Decode([]byte(data))
+}
+
+// MustDecodeString decodes string with BASE64 algorithm.
+// It panics if any error occurs.
+func MustDecodeString(data string) []byte {
+ result, err := DecodeString(data)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// DecodeToString decodes string with BASE64 algorithm.
+func DecodeToString(data string) (string, error) {
+ b, err := DecodeString(data)
+ return string(b), err
+}
+
+// MustDecodeToString decodes string with BASE64 algorithm.
+// It panics if any error occurs.
+func MustDecodeToString(data string) string {
+ result, err := DecodeToString(data)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary.go
new file mode 100644
index 000000000000..5fbc48477f8c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary.go
@@ -0,0 +1,134 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gbinary provides useful API for handling binary/bytes data.
+//
+// Note that package gbinary encodes the data using LittleEndian in default.
+package gbinary
+
+func Encode(values ...interface{}) []byte {
+ return LeEncode(values...)
+}
+
+func EncodeByLength(length int, values ...interface{}) []byte {
+ return LeEncodeByLength(length, values...)
+}
+
+func Decode(b []byte, values ...interface{}) error {
+ return LeDecode(b, values...)
+}
+
+func EncodeString(s string) []byte {
+ return LeEncodeString(s)
+}
+
+func DecodeToString(b []byte) string {
+ return LeDecodeToString(b)
+}
+
+func EncodeBool(b bool) []byte {
+ return LeEncodeBool(b)
+}
+
+func EncodeInt(i int) []byte {
+ return LeEncodeInt(i)
+}
+
+func EncodeUint(i uint) []byte {
+ return LeEncodeUint(i)
+}
+
+func EncodeInt8(i int8) []byte {
+ return LeEncodeInt8(i)
+}
+
+func EncodeUint8(i uint8) []byte {
+ return LeEncodeUint8(i)
+}
+
+func EncodeInt16(i int16) []byte {
+ return LeEncodeInt16(i)
+}
+
+func EncodeUint16(i uint16) []byte {
+ return LeEncodeUint16(i)
+}
+
+func EncodeInt32(i int32) []byte {
+ return LeEncodeInt32(i)
+}
+
+func EncodeUint32(i uint32) []byte {
+ return LeEncodeUint32(i)
+}
+
+func EncodeInt64(i int64) []byte {
+ return LeEncodeInt64(i)
+}
+
+func EncodeUint64(i uint64) []byte {
+ return LeEncodeUint64(i)
+}
+
+func EncodeFloat32(f float32) []byte {
+ return LeEncodeFloat32(f)
+}
+
+func EncodeFloat64(f float64) []byte {
+ return LeEncodeFloat64(f)
+}
+
+func DecodeToInt(b []byte) int {
+ return LeDecodeToInt(b)
+}
+
+func DecodeToUint(b []byte) uint {
+ return LeDecodeToUint(b)
+}
+
+func DecodeToBool(b []byte) bool {
+ return LeDecodeToBool(b)
+}
+
+func DecodeToInt8(b []byte) int8 {
+ return LeDecodeToInt8(b)
+}
+
+func DecodeToUint8(b []byte) uint8 {
+ return LeDecodeToUint8(b)
+}
+
+func DecodeToInt16(b []byte) int16 {
+ return LeDecodeToInt16(b)
+}
+
+func DecodeToUint16(b []byte) uint16 {
+ return LeDecodeToUint16(b)
+}
+
+func DecodeToInt32(b []byte) int32 {
+ return LeDecodeToInt32(b)
+}
+
+func DecodeToUint32(b []byte) uint32 {
+ return LeDecodeToUint32(b)
+}
+
+func DecodeToInt64(b []byte) int64 {
+ return LeDecodeToInt64(b)
+}
+
+func DecodeToUint64(b []byte) uint64 {
+ return LeDecodeToUint64(b)
+}
+
+func DecodeToFloat32(b []byte) float32 {
+ return LeDecodeToFloat32(b)
+}
+
+func DecodeToFloat64(b []byte) float64 {
+ return LeDecodeToFloat64(b)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_be.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_be.go
new file mode 100644
index 000000000000..1045d24265d4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_be.go
@@ -0,0 +1,287 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gbinary
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "math"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// BeEncode encodes one or multiple `values` into bytes using BigEndian.
+// It uses type asserting checking the type of each value of `values` and internally
+// calls corresponding converting function do the bytes converting.
+//
+// It supports common variable type asserting, and finally it uses fmt.Sprintf converting
+// value to string and then to bytes.
+func BeEncode(values ...interface{}) []byte {
+ buf := new(bytes.Buffer)
+ for i := 0; i < len(values); i++ {
+ if values[i] == nil {
+ return buf.Bytes()
+ }
+
+ switch value := values[i].(type) {
+ case int:
+ buf.Write(BeEncodeInt(value))
+ case int8:
+ buf.Write(BeEncodeInt8(value))
+ case int16:
+ buf.Write(BeEncodeInt16(value))
+ case int32:
+ buf.Write(BeEncodeInt32(value))
+ case int64:
+ buf.Write(BeEncodeInt64(value))
+ case uint:
+ buf.Write(BeEncodeUint(value))
+ case uint8:
+ buf.Write(BeEncodeUint8(value))
+ case uint16:
+ buf.Write(BeEncodeUint16(value))
+ case uint32:
+ buf.Write(BeEncodeUint32(value))
+ case uint64:
+ buf.Write(BeEncodeUint64(value))
+ case bool:
+ buf.Write(BeEncodeBool(value))
+ case string:
+ buf.Write(BeEncodeString(value))
+ case []byte:
+ buf.Write(value)
+ case float32:
+ buf.Write(BeEncodeFloat32(value))
+ case float64:
+ buf.Write(BeEncodeFloat64(value))
+ default:
+ if err := binary.Write(buf, binary.BigEndian, value); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ buf.Write(BeEncodeString(fmt.Sprintf("%v", value)))
+ }
+ }
+ }
+ return buf.Bytes()
+}
+
+func BeEncodeByLength(length int, values ...interface{}) []byte {
+ b := BeEncode(values...)
+ if len(b) < length {
+ b = append(b, make([]byte, length-len(b))...)
+ } else if len(b) > length {
+ b = b[0:length]
+ }
+ return b
+}
+
+func BeDecode(b []byte, values ...interface{}) error {
+ var (
+ err error
+ buf = bytes.NewBuffer(b)
+ )
+ for i := 0; i < len(values); i++ {
+ if err = binary.Read(buf, binary.BigEndian, values[i]); err != nil {
+ err = gerror.Wrap(err, `binary.Read failed`)
+ return err
+ }
+ }
+ return nil
+}
+
+func BeEncodeString(s string) []byte {
+ return []byte(s)
+}
+
+func BeDecodeToString(b []byte) string {
+ return string(b)
+}
+
+func BeEncodeBool(b bool) []byte {
+ if b == true {
+ return []byte{1}
+ } else {
+ return []byte{0}
+ }
+}
+
+func BeEncodeInt(i int) []byte {
+ if i <= math.MaxInt8 {
+ return BeEncodeInt8(int8(i))
+ } else if i <= math.MaxInt16 {
+ return BeEncodeInt16(int16(i))
+ } else if i <= math.MaxInt32 {
+ return BeEncodeInt32(int32(i))
+ } else {
+ return BeEncodeInt64(int64(i))
+ }
+}
+
+func BeEncodeUint(i uint) []byte {
+ if i <= math.MaxUint8 {
+ return BeEncodeUint8(uint8(i))
+ } else if i <= math.MaxUint16 {
+ return BeEncodeUint16(uint16(i))
+ } else if i <= math.MaxUint32 {
+ return BeEncodeUint32(uint32(i))
+ } else {
+ return BeEncodeUint64(uint64(i))
+ }
+}
+
+func BeEncodeInt8(i int8) []byte {
+ return []byte{byte(i)}
+}
+
+func BeEncodeUint8(i uint8) []byte {
+ return []byte{i}
+}
+
+func BeEncodeInt16(i int16) []byte {
+ b := make([]byte, 2)
+ binary.BigEndian.PutUint16(b, uint16(i))
+ return b
+}
+
+func BeEncodeUint16(i uint16) []byte {
+ b := make([]byte, 2)
+ binary.BigEndian.PutUint16(b, i)
+ return b
+}
+
+func BeEncodeInt32(i int32) []byte {
+ b := make([]byte, 4)
+ binary.BigEndian.PutUint32(b, uint32(i))
+ return b
+}
+
+func BeEncodeUint32(i uint32) []byte {
+ b := make([]byte, 4)
+ binary.BigEndian.PutUint32(b, i)
+ return b
+}
+
+func BeEncodeInt64(i int64) []byte {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, uint64(i))
+ return b
+}
+
+func BeEncodeUint64(i uint64) []byte {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, i)
+ return b
+}
+
+func BeEncodeFloat32(f float32) []byte {
+ bits := math.Float32bits(f)
+ b := make([]byte, 4)
+ binary.BigEndian.PutUint32(b, bits)
+ return b
+}
+
+func BeEncodeFloat64(f float64) []byte {
+ bits := math.Float64bits(f)
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, bits)
+ return b
+}
+
+func BeDecodeToInt(b []byte) int {
+ if len(b) < 2 {
+ return int(BeDecodeToUint8(b))
+ } else if len(b) < 3 {
+ return int(BeDecodeToUint16(b))
+ } else if len(b) < 5 {
+ return int(BeDecodeToUint32(b))
+ } else {
+ return int(BeDecodeToUint64(b))
+ }
+}
+
+func BeDecodeToUint(b []byte) uint {
+ if len(b) < 2 {
+ return uint(BeDecodeToUint8(b))
+ } else if len(b) < 3 {
+ return uint(BeDecodeToUint16(b))
+ } else if len(b) < 5 {
+ return uint(BeDecodeToUint32(b))
+ } else {
+ return uint(BeDecodeToUint64(b))
+ }
+}
+
+func BeDecodeToBool(b []byte) bool {
+ if len(b) == 0 {
+ return false
+ }
+ if bytes.Compare(b, make([]byte, len(b))) == 0 {
+ return false
+ }
+ return true
+}
+
+func BeDecodeToInt8(b []byte) int8 {
+ if len(b) == 0 {
+ panic(`empty slice given`)
+ }
+ return int8(b[0])
+}
+
+func BeDecodeToUint8(b []byte) uint8 {
+ if len(b) == 0 {
+ panic(`empty slice given`)
+ }
+ return b[0]
+}
+
+func BeDecodeToInt16(b []byte) int16 {
+ return int16(binary.BigEndian.Uint16(BeFillUpSize(b, 2)))
+}
+
+func BeDecodeToUint16(b []byte) uint16 {
+ return binary.BigEndian.Uint16(BeFillUpSize(b, 2))
+}
+
+func BeDecodeToInt32(b []byte) int32 {
+ return int32(binary.BigEndian.Uint32(BeFillUpSize(b, 4)))
+}
+
+func BeDecodeToUint32(b []byte) uint32 {
+ return binary.BigEndian.Uint32(BeFillUpSize(b, 4))
+}
+
+func BeDecodeToInt64(b []byte) int64 {
+ return int64(binary.BigEndian.Uint64(BeFillUpSize(b, 8)))
+}
+
+func BeDecodeToUint64(b []byte) uint64 {
+ return binary.BigEndian.Uint64(BeFillUpSize(b, 8))
+}
+
+func BeDecodeToFloat32(b []byte) float32 {
+ return math.Float32frombits(binary.BigEndian.Uint32(BeFillUpSize(b, 4)))
+}
+
+func BeDecodeToFloat64(b []byte) float64 {
+ return math.Float64frombits(binary.BigEndian.Uint64(BeFillUpSize(b, 8)))
+}
+
+// BeFillUpSize fills up the bytes `b` to given length `l` using big BigEndian.
+//
+// Note that it creates a new bytes slice by copying the original one to avoid changing
+// the original parameter bytes.
+func BeFillUpSize(b []byte, l int) []byte {
+ if len(b) >= l {
+ return b[:l]
+ }
+ c := make([]byte, l)
+ copy(c[l-len(b):], b)
+ return c
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_bit.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_bit.go
new file mode 100644
index 000000000000..3e93dcab6d84
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_bit.go
@@ -0,0 +1,74 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gbinary
+
+// NOTE: THIS IS AN EXPERIMENTAL FEATURE!
+
+// Bit Binary bit (0 | 1)
+type Bit int8
+
+// EncodeBits does encode bits return bits Default coding
+func EncodeBits(bits []Bit, i int, l int) []Bit {
+ return EncodeBitsWithUint(bits, uint(i), l)
+}
+
+// EncodeBitsWithUint . Merge ui bitwise into the bits array and occupy the length bits
+// (Note: binary 0 | 1 digits are stored in the uis array)
+func EncodeBitsWithUint(bits []Bit, ui uint, l int) []Bit {
+ a := make([]Bit, l)
+ for i := l - 1; i >= 0; i-- {
+ a[i] = Bit(ui & 1)
+ ui >>= 1
+ }
+ if bits != nil {
+ return append(bits, a...)
+ }
+ return a
+}
+
+// EncodeBitsToBytes . does encode bits to bytes
+// Convert bits to [] byte, encode from left to right, and add less than 1 byte from 0 to the end.
+func EncodeBitsToBytes(bits []Bit) []byte {
+ if len(bits)%8 != 0 {
+ for i := 0; i < len(bits)%8; i++ {
+ bits = append(bits, 0)
+ }
+ }
+ b := make([]byte, 0)
+ for i := 0; i < len(bits); i += 8 {
+ b = append(b, byte(DecodeBitsToUint(bits[i:i+8])))
+ }
+ return b
+}
+
+// DecodeBits .does decode bits to int
+// Resolve to int
+func DecodeBits(bits []Bit) int {
+ v := 0
+ for _, i := range bits {
+ v = v<<1 | int(i)
+ }
+ return v
+}
+
+// DecodeBitsToUint .Resolve to uint
+func DecodeBitsToUint(bits []Bit) uint {
+ v := uint(0)
+ for _, i := range bits {
+ v = v<<1 | uint(i)
+ }
+ return v
+}
+
+// DecodeBytesToBits .Parsing [] byte into character array [] uint8
+func DecodeBytesToBits(bs []byte) []Bit {
+ bits := make([]Bit, 0)
+ for _, b := range bs {
+ bits = EncodeBitsWithUint(bits, uint(b), 8)
+ }
+ return bits
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_func.go
new file mode 100644
index 000000000000..6e1fba246034
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_func.go
@@ -0,0 +1,7 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gbinary
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_le.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_le.go
new file mode 100644
index 000000000000..76186c46f098
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gbinary/gbinary_le.go
@@ -0,0 +1,287 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gbinary
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "math"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// LeEncode encodes one or multiple `values` into bytes using LittleEndian.
+// It uses type asserting checking the type of each value of `values` and internally
+// calls corresponding converting function do the bytes converting.
+//
+// It supports common variable type asserting, and finally it uses fmt.Sprintf converting
+// value to string and then to bytes.
+func LeEncode(values ...interface{}) []byte {
+ buf := new(bytes.Buffer)
+ for i := 0; i < len(values); i++ {
+ if values[i] == nil {
+ return buf.Bytes()
+ }
+ switch value := values[i].(type) {
+ case int:
+ buf.Write(LeEncodeInt(value))
+ case int8:
+ buf.Write(LeEncodeInt8(value))
+ case int16:
+ buf.Write(LeEncodeInt16(value))
+ case int32:
+ buf.Write(LeEncodeInt32(value))
+ case int64:
+ buf.Write(LeEncodeInt64(value))
+ case uint:
+ buf.Write(LeEncodeUint(value))
+ case uint8:
+ buf.Write(LeEncodeUint8(value))
+ case uint16:
+ buf.Write(LeEncodeUint16(value))
+ case uint32:
+ buf.Write(LeEncodeUint32(value))
+ case uint64:
+ buf.Write(LeEncodeUint64(value))
+ case bool:
+ buf.Write(LeEncodeBool(value))
+ case string:
+ buf.Write(LeEncodeString(value))
+ case []byte:
+ buf.Write(value)
+ case float32:
+ buf.Write(LeEncodeFloat32(value))
+ case float64:
+ buf.Write(LeEncodeFloat64(value))
+
+ default:
+ if err := binary.Write(buf, binary.LittleEndian, value); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ buf.Write(LeEncodeString(fmt.Sprintf("%v", value)))
+ }
+ }
+ }
+ return buf.Bytes()
+}
+
+func LeEncodeByLength(length int, values ...interface{}) []byte {
+ b := LeEncode(values...)
+ if len(b) < length {
+ b = append(b, make([]byte, length-len(b))...)
+ } else if len(b) > length {
+ b = b[0:length]
+ }
+ return b
+}
+
+func LeDecode(b []byte, values ...interface{}) error {
+ var (
+ err error
+ buf = bytes.NewBuffer(b)
+ )
+ for i := 0; i < len(values); i++ {
+ if err = binary.Read(buf, binary.LittleEndian, values[i]); err != nil {
+ err = gerror.Wrap(err, `binary.Read failed`)
+ return err
+ }
+ }
+ return nil
+}
+
+func LeEncodeString(s string) []byte {
+ return []byte(s)
+}
+
+func LeDecodeToString(b []byte) string {
+ return string(b)
+}
+
+func LeEncodeBool(b bool) []byte {
+ if b == true {
+ return []byte{1}
+ } else {
+ return []byte{0}
+ }
+}
+
+func LeEncodeInt(i int) []byte {
+ if i <= math.MaxInt8 {
+ return EncodeInt8(int8(i))
+ } else if i <= math.MaxInt16 {
+ return EncodeInt16(int16(i))
+ } else if i <= math.MaxInt32 {
+ return EncodeInt32(int32(i))
+ } else {
+ return EncodeInt64(int64(i))
+ }
+}
+
+func LeEncodeUint(i uint) []byte {
+ if i <= math.MaxUint8 {
+ return EncodeUint8(uint8(i))
+ } else if i <= math.MaxUint16 {
+ return EncodeUint16(uint16(i))
+ } else if i <= math.MaxUint32 {
+ return EncodeUint32(uint32(i))
+ } else {
+ return EncodeUint64(uint64(i))
+ }
+}
+
+func LeEncodeInt8(i int8) []byte {
+ return []byte{byte(i)}
+}
+
+func LeEncodeUint8(i uint8) []byte {
+ return []byte{i}
+}
+
+func LeEncodeInt16(i int16) []byte {
+ b := make([]byte, 2)
+ binary.LittleEndian.PutUint16(b, uint16(i))
+ return b
+}
+
+func LeEncodeUint16(i uint16) []byte {
+ b := make([]byte, 2)
+ binary.LittleEndian.PutUint16(b, i)
+ return b
+}
+
+func LeEncodeInt32(i int32) []byte {
+ b := make([]byte, 4)
+ binary.LittleEndian.PutUint32(b, uint32(i))
+ return b
+}
+
+func LeEncodeUint32(i uint32) []byte {
+ b := make([]byte, 4)
+ binary.LittleEndian.PutUint32(b, i)
+ return b
+}
+
+func LeEncodeInt64(i int64) []byte {
+ b := make([]byte, 8)
+ binary.LittleEndian.PutUint64(b, uint64(i))
+ return b
+}
+
+func LeEncodeUint64(i uint64) []byte {
+ b := make([]byte, 8)
+ binary.LittleEndian.PutUint64(b, i)
+ return b
+}
+
+func LeEncodeFloat32(f float32) []byte {
+ bits := math.Float32bits(f)
+ b := make([]byte, 4)
+ binary.LittleEndian.PutUint32(b, bits)
+ return b
+}
+
+func LeEncodeFloat64(f float64) []byte {
+ bits := math.Float64bits(f)
+ b := make([]byte, 8)
+ binary.LittleEndian.PutUint64(b, bits)
+ return b
+}
+
+func LeDecodeToInt(b []byte) int {
+ if len(b) < 2 {
+ return int(LeDecodeToUint8(b))
+ } else if len(b) < 3 {
+ return int(LeDecodeToUint16(b))
+ } else if len(b) < 5 {
+ return int(LeDecodeToUint32(b))
+ } else {
+ return int(LeDecodeToUint64(b))
+ }
+}
+
+func LeDecodeToUint(b []byte) uint {
+ if len(b) < 2 {
+ return uint(LeDecodeToUint8(b))
+ } else if len(b) < 3 {
+ return uint(LeDecodeToUint16(b))
+ } else if len(b) < 5 {
+ return uint(LeDecodeToUint32(b))
+ } else {
+ return uint(LeDecodeToUint64(b))
+ }
+}
+
+func LeDecodeToBool(b []byte) bool {
+ if len(b) == 0 {
+ return false
+ }
+ if bytes.Compare(b, make([]byte, len(b))) == 0 {
+ return false
+ }
+ return true
+}
+
+func LeDecodeToInt8(b []byte) int8 {
+ if len(b) == 0 {
+ panic(`empty slice given`)
+ }
+ return int8(b[0])
+}
+
+func LeDecodeToUint8(b []byte) uint8 {
+ if len(b) == 0 {
+ panic(`empty slice given`)
+ }
+ return b[0]
+}
+
+func LeDecodeToInt16(b []byte) int16 {
+ return int16(binary.LittleEndian.Uint16(LeFillUpSize(b, 2)))
+}
+
+func LeDecodeToUint16(b []byte) uint16 {
+ return binary.LittleEndian.Uint16(LeFillUpSize(b, 2))
+}
+
+func LeDecodeToInt32(b []byte) int32 {
+ return int32(binary.LittleEndian.Uint32(LeFillUpSize(b, 4)))
+}
+
+func LeDecodeToUint32(b []byte) uint32 {
+ return binary.LittleEndian.Uint32(LeFillUpSize(b, 4))
+}
+
+func LeDecodeToInt64(b []byte) int64 {
+ return int64(binary.LittleEndian.Uint64(LeFillUpSize(b, 8)))
+}
+
+func LeDecodeToUint64(b []byte) uint64 {
+ return binary.LittleEndian.Uint64(LeFillUpSize(b, 8))
+}
+
+func LeDecodeToFloat32(b []byte) float32 {
+ return math.Float32frombits(binary.LittleEndian.Uint32(LeFillUpSize(b, 4)))
+}
+
+func LeDecodeToFloat64(b []byte) float64 {
+ return math.Float64frombits(binary.LittleEndian.Uint64(LeFillUpSize(b, 8)))
+}
+
+// LeFillUpSize fills up the bytes `b` to given length `l` using LittleEndian.
+//
+// Note that it creates a new bytes slice by copying the original one to avoid changing
+// the original parameter bytes.
+func LeFillUpSize(b []byte, l int) []byte {
+ if len(b) >= l {
+ return b[:l]
+ }
+ c := make([]byte, l)
+ copy(c, b)
+ return c
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcharset/gcharset.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcharset/gcharset.go
new file mode 100644
index 000000000000..e895900948cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcharset/gcharset.go
@@ -0,0 +1,115 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcharset implements character-set conversion functionality.
+//
+// Supported Character Set:
+//
+// Chinese : GBK/GB18030/GB2312/Big5
+//
+// Japanese: EUCJP/ISO2022JP/ShiftJIS
+//
+// Korean : EUCKR
+//
+// Unicode : UTF-8/UTF-16/UTF-16BE/UTF-16LE
+//
+// Other : macintosh/IBM*/Windows*/ISO-*
+package gcharset
+
+import (
+ "bytes"
+ "context"
+ "io/ioutil"
+
+ "golang.org/x/text/encoding"
+ "golang.org/x/text/encoding/ianaindex"
+ "golang.org/x/text/transform"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+var (
+ // Alias for charsets.
+ charsetAlias = map[string]string{
+ "HZGB2312": "HZ-GB-2312",
+ "hzgb2312": "HZ-GB-2312",
+ "GB2312": "HZ-GB-2312",
+ "gb2312": "HZ-GB-2312",
+ }
+)
+
+// Supported returns whether charset `charset` is supported.
+func Supported(charset string) bool {
+ return getEncoding(charset) != nil
+}
+
+// Convert converts `src` charset encoding from `srcCharset` to `dstCharset`,
+// and returns the converted string.
+// It returns `src` as `dst` if it fails converting.
+func Convert(dstCharset string, srcCharset string, src string) (dst string, err error) {
+ if dstCharset == srcCharset {
+ return src, nil
+ }
+ dst = src
+ // Converting `src` to UTF-8.
+ if srcCharset != "UTF-8" {
+ if e := getEncoding(srcCharset); e != nil {
+ tmp, err := ioutil.ReadAll(
+ transform.NewReader(bytes.NewReader([]byte(src)), e.NewDecoder()),
+ )
+ if err != nil {
+ return "", gerror.Wrapf(err, `convert string "%s" to utf8 failed`, srcCharset)
+ }
+ src = string(tmp)
+ } else {
+ return dst, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported srcCharset "%s"`, srcCharset)
+ }
+ }
+ // Do the converting from UTF-8 to `dstCharset`.
+ if dstCharset != "UTF-8" {
+ if e := getEncoding(dstCharset); e != nil {
+ tmp, err := ioutil.ReadAll(
+ transform.NewReader(bytes.NewReader([]byte(src)), e.NewEncoder()),
+ )
+ if err != nil {
+ return "", gerror.Wrapf(err, `convert string from utf8 to "%s" failed`, dstCharset)
+ }
+ dst = string(tmp)
+ } else {
+ return dst, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported dstCharset "%s"`, dstCharset)
+ }
+ } else {
+ dst = src
+ }
+ return dst, nil
+}
+
+// ToUTF8 converts `src` charset encoding from `srcCharset` to UTF-8 ,
+// and returns the converted string.
+func ToUTF8(srcCharset string, src string) (dst string, err error) {
+ return Convert("UTF-8", srcCharset, src)
+}
+
+// UTF8To converts `src` charset encoding from UTF-8 to `dstCharset`,
+// and returns the converted string.
+func UTF8To(dstCharset string, src string) (dst string, err error) {
+ return Convert(dstCharset, "UTF-8", src)
+}
+
+// getEncoding returns the encoding.Encoding interface object for `charset`.
+// It returns nil if `charset` is not supported.
+func getEncoding(charset string) encoding.Encoding {
+ if c, ok := charsetAlias[charset]; ok {
+ charset = c
+ }
+ enc, err := ianaindex.MIB.Encoding(charset)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ return enc
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress.go
new file mode 100644
index 000000000000..1b4ca9423b64
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcompress provides kinds of compression algorithms for binary/bytes data.
+package gcompress
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_gzip.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_gzip.go
new file mode 100644
index 000000000000..ac05e83a6a36
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_gzip.go
@@ -0,0 +1,129 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcompress
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gfile"
+)
+
+// Gzip compresses `data` using gzip algorithm.
+// The optional parameter `level` specifies the compression level from
+// 1 to 9 which means from none to the best compression.
+//
+// Note that it returns error if given `level` is invalid.
+func Gzip(data []byte, level ...int) ([]byte, error) {
+ var (
+ writer *gzip.Writer
+ buf bytes.Buffer
+ err error
+ )
+ if len(level) > 0 {
+ writer, err = gzip.NewWriterLevel(&buf, level[0])
+ if err != nil {
+ err = gerror.Wrapf(err, `gzip.NewWriterLevel failed for level "%d"`, level[0])
+ return nil, err
+ }
+ } else {
+ writer = gzip.NewWriter(&buf)
+ }
+ if _, err = writer.Write(data); err != nil {
+ err = gerror.Wrap(err, `writer.Write failed`)
+ return nil, err
+ }
+ if err = writer.Close(); err != nil {
+ err = gerror.Wrap(err, `writer.Close failed`)
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// GzipFile compresses the file `src` to `dst` using gzip algorithm.
+func GzipFile(src, dst string, level ...int) error {
+ var (
+ writer *gzip.Writer
+ err error
+ )
+ srcFile, err := gfile.Open(src)
+ if err != nil {
+ return err
+ }
+ defer srcFile.Close()
+ dstFile, err := gfile.Create(dst)
+ if err != nil {
+ return err
+ }
+ defer dstFile.Close()
+
+ if len(level) > 0 {
+ writer, err = gzip.NewWriterLevel(dstFile, level[0])
+ if err != nil {
+ err = gerror.Wrap(err, `gzip.NewWriterLevel failed`)
+ return err
+ }
+ } else {
+ writer = gzip.NewWriter(dstFile)
+ }
+ defer writer.Close()
+
+ _, err = io.Copy(writer, srcFile)
+ if err != nil {
+ err = gerror.Wrap(err, `io.Copy failed`)
+ return err
+ }
+ return nil
+}
+
+// UnGzip decompresses `data` with gzip algorithm.
+func UnGzip(data []byte) ([]byte, error) {
+ var buf bytes.Buffer
+ reader, err := gzip.NewReader(bytes.NewReader(data))
+ if err != nil {
+ err = gerror.Wrap(err, `gzip.NewReader failed`)
+ return nil, err
+ }
+ if _, err = io.Copy(&buf, reader); err != nil {
+ err = gerror.Wrap(err, `io.Copy failed`)
+ return nil, err
+ }
+ if err = reader.Close(); err != nil {
+ err = gerror.Wrap(err, `reader.Close failed`)
+ return buf.Bytes(), err
+ }
+ return buf.Bytes(), nil
+}
+
+// UnGzipFile decompresses file `src` to `dst` using gzip algorithm.
+func UnGzipFile(src, dst string) error {
+ srcFile, err := gfile.Open(src)
+ if err != nil {
+ return err
+ }
+ defer srcFile.Close()
+ dstFile, err := gfile.Create(dst)
+ if err != nil {
+ return err
+ }
+ defer dstFile.Close()
+
+ reader, err := gzip.NewReader(srcFile)
+ if err != nil {
+ err = gerror.Wrap(err, `gzip.NewReader failed`)
+ return err
+ }
+ defer reader.Close()
+
+ if _, err = io.Copy(dstFile, reader); err != nil {
+ err = gerror.Wrap(err, `io.Copy failed`)
+ return err
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_zip.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_zip.go
new file mode 100644
index 000000000000..cdeae621c74f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_zip.go
@@ -0,0 +1,263 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcompress
+
+import (
+ "archive/zip"
+ "bytes"
+ "context"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// ZipPath compresses `paths` to `dest` using zip compressing algorithm.
+// The unnecessary parameter `prefix` indicates the path prefix for zip file.
+//
+// Note that the parameter `paths` can be either a directory or a file, which
+// supports multiple paths join with ','.
+func ZipPath(paths, dest string, prefix ...string) error {
+ writer, err := os.Create(dest)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Create failed for name "%s"`, dest)
+ return err
+ }
+ defer writer.Close()
+ zipWriter := zip.NewWriter(writer)
+ defer zipWriter.Close()
+ for _, path := range strings.Split(paths, ",") {
+ path = strings.TrimSpace(path)
+ if err = doZipPathWriter(path, gfile.RealPath(dest), zipWriter, prefix...); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ZipPathWriter compresses `paths` to `writer` using zip compressing algorithm.
+// The unnecessary parameter `prefix` indicates the path prefix for zip file.
+//
+// Note that the parameter `paths` can be either a directory or a file, which
+// supports multiple paths join with ','.
+func ZipPathWriter(paths string, writer io.Writer, prefix ...string) error {
+ zipWriter := zip.NewWriter(writer)
+ defer zipWriter.Close()
+ for _, path := range strings.Split(paths, ",") {
+ path = strings.TrimSpace(path)
+ if err := doZipPathWriter(path, "", zipWriter, prefix...); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// doZipPathWriter compresses the file of given `path` and writes the content to `zipWriter`.
+// The parameter `exclude` specifies the exclusive file path that is not compressed to `zipWriter`,
+// commonly the destination zip file path.
+// The unnecessary parameter `prefix` indicates the path prefix for zip file.
+func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix ...string) error {
+ var (
+ err error
+ files []string
+ )
+ path, err = gfile.Search(path)
+ if err != nil {
+ return err
+ }
+ if gfile.IsDir(path) {
+ files, err = gfile.ScanDir(path, "*", true)
+ if err != nil {
+ return err
+ }
+ } else {
+ files = []string{path}
+ }
+ headerPrefix := ""
+ if len(prefix) > 0 && prefix[0] != "" {
+ headerPrefix = prefix[0]
+ }
+ headerPrefix = strings.TrimRight(headerPrefix, "\\/")
+ if gfile.IsDir(path) {
+ if len(headerPrefix) > 0 {
+ headerPrefix += "/"
+ } else {
+ headerPrefix = gfile.Basename(path)
+ }
+
+ }
+ headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
+ for _, file := range files {
+ if exclude == file {
+ intlog.Printf(context.TODO(), `exclude file path: %s`, file)
+ continue
+ }
+ dir := gfile.Dir(file[len(path):])
+ if dir == "." {
+ dir = ""
+ }
+ if err = zipFile(file, headerPrefix+dir, zipWriter); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// UnZipFile decompresses `archive` to `dest` using zip compressing algorithm.
+// The optional parameter `path` specifies the unzipped path of `archive`,
+// which can be used to specify part of the archive file to unzip.
+//
+// Note that the parameter `dest` should be a directory.
+func UnZipFile(archive, dest string, path ...string) error {
+ readerCloser, err := zip.OpenReader(archive)
+ if err != nil {
+ err = gerror.Wrapf(err, `zip.OpenReader failed for name "%s"`, dest)
+ return err
+ }
+ defer readerCloser.Close()
+ return unZipFileWithReader(&readerCloser.Reader, dest, path...)
+}
+
+// UnZipContent decompresses `data` to `dest` using zip compressing algorithm.
+// The parameter `path` specifies the unzipped path of `archive`,
+// which can be used to specify part of the archive file to unzip.
+//
+// Note that the parameter `dest` should be a directory.
+func UnZipContent(data []byte, dest string, path ...string) error {
+ reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
+ if err != nil {
+ err = gerror.Wrapf(err, `zip.NewReader failed`)
+ return err
+ }
+ return unZipFileWithReader(reader, dest, path...)
+}
+
+func unZipFileWithReader(reader *zip.Reader, dest string, path ...string) error {
+ prefix := ""
+ if len(path) > 0 {
+ prefix = gstr.Replace(path[0], `\`, `/`)
+ }
+ if err := os.MkdirAll(dest, 0755); err != nil {
+ return err
+ }
+ var (
+ name string
+ dstPath string
+ dstDir string
+ )
+ for _, file := range reader.File {
+ name = gstr.Replace(file.Name, `\`, `/`)
+ name = gstr.Trim(name, "/")
+ if prefix != "" {
+ if name[0:len(prefix)] != prefix {
+ continue
+ }
+ name = name[len(prefix):]
+ }
+ dstPath = filepath.Join(dest, name)
+ if file.FileInfo().IsDir() {
+ _ = os.MkdirAll(dstPath, file.Mode())
+ continue
+ }
+ dstDir = filepath.Dir(dstPath)
+ if len(dstDir) > 0 {
+ if _, err := os.Stat(dstDir); os.IsNotExist(err) {
+ if err = os.MkdirAll(dstDir, 0755); err != nil {
+ err = gerror.Wrapf(err, `os.MkdirAll failed for path "%s"`, dstDir)
+ return err
+ }
+ }
+ }
+ fileReader, err := file.Open()
+ if err != nil {
+ err = gerror.Wrapf(err, `file.Open failed`)
+ return err
+ }
+ // The fileReader is closed in function doCopyForUnZipFileWithReader.
+ if err = doCopyForUnZipFileWithReader(file, fileReader, dstPath); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func doCopyForUnZipFileWithReader(file *zip.File, fileReader io.ReadCloser, dstPath string) error {
+ defer fileReader.Close()
+ targetFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
+ if err != nil {
+ err = gerror.Wrapf(err, `os.OpenFile failed for name "%s"`, dstPath)
+ return err
+ }
+ defer targetFile.Close()
+
+ if _, err = io.Copy(targetFile, fileReader); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed from "%s" to "%s"`, file.Name, dstPath)
+ return err
+ }
+ return nil
+}
+
+// zipFile compresses the file of given `path` and writes the content to `zw`.
+// The parameter `prefix` indicates the path prefix for zip file.
+func zipFile(path string, prefix string, zw *zip.Writer) error {
+ file, err := os.Open(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Open failed for name "%s"`, path)
+ return nil
+ }
+ defer file.Close()
+
+ info, err := file.Stat()
+ if err != nil {
+ err = gerror.Wrapf(err, `file.Stat failed for name "%s"`, path)
+ return err
+ }
+
+ header, err := createFileHeader(info, prefix)
+ if err != nil {
+ return err
+ }
+
+ if info.IsDir() {
+ header.Name += "/"
+ } else {
+ header.Method = zip.Deflate
+ }
+
+ writer, err := zw.CreateHeader(header)
+ if err != nil {
+ err = gerror.Wrapf(err, `zip.Writer.CreateHeader failed for header "%#v"`, header)
+ return err
+ }
+ if !info.IsDir() {
+ if _, err = io.Copy(writer, file); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed from "%s" to "%s"`, path, header.Name)
+ return err
+ }
+ }
+ return nil
+}
+
+func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {
+ header, err := zip.FileInfoHeader(info)
+ if err != nil {
+ err = gerror.Wrapf(err, `zip.FileInfoHeader failed for info "%#v"`, info)
+ return nil, err
+ }
+
+ if len(prefix) > 0 {
+ prefix = strings.Replace(prefix, `\`, `/`, -1)
+ prefix = strings.TrimRight(prefix, `/`)
+ header.Name = prefix + `/` + header.Name
+ }
+ return header, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_zlib.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_zlib.go
new file mode 100644
index 000000000000..c45b3d2bd5c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gcompress/gcompress_zlib.go
@@ -0,0 +1,59 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcompress provides kinds of compression algorithms for binary/bytes data.
+package gcompress
+
+import (
+ "bytes"
+ "compress/zlib"
+ "io"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Zlib compresses `data` with zlib algorithm.
+func Zlib(data []byte) ([]byte, error) {
+ if data == nil || len(data) < 13 {
+ return data, nil
+ }
+ var (
+ err error
+ in bytes.Buffer
+ writer = zlib.NewWriter(&in)
+ )
+
+ if _, err = writer.Write(data); err != nil {
+ err = gerror.Wrapf(err, `zlib.Writer.Write failed`)
+ return nil, err
+ }
+ if err = writer.Close(); err != nil {
+ err = gerror.Wrapf(err, `zlib.Writer.Close failed`)
+ return in.Bytes(), err
+ }
+ return in.Bytes(), nil
+}
+
+// UnZlib decompresses `data` with zlib algorithm.
+func UnZlib(data []byte) ([]byte, error) {
+ if data == nil || len(data) < 13 {
+ return data, nil
+ }
+ var (
+ out bytes.Buffer
+ bytesReader = bytes.NewReader(data)
+ zlibReader, err = zlib.NewReader(bytesReader)
+ )
+ if err != nil {
+ err = gerror.Wrapf(err, `zlib.NewReader failed`)
+ return nil, err
+ }
+ if _, err = io.Copy(&out, zlibReader); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed`)
+ return nil, err
+ }
+ return out.Bytes(), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash.go
new file mode 100644
index 000000000000..de7d1573d8b2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package ghash provides some classic hash functions(uint32/uint64) in go.
+package ghash
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_ap.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_ap.go
new file mode 100644
index 000000000000..099fd2b3abe5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_ap.go
@@ -0,0 +1,33 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// AP implements the classic AP hash algorithm for 32 bits.
+func AP(str []byte) uint32 {
+ var hash uint32 = 0
+ for i := 0; i < len(str); i++ {
+ if (i & 1) == 0 {
+ hash ^= (hash << 7) ^ uint32(str[i]) ^ (hash >> 3)
+ } else {
+ hash ^= ^((hash << 11) ^ uint32(str[i]) ^ (hash >> 5)) + 1
+ }
+ }
+ return hash
+}
+
+// AP64 implements the classic AP hash algorithm for 64 bits.
+func AP64(str []byte) uint64 {
+ var hash uint64 = 0
+ for i := 0; i < len(str); i++ {
+ if (i & 1) == 0 {
+ hash ^= (hash << 7) ^ uint64(str[i]) ^ (hash >> 3)
+ } else {
+ hash ^= ^((hash << 11) ^ uint64(str[i]) ^ (hash >> 5)) + 1
+ }
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_bkdr.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_bkdr.go
new file mode 100644
index 000000000000..2f4cc9694f07
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_bkdr.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// BKDR implements the classic BKDR hash algorithm for 32 bits.
+func BKDR(str []byte) uint32 {
+ var (
+ seed uint32 = 131 // 31 131 1313 13131 131313 etc..
+ hash uint32 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = hash*seed + uint32(str[i])
+ }
+ return hash
+}
+
+// BKDR64 implements the classic BKDR hash algorithm for 64 bits.
+func BKDR64(str []byte) uint64 {
+ var (
+ seed uint64 = 131 // 31 131 1313 13131 131313 etc..
+ hash uint64 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = hash*seed + uint64(str[i])
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_djb.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_djb.go
new file mode 100644
index 000000000000..da5f0646440a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_djb.go
@@ -0,0 +1,25 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// DJB implements the classic DJB hash algorithm for 32 bits.
+func DJB(str []byte) uint32 {
+ var hash uint32 = 5381
+ for i := 0; i < len(str); i++ {
+ hash += (hash << 5) + uint32(str[i])
+ }
+ return hash
+}
+
+// DJB64 implements the classic DJB hash algorithm for 64 bits.
+func DJB64(str []byte) uint64 {
+ var hash uint64 = 5381
+ for i := 0; i < len(str); i++ {
+ hash += (hash << 5) + uint64(str[i])
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_elf.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_elf.go
new file mode 100644
index 000000000000..d46713a91d80
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_elf.go
@@ -0,0 +1,37 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// ELF implements the classic ELF hash algorithm for 32 bits.
+func ELF(str []byte) uint32 {
+ var hash uint32 = 0
+ var x uint32 = 0
+ for i := 0; i < len(str); i++ {
+ hash = (hash << 4) + uint32(str[i])
+ if x = hash & 0xF0000000; x != 0 {
+ hash ^= x >> 24
+ hash &= ^x + 1
+ }
+ }
+ return hash
+}
+
+// ELF64 implements the classic ELF hash algorithm for 64 bits.
+func ELF64(str []byte) uint64 {
+ var (
+ hash uint64 = 0
+ x uint64 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = (hash << 4) + uint64(str[i])
+ if x = hash & 0xF000000000000000; x != 0 {
+ hash ^= x >> 24
+ hash &= ^x + 1
+ }
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_jshash.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_jshash.go
new file mode 100644
index 000000000000..91220c7124ac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_jshash.go
@@ -0,0 +1,25 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// JS implements the classic JS hash algorithm for 32 bits.
+func JS(str []byte) uint32 {
+ var hash uint32 = 1315423911
+ for i := 0; i < len(str); i++ {
+ hash ^= (hash << 5) + uint32(str[i]) + (hash >> 2)
+ }
+ return hash
+}
+
+// JS64 implements the classic JS hash algorithm for 64 bits.
+func JS64(str []byte) uint64 {
+ var hash uint64 = 1315423911
+ for i := 0; i < len(str); i++ {
+ hash ^= (hash << 5) + uint64(str[i]) + (hash >> 2)
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_pjw.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_pjw.go
new file mode 100644
index 000000000000..39d2813e4841
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_pjw.go
@@ -0,0 +1,45 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// PJW implements the classic PJW hash algorithm for 32 bits.
+func PJW(str []byte) uint32 {
+ var (
+ BitsInUnsignedInt uint32 = 4 * 8
+ ThreeQuarters uint32 = (BitsInUnsignedInt * 3) / 4
+ OneEighth uint32 = BitsInUnsignedInt / 8
+ HighBits uint32 = (0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth)
+ hash uint32 = 0
+ test uint32 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = (hash << OneEighth) + uint32(str[i])
+ if test = hash & HighBits; test != 0 {
+ hash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)
+ }
+ }
+ return hash
+}
+
+// PJW64 implements the classic PJW hash algorithm for 64 bits.
+func PJW64(str []byte) uint64 {
+ var (
+ BitsInUnsignedInt uint64 = 4 * 8
+ ThreeQuarters uint64 = (BitsInUnsignedInt * 3) / 4
+ OneEighth uint64 = BitsInUnsignedInt / 8
+ HighBits uint64 = (0xFFFFFFFFFFFFFFFF) << (BitsInUnsignedInt - OneEighth)
+ hash uint64 = 0
+ test uint64 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = (hash << OneEighth) + uint64(str[i])
+ if test = hash & HighBits; test != 0 {
+ hash = (hash ^ (test >> ThreeQuarters)) & (^HighBits + 1)
+ }
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_rs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_rs.go
new file mode 100644
index 000000000000..e9e95563657e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_rs.go
@@ -0,0 +1,35 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// RS implements the classic RS hash algorithm for 32 bits.
+func RS(str []byte) uint32 {
+ var (
+ b uint32 = 378551
+ a uint32 = 63689
+ hash uint32 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = hash*a + uint32(str[i])
+ a *= b
+ }
+ return hash
+}
+
+// RS64 implements the classic RS hash algorithm for 64 bits.
+func RS64(str []byte) uint64 {
+ var (
+ b uint64 = 378551
+ a uint64 = 63689
+ hash uint64 = 0
+ )
+ for i := 0; i < len(str); i++ {
+ hash = hash*a + uint64(str[i])
+ a *= b
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_sdbm.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_sdbm.go
new file mode 100644
index 000000000000..0f2fa6bf9563
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghash/ghash_sdbm.go
@@ -0,0 +1,27 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghash
+
+// SDBM implements the classic SDBM hash algorithm for 32 bits.
+func SDBM(str []byte) uint32 {
+ var hash uint32 = 0
+ for i := 0; i < len(str); i++ {
+ // equivalent to: hash = 65599*hash + uint32(str[i]);
+ hash = uint32(str[i]) + (hash << 6) + (hash << 16) - hash
+ }
+ return hash
+}
+
+// SDBM64 implements the classic SDBM hash algorithm for 64 bits.
+func SDBM64(str []byte) uint64 {
+ var hash uint64 = 0
+ for i := 0; i < len(str); i++ {
+ // equivalent to: hash = 65599*hash + uint32(str[i])
+ hash = uint64(str[i]) + (hash << 6) + (hash << 16) - hash
+ }
+ return hash
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghtml/ghtml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghtml/ghtml.go
new file mode 100644
index 000000000000..da0b798cd2ff
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/ghtml/ghtml.go
@@ -0,0 +1,103 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package ghtml provides useful API for HTML content handling.
+package ghtml
+
+import (
+ "html"
+ "reflect"
+ "strings"
+
+ strip "github.com/grokify/html-strip-tags-go"
+)
+
+// StripTags strips HTML tags from content, and returns only text.
+// Referer: http://php.net/manual/zh/function.strip-tags.php
+func StripTags(s string) string {
+ return strip.StripTags(s)
+}
+
+// Entities encodes all HTML chars for content.
+// Referer: http://php.net/manual/zh/function.htmlentities.php
+func Entities(s string) string {
+ return html.EscapeString(s)
+}
+
+// EntitiesDecode decodes all HTML chars for content.
+// Referer: http://php.net/manual/zh/function.html-entity-decode.php
+func EntitiesDecode(s string) string {
+ return html.UnescapeString(s)
+}
+
+// SpecialChars encodes some special chars for content, these special chars are:
+// "&", "<", ">", `"`, "'".
+// Referer: http://php.net/manual/zh/function.htmlspecialchars.php
+func SpecialChars(s string) string {
+ return strings.NewReplacer(
+ "&", "&",
+ "<", "<",
+ ">", ">",
+ `"`, """,
+ "'", "'",
+ ).Replace(s)
+}
+
+// SpecialCharsDecode decodes some special chars for content, these special chars are:
+// "&", "<", ">", `"`, "'".
+// Referer: http://php.net/manual/zh/function.htmlspecialchars-decode.php
+func SpecialCharsDecode(s string) string {
+ return strings.NewReplacer(
+ "&", "&",
+ "<", "<",
+ ">", ">",
+ """, `"`,
+ "'", "'",
+ ).Replace(s)
+}
+
+// SpecialCharsMapOrStruct automatically encodes string values/attributes for map/struct.
+func SpecialCharsMapOrStruct(mapOrStruct interface{}) error {
+ var (
+ reflectValue = reflect.ValueOf(mapOrStruct)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectValue.IsValid() && (reflectKind == reflect.Ptr || reflectKind == reflect.Interface) {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Map:
+ var (
+ mapKeys = reflectValue.MapKeys()
+ mapValue reflect.Value
+ )
+ for _, key := range mapKeys {
+ mapValue = reflectValue.MapIndex(key)
+ switch mapValue.Kind() {
+ case reflect.String:
+ reflectValue.SetMapIndex(key, reflect.ValueOf(SpecialChars(mapValue.String())))
+ case reflect.Interface:
+ if mapValue.Elem().Kind() == reflect.String {
+ reflectValue.SetMapIndex(key, reflect.ValueOf(SpecialChars(mapValue.Elem().String())))
+ }
+ }
+ }
+
+ case reflect.Struct:
+ var (
+ fieldValue reflect.Value
+ )
+ for i := 0; i < reflectValue.NumField(); i++ {
+ fieldValue = reflectValue.Field(i)
+ switch fieldValue.Kind() {
+ case reflect.String:
+ fieldValue.Set(reflect.ValueOf(SpecialChars(fieldValue.String())))
+ }
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gini/gini.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gini/gini.go
new file mode 100644
index 000000000000..dbc4e9838040
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gini/gini.go
@@ -0,0 +1,125 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gini provides accessing and converting for INI content.
+package gini
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// Decode converts INI format to map.
+func Decode(data []byte) (res map[string]interface{}, err error) {
+ res = make(map[string]interface{})
+ var (
+ fieldMap = make(map[string]interface{})
+ bytesReader = bytes.NewReader(data)
+ bufioReader = bufio.NewReader(bytesReader)
+ section string
+ lastSection string
+ haveSection bool
+ line string
+ )
+
+ for {
+ line, err = bufioReader.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ err = gerror.Wrapf(err, `bufioReader.ReadString failed`)
+ return nil, err
+ }
+ if line = strings.TrimSpace(line); len(line) == 0 {
+ continue
+ }
+
+ if line[0] == ';' || line[0] == '#' {
+ continue
+ }
+ var (
+ sectionBeginPos = strings.Index(line, "[")
+ sectionEndPos = strings.Index(line, "]")
+ )
+ if sectionBeginPos >= 0 && sectionEndPos >= 2 {
+ section = line[sectionBeginPos+1 : sectionEndPos]
+ if lastSection == "" {
+ lastSection = section
+ } else if lastSection != section {
+ lastSection = section
+ fieldMap = make(map[string]interface{})
+ }
+ haveSection = true
+ } else if haveSection == false {
+ continue
+ }
+
+ if strings.Contains(line, "=") && haveSection {
+ values := strings.Split(line, "=")
+ fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], "="))
+ res[section] = fieldMap
+ }
+ }
+
+ if haveSection == false {
+ return nil, gerror.NewCode(gcode.CodeInvalidParameter, "failed to parse INI file, section not found")
+ }
+ return res, nil
+}
+
+// Encode converts map to INI format.
+func Encode(data map[string]interface{}) (res []byte, err error) {
+ var (
+ n int
+ w = new(bytes.Buffer)
+ m map[string]interface{}
+ ok bool
+ )
+ for section, item := range data {
+ // Section key-value pairs.
+ if m, ok = item.(map[string]interface{}); ok {
+ n, err = w.WriteString(fmt.Sprintf("[%s]\n", section))
+ if err != nil || n == 0 {
+ return nil, gerror.Wrapf(err, "w.WriteString failed")
+ }
+ for k, v := range m {
+ if n, err = w.WriteString(fmt.Sprintf("%s=%v\n", k, v)); err != nil || n == 0 {
+ return nil, gerror.Wrapf(err, "w.WriteString failed")
+ }
+ }
+ continue
+ }
+ // Simple key-value pairs.
+ for k, v := range data {
+ if n, err = w.WriteString(fmt.Sprintf("%s=%v\n", k, v)); err != nil || n == 0 {
+ return nil, gerror.Wrapf(err, "w.WriteString failed")
+ }
+ }
+ break
+ }
+ res = make([]byte, w.Len())
+ if n, err = w.Read(res); err != nil || n == 0 {
+ return nil, gerror.Wrapf(err, "w.Read failed")
+ }
+ return res, nil
+}
+
+// ToJson convert INI format to JSON.
+func ToJson(data []byte) (res []byte, err error) {
+ iniMap, err := Decode(data)
+ if err != nil {
+ return nil, err
+ }
+ return json.Marshal(iniMap)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson.go
new file mode 100644
index 000000000000..e35a7b026e5c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson.go
@@ -0,0 +1,452 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gjson provides convenient API for JSON/XML/INI/YAML/TOML data handling.
+package gjson
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ // Separator char for hierarchical data access.
+ defaultSplitChar = '.'
+)
+
+// Json is the customized JSON struct.
+type Json struct {
+ mu *rwmutex.RWMutex
+ p *interface{} // Pointer for hierarchical data access, it's the root of data in default.
+ c byte // Char separator('.' in default).
+ vc bool // Violence Check(false in default), which is used to access data when the hierarchical data key contains separator char.
+}
+
+// Options for Json object creating.
+type Options struct {
+ Safe bool // Mark this object is for in concurrent-safe usage. This is especially for Json object creating.
+ Tags string // Custom priority tags for decoding. Eg: "json,yaml,MyTag". This is especially for struct parsing into Json object.
+ StrNumber bool // StrNumber causes the Decoder to unmarshal a number into an interface{} as a string instead of as a float64.
+}
+
+// iInterfaces is used for type assert api for Interfaces().
+type iInterfaces interface {
+ Interfaces() []interface{}
+}
+
+// iMapStrAny is the interface support for converting struct parameter to map.
+type iMapStrAny interface {
+ MapStrAny() map[string]interface{}
+}
+
+// iVal is the interface for underlying interface{} retrieving.
+type iVal interface {
+ Val() interface{}
+}
+
+// setValue sets `value` to `j` by `pattern`.
+// Note:
+// 1. If value is nil and removed is true, means deleting this value;
+// 2. It's quite complicated in hierarchical data search, node creating and data assignment;
+func (j *Json) setValue(pattern string, value interface{}, removed bool) error {
+ var (
+ err error
+ array = strings.Split(pattern, string(j.c))
+ length = len(array)
+ )
+ if value, err = j.convertValue(value); err != nil {
+ return err
+ }
+ // Initialization checks.
+ if *j.p == nil {
+ if gstr.IsNumeric(array[0]) {
+ *j.p = make([]interface{}, 0)
+ } else {
+ *j.p = make(map[string]interface{})
+ }
+ }
+ var (
+ pparent *interface{} = nil // Parent pointer.
+ pointer *interface{} = j.p // Current pointer.
+ )
+ j.mu.Lock()
+ defer j.mu.Unlock()
+ for i := 0; i < length; i++ {
+ switch (*pointer).(type) {
+ case map[string]interface{}:
+ if i == length-1 {
+ if removed && value == nil {
+ // Delete item from map.
+ delete((*pointer).(map[string]interface{}), array[i])
+ } else {
+ (*pointer).(map[string]interface{})[array[i]] = value
+ }
+ } else {
+ // If the key does not exit in the map.
+ if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok {
+ if removed && value == nil {
+ goto done
+ }
+ // Creating new node.
+ if gstr.IsNumeric(array[i+1]) {
+ // Creating array node.
+ n, _ := strconv.Atoi(array[i+1])
+ var v interface{} = make([]interface{}, n+1)
+ pparent = j.setPointerWithValue(pointer, array[i], v)
+ pointer = &v
+ } else {
+ // Creating map node.
+ var v interface{} = make(map[string]interface{})
+ pparent = j.setPointerWithValue(pointer, array[i], v)
+ pointer = &v
+ }
+ } else {
+ pparent = pointer
+ pointer = &v
+ }
+ }
+
+ case []interface{}:
+ // A string key.
+ if !gstr.IsNumeric(array[i]) {
+ if i == length-1 {
+ *pointer = map[string]interface{}{array[i]: value}
+ } else {
+ var v interface{} = make(map[string]interface{})
+ *pointer = v
+ pparent = pointer
+ pointer = &v
+ }
+ continue
+ }
+ // Numeric index.
+ valueNum, err := strconv.Atoi(array[i])
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.Atoi failed for string "%s"`, array[i])
+ return err
+ }
+
+ if i == length-1 {
+ // Leaf node.
+ if len((*pointer).([]interface{})) > valueNum {
+ if removed && value == nil {
+ // Deleting element.
+ if pparent == nil {
+ *pointer = append((*pointer).([]interface{})[:valueNum], (*pointer).([]interface{})[valueNum+1:]...)
+ } else {
+ j.setPointerWithValue(pparent, array[i-1], append((*pointer).([]interface{})[:valueNum], (*pointer).([]interface{})[valueNum+1:]...))
+ }
+ } else {
+ (*pointer).([]interface{})[valueNum] = value
+ }
+ } else {
+ if removed && value == nil {
+ goto done
+ }
+ if pparent == nil {
+ // It is the root node.
+ j.setPointerWithValue(pointer, array[i], value)
+ } else {
+ // It is not the root node.
+ s := make([]interface{}, valueNum+1)
+ copy(s, (*pointer).([]interface{}))
+ s[valueNum] = value
+ j.setPointerWithValue(pparent, array[i-1], s)
+ }
+ }
+ } else {
+ // Branch node.
+ if gstr.IsNumeric(array[i+1]) {
+ n, _ := strconv.Atoi(array[i+1])
+ pSlice := (*pointer).([]interface{})
+ if len(pSlice) > valueNum {
+ item := pSlice[valueNum]
+ if s, ok := item.([]interface{}); ok {
+ for i := 0; i < n-len(s); i++ {
+ s = append(s, nil)
+ }
+ pparent = pointer
+ pointer = &pSlice[valueNum]
+ } else {
+ if removed && value == nil {
+ goto done
+ }
+ var v interface{} = make([]interface{}, n+1)
+ pparent = j.setPointerWithValue(pointer, array[i], v)
+ pointer = &v
+ }
+ } else {
+ if removed && value == nil {
+ goto done
+ }
+ var v interface{} = make([]interface{}, n+1)
+ pparent = j.setPointerWithValue(pointer, array[i], v)
+ pointer = &v
+ }
+ } else {
+ pSlice := (*pointer).([]interface{})
+ if len(pSlice) > valueNum {
+ pparent = pointer
+ pointer = &(*pointer).([]interface{})[valueNum]
+ } else {
+ s := make([]interface{}, valueNum+1)
+ copy(s, pSlice)
+ s[valueNum] = make(map[string]interface{})
+ if pparent != nil {
+ // i > 0
+ j.setPointerWithValue(pparent, array[i-1], s)
+ pparent = pointer
+ pointer = &s[valueNum]
+ } else {
+ // i = 0
+ var v interface{} = s
+ *pointer = v
+ pparent = pointer
+ pointer = &s[valueNum]
+ }
+ }
+ }
+ }
+
+ // If the variable pointed to by the `pointer` is not of a reference type,
+ // then it modifies the variable via its the parent, ie: pparent.
+ default:
+ if removed && value == nil {
+ goto done
+ }
+ if gstr.IsNumeric(array[i]) {
+ n, _ := strconv.Atoi(array[i])
+ s := make([]interface{}, n+1)
+ if i == length-1 {
+ s[n] = value
+ }
+ if pparent != nil {
+ pparent = j.setPointerWithValue(pparent, array[i-1], s)
+ } else {
+ *pointer = s
+ pparent = pointer
+ }
+ } else {
+ var v1, v2 interface{}
+ if i == length-1 {
+ v1 = map[string]interface{}{
+ array[i]: value,
+ }
+ } else {
+ v1 = map[string]interface{}{
+ array[i]: nil,
+ }
+ }
+ if pparent != nil {
+ pparent = j.setPointerWithValue(pparent, array[i-1], v1)
+ } else {
+ *pointer = v1
+ pparent = pointer
+ }
+ v2 = v1.(map[string]interface{})[array[i]]
+ pointer = &v2
+ }
+ }
+ }
+done:
+ return nil
+}
+
+// convertValue converts `value` to map[string]interface{} or []interface{},
+// which can be supported for hierarchical data access.
+func (j *Json) convertValue(value interface{}) (convertedValue interface{}, err error) {
+ if value == nil {
+ return
+ }
+
+ switch value.(type) {
+ case map[string]interface{}:
+ return value, nil
+
+ case []interface{}:
+ return value, nil
+
+ default:
+ var (
+ reflectInfo = utils.OriginValueAndKind(value)
+ )
+ switch reflectInfo.OriginKind {
+ case reflect.Array:
+ return gconv.Interfaces(value), nil
+
+ case reflect.Slice:
+ return gconv.Interfaces(value), nil
+
+ case reflect.Map:
+ return gconv.Map(value), nil
+
+ case reflect.Struct:
+ if v, ok := value.(iMapStrAny); ok {
+ convertedValue = v.MapStrAny()
+ }
+ if utils.IsNil(convertedValue) {
+ if v, ok := value.(iInterfaces); ok {
+ convertedValue = v.Interfaces()
+ }
+ }
+ if utils.IsNil(convertedValue) {
+ convertedValue = gconv.Map(value)
+ }
+ if utils.IsNil(convertedValue) {
+ err = gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type "%s"`, reflect.TypeOf(value))
+ }
+ return
+
+ default:
+ return value, nil
+ }
+ }
+}
+
+// setPointerWithValue sets `key`:`value` to `pointer`, the `key` may be a map key or slice index.
+// It returns the pointer to the new value set.
+func (j *Json) setPointerWithValue(pointer *interface{}, key string, value interface{}) *interface{} {
+ switch (*pointer).(type) {
+ case map[string]interface{}:
+ (*pointer).(map[string]interface{})[key] = value
+ return &value
+ case []interface{}:
+ n, _ := strconv.Atoi(key)
+ if len((*pointer).([]interface{})) > n {
+ (*pointer).([]interface{})[n] = value
+ return &(*pointer).([]interface{})[n]
+ } else {
+ s := make([]interface{}, n+1)
+ copy(s, (*pointer).([]interface{}))
+ s[n] = value
+ *pointer = s
+ return &s[n]
+ }
+ default:
+ *pointer = value
+ }
+ return pointer
+}
+
+// getPointerByPattern returns a pointer to the value by specified `pattern`.
+func (j *Json) getPointerByPattern(pattern string) *interface{} {
+ if j.vc {
+ return j.getPointerByPatternWithViolenceCheck(pattern)
+ } else {
+ return j.getPointerByPatternWithoutViolenceCheck(pattern)
+ }
+}
+
+// getPointerByPatternWithViolenceCheck returns a pointer to the value of specified `pattern` with violence check.
+func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} {
+ if !j.vc {
+ return j.getPointerByPatternWithoutViolenceCheck(pattern)
+ }
+
+ // It returns nil if pattern is empty.
+ if pattern == "" {
+ return nil
+ }
+ // It returns all if pattern is ".".
+ if pattern == "." {
+ return j.p
+ }
+
+ var (
+ index = len(pattern)
+ start = 0
+ length = 0
+ pointer = j.p
+ )
+ if index == 0 {
+ return pointer
+ }
+ for {
+ if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {
+ if length += index - start; start > 0 {
+ length += 1
+ }
+ start = index + 1
+ index = len(pattern)
+ if length == len(pattern) {
+ return r
+ } else {
+ pointer = r
+ }
+ } else {
+ // Get the position for next separator char.
+ index = strings.LastIndexByte(pattern[start:index], j.c)
+ if index != -1 && length > 0 {
+ index += length + 1
+ }
+ }
+ if start >= index {
+ break
+ }
+ }
+ return nil
+}
+
+// getPointerByPatternWithoutViolenceCheck returns a pointer to the value of specified `pattern`, with no violence check.
+func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interface{} {
+ if j.vc {
+ return j.getPointerByPatternWithViolenceCheck(pattern)
+ }
+
+ // It returns nil if pattern is empty.
+ if pattern == "" {
+ return nil
+ }
+ // It returns all if pattern is ".".
+ if pattern == "." {
+ return j.p
+ }
+
+ pointer := j.p
+ if len(pattern) == 0 {
+ return pointer
+ }
+ array := strings.Split(pattern, string(j.c))
+ for k, v := range array {
+ if r := j.checkPatternByPointer(v, pointer); r != nil {
+ if k == len(array)-1 {
+ return r
+ } else {
+ pointer = r
+ }
+ } else {
+ break
+ }
+ }
+ return nil
+}
+
+// checkPatternByPointer checks whether there's value by `key` in specified `pointer`.
+// It returns a pointer to the value.
+func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interface{} {
+ switch (*pointer).(type) {
+ case map[string]interface{}:
+ if v, ok := (*pointer).(map[string]interface{})[key]; ok {
+ return &v
+ }
+ case []interface{}:
+ if gstr.IsNumeric(key) {
+ n, err := strconv.Atoi(key)
+ if err == nil && len((*pointer).([]interface{})) > n {
+ return &(*pointer).([]interface{})[n]
+ }
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api.go
new file mode 100644
index 000000000000..6abfc16c4906
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api.go
@@ -0,0 +1,214 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gjson
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// Interface returns the json value.
+func (j *Json) Interface() interface{} {
+ if j == nil {
+ return nil
+ }
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return *(j.p)
+}
+
+// Var returns the json value as *gvar.Var.
+func (j *Json) Var() *gvar.Var {
+ return gvar.New(j.Interface())
+}
+
+// IsNil checks whether the value pointed by `j` is nil.
+func (j *Json) IsNil() bool {
+ if j == nil {
+ return true
+ }
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return j.p == nil || *(j.p) == nil
+}
+
+// Get retrieves and returns value by specified `pattern`.
+// It returns all values of current Json object if `pattern` is given empty or string ".".
+// It returns nil if no value found by `pattern`.
+//
+// We can also access slice item by its index number in `pattern` like:
+// "list.10", "array.0.name", "array.0.1.id".
+//
+// It returns a default value specified by `def` if value for `pattern` is not found.
+func (j *Json) Get(pattern string, def ...interface{}) *gvar.Var {
+ if j == nil {
+ return nil
+ }
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+
+ // It returns nil if pattern is empty.
+ if pattern == "" {
+ return nil
+ }
+
+ var result *interface{}
+ if j.vc {
+ result = j.getPointerByPattern(pattern)
+ } else {
+ result = j.getPointerByPatternWithoutViolenceCheck(pattern)
+ }
+ if result != nil {
+ return gvar.New(*result)
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// GetJson gets the value by specified `pattern`,
+// and converts it to a un-concurrent-safe Json object.
+func (j *Json) GetJson(pattern string, def ...interface{}) *Json {
+ return New(j.Get(pattern, def...).Val())
+}
+
+// GetJsons gets the value by specified `pattern`,
+// and converts it to a slice of un-concurrent-safe Json object.
+func (j *Json) GetJsons(pattern string, def ...interface{}) []*Json {
+ array := j.Get(pattern, def...).Array()
+ if len(array) > 0 {
+ jsonSlice := make([]*Json, len(array))
+ for i := 0; i < len(array); i++ {
+ jsonSlice[i] = New(array[i])
+ }
+ return jsonSlice
+ }
+ return nil
+}
+
+// GetJsonMap gets the value by specified `pattern`,
+// and converts it to a map of un-concurrent-safe Json object.
+func (j *Json) GetJsonMap(pattern string, def ...interface{}) map[string]*Json {
+ m := j.Get(pattern, def...).Map()
+ if len(m) > 0 {
+ jsonMap := make(map[string]*Json, len(m))
+ for k, v := range m {
+ jsonMap[k] = New(v)
+ }
+ return jsonMap
+ }
+ return nil
+}
+
+// Set sets value with specified `pattern`.
+// It supports hierarchical data access by char separator, which is '.' in default.
+func (j *Json) Set(pattern string, value interface{}) error {
+ return j.setValue(pattern, value, false)
+}
+
+// MustSet performs as Set, but it panics if any error occurs.
+func (j *Json) MustSet(pattern string, value interface{}) {
+ if err := j.Set(pattern, value); err != nil {
+ panic(err)
+ }
+}
+
+// Remove deletes value with specified `pattern`.
+// It supports hierarchical data access by char separator, which is '.' in default.
+func (j *Json) Remove(pattern string) error {
+ return j.setValue(pattern, nil, true)
+}
+
+// MustRemove performs as Remove, but it panics if any error occurs.
+func (j *Json) MustRemove(pattern string) {
+ if err := j.Remove(pattern); err != nil {
+ panic(err)
+ }
+}
+
+// Contains checks whether the value by specified `pattern` exist.
+func (j *Json) Contains(pattern string) bool {
+ return j.Get(pattern) != nil
+}
+
+// Len returns the length/size of the value by specified `pattern`.
+// The target value by `pattern` should be type of slice or map.
+// It returns -1 if the target value is not found, or its type is invalid.
+func (j *Json) Len(pattern string) int {
+ p := j.getPointerByPattern(pattern)
+ if p != nil {
+ switch (*p).(type) {
+ case map[string]interface{}:
+ return len((*p).(map[string]interface{}))
+ case []interface{}:
+ return len((*p).([]interface{}))
+ default:
+ return -1
+ }
+ }
+ return -1
+}
+
+// Append appends value to the value by specified `pattern`.
+// The target value by `pattern` should be type of slice.
+func (j *Json) Append(pattern string, value interface{}) error {
+ p := j.getPointerByPattern(pattern)
+ if p == nil || *p == nil {
+ if pattern == "." {
+ return j.Set("0", value)
+ }
+ return j.Set(fmt.Sprintf("%s.0", pattern), value)
+ }
+ switch (*p).(type) {
+ case []interface{}:
+ if pattern == "." {
+ return j.Set(fmt.Sprintf("%d", len((*p).([]interface{}))), value)
+ }
+ return j.Set(fmt.Sprintf("%s.%d", pattern, len((*p).([]interface{}))), value)
+ }
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "invalid variable type of %s", pattern)
+}
+
+// MustAppend performs as Append, but it panics if any error occurs.
+func (j *Json) MustAppend(pattern string, value interface{}) {
+ if err := j.Append(pattern, value); err != nil {
+ panic(err)
+ }
+}
+
+// Map converts current Json object to map[string]interface{}.
+// It returns nil if fails.
+func (j *Json) Map() map[string]interface{} {
+ return j.Var().Map()
+}
+
+// Array converts current Json object to []interface{}.
+// It returns nil if fails.
+func (j *Json) Array() []interface{} {
+ return j.Var().Array()
+}
+
+// Scan automatically calls Struct or Structs function according to the type of parameter
+// `pointer` to implement the converting.
+func (j *Json) Scan(pointer interface{}, mapping ...map[string]string) error {
+ return j.Var().Scan(pointer, mapping...)
+}
+
+// Dump prints current Json object with more manually readable.
+func (j *Json) Dump() {
+ if j == nil {
+ return
+ }
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ gutil.Dump(*j.p)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_config.go
new file mode 100644
index 000000000000..1fe53a9ac9c7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_config.go
@@ -0,0 +1,21 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gjson
+
+// SetSplitChar sets the separator char for hierarchical data access.
+func (j *Json) SetSplitChar(char byte) {
+ j.mu.Lock()
+ j.c = char
+ j.mu.Unlock()
+}
+
+// SetViolenceCheck enables/disables violence check for hierarchical data access.
+func (j *Json) SetViolenceCheck(enabled bool) {
+ j.mu.Lock()
+ j.vc = enabled
+ j.mu.Unlock()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_encoding.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_encoding.go
new file mode 100644
index 000000000000..8d95cb946484
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_encoding.go
@@ -0,0 +1,199 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gjson
+
+import (
+ "github.com/gogf/gf/v2/encoding/gini"
+ "github.com/gogf/gf/v2/encoding/gtoml"
+ "github.com/gogf/gf/v2/encoding/gxml"
+ "github.com/gogf/gf/v2/encoding/gyaml"
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// ========================================================================
+// JSON
+// ========================================================================
+
+func (j *Json) ToJson() ([]byte, error) {
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return Encode(*(j.p))
+}
+
+func (j *Json) ToJsonString() (string, error) {
+ b, e := j.ToJson()
+ return string(b), e
+}
+
+func (j *Json) ToJsonIndent() ([]byte, error) {
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return json.MarshalIndent(*(j.p), "", "\t")
+}
+
+func (j *Json) ToJsonIndentString() (string, error) {
+ b, e := j.ToJsonIndent()
+ return string(b), e
+}
+
+func (j *Json) MustToJson() []byte {
+ result, err := j.ToJson()
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+func (j *Json) MustToJsonString() string {
+ return string(j.MustToJson())
+}
+
+func (j *Json) MustToJsonIndent() []byte {
+ result, err := j.ToJsonIndent()
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+func (j *Json) MustToJsonIndentString() string {
+ return string(j.MustToJsonIndent())
+}
+
+// ========================================================================
+// XML
+// ========================================================================
+
+func (j *Json) ToXml(rootTag ...string) ([]byte, error) {
+ return gxml.Encode(j.Var().Map(), rootTag...)
+}
+
+func (j *Json) ToXmlString(rootTag ...string) (string, error) {
+ b, e := j.ToXml(rootTag...)
+ return string(b), e
+}
+
+func (j *Json) ToXmlIndent(rootTag ...string) ([]byte, error) {
+ return gxml.EncodeWithIndent(j.Var().Map(), rootTag...)
+}
+
+func (j *Json) ToXmlIndentString(rootTag ...string) (string, error) {
+ b, e := j.ToXmlIndent(rootTag...)
+ return string(b), e
+}
+
+func (j *Json) MustToXml(rootTag ...string) []byte {
+ result, err := j.ToXml(rootTag...)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+func (j *Json) MustToXmlString(rootTag ...string) string {
+ return string(j.MustToXml(rootTag...))
+}
+
+func (j *Json) MustToXmlIndent(rootTag ...string) []byte {
+ result, err := j.ToXmlIndent(rootTag...)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+func (j *Json) MustToXmlIndentString(rootTag ...string) string {
+ return string(j.MustToXmlIndent(rootTag...))
+}
+
+// ========================================================================
+// YAML
+// ========================================================================
+
+func (j *Json) ToYaml() ([]byte, error) {
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return gyaml.Encode(*(j.p))
+}
+
+func (j *Json) ToYamlIndent(indent string) ([]byte, error) {
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return gyaml.EncodeIndent(*(j.p), indent)
+}
+
+func (j *Json) ToYamlString() (string, error) {
+ b, e := j.ToYaml()
+ return string(b), e
+}
+
+func (j *Json) MustToYaml() []byte {
+ result, err := j.ToYaml()
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+func (j *Json) MustToYamlString() string {
+ return string(j.MustToYaml())
+}
+
+// ========================================================================
+// TOML
+// ========================================================================
+
+func (j *Json) ToToml() ([]byte, error) {
+ j.mu.RLock()
+ defer j.mu.RUnlock()
+ return gtoml.Encode(*(j.p))
+}
+
+func (j *Json) ToTomlString() (string, error) {
+ b, e := j.ToToml()
+ return string(b), e
+}
+
+func (j *Json) MustToToml() []byte {
+ result, err := j.ToToml()
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+func (j *Json) MustToTomlString() string {
+ return string(j.MustToToml())
+}
+
+// ========================================================================
+// INI
+// ========================================================================
+
+// ToIni json to ini
+func (j *Json) ToIni() ([]byte, error) {
+ return gini.Encode(j.Map())
+}
+
+// ToIniString ini to string
+func (j *Json) ToIniString() (string, error) {
+ b, e := j.ToIni()
+ return string(b), e
+}
+
+func (j *Json) MustToIni() []byte {
+ result, err := j.ToIni()
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
+
+// MustToIniString .
+func (j *Json) MustToIniString() string {
+ return string(j.MustToIni())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_new_load.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_new_load.go
new file mode 100644
index 000000000000..367657fa538e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_api_new_load.go
@@ -0,0 +1,314 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gjson
+
+import (
+ "bytes"
+ "reflect"
+
+ "github.com/gogf/gf/v2/encoding/gini"
+ "github.com/gogf/gf/v2/encoding/gtoml"
+ "github.com/gogf/gf/v2/encoding/gxml"
+ "github.com/gogf/gf/v2/encoding/gyaml"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/rwmutex"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// New creates a Json object with any variable type of `data`, but `data` should be a map
+// or slice for data access reason, or it will make no sense.
+//
+// The parameter `safe` specifies whether using this Json object in concurrent-safe context,
+// which is false in default.
+func New(data interface{}, safe ...bool) *Json {
+ return NewWithTag(data, "json", safe...)
+}
+
+// NewWithTag creates a Json object with any variable type of `data`, but `data` should be a map
+// or slice for data access reason, or it will make no sense.
+//
+// The parameter `tags` specifies priority tags for struct conversion to map, multiple tags joined
+// with char ','.
+//
+// The parameter `safe` specifies whether using this Json object in concurrent-safe context, which
+// is false in default.
+func NewWithTag(data interface{}, tags string, safe ...bool) *Json {
+ option := Options{
+ Tags: tags,
+ }
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return NewWithOptions(data, option)
+}
+
+// NewWithOptions creates a Json object with any variable type of `data`, but `data` should be a map
+// or slice for data access reason, or it will make no sense.
+func NewWithOptions(data interface{}, options Options) *Json {
+ var j *Json
+ switch data.(type) {
+ case string, []byte:
+ if r, err := loadContentWithOptions(data, options); err == nil {
+ j = r
+ } else {
+ j = &Json{
+ p: &data,
+ c: byte(defaultSplitChar),
+ vc: false,
+ }
+ }
+ default:
+ var reflectInfo = utils.OriginValueAndKind(data)
+ switch reflectInfo.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var i interface{} = gconv.Interfaces(data)
+ j = &Json{
+ p: &i,
+ c: byte(defaultSplitChar),
+ vc: false,
+ }
+ case reflect.Map:
+ var i interface{} = gconv.MapDeep(data, options.Tags)
+ j = &Json{
+ p: &i,
+ c: byte(defaultSplitChar),
+ vc: false,
+ }
+ case reflect.Struct:
+ if v, ok := data.(iVal); ok {
+ return NewWithOptions(v.Val(), options)
+ }
+ var i interface{} = gconv.MapDeep(data, options.Tags)
+ j = &Json{
+ p: &i,
+ c: byte(defaultSplitChar),
+ vc: false,
+ }
+ default:
+ j = &Json{
+ p: &data,
+ c: byte(defaultSplitChar),
+ vc: false,
+ }
+ }
+ }
+ j.mu = rwmutex.New(options.Safe)
+ return j
+}
+
+// Load loads content from specified file `path`, and creates a Json object from its content.
+func Load(path string, safe ...bool) (*Json, error) {
+ if p, err := gfile.Search(path); err != nil {
+ return nil, err
+ } else {
+ path = p
+ }
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions(gfile.Ext(path), gfile.GetBytesWithCache(path), option)
+}
+
+// LoadJson creates a Json object from given JSON format content.
+func LoadJson(data interface{}, safe ...bool) (*Json, error) {
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions("json", gconv.Bytes(data), option)
+}
+
+// LoadXml creates a Json object from given XML format content.
+func LoadXml(data interface{}, safe ...bool) (*Json, error) {
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions("xml", gconv.Bytes(data), option)
+}
+
+// LoadIni creates a Json object from given INI format content.
+func LoadIni(data interface{}, safe ...bool) (*Json, error) {
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions("ini", gconv.Bytes(data), option)
+}
+
+// LoadYaml creates a Json object from given YAML format content.
+func LoadYaml(data interface{}, safe ...bool) (*Json, error) {
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions("yaml", gconv.Bytes(data), option)
+}
+
+// LoadToml creates a Json object from given TOML format content.
+func LoadToml(data interface{}, safe ...bool) (*Json, error) {
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions("toml", gconv.Bytes(data), option)
+}
+
+// LoadContent creates a Json object from given content, it checks the data type of `content`
+// automatically, supporting data content type as follows:
+// JSON, XML, INI, YAML and TOML.
+func LoadContent(data interface{}, safe ...bool) (*Json, error) {
+ content := gconv.Bytes(data)
+ if len(content) == 0 {
+ return New(nil, safe...), nil
+ }
+ return LoadContentType(checkDataType(content), content, safe...)
+}
+
+// LoadContentType creates a Json object from given type and content,
+// supporting data content type as follows:
+// JSON, XML, INI, YAML and TOML.
+func LoadContentType(dataType string, data interface{}, safe ...bool) (*Json, error) {
+ content := gconv.Bytes(data)
+ if len(content) == 0 {
+ return New(nil, safe...), nil
+ }
+ // ignore UTF8-BOM
+ if content[0] == 0xEF && content[1] == 0xBB && content[2] == 0xBF {
+ content = content[3:]
+ }
+ option := Options{}
+ if len(safe) > 0 && safe[0] {
+ option.Safe = true
+ }
+ return doLoadContentWithOptions(dataType, content, option)
+}
+
+// IsValidDataType checks and returns whether given `dataType` a valid data type for loading.
+func IsValidDataType(dataType string) bool {
+ if dataType == "" {
+ return false
+ }
+ if dataType[0] == '.' {
+ dataType = dataType[1:]
+ }
+ switch dataType {
+ case "json", "js", "xml", "yaml", "yml", "toml", "ini":
+ return true
+ }
+ return false
+}
+
+func loadContentWithOptions(data interface{}, options Options) (*Json, error) {
+ content := gconv.Bytes(data)
+ if len(content) == 0 {
+ return NewWithOptions(nil, options), nil
+ }
+ return loadContentTypeWithOptions(checkDataType(content), content, options)
+}
+
+func loadContentTypeWithOptions(dataType string, data interface{}, options Options) (*Json, error) {
+ content := gconv.Bytes(data)
+ if len(content) == 0 {
+ return NewWithOptions(nil, options), nil
+ }
+ // ignore UTF8-BOM
+ if content[0] == 0xEF && content[1] == 0xBB && content[2] == 0xBF {
+ content = content[3:]
+ }
+ return doLoadContentWithOptions(dataType, content, options)
+}
+
+// doLoadContent creates a Json object from given content.
+// It supports data content type as follows:
+// JSON, XML, INI, YAML and TOML.
+func doLoadContentWithOptions(dataType string, data []byte, options Options) (*Json, error) {
+ var (
+ err error
+ result interface{}
+ )
+ if len(data) == 0 {
+ return NewWithOptions(nil, options), nil
+ }
+ if dataType == "" {
+ dataType = checkDataType(data)
+ }
+ switch dataType {
+ case "json", ".json", ".js":
+
+ case "xml", ".xml":
+ if data, err = gxml.ToJson(data); err != nil {
+ return nil, err
+ }
+
+ case "yml", "yaml", ".yml", ".yaml":
+ if data, err = gyaml.ToJson(data); err != nil {
+ return nil, err
+ }
+
+ case "toml", ".toml":
+ if data, err = gtoml.ToJson(data); err != nil {
+ return nil, err
+ }
+
+ case "ini", ".ini":
+ if data, err = gini.ToJson(data); err != nil {
+ return nil, err
+ }
+
+ default:
+ err = gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported type "%s" for loading`, dataType)
+ }
+ if err != nil {
+ return nil, err
+ }
+ decoder := json.NewDecoder(bytes.NewReader(data))
+ if options.StrNumber {
+ decoder.UseNumber()
+ }
+ if err := decoder.Decode(&result); err != nil {
+ return nil, err
+ }
+ switch result.(type) {
+ case string, []byte:
+ return nil, gerror.Newf(`json decoding failed for content: %s`, data)
+ }
+ return NewWithOptions(result, options), nil
+}
+
+// checkDataType automatically checks and returns the data type for `content`.
+// Note that it uses regular expression for loose checking, you can use LoadXXX/LoadContentType
+// functions to load the content for certain content type.
+func checkDataType(content []byte) string {
+ if json.Valid(content) {
+ return "json"
+ } else if gregex.IsMatch(`^<.+>[\S\s]+<.+>\s*$`, content) {
+ return "xml"
+ } else if !gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*"""[\s\S]+"""`, content) &&
+ !gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*'''[\s\S]+'''`, content) &&
+ ((gregex.IsMatch(`^[\n\r]*[\w\-\s\t]+\s*:\s*".+"`, content) || gregex.IsMatch(`^[\n\r]*[\w\-\s\t]+\s*:\s*\w+`, content)) ||
+ (gregex.IsMatch(`[\n\r]+[\w\-\s\t]+\s*:\s*".+"`, content) || gregex.IsMatch(`[\n\r]+[\w\-\s\t]+\s*:\s*\w+`, content))) {
+ return "yml"
+ } else if !gregex.IsMatch(`^[\s\t\n\r]*;.+`, content) &&
+ !gregex.IsMatch(`[\s\t\n\r]+;.+`, content) &&
+ !gregex.IsMatch(`[\n\r]+[\s\t\w\-]+\.[\s\t\w\-]+\s*=\s*.+`, content) &&
+ (gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*".+"`, content) || gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, content)) {
+ return "toml"
+ } else if gregex.IsMatch(`\[[\w\.]+\]`, content) &&
+ (gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*".+"`, content) || gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, content)) {
+ // Must contain "[xxx]" section.
+ return "ini"
+ } else {
+ return ""
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_implements.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_implements.go
new file mode 100644
index 000000000000..60e146885c59
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_implements.go
@@ -0,0 +1,41 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gjson
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (j Json) MarshalJSON() ([]byte, error) {
+ return j.ToJson()
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (j *Json) UnmarshalJSON(b []byte) error {
+ r, err := LoadContent(b)
+ if r != nil {
+ // Value copy.
+ *j = *r
+ }
+ return err
+}
+
+// UnmarshalValue is an interface implement which sets any type of value for Json.
+func (j *Json) UnmarshalValue(value interface{}) error {
+ if r := New(value); r != nil {
+ // Value copy.
+ *j = *r
+ }
+ return nil
+}
+
+// MapStrAny implements interface function MapStrAny().
+func (j *Json) MapStrAny() map[string]interface{} {
+ return j.Map()
+}
+
+// Interfaces implements interface function Interfaces().
+func (j *Json) Interfaces() []interface{} {
+ return j.Array()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_stdlib_json_util.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_stdlib_json_util.go
new file mode 100644
index 000000000000..7ce04b81d2e1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gjson/gjson_stdlib_json_util.go
@@ -0,0 +1,105 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gjson
+
+import (
+ "bytes"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Valid checks whether `data` is a valid JSON data type.
+// The parameter `data` specifies the json format data, which can be either
+// bytes or string type.
+func Valid(data interface{}) bool {
+ return json.Valid(gconv.Bytes(data))
+}
+
+// Marshal is alias of Encode in order to fit the habit of json.Marshal/Unmarshal functions.
+func Marshal(v interface{}) (marshaledBytes []byte, err error) {
+ return Encode(v)
+}
+
+// MarshalIndent is alias of json.MarshalIndent in order to fit the habit of json.MarshalIndent function.
+func MarshalIndent(v interface{}, prefix, indent string) (marshaledBytes []byte, err error) {
+ return json.MarshalIndent(v, prefix, indent)
+}
+
+// Unmarshal is alias of DecodeTo in order to fit the habit of json.Marshal/Unmarshal functions.
+func Unmarshal(data []byte, v interface{}) (err error) {
+ return DecodeTo(data, v)
+}
+
+// Encode encodes any golang variable `value` to JSON bytes.
+func Encode(value interface{}) ([]byte, error) {
+ return json.Marshal(value)
+}
+
+// MustEncode performs as Encode, but it panics if any error occurs.
+func MustEncode(value interface{}) []byte {
+ b, err := Encode(value)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+// EncodeString encodes any golang variable `value` to JSON string.
+func EncodeString(value interface{}) (string, error) {
+ b, err := json.Marshal(value)
+ return string(b), err
+}
+
+// MustEncodeString encodes any golang variable `value` to JSON string.
+// It panics if any error occurs.
+func MustEncodeString(value interface{}) string {
+ return string(MustEncode(value))
+}
+
+// Decode decodes json format `data` to golang variable.
+// The parameter `data` can be either bytes or string type.
+func Decode(data interface{}, options ...Options) (interface{}, error) {
+ var value interface{}
+ if err := DecodeTo(gconv.Bytes(data), &value, options...); err != nil {
+ return nil, err
+ } else {
+ return value, nil
+ }
+}
+
+// DecodeTo decodes json format `data` to specified golang variable `v`.
+// The parameter `data` can be either bytes or string type.
+// The parameter `v` should be a pointer type.
+func DecodeTo(data interface{}, v interface{}, options ...Options) (err error) {
+ decoder := json.NewDecoder(bytes.NewReader(gconv.Bytes(data)))
+ if len(options) > 0 {
+ // The StrNumber option is for certain situations, not for all.
+ // For example, it causes converting issue for other data formats, for example: yaml.
+ if options[0].StrNumber {
+ decoder.UseNumber()
+ }
+ }
+ if err = decoder.Decode(v); err != nil {
+ err = gerror.Wrap(err, `json Decode failed`)
+ }
+ return
+}
+
+// DecodeToJson codes json format `data` to a Json object.
+// The parameter `data` can be either bytes or string type.
+func DecodeToJson(data interface{}, options ...Options) (*Json, error) {
+ if v, err := Decode(gconv.Bytes(data), options...); err != nil {
+ return nil, err
+ } else {
+ if len(options) > 0 {
+ return New(v, options[0].Safe), nil
+ }
+ return New(v), nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gtoml/gtoml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gtoml/gtoml.go
new file mode 100644
index 000000000000..79137d6b894f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gtoml/gtoml.go
@@ -0,0 +1,51 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtoml provides accessing and converting for TOML content.
+package gtoml
+
+import (
+ "bytes"
+
+ "github.com/BurntSushi/toml"
+ "github.com/gogf/gf/v2/errors/gerror"
+
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+func Encode(v interface{}) ([]byte, error) {
+ buffer := bytes.NewBuffer(nil)
+ if err := toml.NewEncoder(buffer).Encode(v); err != nil {
+ err = gerror.Wrap(err, `toml.Encoder.Encode failed`)
+ return nil, err
+ }
+ return buffer.Bytes(), nil
+}
+
+func Decode(v []byte) (interface{}, error) {
+ var result interface{}
+ if err := toml.Unmarshal(v, &result); err != nil {
+ err = gerror.Wrap(err, `toml.Unmarshal failed`)
+ return nil, err
+ }
+ return result, nil
+}
+
+func DecodeTo(v []byte, result interface{}) (err error) {
+ err = toml.Unmarshal(v, result)
+ if err != nil {
+ err = gerror.Wrap(err, `toml.Unmarshal failed`)
+ }
+ return err
+}
+
+func ToJson(v []byte) ([]byte, error) {
+ if r, err := Decode(v); err != nil {
+ return nil, err
+ } else {
+ return json.Marshal(r)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gurl/url.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gurl/url.go
new file mode 100644
index 000000000000..e64d0a28b292
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gurl/url.go
@@ -0,0 +1,90 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gurl provides useful API for URL handling.
+package gurl
+
+import (
+ "net/url"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Encode escapes the string so it can be safely placed
+// inside a URL query.
+func Encode(str string) string {
+ return url.QueryEscape(str)
+}
+
+// Decode does the inverse transformation of Encode,
+// converting each 3-byte encoded substring of the form "%AB" into the
+// hex-decoded byte 0xAB.
+// It returns an error if any % is not followed by two hexadecimal
+// digits.
+func Decode(str string) (string, error) {
+ return url.QueryUnescape(str)
+}
+
+// RawEncode does encode the given string according
+// URL-encode according to RFC 3986.
+// See http://php.net/manual/en/function.rawurlencode.php.
+func RawEncode(str string) string {
+ return strings.Replace(url.QueryEscape(str), "+", "%20", -1)
+}
+
+// RawDecode does decode the given string
+// Decode URL-encoded strings.
+// See http://php.net/manual/en/function.rawurldecode.php.
+func RawDecode(str string) (string, error) {
+ return url.QueryUnescape(strings.Replace(str, "%20", "+", -1))
+}
+
+// BuildQuery Generate URL-encoded query string.
+// See http://php.net/manual/en/function.http-build-query.php.
+func BuildQuery(queryData url.Values) string {
+ return queryData.Encode()
+}
+
+// ParseURL Parse a URL and return its components.
+// -1: all; 1: scheme; 2: host; 4: port; 8: user; 16: pass; 32: path; 64: query; 128: fragment.
+// See http://php.net/manual/en/function.parse-url.php.
+func ParseURL(str string, component int) (map[string]string, error) {
+ u, err := url.Parse(str)
+ if err != nil {
+ err = gerror.Wrapf(err, `url.Parse failed for URL "%s"`, str)
+ return nil, err
+ }
+ if component == -1 {
+ component = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128
+ }
+ var components = make(map[string]string)
+ if (component & 1) == 1 {
+ components["scheme"] = u.Scheme
+ }
+ if (component & 2) == 2 {
+ components["host"] = u.Hostname()
+ }
+ if (component & 4) == 4 {
+ components["port"] = u.Port()
+ }
+ if (component & 8) == 8 {
+ components["user"] = u.User.Username()
+ }
+ if (component & 16) == 16 {
+ components["pass"], _ = u.User.Password()
+ }
+ if (component & 32) == 32 {
+ components["path"] = u.Path
+ }
+ if (component & 64) == 64 {
+ components["query"] = u.RawQuery
+ }
+ if (component & 128) == 128 {
+ components["fragment"] = u.Fragment
+ }
+ return components, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gxml/gxml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gxml/gxml.go
new file mode 100644
index 000000000000..efd3c7b1dd7b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gxml/gxml.go
@@ -0,0 +1,109 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gxml provides accessing and converting for XML content.
+package gxml
+
+import (
+ "strings"
+
+ "github.com/clbanning/mxj/v2"
+ "github.com/gogf/gf/v2/errors/gerror"
+
+ "github.com/gogf/gf/v2/encoding/gcharset"
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+// Decode parses `content` into and returns as map.
+func Decode(content []byte) (map[string]interface{}, error) {
+ res, err := convert(content)
+ if err != nil {
+ return nil, err
+ }
+ m, err := mxj.NewMapXml(res)
+ if err != nil {
+ err = gerror.Wrapf(err, `mxj.NewMapXml failed`)
+ }
+ return m, err
+}
+
+// DecodeWithoutRoot parses `content` into a map, and returns the map without root level.
+func DecodeWithoutRoot(content []byte) (map[string]interface{}, error) {
+ res, err := convert(content)
+ if err != nil {
+ return nil, err
+ }
+ m, err := mxj.NewMapXml(res)
+ if err != nil {
+ err = gerror.Wrapf(err, `mxj.NewMapXml failed`)
+ return nil, err
+ }
+ for _, v := range m {
+ if r, ok := v.(map[string]interface{}); ok {
+ return r, nil
+ }
+ }
+ return m, nil
+}
+
+// Encode encodes map `m` to an XML format content as bytes.
+// The optional parameter `rootTag` is used to specify the XML root tag.
+func Encode(m map[string]interface{}, rootTag ...string) ([]byte, error) {
+ b, err := mxj.Map(m).Xml(rootTag...)
+ if err != nil {
+ err = gerror.Wrapf(err, `mxj.Map.Xml failed`)
+ }
+ return b, err
+}
+
+// EncodeWithIndent encodes map `m` to an XML format content as bytes with indent.
+// The optional parameter `rootTag` is used to specify the XML root tag.
+func EncodeWithIndent(m map[string]interface{}, rootTag ...string) ([]byte, error) {
+ b, err := mxj.Map(m).XmlIndent("", "\t", rootTag...)
+ if err != nil {
+ err = gerror.Wrapf(err, `mxj.Map.XmlIndent failed`)
+ }
+ return b, err
+}
+
+// ToJson converts `content` as XML format into JSON format bytes.
+func ToJson(content []byte) ([]byte, error) {
+ res, err := convert(content)
+ if err != nil {
+ return nil, err
+ }
+ mv, err := mxj.NewMapXml(res)
+ if err == nil {
+ err = gerror.Wrapf(err, `mxj.NewMapXml failed`)
+ return mv.Json()
+ }
+ return nil, err
+}
+
+// convert does convert the encoding of given XML content from XML root tag into UTF-8 encoding content.
+func convert(xml []byte) (res []byte, err error) {
+ var (
+ patten = `<\?xml.*encoding\s*=\s*['|"](.*?)['|"].*\?>`
+ matchStr, _ = gregex.MatchString(patten, string(xml))
+ xmlEncode = "UTF-8"
+ )
+ if len(matchStr) == 2 {
+ xmlEncode = matchStr[1]
+ }
+ xmlEncode = strings.ToUpper(xmlEncode)
+ res, err = gregex.Replace(patten, []byte(""), xml)
+ if err != nil {
+ return nil, err
+ }
+ if xmlEncode != "UTF-8" && xmlEncode != "UTF8" {
+ dst, err := gcharset.Convert("UTF-8", xmlEncode, string(res))
+ if err != nil {
+ return nil, err
+ }
+ res = []byte(dst)
+ }
+ return res, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gyaml/gyaml.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gyaml/gyaml.go
new file mode 100644
index 000000000000..b646b270d448
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/encoding/gyaml/gyaml.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gyaml provides accessing and converting for YAML content.
+package gyaml
+
+import (
+ "bytes"
+ "strings"
+
+ "gopkg.in/yaml.v3"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+func Encode(value interface{}) (out []byte, err error) {
+ if out, err = yaml.Marshal(value); err != nil {
+ err = gerror.Wrap(err, `yaml.Marshal failed`)
+ }
+ return
+}
+
+func EncodeIndent(value interface{}, indent string) (out []byte, err error) {
+ out, err = Encode(value)
+ if err != nil {
+ return
+ }
+ if indent != "" {
+ var (
+ buffer = bytes.NewBuffer(nil)
+ array = strings.Split(strings.TrimSpace(string(out)), "\n")
+ )
+ for _, v := range array {
+ buffer.WriteString(indent)
+ buffer.WriteString(v)
+ buffer.WriteString("\n")
+ }
+ out = buffer.Bytes()
+ }
+ return
+}
+
+func Decode(value []byte) (interface{}, error) {
+ var (
+ result map[string]interface{}
+ err error
+ )
+ if err = yaml.Unmarshal(value, &result); err != nil {
+ err = gerror.Wrap(err, `yaml.Unmarshal failed`)
+ return nil, err
+ }
+ return gconv.MapDeep(result), nil
+}
+
+func DecodeTo(value []byte, result interface{}) (err error) {
+ err = yaml.Unmarshal(value, result)
+ if err != nil {
+ err = gerror.Wrap(err, `yaml.Unmarshal failed`)
+ }
+ return
+}
+
+func ToJson(value []byte) (out []byte, err error) {
+ var (
+ result interface{}
+ )
+ if result, err = Decode(value); err != nil {
+ return nil, err
+ } else {
+ return json.Marshal(result)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gcode/gcode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gcode/gcode.go
new file mode 100644
index 000000000000..6f96eee8f288
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gcode/gcode.go
@@ -0,0 +1,69 @@
+// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcode provides universal error code definition and common error codes implements.
+package gcode
+
+// Code is universal error code interface definition.
+type Code interface {
+ // Code returns the integer number of current error code.
+ Code() int
+
+ // Message returns the brief message for current error code.
+ Message() string
+
+ // Detail returns the detailed information of current error code,
+ // which is mainly designed as an extension field for error code.
+ Detail() interface{}
+}
+
+// ================================================================================================================
+// Common error code definition.
+// There are reserved internal error code by framework: code < 1000.
+// ================================================================================================================
+
+var (
+ CodeNil = localCode{-1, "", nil} // No error code specified.
+ CodeOK = localCode{0, "OK", nil} // It is OK.
+ CodeInternalError = localCode{50, "Internal Error", nil} // An error occurred internally.
+ CodeValidationFailed = localCode{51, "Validation Failed", nil} // Data validation failed.
+ CodeDbOperationError = localCode{52, "Database Operation Error", nil} // Database operation error.
+ CodeInvalidParameter = localCode{53, "Invalid Parameter", nil} // The given parameter for current operation is invalid.
+ CodeMissingParameter = localCode{54, "Missing Parameter", nil} // Parameter for current operation is missing.
+ CodeInvalidOperation = localCode{55, "Invalid Operation", nil} // The function cannot be used like this.
+ CodeInvalidConfiguration = localCode{56, "Invalid Configuration", nil} // The configuration is invalid for current operation.
+ CodeMissingConfiguration = localCode{57, "Missing Configuration", nil} // The configuration is missing for current operation.
+ CodeNotImplemented = localCode{58, "Not Implemented", nil} // The operation is not implemented yet.
+ CodeNotSupported = localCode{59, "Not Supported", nil} // The operation is not supported yet.
+ CodeOperationFailed = localCode{60, "Operation Failed", nil} // I tried, but I cannot give you what you want.
+ CodeNotAuthorized = localCode{61, "Not Authorized", nil} // Not Authorized.
+ CodeSecurityReason = localCode{62, "Security Reason", nil} // Security Reason.
+ CodeServerBusy = localCode{63, "Server Is Busy", nil} // Server is busy, please try again later.
+ CodeUnknown = localCode{64, "Unknown Error", nil} // Unknown error.
+ CodeNotFound = localCode{65, "Not Found", nil} // Resource does not exist.
+ CodeInvalidRequest = localCode{66, "Invalid Request", nil} // Invalid request.
+ CodeBusinessValidationFailed = localCode{300, "Business Validation Failed", nil} // Business validation failed.
+)
+
+// New creates and returns an error code.
+// Note that it returns an interface object of Code.
+func New(code int, message string, detail interface{}) Code {
+ return localCode{
+ code: code,
+ message: message,
+ detail: detail,
+ }
+}
+
+// WithCode creates and returns a new error code based on given Code.
+// The code and message is from given `code`, but the detail if from given `detail`.
+func WithCode(code Code, detail interface{}) Code {
+ return localCode{
+ code: code.Code(),
+ message: code.Message(),
+ detail: detail,
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gcode/gcode_local.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gcode/gcode_local.go
new file mode 100644
index 000000000000..1ec1d1ea99f9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gcode/gcode_local.go
@@ -0,0 +1,43 @@
+// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcode
+
+import "fmt"
+
+// localCode is an implementer for interface Code for internal usage only.
+type localCode struct {
+ code int // Error code, usually an integer.
+ message string // Brief message for this error code.
+ detail interface{} // As type of interface, it is mainly designed as an extension field for error code.
+}
+
+// Code returns the integer number of current error code.
+func (c localCode) Code() int {
+ return c.code
+}
+
+// Message returns the brief message for current error code.
+func (c localCode) Message() string {
+ return c.message
+}
+
+// Detail returns the detailed information of current error code,
+// which is mainly designed as an extension field for error code.
+func (c localCode) Detail() interface{} {
+ return c.detail
+}
+
+// String returns current error code as a string.
+func (c localCode) String() string {
+ if c.detail != nil {
+ return fmt.Sprintf(`%d:%s %v`, c.code, c.message, c.detail)
+ }
+ if c.message != "" {
+ return fmt.Sprintf(`%d:%s`, c.code, c.message)
+ }
+ return fmt.Sprintf(`%d`, c.code)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror.go
new file mode 100644
index 000000000000..282dcb40a9cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror.go
@@ -0,0 +1,312 @@
+// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gerror provides simple functions to manipulate errors.
+//
+// Very note that, this package is quite a basic package, which SHOULD NOT import extra packages
+// except standard packages and internal packages, to avoid cycle imports.
+package gerror
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+)
+
+// iCode is the interface for Code feature.
+type iCode interface {
+ Error() string
+ Code() gcode.Code
+}
+
+// iStack is the interface for Stack feature.
+type iStack interface {
+ Error() string
+ Stack() string
+}
+
+// iCause is the interface for Cause feature.
+type iCause interface {
+ Error() string
+ Cause() error
+}
+
+// iCurrent is the interface for Current feature.
+type iCurrent interface {
+ Error() string
+ Current() error
+}
+
+// iNext is the interface for Next feature.
+type iNext interface {
+ Error() string
+ Next() error
+}
+
+// New creates and returns an error which is formatted from given text.
+func New(text string) error {
+ return &Error{
+ stack: callers(),
+ text: text,
+ code: gcode.CodeNil,
+ }
+}
+
+// Newf returns an error that formats as the given format and args.
+func Newf(format string, args ...interface{}) error {
+ return &Error{
+ stack: callers(),
+ text: fmt.Sprintf(format, args...),
+ code: gcode.CodeNil,
+ }
+}
+
+// NewSkip creates and returns an error which is formatted from given text.
+// The parameter `skip` specifies the stack callers skipped amount.
+func NewSkip(skip int, text string) error {
+ return &Error{
+ stack: callers(skip),
+ text: text,
+ code: gcode.CodeNil,
+ }
+}
+
+// NewSkipf returns an error that formats as the given format and args.
+// The parameter `skip` specifies the stack callers skipped amount.
+func NewSkipf(skip int, format string, args ...interface{}) error {
+ return &Error{
+ stack: callers(skip),
+ text: fmt.Sprintf(format, args...),
+ code: gcode.CodeNil,
+ }
+}
+
+// Wrap wraps error with text. It returns nil if given err is nil.
+// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
+func Wrap(err error, text string) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(),
+ text: text,
+ code: Code(err),
+ }
+}
+
+// Wrapf returns an error annotating err with a stack trace at the point Wrapf is called, and the format specifier.
+// It returns nil if given `err` is nil.
+// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
+func Wrapf(err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(),
+ text: fmt.Sprintf(format, args...),
+ code: Code(err),
+ }
+}
+
+// WrapSkip wraps error with text. It returns nil if given err is nil.
+// The parameter `skip` specifies the stack callers skipped amount.
+// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
+func WrapSkip(skip int, err error, text string) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(skip),
+ text: text,
+ code: Code(err),
+ }
+}
+
+// WrapSkipf wraps error with text that is formatted with given format and args. It returns nil if given err is nil.
+// The parameter `skip` specifies the stack callers skipped amount.
+// Note that it does not lose the error code of wrapped error, as it inherits the error code from it.
+func WrapSkipf(skip int, err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(skip),
+ text: fmt.Sprintf(format, args...),
+ code: Code(err),
+ }
+}
+
+// NewCode creates and returns an error that has error code and given text.
+func NewCode(code gcode.Code, text ...string) error {
+ return &Error{
+ stack: callers(),
+ text: strings.Join(text, ", "),
+ code: code,
+ }
+}
+
+// NewCodef returns an error that has error code and formats as the given format and args.
+func NewCodef(code gcode.Code, format string, args ...interface{}) error {
+ return &Error{
+ stack: callers(),
+ text: fmt.Sprintf(format, args...),
+ code: code,
+ }
+}
+
+// NewCodeSkip creates and returns an error which has error code and is formatted from given text.
+// The parameter `skip` specifies the stack callers skipped amount.
+func NewCodeSkip(code gcode.Code, skip int, text ...string) error {
+ return &Error{
+ stack: callers(skip),
+ text: strings.Join(text, ", "),
+ code: code,
+ }
+}
+
+// NewCodeSkipf returns an error that has error code and formats as the given format and args.
+// The parameter `skip` specifies the stack callers skipped amount.
+func NewCodeSkipf(code gcode.Code, skip int, format string, args ...interface{}) error {
+ return &Error{
+ stack: callers(skip),
+ text: fmt.Sprintf(format, args...),
+ code: code,
+ }
+}
+
+// WrapCode wraps error with code and text.
+// It returns nil if given err is nil.
+func WrapCode(code gcode.Code, err error, text ...string) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(),
+ text: strings.Join(text, ", "),
+ code: code,
+ }
+}
+
+// WrapCodef wraps error with code and format specifier.
+// It returns nil if given `err` is nil.
+func WrapCodef(code gcode.Code, err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(),
+ text: fmt.Sprintf(format, args...),
+ code: code,
+ }
+}
+
+// WrapCodeSkip wraps error with code and text.
+// It returns nil if given err is nil.
+// The parameter `skip` specifies the stack callers skipped amount.
+func WrapCodeSkip(code gcode.Code, skip int, err error, text ...string) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(skip),
+ text: strings.Join(text, ", "),
+ code: code,
+ }
+}
+
+// WrapCodeSkipf wraps error with code and text that is formatted with given format and args.
+// It returns nil if given err is nil.
+// The parameter `skip` specifies the stack callers skipped amount.
+func WrapCodeSkipf(code gcode.Code, skip int, err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: err,
+ stack: callers(skip),
+ text: fmt.Sprintf(format, args...),
+ code: code,
+ }
+}
+
+// Code returns the error code of current error.
+// It returns CodeNil if it has no error code neither it does not implement interface Code.
+func Code(err error) gcode.Code {
+ if err == nil {
+ return gcode.CodeNil
+ }
+ if e, ok := err.(iCode); ok {
+ return e.Code()
+ }
+ if e, ok := err.(iNext); ok {
+ return Code(e.Next())
+ }
+ return gcode.CodeNil
+}
+
+// Cause returns the root cause error of `err`.
+func Cause(err error) error {
+ if err == nil {
+ return nil
+ }
+ if e, ok := err.(iCause); ok {
+ return e.Cause()
+ }
+ if e, ok := err.(iNext); ok {
+ return Cause(e.Next())
+ }
+ return err
+}
+
+// Stack returns the stack callers as string.
+// It returns the error string directly if the `err` does not support stacks.
+func Stack(err error) string {
+ if err == nil {
+ return ""
+ }
+ if e, ok := err.(iStack); ok {
+ return e.Stack()
+ }
+ return err.Error()
+}
+
+// Current creates and returns the current level error.
+// It returns nil if current level error is nil.
+func Current(err error) error {
+ if err == nil {
+ return nil
+ }
+ if e, ok := err.(iCurrent); ok {
+ return e.Current()
+ }
+ return err
+}
+
+// Next returns the next level error.
+// It returns nil if current level error or the next level error is nil.
+func Next(err error) error {
+ if err == nil {
+ return nil
+ }
+ if e, ok := err.(iNext); ok {
+ return e.Next()
+ }
+ return nil
+}
+
+// HasStack checks and returns whether `err` implemented interface `iStack`.
+func HasStack(err error) bool {
+ _, ok := err.(iStack)
+ return ok
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_error.go
new file mode 100644
index 000000000000..e3491b7bffbf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_error.go
@@ -0,0 +1,230 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gerror
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "runtime"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+)
+
+// Error is custom error for additional features.
+type Error struct {
+ error error // Wrapped error.
+ stack stack // Stack array, which records the stack information when this error is created or wrapped.
+ text string // Custom Error text when Error is created, might be empty when its code is not nil.
+ code gcode.Code // Error code if necessary.
+}
+
+const (
+ // Filtering key for current error module paths.
+ stackFilterKeyLocal = "/errors/gerror/gerror"
+)
+
+var (
+ // goRootForFilter is used for stack filtering in development environment purpose.
+ goRootForFilter = runtime.GOROOT()
+)
+
+func init() {
+ if goRootForFilter != "" {
+ goRootForFilter = strings.Replace(goRootForFilter, "\\", "/", -1)
+ }
+}
+
+// Error implements the interface of Error, it returns all the error as string.
+func (err *Error) Error() string {
+ if err == nil {
+ return ""
+ }
+ errStr := err.text
+ if errStr == "" && err.code != nil {
+ errStr = err.code.Message()
+ }
+ if err.error != nil {
+ if errStr != "" {
+ errStr += ": "
+ }
+ errStr += err.error.Error()
+ }
+ return errStr
+}
+
+// Code returns the error code.
+// It returns CodeNil if it has no error code.
+func (err *Error) Code() gcode.Code {
+ if err == nil {
+ return gcode.CodeNil
+ }
+ if err.code == gcode.CodeNil {
+ return Code(err.Next())
+ }
+ return err.code
+}
+
+// Cause returns the root cause error.
+func (err *Error) Cause() error {
+ if err == nil {
+ return nil
+ }
+ loop := err
+ for loop != nil {
+ if loop.error != nil {
+ if e, ok := loop.error.(*Error); ok {
+ // Internal Error struct.
+ loop = e
+ } else if e, ok := loop.error.(iCause); ok {
+ // Other Error that implements ApiCause interface.
+ return e.Cause()
+ } else {
+ return loop.error
+ }
+ } else {
+ // return loop
+ // To be compatible with Case of https://github.com/pkg/errors.
+ return errors.New(loop.text)
+ }
+ }
+ return nil
+}
+
+// Format formats the frame according to the fmt.Formatter interface.
+//
+// %v, %s : Print all the error string;
+// %-v, %-s : Print current level error string;
+// %+s : Print full stack error list;
+// %+v : Print the error string and full stack error list;
+func (err *Error) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 's', 'v':
+ switch {
+ case s.Flag('-'):
+ if err.text != "" {
+ _, _ = io.WriteString(s, err.text)
+ } else {
+ _, _ = io.WriteString(s, err.Error())
+ }
+ case s.Flag('+'):
+ if verb == 's' {
+ _, _ = io.WriteString(s, err.Stack())
+ } else {
+ _, _ = io.WriteString(s, err.Error()+"\n"+err.Stack())
+ }
+ default:
+ _, _ = io.WriteString(s, err.Error())
+ }
+ }
+}
+
+// Stack returns the stack callers as string.
+// It returns an empty string if the `err` does not support stacks.
+func (err *Error) Stack() string {
+ if err == nil {
+ return ""
+ }
+ var (
+ loop = err
+ index = 1
+ buffer = bytes.NewBuffer(nil)
+ )
+ for loop != nil {
+ buffer.WriteString(fmt.Sprintf("%d. %-v\n", index, loop))
+ index++
+ formatSubStack(loop.stack, buffer)
+ if loop.error != nil {
+ if e, ok := loop.error.(*Error); ok {
+ loop = e
+ } else {
+ buffer.WriteString(fmt.Sprintf("%d. %s\n", index, loop.error.Error()))
+ index++
+ break
+ }
+ } else {
+ break
+ }
+ }
+ return buffer.String()
+}
+
+// Current creates and returns the current level error.
+// It returns nil if current level error is nil.
+func (err *Error) Current() error {
+ if err == nil {
+ return nil
+ }
+ return &Error{
+ error: nil,
+ stack: err.stack,
+ text: err.text,
+ code: err.code,
+ }
+}
+
+// Next returns the next level error.
+// It returns nil if current level error or the next level error is nil.
+func (err *Error) Next() error {
+ if err == nil {
+ return nil
+ }
+ return err.error
+}
+
+// SetCode updates the internal code with given code.
+func (err *Error) SetCode(code gcode.Code) {
+ if err == nil {
+ return
+ }
+ err.code = code
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that do not use pointer as its receiver here.
+func (err Error) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + err.Error() + `"`), nil
+}
+
+// formatSubStack formats the stack for error.
+func formatSubStack(st stack, buffer *bytes.Buffer) {
+ if st == nil {
+ return
+ }
+ index := 1
+ space := " "
+ for _, p := range st {
+ if fn := runtime.FuncForPC(p - 1); fn != nil {
+ file, line := fn.FileLine(p - 1)
+ // Custom filtering.
+ if strings.Contains(file, stackFilterKeyLocal) {
+ continue
+ }
+ // Avoid stack string like "`autogenerated`"
+ if strings.Contains(file, "<") {
+ continue
+ }
+ // Ignore GO ROOT paths.
+ if goRootForFilter != "" &&
+ len(file) >= len(goRootForFilter) &&
+ file[0:len(goRootForFilter)] == goRootForFilter {
+ continue
+ }
+ // Graceful indent.
+ if index > 9 {
+ space = " "
+ }
+ buffer.WriteString(fmt.Sprintf(
+ " %d).%s%s\n \t%s:%d\n",
+ index, space, fn.Name(), file, line,
+ ))
+ index++
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_option.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_option.go
new file mode 100644
index 000000000000..c2ff7115216f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_option.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gerror
+
+import "github.com/gogf/gf/v2/errors/gcode"
+
+// Option is option for creating error.
+type Option struct {
+ Error error // Wrapped error if any.
+ Stack bool // Whether recording stack information into error.
+ Text string // Error text, which is created by New* functions.
+ Code gcode.Code // Error code if necessary.
+}
+
+// NewOption creates and returns an error with Option.
+// It is the senior usage for creating error, which is often used internally in framework.
+func NewOption(option Option) error {
+ err := &Error{
+ error: option.Error,
+ text: option.Text,
+ code: option.Code,
+ }
+ if option.Stack {
+ err.stack = callers()
+ }
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_stack.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_stack.go
new file mode 100644
index 000000000000..b65cce769ba9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/errors/gerror/gerror_stack.go
@@ -0,0 +1,30 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gerror
+
+import "runtime"
+
+// stack represents a stack of program counters.
+type stack []uintptr
+
+const (
+ // maxStackDepth marks the max stack depth for error back traces.
+ maxStackDepth = 32
+)
+
+// callers returns the stack callers.
+// Note that it here just retrieves the caller memory address array not the caller information.
+func callers(skip ...int) stack {
+ var (
+ pcs [maxStackDepth]uintptr
+ n = 3
+ )
+ if len(skip) > 0 {
+ n += skip[0]
+ }
+ return pcs[:runtime.Callers(n, pcs[:])]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g.go
new file mode 100644
index 000000000000..e2e6d2f3f7a7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g.go
@@ -0,0 +1,66 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package g
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/util/gmeta"
+)
+
+type (
+ Var = gvar.Var // Var is a universal variable interface, like generics.
+ Ctx = context.Context // Ctx is alias of frequently-used type context.Context.
+ Meta = gmeta.Meta // Meta is alias of frequently-used type gmeta.Meta.
+)
+
+type (
+ Map = map[string]interface{} // Map is alias of frequently-used map type map[string]interface{}.
+ MapAnyAny = map[interface{}]interface{} // MapAnyAny is alias of frequently-used map type map[interface{}]interface{}.
+ MapAnyStr = map[interface{}]string // MapAnyStr is alias of frequently-used map type map[interface{}]string.
+ MapAnyInt = map[interface{}]int // MapAnyInt is alias of frequently-used map type map[interface{}]int.
+ MapStrAny = map[string]interface{} // MapStrAny is alias of frequently-used map type map[string]interface{}.
+ MapStrStr = map[string]string // MapStrStr is alias of frequently-used map type map[string]string.
+ MapStrInt = map[string]int // MapStrInt is alias of frequently-used map type map[string]int.
+ MapIntAny = map[int]interface{} // MapIntAny is alias of frequently-used map type map[int]interface{}.
+ MapIntStr = map[int]string // MapIntStr is alias of frequently-used map type map[int]string.
+ MapIntInt = map[int]int // MapIntInt is alias of frequently-used map type map[int]int.
+ MapAnyBool = map[interface{}]bool // MapAnyBool is alias of frequently-used map type map[interface{}]bool.
+ MapStrBool = map[string]bool // MapStrBool is alias of frequently-used map type map[string]bool.
+ MapIntBool = map[int]bool // MapIntBool is alias of frequently-used map type map[int]bool.
+)
+
+type (
+ List = []Map // List is alias of frequently-used slice type []Map.
+ ListAnyAny = []MapAnyAny // ListAnyAny is alias of frequently-used slice type []MapAnyAny.
+ ListAnyStr = []MapAnyStr // ListAnyStr is alias of frequently-used slice type []MapAnyStr.
+ ListAnyInt = []MapAnyInt // ListAnyInt is alias of frequently-used slice type []MapAnyInt.
+ ListStrAny = []MapStrAny // ListStrAny is alias of frequently-used slice type []MapStrAny.
+ ListStrStr = []MapStrStr // ListStrStr is alias of frequently-used slice type []MapStrStr.
+ ListStrInt = []MapStrInt // ListStrInt is alias of frequently-used slice type []MapStrInt.
+ ListIntAny = []MapIntAny // ListIntAny is alias of frequently-used slice type []MapIntAny.
+ ListIntStr = []MapIntStr // ListIntStr is alias of frequently-used slice type []MapIntStr.
+ ListIntInt = []MapIntInt // ListIntInt is alias of frequently-used slice type []MapIntInt.
+ ListAnyBool = []MapAnyBool // ListAnyBool is alias of frequently-used slice type []MapAnyBool.
+ ListStrBool = []MapStrBool // ListStrBool is alias of frequently-used slice type []MapStrBool.
+ ListIntBool = []MapIntBool // ListIntBool is alias of frequently-used slice type []MapIntBool.
+)
+
+type (
+ Slice = []interface{} // Slice is alias of frequently-used slice type []interface{}.
+ SliceAny = []interface{} // SliceAny is alias of frequently-used slice type []interface{}.
+ SliceStr = []string // SliceStr is alias of frequently-used slice type []string.
+ SliceInt = []int // SliceInt is alias of frequently-used slice type []int.
+)
+
+type (
+ Array = []interface{} // Array is alias of frequently-used slice type []interface{}.
+ ArrayAny = []interface{} // ArrayAny is alias of frequently-used slice type []interface{}.
+ ArrayStr = []string // ArrayStr is alias of frequently-used slice type []string.
+ ArrayInt = []int // ArrayInt is alias of frequently-used slice type []int.
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_func.go
new file mode 100644
index 000000000000..f4a16932508a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_func.go
@@ -0,0 +1,95 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package g
+
+import (
+ "context"
+ "io"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/gogf/gf/v2/os/gproc"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// NewVar returns a gvar.Var.
+func NewVar(i interface{}, safe ...bool) *Var {
+ return gvar.New(i, safe...)
+}
+
+// Wait is an alias of ghttp.Wait, which blocks until all the web servers shutdown.
+// It's commonly used in multiple servers' situation.
+func Wait() {
+ ghttp.Wait()
+}
+
+// Listen is an alias of gproc.Listen, which handles the signals received and automatically
+// calls registered signal handler functions.
+// It blocks until shutdown signals received and all registered shutdown handlers done.
+func Listen() {
+ gproc.Listen()
+}
+
+// Dump dumps a variable to stdout with more manually readable.
+func Dump(values ...interface{}) {
+ gutil.Dump(values...)
+}
+
+// DumpTo writes variables `values` as a string in to `writer` with more manually readable
+func DumpTo(writer io.Writer, value interface{}, option gutil.DumpOption) {
+ gutil.DumpTo(writer, value, option)
+}
+
+// DumpWithType acts like Dump, but with type information.
+// Also see Dump.
+func DumpWithType(values ...interface{}) {
+ gutil.DumpWithType(values...)
+}
+
+// DumpWithOption returns variables `values` as a string with more manually readable.
+func DumpWithOption(value interface{}, option gutil.DumpOption) {
+ gutil.DumpWithOption(value, option)
+}
+
+// Throw throws an exception, which can be caught by TryCatch function.
+func Throw(exception interface{}) {
+ gutil.Throw(exception)
+}
+
+// Try implements try... logistics using internal panic...recover.
+// It returns error if any exception occurs, or else it returns nil.
+func Try(try func()) (err error) {
+ return gutil.Try(try)
+}
+
+// TryCatch implements try...catch... logistics using internal panic...recover.
+// It automatically calls function `catch` if any exception occurs ans passes the exception as an error.
+func TryCatch(try func(), catch ...func(exception error)) {
+ gutil.TryCatch(try, catch...)
+}
+
+// IsNil checks whether given `value` is nil.
+// Parameter `traceSource` is used for tracing to the source variable if given `value` is type
+// of pinter that also points to a pointer. It returns nil if the source is nil when `traceSource`
+// is true.
+// Note that it might use reflect feature which affects performance a little.
+func IsNil(value interface{}, traceSource ...bool) bool {
+ return empty.IsNil(value, traceSource...)
+}
+
+// IsEmpty checks whether given `value` empty.
+// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0.
+// Or else it returns true.
+func IsEmpty(value interface{}) bool {
+ return empty.IsEmpty(value)
+}
+
+// RequestFromCtx retrieves and returns the Request object from context.
+func RequestFromCtx(ctx context.Context) *ghttp.Request {
+ return ghttp.RequestFromCtx(ctx)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_object.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_object.go
new file mode 100644
index 000000000000..86fd9700466d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_object.go
@@ -0,0 +1,108 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package g
+
+import (
+ "github.com/gogf/gf/v2/database/gdb"
+ "github.com/gogf/gf/v2/database/gredis"
+ "github.com/gogf/gf/v2/frame/gins"
+ "github.com/gogf/gf/v2/i18n/gi18n"
+ "github.com/gogf/gf/v2/net/gclient"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/gogf/gf/v2/net/gtcp"
+ "github.com/gogf/gf/v2/net/gudp"
+ "github.com/gogf/gf/v2/os/gcfg"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gview"
+ "github.com/gogf/gf/v2/util/gvalid"
+)
+
+// Client is a convenience function, which creates and returns a new HTTP client.
+func Client() *gclient.Client {
+ return gclient.New()
+}
+
+// Server returns an instance of http server with specified name.
+func Server(name ...interface{}) *ghttp.Server {
+ return gins.Server(name...)
+}
+
+// TCPServer returns an instance of tcp server with specified name.
+func TCPServer(name ...interface{}) *gtcp.Server {
+ return gtcp.GetServer(name...)
+}
+
+// UDPServer returns an instance of udp server with specified name.
+func UDPServer(name ...interface{}) *gudp.Server {
+ return gudp.GetServer(name...)
+}
+
+// View returns an instance of template engine object with specified name.
+func View(name ...string) *gview.View {
+ return gins.View(name...)
+}
+
+// Config returns an instance of config object with specified name.
+func Config(name ...string) *gcfg.Config {
+ return gins.Config(name...)
+}
+
+// Cfg is alias of Config.
+// See Config.
+func Cfg(name ...string) *gcfg.Config {
+ return Config(name...)
+}
+
+// Resource returns an instance of Resource.
+// The parameter `name` is the name for the instance.
+func Resource(name ...string) *gres.Resource {
+ return gins.Resource(name...)
+}
+
+// I18n returns an instance of gi18n.Manager.
+// The parameter `name` is the name for the instance.
+func I18n(name ...string) *gi18n.Manager {
+ return gins.I18n(name...)
+}
+
+// Res is alias of Resource.
+// See Resource.
+func Res(name ...string) *gres.Resource {
+ return Resource(name...)
+}
+
+// Log returns an instance of glog.Logger.
+// The parameter `name` is the name for the instance.
+func Log(name ...string) *glog.Logger {
+ return gins.Log(name...)
+}
+
+// DB returns an instance of database ORM object with specified configuration group name.
+func DB(name ...string) gdb.DB {
+ return gins.Database(name...)
+}
+
+// Model creates and returns a model based on configuration of default database group.
+func Model(tableNameOrStruct ...interface{}) *gdb.Model {
+ return DB().Model(tableNameOrStruct...)
+}
+
+// ModelRaw creates and returns a model based on a raw sql not a table.
+func ModelRaw(rawSql string, args ...interface{}) *gdb.Model {
+ return DB().Raw(rawSql, args...)
+}
+
+// Redis returns an instance of redis client with specified configuration group name.
+func Redis(name ...string) *gredis.Redis {
+ return gins.Redis(name...)
+}
+
+// Validator is a convenience function, which creates and returns a new validation manager object.
+func Validator() *gvalid.Validator {
+ return gvalid.New()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_setting.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_setting.go
new file mode 100644
index 000000000000..6f95cd44b5f8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/g/g_setting.go
@@ -0,0 +1,18 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package g
+
+import (
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// SetDebug enables/disables the GoFrame internal logging manually.
+// Note that this function is not concurrent safe, be aware of the DATA RACE,
+// which means you should call this function in your boot but not the runtime.
+func SetDebug(enabled bool) {
+ intlog.SetEnabled(enabled)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins.go
new file mode 100644
index 000000000000..c6fab084edec
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins.go
@@ -0,0 +1,56 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gins provides instances and core components management.
+package gins
+
+import (
+ "github.com/gogf/gf/v2/container/gmap"
+)
+
+var (
+ // localInstances is the instance map for common used components.
+ localInstances = gmap.NewStrAnyMap(true)
+)
+
+// Get returns the instance by given name.
+func Get(name string) interface{} {
+ return localInstances.Get(name)
+}
+
+// Set sets an instance object to the instance manager with given name.
+func Set(name string, instance interface{}) {
+ localInstances.Set(name, instance)
+}
+
+// GetOrSet returns the instance by name,
+// or set instance to the instance manager if it does not exist and returns this instance.
+func GetOrSet(name string, instance interface{}) interface{} {
+ return localInstances.GetOrSet(name, instance)
+}
+
+// GetOrSetFunc returns the instance by name,
+// or sets instance with returned value of callback function `f` if it does not exist
+// and then returns this instance.
+func GetOrSetFunc(name string, f func() interface{}) interface{} {
+ return localInstances.GetOrSetFunc(name, f)
+}
+
+// GetOrSetFuncLock returns the instance by name,
+// or sets instance with returned value of callback function `f` if it does not exist
+// and then returns this instance.
+//
+// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
+// with mutex.Lock of the hash map.
+func GetOrSetFuncLock(name string, f func() interface{}) interface{} {
+ return localInstances.GetOrSetFuncLock(name, f)
+}
+
+// SetIfNotExist sets `instance` to the map if the `name` does not exist, then returns true.
+// It returns false if `name` exists, and `instance` would be ignored.
+func SetIfNotExist(name string, instance interface{}) bool {
+ return localInstances.SetIfNotExist(name, instance)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_config.go
new file mode 100644
index 000000000000..c8eb28f80635
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_config.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "github.com/gogf/gf/v2/os/gcfg"
+)
+
+// Config returns an instance of View with default settings.
+// The parameter `name` is the name for the instance.
+func Config(name ...string) *gcfg.Config {
+ return gcfg.Instance(name...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_database.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_database.go
new file mode 100644
index 000000000000..67e90bea82ac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_database.go
@@ -0,0 +1,203 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/database/gdb"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcfg"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ frameCoreComponentNameDatabase = "gf.core.component.database"
+ configNodeNameDatabase = "database"
+)
+
+// Database returns an instance of database ORM object with specified configuration group name.
+// Note that it panics if any error occurs duration instance creating.
+func Database(name ...string) gdb.DB {
+ var (
+ ctx = context.Background()
+ group = gdb.DefaultGroupName
+ )
+
+ if len(name) > 0 && name[0] != "" {
+ group = name[0]
+ }
+ instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameDatabase, group)
+ db := localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ // It ignores returned error to avoid file no found error while it's not necessary.
+ var (
+ configMap map[string]interface{}
+ configNodeKey = configNodeNameDatabase
+ )
+ // It firstly searches the configuration of the instance name.
+ if configData, _ := Config().Data(ctx); len(configData) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configData, configNodeNameDatabase); v != "" {
+ configNodeKey = v
+ }
+ }
+ if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
+ configMap = v.Map()
+ }
+ if len(configMap) == 0 && !gdb.IsConfigured() {
+ // File configuration object checks.
+ var (
+ err error
+ configFilePath string
+ )
+ if fileConfig, ok := Config().GetAdapter().(*gcfg.AdapterFile); ok {
+ if configFilePath, _ = fileConfig.GetFilePath(); configFilePath == "" {
+ var (
+ exampleFileName = "config.example.toml"
+ exampleConfigFilePath string
+ )
+ if exampleConfigFilePath, _ = fileConfig.GetFilePath(exampleFileName); exampleConfigFilePath != "" {
+ err = gerror.NewCodef(
+ gcode.CodeMissingConfiguration,
+ `configuration file "%s" not found, but found "%s", did you miss renaming the example configuration file?`,
+ fileConfig.GetFileName(),
+ exampleFileName,
+ )
+ } else {
+ err = gerror.NewCodef(
+ gcode.CodeMissingConfiguration,
+ `configuration file "%s" not found, did you miss the configuration file or the misspell the configuration file name?`,
+ fileConfig.GetFileName(),
+ )
+ }
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+ // Panic if nothing found in Config object or in gdb configuration.
+ if len(configMap) == 0 && !gdb.IsConfigured() {
+ err = gerror.NewCodef(
+ gcode.CodeMissingConfiguration,
+ `database initialization failed: "%s" node not found, is configuration file or configuration node missing?`,
+ configNodeNameDatabase,
+ )
+ panic(err)
+ }
+ }
+
+ if len(configMap) == 0 {
+ configMap = make(map[string]interface{})
+ }
+ // Parse `m` as map-slice and adds it to global configurations for package gdb.
+ for g, groupConfig := range configMap {
+ cg := gdb.ConfigGroup{}
+ switch value := groupConfig.(type) {
+ case []interface{}:
+ for _, v := range value {
+ if node := parseDBConfigNode(v); node != nil {
+ cg = append(cg, *node)
+ }
+ }
+ case map[string]interface{}:
+ if node := parseDBConfigNode(value); node != nil {
+ cg = append(cg, *node)
+ }
+ }
+ if len(cg) > 0 {
+ if gdb.GetConfig(group) == nil {
+ intlog.Printf(ctx, "add configuration for group: %s, %#v", g, cg)
+ gdb.SetConfigGroup(g, cg)
+ } else {
+ intlog.Printf(ctx, "ignore configuration as it already exists for group: %s, %#v", g, cg)
+ intlog.Printf(ctx, "%s, %#v", g, cg)
+ }
+ }
+ }
+ // Parse `m` as a single node configuration,
+ // which is the default group configuration.
+ if node := parseDBConfigNode(configMap); node != nil {
+ cg := gdb.ConfigGroup{}
+ if node.Link != "" || node.Host != "" {
+ cg = append(cg, *node)
+ }
+
+ if len(cg) > 0 {
+ if gdb.GetConfig(group) == nil {
+ intlog.Printf(ctx, "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
+ gdb.SetConfigGroup(gdb.DefaultGroupName, cg)
+ } else {
+ intlog.Printf(ctx, "ignore configuration as it already exists for group: %s, %#v", gdb.DefaultGroupName, cg)
+ intlog.Printf(ctx, "%s, %#v", gdb.DefaultGroupName, cg)
+ }
+ }
+ }
+
+ // Create a new ORM object with given configurations.
+ if db, err := gdb.NewByGroup(name...); err == nil {
+ // Initialize logger for ORM.
+ var (
+ loggerConfigMap map[string]interface{}
+ loggerNodeName = fmt.Sprintf("%s.%s", configNodeKey, configNodeNameLogger)
+ )
+ if v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {
+ loggerConfigMap = v.Map()
+ }
+ if len(loggerConfigMap) == 0 {
+ if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
+ loggerConfigMap = v.Map()
+ }
+ }
+ if len(loggerConfigMap) > 0 {
+ if err = db.GetLogger().SetConfigWithMap(loggerConfigMap); err != nil {
+ panic(err)
+ }
+ }
+ return db
+ } else {
+ // If panics, often because it does not find its configuration for given group.
+ panic(err)
+ }
+ return nil
+ })
+ if db != nil {
+ return db.(gdb.DB)
+ }
+ return nil
+}
+
+func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
+ nodeMap, ok := value.(map[string]interface{})
+ if !ok {
+ return nil
+ }
+ var (
+ node = &gdb.ConfigNode{}
+ err = gconv.Struct(nodeMap, node)
+ )
+ if err != nil {
+ panic(err)
+ }
+ // Find possible `Link` configuration content.
+ if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil {
+ node.Link = gconv.String(v)
+ }
+ // Parse `Link` configuration syntax.
+ if node.Link != "" && node.Type == "" {
+ match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)
+ if len(match) == 3 {
+ node.Type = gstr.Trim(match[1])
+ node.Link = gstr.Trim(match[2])
+ }
+ }
+ return node
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_httpclient.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_httpclient.go
new file mode 100644
index 000000000000..324307d394ab
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_httpclient.go
@@ -0,0 +1,25 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/net/gclient"
+)
+
+const (
+ frameCoreComponentNameHttpClient = "gf.core.component.httpclient"
+)
+
+// HttpClient returns an instance of http client with specified name.
+func HttpClient(name ...interface{}) *gclient.Client {
+ var instanceKey = fmt.Sprintf("%s.%v", frameCoreComponentNameHttpClient, name)
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ return gclient.New()
+ }).(*gclient.Client)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_i18n.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_i18n.go
new file mode 100644
index 000000000000..146952a11490
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_i18n.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "github.com/gogf/gf/v2/i18n/gi18n"
+)
+
+// I18n returns an instance of gi18n.Manager.
+// The parameter `name` is the name for the instance.
+func I18n(name ...string) *gi18n.Manager {
+ return gi18n.Instance(name...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_log.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_log.go
new file mode 100644
index 000000000000..a1a3938f0c5f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_log.go
@@ -0,0 +1,66 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ frameCoreComponentNameLogger = "gf.core.component.logger"
+ configNodeNameLogger = "logger"
+)
+
+// Log returns an instance of glog.Logger.
+// The parameter `name` is the name for the instance.
+// Note that it panics if any error occurs duration instance creating.
+func Log(name ...string) *glog.Logger {
+ var (
+ ctx = context.Background()
+ instanceName = glog.DefaultName
+ )
+ if len(name) > 0 && name[0] != "" {
+ instanceName = name[0]
+ }
+ instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameLogger, instanceName)
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ logger := glog.Instance(instanceName)
+ // To avoid file no found error while it's not necessary.
+ var (
+ configMap map[string]interface{}
+ loggerNodeName = configNodeNameLogger
+ )
+ // Try to find possible `loggerNodeName` in case-insensitive way.
+ if configData, _ := Config().Data(ctx); len(configData) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configData, configNodeNameLogger); v != "" {
+ loggerNodeName = v
+ }
+ }
+ // Retrieve certain logger configuration by logger name.
+ certainLoggerNodeName := fmt.Sprintf(`%s.%s`, loggerNodeName, instanceName)
+ if v, _ := Config().Get(ctx, certainLoggerNodeName); !v.IsEmpty() {
+ configMap = v.Map()
+ }
+ // Retrieve global logger configuration if configuration for certain logger name does not exist.
+ if len(configMap) == 0 {
+ if v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {
+ configMap = v.Map()
+ }
+ }
+ // Set logger config if config map is not empty.
+ if len(configMap) > 0 {
+ if err := logger.SetConfigWithMap(configMap); err != nil {
+ panic(err)
+ }
+ }
+ return logger
+ }).(*glog.Logger)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_redis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_redis.go
new file mode 100644
index 000000000000..ea5b2aebb622
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_redis.go
@@ -0,0 +1,75 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/database/gredis"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ frameCoreComponentNameRedis = "gf.core.component.redis"
+ configNodeNameRedis = "redis"
+)
+
+// Redis returns an instance of redis client with specified configuration group name.
+// Note that it panics if any error occurs duration instance creating.
+func Redis(name ...string) *gredis.Redis {
+ var (
+ err error
+ ctx = context.Background()
+ group = gredis.DefaultGroupName
+ )
+ if len(name) > 0 && name[0] != "" {
+ group = name[0]
+ }
+ instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameRedis, group)
+ result := localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ // If already configured, it returns the redis instance.
+ if _, ok := gredis.GetConfig(group); ok {
+ return gredis.Instance(group)
+ }
+ if Config().Available(ctx) {
+ var (
+ configMap map[string]interface{}
+ redisConfig *gredis.Config
+ redisClient *gredis.Redis
+ )
+ if configMap, err = Config().Data(ctx); err != nil {
+ intlog.Errorf(ctx, `retrieve config data map failed: %+v`, err)
+ }
+ if _, v := gutil.MapPossibleItemByKey(configMap, configNodeNameRedis); v != nil {
+ configMap = gconv.Map(v)
+ }
+ if len(configMap) > 0 {
+ if v, ok := configMap[group]; ok {
+ if redisConfig, err = gredis.ConfigFromMap(gconv.Map(v)); err != nil {
+ panic(err)
+ }
+ } else {
+ intlog.Printf(ctx, `missing configuration for redis group "%s"`, group)
+ }
+ } else {
+ intlog.Print(ctx, `missing configuration for redis: "redis" node not found`)
+ }
+ if redisClient, err = gredis.New(redisConfig); err != nil {
+ panic(err)
+ }
+ return redisClient
+ }
+ return nil
+ })
+ if result != nil {
+ return result.(*gredis.Redis)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_resource.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_resource.go
new file mode 100644
index 000000000000..bd84d50b2723
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_resource.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "github.com/gogf/gf/v2/os/gres"
+)
+
+// Resource returns an instance of Resource.
+// The parameter `name` is the name for the instance.
+func Resource(name ...string) *gres.Resource {
+ return gres.Instance(name...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_server.go
new file mode 100644
index 000000000000..2455d7925731
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_server.go
@@ -0,0 +1,101 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ frameCoreComponentNameServer = "gf.core.component.server" // Prefix for HTTP server instance.
+ configNodeNameServer = "server" // General version configuration item name.
+ configNodeNameServerSecondary = "httpserver" // New version configuration item name support from v2.
+)
+
+// Server returns an instance of http server with specified name.
+// Note that it panics if any error occurs duration instance creating.
+func Server(name ...interface{}) *ghttp.Server {
+ var (
+ err error
+ ctx = context.Background()
+ instanceName = ghttp.DefaultServerName
+ instanceKey = fmt.Sprintf("%s.%v", frameCoreComponentNameServer, name)
+ )
+ if len(name) > 0 && name[0] != "" {
+ instanceName = gconv.String(name[0])
+ }
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ server := ghttp.GetServer(instanceName)
+ if Config().Available(ctx) {
+ // Server initialization from configuration.
+ var (
+ configMap map[string]interface{}
+ serverConfigMap map[string]interface{}
+ serverLoggerConfigMap map[string]interface{}
+ configNodeName string
+ )
+ if configMap, err = Config().Data(ctx); err != nil {
+ intlog.Errorf(ctx, `retrieve config data map failed: %+v`, err)
+ }
+ // Find possible server configuration item by possible names.
+ if len(configMap) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configMap, configNodeNameServer); v != "" {
+ configNodeName = v
+ }
+ if configNodeName == "" {
+ if v, _ := gutil.MapPossibleItemByKey(configMap, configNodeNameServerSecondary); v != "" {
+ configNodeName = v
+ }
+ }
+ }
+ // Server configuration.
+ serverConfigMap = Config().MustGet(
+ ctx,
+ fmt.Sprintf(`%s.%s`, configNodeName, server.GetName()),
+ ).Map()
+ if len(serverConfigMap) == 0 {
+ serverConfigMap = Config().MustGet(ctx, configNodeName).Map()
+ }
+ if len(serverConfigMap) > 0 {
+ if err = server.SetConfigWithMap(serverConfigMap); err != nil {
+ panic(err)
+ }
+ } else {
+ // The configuration is not necessary, so it just prints internal logs.
+ intlog.Printf(
+ ctx,
+ `missing configuration from configuration component for HTTP server "%s"`,
+ instanceName,
+ )
+ }
+ // Server logger configuration checks.
+ serverLoggerConfigMap = Config().MustGet(
+ ctx,
+ fmt.Sprintf(`%s.%s.%s`, configNodeName, server.GetName(), configNodeNameLogger),
+ ).Map()
+ if len(serverLoggerConfigMap) > 0 {
+ if err = server.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil {
+ panic(err)
+ }
+ }
+ }
+ // The server name is necessary. It sets a default server name is it is not configured.
+ if server.GetName() == "" || server.GetName() == ghttp.DefaultServerName {
+ server.SetName(instanceName)
+ }
+ // As it might use template feature,
+ // it initializes the view instance as well.
+ _ = getViewInstance()
+ return server
+ }).(*ghttp.Server)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_view.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_view.go
new file mode 100644
index 000000000000..953d39ff169d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/frame/gins/gins_view.go
@@ -0,0 +1,71 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gins
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gview"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ frameCoreComponentNameViewer = "gf.core.component.viewer"
+ configNodeNameViewer = "viewer"
+)
+
+// View returns an instance of View with default settings.
+// The parameter `name` is the name for the instance.
+// Note that it panics if any error occurs duration instance creating.
+func View(name ...string) *gview.View {
+ instanceName := gview.DefaultName
+ if len(name) > 0 && name[0] != "" {
+ instanceName = name[0]
+ }
+ instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameViewer, instanceName)
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ return getViewInstance(instanceName)
+ }).(*gview.View)
+}
+
+func getViewInstance(name ...string) *gview.View {
+ var (
+ err error
+ ctx = context.Background()
+ instanceName = gview.DefaultName
+ )
+ if len(name) > 0 && name[0] != "" {
+ instanceName = name[0]
+ }
+ view := gview.Instance(instanceName)
+ if Config().Available(ctx) {
+ var (
+ configMap map[string]interface{}
+ configNodeName = configNodeNameViewer
+ )
+ if configMap, err = Config().Data(ctx); err != nil {
+ intlog.Errorf(ctx, `retrieve config data map failed: %+v`, err)
+ }
+ if len(configMap) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configMap, configNodeNameViewer); v != "" {
+ configNodeName = v
+ }
+ }
+ configMap = Config().MustGet(ctx, fmt.Sprintf(`%s.%s`, configNodeName, instanceName)).Map()
+ if len(configMap) == 0 {
+ configMap = Config().MustGet(ctx, configNodeName).Map()
+ }
+ if len(configMap) > 0 {
+ if err = view.SetConfigWithMap(configMap); err != nil {
+ panic(err)
+ }
+ }
+ }
+ return view
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n.go
new file mode 100644
index 000000000000..09b78f114161
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n.go
@@ -0,0 +1,52 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gi18n implements internationalization and localization.
+package gi18n
+
+import "context"
+
+// SetPath sets the directory path storing i18n files.
+func SetPath(path string) error {
+ return Instance().SetPath(path)
+}
+
+// SetLanguage sets the language for translator.
+func SetLanguage(language string) {
+ Instance().SetLanguage(language)
+}
+
+// SetDelimiters sets the delimiters for translator.
+func SetDelimiters(left, right string) {
+ Instance().SetDelimiters(left, right)
+}
+
+// T is alias of Translate for convenience.
+func T(ctx context.Context, content string) string {
+ return Instance().T(ctx, content)
+}
+
+// Tf is alias of TranslateFormat for convenience.
+func Tf(ctx context.Context, format string, values ...interface{}) string {
+ return Instance().TranslateFormat(ctx, format, values...)
+}
+
+// TranslateFormat translates, formats and returns the `format` with configured language
+// and given `values`.
+func TranslateFormat(ctx context.Context, format string, values ...interface{}) string {
+ return Instance().TranslateFormat(ctx, format, values...)
+}
+
+// Translate translates `content` with configured language and returns the translated content.
+func Translate(ctx context.Context, content string) string {
+ return Instance().Translate(ctx, content)
+}
+
+// GetContent retrieves and returns the configured content for given key and specified language.
+// It returns an empty string if not found.
+func GetContent(ctx context.Context, key string) string {
+ return Instance().GetContent(ctx, key)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_ctx.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_ctx.go
new file mode 100644
index 000000000000..a2c7293a769f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_ctx.go
@@ -0,0 +1,35 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gi18n implements internationalization and localization.
+package gi18n
+
+import "context"
+
+const (
+ ctxLanguage = "I18nLanguage"
+)
+
+// WithLanguage append language setting to the context and returns a new context.
+func WithLanguage(ctx context.Context, language string) context.Context {
+ if ctx == nil {
+ ctx = context.TODO()
+ }
+ return context.WithValue(ctx, ctxLanguage, language)
+}
+
+// LanguageFromCtx retrieves and returns language name from context.
+// It returns an empty string if it is not set previously.
+func LanguageFromCtx(ctx context.Context) string {
+ if ctx == nil {
+ return ""
+ }
+ v := ctx.Value(ctxLanguage)
+ if v != nil {
+ return v.(string)
+ }
+ return ""
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_instance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_instance.go
new file mode 100644
index 000000000000..58505b94897e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_instance.go
@@ -0,0 +1,32 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gi18n
+
+import "github.com/gogf/gf/v2/container/gmap"
+
+const (
+ // DefaultName is the default group name for instance usage.
+ DefaultName = "default"
+)
+
+var (
+ // instances is the instances map for management
+ // for multiple i18n instance by name.
+ instances = gmap.NewStrAnyMap(true)
+)
+
+// Instance returns an instance of Resource.
+// The parameter `name` is the name for the instance.
+func Instance(name ...string) *Manager {
+ key := DefaultName
+ if len(name) > 0 && name[0] != "" {
+ key = name[0]
+ }
+ return instances.GetOrSetFuncLock(key, func() interface{} {
+ return New()
+ }).(*Manager)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_manager.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_manager.go
new file mode 100644
index 000000000000..94aee52ccee8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/i18n/gi18n/gi18n_manager.go
@@ -0,0 +1,266 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gi18n
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gfsnotify"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Manager for i18n contents, it is concurrent safe, supporting hot reload.
+type Manager struct {
+ mu sync.RWMutex
+ data map[string]map[string]string // Translating map.
+ pattern string // Pattern for regex parsing.
+ options Options // configuration options.
+}
+
+// Options is used for i18n object configuration.
+type Options struct {
+ Path string // I18n files storage path.
+ Language string // Default local language.
+ Delimiters []string // Delimiters for variable parsing.
+}
+
+var (
+ defaultLanguage = "en" // defaultDelimiters defines the default language if user does not specified in options.
+ defaultDelimiters = []string{"{#", "}"} // defaultDelimiters defines the default key variable delimiters.
+)
+
+// New creates and returns a new i18n manager.
+// The optional parameter `option` specifies the custom options for i18n manager.
+// It uses a default one if it's not passed.
+func New(options ...Options) *Manager {
+ var opts Options
+ if len(options) > 0 {
+ opts = options[0]
+ } else {
+ opts = DefaultOptions()
+ }
+ if len(opts.Language) == 0 {
+ opts.Language = defaultLanguage
+ }
+ if len(opts.Delimiters) == 0 {
+ opts.Delimiters = defaultDelimiters
+ }
+ m := &Manager{
+ options: opts,
+ pattern: fmt.Sprintf(
+ `%s(\w+)%s`,
+ gregex.Quote(opts.Delimiters[0]),
+ gregex.Quote(opts.Delimiters[1]),
+ ),
+ }
+ intlog.Printf(context.TODO(), `New: %#v`, m)
+ return m
+}
+
+// DefaultOptions creates and returns a default options for i18n manager.
+func DefaultOptions() Options {
+ var (
+ path = "i18n"
+ realPath, _ = gfile.Search(path)
+ )
+ if realPath != "" {
+ path = realPath
+ // To avoid of the source path of GF: github.com/gogf/i18n/gi18n
+ if gfile.Exists(path + gfile.Separator + "gi18n") {
+ path = ""
+ }
+ }
+ return Options{
+ Path: path,
+ Language: "en",
+ Delimiters: defaultDelimiters,
+ }
+}
+
+// SetPath sets the directory path storing i18n files.
+func (m *Manager) SetPath(path string) error {
+ if gres.Contains(path) {
+ m.options.Path = path
+ } else {
+ realPath, _ := gfile.Search(path)
+ if realPath == "" {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `%s does not exist`, path)
+ }
+ m.options.Path = realPath
+ }
+ intlog.Printf(context.TODO(), `SetPath: %s`, m.options.Path)
+ return nil
+}
+
+// SetLanguage sets the language for translator.
+func (m *Manager) SetLanguage(language string) {
+ m.options.Language = language
+ intlog.Printf(context.TODO(), `SetLanguage: %s`, m.options.Language)
+}
+
+// SetDelimiters sets the delimiters for translator.
+func (m *Manager) SetDelimiters(left, right string) {
+ m.pattern = fmt.Sprintf(`%s(\w+)%s`, gregex.Quote(left), gregex.Quote(right))
+ intlog.Printf(context.TODO(), `SetDelimiters: %v`, m.pattern)
+}
+
+// T is alias of Translate for convenience.
+func (m *Manager) T(ctx context.Context, content string) string {
+ return m.Translate(ctx, content)
+}
+
+// Tf is alias of TranslateFormat for convenience.
+func (m *Manager) Tf(ctx context.Context, format string, values ...interface{}) string {
+ return m.TranslateFormat(ctx, format, values...)
+}
+
+// TranslateFormat translates, formats and returns the `format` with configured language
+// and given `values`.
+func (m *Manager) TranslateFormat(ctx context.Context, format string, values ...interface{}) string {
+ return fmt.Sprintf(m.Translate(ctx, format), values...)
+}
+
+// Translate translates `content` with configured language.
+func (m *Manager) Translate(ctx context.Context, content string) string {
+ m.init(ctx)
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ transLang := m.options.Language
+ if lang := LanguageFromCtx(ctx); lang != "" {
+ transLang = lang
+ }
+ data := m.data[transLang]
+ if data == nil {
+ return content
+ }
+ // Parse content as name.
+ if v, ok := data[content]; ok {
+ return v
+ }
+ // Parse content as variables container.
+ result, _ := gregex.ReplaceStringFuncMatch(
+ m.pattern, content,
+ func(match []string) string {
+ if v, ok := data[match[1]]; ok {
+ return v
+ }
+ return match[0]
+ })
+ intlog.Printf(ctx, `Translate for language: %s`, transLang)
+ return result
+}
+
+// GetContent retrieves and returns the configured content for given key and specified language.
+// It returns an empty string if not found.
+func (m *Manager) GetContent(ctx context.Context, key string) string {
+ m.init(ctx)
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ transLang := m.options.Language
+ if lang := LanguageFromCtx(ctx); lang != "" {
+ transLang = lang
+ }
+ if data, ok := m.data[transLang]; ok {
+ return data[key]
+ }
+ return ""
+}
+
+// init initializes the manager for lazy initialization design.
+// The i18n manager is only initialized once.
+func (m *Manager) init(ctx context.Context) {
+ m.mu.RLock()
+ // If the data is not nil, means it's already initialized.
+ if m.data != nil {
+ m.mu.RUnlock()
+ return
+ }
+ m.mu.RUnlock()
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if gres.Contains(m.options.Path) {
+ files := gres.ScanDirFile(m.options.Path, "*.*", true)
+ if len(files) > 0 {
+ var (
+ path string
+ name string
+ lang string
+ array []string
+ )
+ m.data = make(map[string]map[string]string)
+ for _, file := range files {
+ name = file.Name()
+ path = name[len(m.options.Path)+1:]
+ array = strings.Split(path, "/")
+ if len(array) > 1 {
+ lang = array[0]
+ } else {
+ lang = gfile.Name(array[0])
+ }
+ if m.data[lang] == nil {
+ m.data[lang] = make(map[string]string)
+ }
+ if j, err := gjson.LoadContent(file.Content()); err == nil {
+ for k, v := range j.Var().Map() {
+ m.data[lang][k] = gconv.String(v)
+ }
+ } else {
+ intlog.Errorf(ctx, "load i18n file '%s' failed: %+v", name, err)
+ }
+ }
+ }
+ } else if m.options.Path != "" {
+ files, _ := gfile.ScanDirFile(m.options.Path, "*.*", true)
+ if len(files) == 0 {
+ return
+ }
+ var (
+ path string
+ lang string
+ array []string
+ )
+ m.data = make(map[string]map[string]string)
+ for _, file := range files {
+ path = file[len(m.options.Path)+1:]
+ array = strings.Split(path, gfile.Separator)
+ if len(array) > 1 {
+ lang = array[0]
+ } else {
+ lang = gfile.Name(array[0])
+ }
+ if m.data[lang] == nil {
+ m.data[lang] = make(map[string]string)
+ }
+ if j, err := gjson.LoadContent(gfile.GetBytes(file)); err == nil {
+ for k, v := range j.Var().Map() {
+ m.data[lang][k] = gconv.String(v)
+ }
+ } else {
+ intlog.Errorf(ctx, "load i18n file '%s' failed: %+v", file, err)
+ }
+ }
+ // Monitor changes of i18n files for hot reload feature.
+ _, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
+ // Any changes of i18n files, clear the data.
+ m.mu.Lock()
+ m.data = nil
+ m.mu.Unlock()
+ gfsnotify.Exit()
+ })
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/command/command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/command/command.go
new file mode 100644
index 000000000000..e704e6a9f094
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/command/command.go
@@ -0,0 +1,135 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+// Package command provides console operations, like options/arguments reading.
+package command
+
+import (
+ "os"
+ "regexp"
+ "strings"
+)
+
+var (
+ defaultParsedArgs = make([]string, 0)
+ defaultParsedOptions = make(map[string]string)
+ argumentRegex = regexp.MustCompile(`^\-{1,2}([\w\?\.\-]+)(=){0,1}(.*)$`)
+)
+
+// Init does custom initialization.
+func Init(args ...string) {
+ if len(args) == 0 {
+ if len(defaultParsedArgs) == 0 && len(defaultParsedOptions) == 0 {
+ args = os.Args
+ } else {
+ return
+ }
+ } else {
+ defaultParsedArgs = make([]string, 0)
+ defaultParsedOptions = make(map[string]string)
+ }
+ // Parsing os.Args with default algorithm.
+ defaultParsedArgs, defaultParsedOptions = ParseUsingDefaultAlgorithm(args...)
+}
+
+// ParseUsingDefaultAlgorithm parses arguments using default algorithm.
+func ParseUsingDefaultAlgorithm(args ...string) (parsedArgs []string, parsedOptions map[string]string) {
+ parsedArgs = make([]string, 0)
+ parsedOptions = make(map[string]string)
+ for i := 0; i < len(args); {
+ array := argumentRegex.FindStringSubmatch(args[i])
+ if len(array) > 2 {
+ if array[2] == "=" {
+ parsedOptions[array[1]] = array[3]
+ } else if i < len(args)-1 {
+ if len(args[i+1]) > 0 && args[i+1][0] == '-' {
+ // Eg: gf gen -d -n 1
+ parsedOptions[array[1]] = array[3]
+ } else {
+ // Eg: gf gen -n 2
+ parsedOptions[array[1]] = args[i+1]
+ i += 2
+ continue
+ }
+ } else {
+ // Eg: gf gen -h
+ parsedOptions[array[1]] = array[3]
+ }
+ } else {
+ parsedArgs = append(parsedArgs, args[i])
+ }
+ i++
+ }
+ return
+}
+
+// GetOpt returns the option value named `name`.
+func GetOpt(name string, def ...string) string {
+ Init()
+ if v, ok := defaultParsedOptions[name]; ok {
+ return v
+ }
+ if len(def) > 0 {
+ return def[0]
+ }
+ return ""
+}
+
+// GetOptAll returns all parsed options.
+func GetOptAll() map[string]string {
+ Init()
+ return defaultParsedOptions
+}
+
+// ContainsOpt checks whether option named `name` exist in the arguments.
+func ContainsOpt(name string) bool {
+ Init()
+ _, ok := defaultParsedOptions[name]
+ return ok
+}
+
+// GetArg returns the argument at `index`.
+func GetArg(index int, def ...string) string {
+ Init()
+ if index < len(defaultParsedArgs) {
+ return defaultParsedArgs[index]
+ }
+ if len(def) > 0 {
+ return def[0]
+ }
+ return ""
+}
+
+// GetArgAll returns all parsed arguments.
+func GetArgAll() []string {
+ Init()
+ return defaultParsedArgs
+}
+
+// GetOptWithEnv returns the command line argument of the specified `key`.
+// If the argument does not exist, then it returns the environment variable with specified `key`.
+// It returns the default value `def` if none of them exists.
+//
+// Fetching Rules:
+// 1. Command line arguments are in lowercase format, eg: gf.package.variable;
+// 2. Environment arguments are in uppercase format, eg: GF_PACKAGE_VARIABLE;
+func GetOptWithEnv(key string, def ...string) string {
+ cmdKey := strings.ToLower(strings.Replace(key, "_", ".", -1))
+ if ContainsOpt(cmdKey) {
+ return GetOpt(cmdKey)
+ } else {
+ envKey := strings.ToUpper(strings.Replace(key, ".", "_", -1))
+ if r, ok := os.LookupEnv(envKey); ok {
+ return r
+ } else {
+ if len(def) > 0 {
+ return def[0]
+ }
+ }
+ }
+ return ""
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/empty/empty.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/empty/empty.go
new file mode 100644
index 000000000000..88b53c814a97
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/empty/empty.go
@@ -0,0 +1,220 @@
+// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package empty provides functions for checking empty/nil variables.
+package empty
+
+import (
+ "reflect"
+ "time"
+)
+
+// iString is used for type assert api for String().
+type iString interface {
+ String() string
+}
+
+// iInterfaces is used for type assert api for Interfaces.
+type iInterfaces interface {
+ Interfaces() []interface{}
+}
+
+// iMapStrAny is the interface support for converting struct parameter to map.
+type iMapStrAny interface {
+ MapStrAny() map[string]interface{}
+}
+
+type iTime interface {
+ Date() (year int, month time.Month, day int)
+ IsZero() bool
+}
+
+// IsEmpty checks whether given `value` empty.
+// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0,
+// or else it returns false.
+func IsEmpty(value interface{}) bool {
+ if value == nil {
+ return true
+ }
+ // It firstly checks the variable as common types using assertion to enhance the performance,
+ // and then using reflection.
+ switch result := value.(type) {
+ case int:
+ return result == 0
+ case int8:
+ return result == 0
+ case int16:
+ return result == 0
+ case int32:
+ return result == 0
+ case int64:
+ return result == 0
+ case uint:
+ return result == 0
+ case uint8:
+ return result == 0
+ case uint16:
+ return result == 0
+ case uint32:
+ return result == 0
+ case uint64:
+ return result == 0
+ case float32:
+ return result == 0
+ case float64:
+ return result == 0
+ case bool:
+ return result == false
+ case string:
+ return result == ""
+ case []byte:
+ return len(result) == 0
+ case []rune:
+ return len(result) == 0
+ case []int:
+ return len(result) == 0
+ case []string:
+ return len(result) == 0
+ case []float32:
+ return len(result) == 0
+ case []float64:
+ return len(result) == 0
+ case map[string]interface{}:
+ return len(result) == 0
+
+ default:
+ // =========================
+ // Common interfaces checks.
+ // =========================
+ if f, ok := value.(iTime); ok {
+ if f == nil {
+ return true
+ }
+ return f.IsZero()
+ }
+ if f, ok := value.(iString); ok {
+ if f == nil {
+ return true
+ }
+ return f.String() == ""
+ }
+ if f, ok := value.(iInterfaces); ok {
+ if f == nil {
+ return true
+ }
+ return len(f.Interfaces()) == 0
+ }
+ if f, ok := value.(iMapStrAny); ok {
+ if f == nil {
+ return true
+ }
+ return len(f.MapStrAny()) == 0
+ }
+ // Finally, using reflect.
+ var rv reflect.Value
+ if v, ok := value.(reflect.Value); ok {
+ rv = v
+ } else {
+ rv = reflect.ValueOf(value)
+ }
+
+ switch rv.Kind() {
+ case reflect.Bool:
+ return !rv.Bool()
+
+ case
+ reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64:
+ return rv.Int() == 0
+
+ case
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64,
+ reflect.Uintptr:
+ return rv.Uint() == 0
+
+ case
+ reflect.Float32,
+ reflect.Float64:
+ return rv.Float() == 0
+
+ case reflect.String:
+ return rv.Len() == 0
+
+ case reflect.Struct:
+ for i := 0; i < rv.NumField(); i++ {
+ if !IsEmpty(rv.Field(i).Interface()) {
+ return false
+ }
+ }
+ return true
+
+ case
+ reflect.Chan,
+ reflect.Map,
+ reflect.Slice,
+ reflect.Array:
+ return rv.Len() == 0
+
+ case
+ reflect.Func,
+ reflect.Ptr,
+ reflect.Interface,
+ reflect.UnsafePointer:
+ if rv.IsNil() {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// IsNil checks whether given `value` is nil, especially for interface{} type value.
+// Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pinter
+// that also points to a pointer. It returns nil if the source is nil when `traceSource` is true.
+// Note that it might use reflect feature which affects performance a little.
+func IsNil(value interface{}, traceSource ...bool) bool {
+ if value == nil {
+ return true
+ }
+ var rv reflect.Value
+ if v, ok := value.(reflect.Value); ok {
+ rv = v
+ } else {
+ rv = reflect.ValueOf(value)
+ }
+ switch rv.Kind() {
+ case reflect.Chan,
+ reflect.Map,
+ reflect.Slice,
+ reflect.Func,
+ reflect.Interface,
+ reflect.UnsafePointer:
+ return !rv.IsValid() || rv.IsNil()
+
+ case reflect.Ptr:
+ if len(traceSource) > 0 && traceSource[0] {
+ for rv.Kind() == reflect.Ptr {
+ rv = rv.Elem()
+ }
+ if !rv.IsValid() {
+ return true
+ }
+ if rv.Kind() == reflect.Ptr {
+ return rv.IsNil()
+ }
+ } else {
+ return !rv.IsValid() || rv.IsNil()
+ }
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/fileinfo/fileinfo.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/fileinfo/fileinfo.go
new file mode 100644
index 000000000000..d469e3ca792e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/fileinfo/fileinfo.go
@@ -0,0 +1,53 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package fileinfo provides virtual os.FileInfo for given information.
+package fileinfo
+
+import (
+ "os"
+ "time"
+)
+
+type Info struct {
+ name string
+ size int64
+ mode os.FileMode
+ modTime time.Time
+}
+
+func New(name string, size int64, mode os.FileMode, modTime time.Time) *Info {
+ return &Info{
+ name: name,
+ size: size,
+ mode: mode,
+ modTime: modTime,
+ }
+}
+
+func (i *Info) Name() string {
+ return i.name
+}
+
+func (i *Info) Size() int64 {
+ return i.size
+}
+
+func (i *Info) IsDir() bool {
+ return i.mode.IsDir()
+}
+
+func (i *Info) Mode() os.FileMode {
+ return i.mode
+}
+
+func (i *Info) ModTime() time.Time {
+ return i.modTime
+}
+
+func (i *Info) Sys() interface{} {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/httputil/httputils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/httputil/httputils.go
new file mode 100644
index 000000000000..7149938b9cc9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/httputil/httputils.go
@@ -0,0 +1,80 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package httputil
+
+import (
+ "net/http"
+ "strings"
+
+ "github.com/gogf/gf/v2/encoding/gurl"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ fileUploadingKey = "@file:"
+)
+
+// BuildParams builds the request string for the http client. The `params` can be type of:
+// string/[]byte/map/struct/*struct.
+//
+// The optional parameter `noUrlEncode` specifies whether ignore the url encoding for the data.
+func BuildParams(params interface{}, noUrlEncode ...bool) (encodedParamStr string) {
+ // If given string/[]byte, converts and returns it directly as string.
+ switch v := params.(type) {
+ case string, []byte:
+ return gconv.String(params)
+ case []interface{}:
+ if len(v) > 0 {
+ params = v[0]
+ } else {
+ params = nil
+ }
+ }
+ // Else converts it to map and does the url encoding.
+ m, urlEncode := gconv.Map(params), true
+ if len(m) == 0 {
+ return gconv.String(params)
+ }
+ if len(noUrlEncode) == 1 {
+ urlEncode = !noUrlEncode[0]
+ }
+ // If there's file uploading, it ignores the url encoding.
+ if urlEncode {
+ for k, v := range m {
+ if gstr.Contains(k, fileUploadingKey) || gstr.Contains(gconv.String(v), fileUploadingKey) {
+ urlEncode = false
+ break
+ }
+ }
+ }
+ s := ""
+ for k, v := range m {
+ if len(encodedParamStr) > 0 {
+ encodedParamStr += "&"
+ }
+ s = gconv.String(v)
+ if urlEncode && len(s) > 6 && strings.Compare(s[0:6], fileUploadingKey) != 0 {
+ s = gurl.Encode(s)
+ }
+ encodedParamStr += k + "=" + s
+ }
+ return
+}
+
+// HeaderToMap coverts request headers to map.
+func HeaderToMap(header http.Header) map[string]interface{} {
+ m := make(map[string]interface{})
+ for k, v := range header {
+ if len(v) > 1 {
+ m[k] = v
+ } else {
+ m[k] = v[0]
+ }
+ }
+ return m
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/intlog/intlog.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/intlog/intlog.go
new file mode 100644
index 000000000000..02245d5a86cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/intlog/intlog.go
@@ -0,0 +1,142 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package intlog provides internal logging for GoFrame development usage only.
+package intlog
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "path/filepath"
+ "time"
+
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2/debug/gdebug"
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+const (
+ stackFilterKey = "/internal/intlog"
+)
+
+var (
+ // isGFDebug marks whether printing GoFrame debug information.
+ isGFDebug = false
+)
+
+func init() {
+ isGFDebug = utils.IsDebugEnabled()
+}
+
+// SetEnabled enables/disables the internal logging manually.
+// Note that this function is not concurrent safe, be aware of the DATA RACE.
+func SetEnabled(enabled bool) {
+ // If they're the same, it does not write the `isGFDebug` but only reading operation.
+ if isGFDebug != enabled {
+ isGFDebug = enabled
+ }
+}
+
+// Print prints `v` with newline using fmt.Println.
+// The parameter `v` can be multiple variables.
+func Print(ctx context.Context, v ...interface{}) {
+ if !isGFDebug {
+ return
+ }
+ doPrint(ctx, fmt.Sprint(v...), false)
+}
+
+// Printf prints `v` with format `format` using fmt.Printf.
+// The parameter `v` can be multiple variables.
+func Printf(ctx context.Context, format string, v ...interface{}) {
+ if !isGFDebug {
+ return
+ }
+ doPrint(ctx, fmt.Sprintf(format, v...), false)
+}
+
+// Error prints `v` with newline using fmt.Println.
+// The parameter `v` can be multiple variables.
+func Error(ctx context.Context, v ...interface{}) {
+ if !isGFDebug {
+ return
+ }
+ doPrint(ctx, fmt.Sprint(v...), true)
+}
+
+// Errorf prints `v` with format `format` using fmt.Printf.
+func Errorf(ctx context.Context, format string, v ...interface{}) {
+ if !isGFDebug {
+ return
+ }
+ doPrint(ctx, fmt.Sprintf(format, v...), true)
+}
+
+// PrintFunc prints the output from function `f`.
+// It only calls function `f` if debug mode is enabled.
+func PrintFunc(ctx context.Context, f func() string) {
+ if !isGFDebug {
+ return
+ }
+ s := f()
+ if s == "" {
+ return
+ }
+ doPrint(ctx, s, false)
+}
+
+// ErrorFunc prints the output from function `f`.
+// It only calls function `f` if debug mode is enabled.
+func ErrorFunc(ctx context.Context, f func() string) {
+ if !isGFDebug {
+ return
+ }
+ s := f()
+ if s == "" {
+ return
+ }
+ doPrint(ctx, s, true)
+}
+
+func doPrint(ctx context.Context, content string, stack bool) {
+ if !isGFDebug {
+ return
+ }
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteString(time.Now().Format("2006-01-02 15:04:05.000"))
+ buffer.WriteString(" [INTE] ")
+ buffer.WriteString(file())
+ buffer.WriteString(" ")
+ if s := traceIdStr(ctx); s != "" {
+ buffer.WriteString(s + " ")
+ }
+ buffer.WriteString(content)
+ buffer.WriteString("\n")
+ if stack {
+ buffer.WriteString(gdebug.StackWithFilter([]string{stackFilterKey}))
+ }
+ fmt.Print(buffer.String())
+}
+
+// traceIdStr retrieves and returns the trace id string for logging output.
+func traceIdStr(ctx context.Context) string {
+ if ctx == nil {
+ return ""
+ }
+ spanCtx := trace.SpanContextFromContext(ctx)
+ if traceId := spanCtx.TraceID(); traceId.IsValid() {
+ return "{" + traceId.String() + "}"
+ }
+ return ""
+}
+
+// file returns caller file name along with its line number.
+func file() string {
+ _, p, l := gdebug.CallerWithFilter([]string{stackFilterKey})
+ return fmt.Sprintf(`%s:%d`, filepath.Base(p), l)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/json/json.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/json/json.go
new file mode 100644
index 000000000000..374aec688eeb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/json/json.go
@@ -0,0 +1,85 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package json provides json operations wrapping ignoring stdlib or third-party lib json.
+package json
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// RawMessage is a raw encoded JSON value.
+// It implements Marshaler and Unmarshaler and can
+// be used to delay JSON decoding or precompute a JSON encoding.
+type RawMessage = json.RawMessage
+
+// Marshal adapts to json/encoding Marshal API.
+//
+// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API
+// Refer to https://godoc.org/encoding/json#Marshal for more information.
+func Marshal(v interface{}) (marshaledBytes []byte, err error) {
+ marshaledBytes, err = json.Marshal(v)
+ if err != nil {
+ err = gerror.Wrap(err, `json.Marshal failed`)
+ }
+ return
+}
+
+// MarshalIndent same as json.MarshalIndent.
+func MarshalIndent(v interface{}, prefix, indent string) (marshaledBytes []byte, err error) {
+ marshaledBytes, err = json.MarshalIndent(v, prefix, indent)
+ if err != nil {
+ err = gerror.Wrap(err, `json.MarshalIndent failed`)
+ }
+ return
+}
+
+// Unmarshal adapts to json/encoding Unmarshal API
+//
+// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.
+// Refer to https://godoc.org/encoding/json#Unmarshal for more information.
+func Unmarshal(data []byte, v interface{}) (err error) {
+ err = json.Unmarshal(data, v)
+ if err != nil {
+ err = gerror.Wrap(err, `json.Unmarshal failed`)
+ }
+ return
+}
+
+// UnmarshalUseNumber decodes the json data bytes to target interface using number option.
+func UnmarshalUseNumber(data []byte, v interface{}) (err error) {
+ decoder := NewDecoder(bytes.NewReader(data))
+ decoder.UseNumber()
+ err = decoder.Decode(v)
+ if err != nil {
+ err = gerror.Wrap(err, `json.UnmarshalUseNumber failed`)
+ }
+ return
+}
+
+// NewEncoder same as json.NewEncoder
+func NewEncoder(writer io.Writer) *json.Encoder {
+ return json.NewEncoder(writer)
+}
+
+// NewDecoder adapts to json/stream NewDecoder API.
+//
+// NewDecoder returns a new decoder that reads from r.
+//
+// Instead of a json/encoding Decoder, a Decoder is returned
+// Refer to https://godoc.org/encoding/json#NewDecoder for more information.
+func NewDecoder(reader io.Reader) *json.Decoder {
+ return json.NewDecoder(reader)
+}
+
+// Valid reports whether data is a valid JSON encoding.
+func Valid(data []byte) bool {
+ return json.Valid(data)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/rwmutex/rwmutex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/rwmutex/rwmutex.go
new file mode 100644
index 000000000000..0d16fb7d38cd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/rwmutex/rwmutex.go
@@ -0,0 +1,73 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package rwmutex provides switch of concurrent safety feature for sync.RWMutex.
+package rwmutex
+
+import "sync"
+
+// RWMutex is a sync.RWMutex with a switch for concurrent safe feature.
+// If its attribute *sync.RWMutex is not nil, it means it's in concurrent safety usage.
+// Its attribute *sync.RWMutex is nil in default, which makes this struct mush lightweight.
+type RWMutex struct {
+ *sync.RWMutex
+}
+
+// New creates and returns a new *RWMutex.
+// The parameter `safe` is used to specify whether using this mutex in concurrent safety,
+// which is false in default.
+func New(safe ...bool) *RWMutex {
+ mu := Create(safe...)
+ return &mu
+}
+
+// Create creates and returns a new RWMutex object.
+// The parameter `safe` is used to specify whether using this mutex in concurrent safety,
+// which is false in default.
+func Create(safe ...bool) RWMutex {
+ mu := RWMutex{}
+ if len(safe) > 0 && safe[0] {
+ mu.RWMutex = new(sync.RWMutex)
+ }
+ return mu
+}
+
+// IsSafe checks and returns whether current mutex is in concurrent-safe usage.
+func (mu *RWMutex) IsSafe() bool {
+ return mu.RWMutex != nil
+}
+
+// Lock locks mutex for writing.
+// It does nothing if it is not in concurrent-safe usage.
+func (mu *RWMutex) Lock() {
+ if mu.RWMutex != nil {
+ mu.RWMutex.Lock()
+ }
+}
+
+// Unlock unlocks mutex for writing.
+// It does nothing if it is not in concurrent-safe usage.
+func (mu *RWMutex) Unlock() {
+ if mu.RWMutex != nil {
+ mu.RWMutex.Unlock()
+ }
+}
+
+// RLock locks mutex for reading.
+// It does nothing if it is not in concurrent-safe usage.
+func (mu *RWMutex) RLock() {
+ if mu.RWMutex != nil {
+ mu.RWMutex.RLock()
+ }
+}
+
+// RUnlock unlocks mutex for reading.
+// It does nothing if it is not in concurrent-safe usage.
+func (mu *RWMutex) RUnlock() {
+ if mu.RWMutex != nil {
+ mu.RWMutex.RUnlock()
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/tracing/tracing.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/tracing/tracing.go
new file mode 100644
index 000000000000..250cb39f32a3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/tracing/tracing.go
@@ -0,0 +1,48 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package tracing provides some utility functions for tracing functionality.
+package tracing
+
+import (
+ "math"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/encoding/gbinary"
+ "github.com/gogf/gf/v2/util/grand"
+ "go.opentelemetry.io/otel/trace"
+)
+
+var (
+ randomInitSequence = int32(grand.Intn(math.MaxInt32))
+ sequence = gtype.NewInt32(randomInitSequence)
+)
+
+// NewIDs creates and returns a new trace and span ID.
+func NewIDs() (traceID trace.TraceID, spanID trace.SpanID) {
+ return NewTraceID(), NewSpanID()
+}
+
+// NewTraceID creates and returns a trace ID.
+func NewTraceID() (traceID trace.TraceID) {
+ var (
+ timestampNanoBytes = gbinary.EncodeInt64(time.Now().UnixNano())
+ sequenceBytes = gbinary.EncodeInt32(sequence.Add(1))
+ randomBytes = grand.B(4)
+ )
+ copy(traceID[:], timestampNanoBytes)
+ copy(traceID[8:], sequenceBytes)
+ copy(traceID[12:], randomBytes)
+ return
+}
+
+// NewSpanID creates and returns a span ID.
+func NewSpanID() (spanID trace.SpanID) {
+ copy(spanID[:], gbinary.EncodeInt64(time.Now().UnixNano()/1e3))
+ copy(spanID[4:], grand.B(4))
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils.go
new file mode 100644
index 000000000000..414a90ca029b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package utils provides some utility functions for internal usage.
+package utils
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_array.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_array.go
new file mode 100644
index 000000000000..b96e039e6fa1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_array.go
@@ -0,0 +1,26 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import "reflect"
+
+// IsArray checks whether given value is array/slice.
+// Note that it uses reflect internally implementing this feature.
+func IsArray(value interface{}) bool {
+ rv := reflect.ValueOf(value)
+ kind := rv.Kind()
+ if kind == reflect.Ptr {
+ rv = rv.Elem()
+ kind = rv.Kind()
+ }
+ switch kind {
+ case reflect.Array, reflect.Slice:
+ return true
+ default:
+ return false
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_debug.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_debug.go
new file mode 100644
index 000000000000..0b2fc17e69d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_debug.go
@@ -0,0 +1,41 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import (
+ "github.com/gogf/gf/v2/internal/command"
+)
+
+const (
+ // Debug key for checking if in debug mode.
+ commandEnvKeyForDebugKey = "gf.debug"
+
+ // StackFilterKeyForGoFrame is the stack filtering key for all GoFrame module paths.
+ // Eg: .../pkg/mod/github.com/gogf/gf/v2@v2.0.0-20211011134327-54dd11f51122/debug/gdebug/gdebug_caller.go
+ StackFilterKeyForGoFrame = "github.com/gogf/gf/"
+)
+
+var (
+ // isDebugEnabled marks whether GoFrame debug mode is enabled.
+ isDebugEnabled = false
+)
+
+func init() {
+ // Debugging configured.
+ value := command.GetOptWithEnv(commandEnvKeyForDebugKey)
+ if value == "" || value == "0" || value == "false" {
+ isDebugEnabled = false
+ } else {
+ isDebugEnabled = true
+ }
+}
+
+// IsDebugEnabled checks and returns whether debug mode is enabled.
+// The debug mode is enabled when command argument "gf.debug" or environment "GF_DEBUG" is passed.
+func IsDebugEnabled() bool {
+ return isDebugEnabled
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_io.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_io.go
new file mode 100644
index 000000000000..f51bbe3b8126
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_io.go
@@ -0,0 +1,66 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import (
+ "io"
+ "io/ioutil"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// ReadCloser implements the io.ReadCloser interface
+// which is used for reading request body content multiple times.
+//
+// Note that it cannot be closed.
+type ReadCloser struct {
+ index int // Current read position.
+ content []byte // Content.
+ repeatable bool
+}
+
+// NewReadCloser creates and returns a RepeatReadCloser object.
+func NewReadCloser(content []byte, repeatable bool) io.ReadCloser {
+ return &ReadCloser{
+ content: content,
+ repeatable: repeatable,
+ }
+}
+
+// NewReadCloserWithReadCloser creates and returns a RepeatReadCloser object
+// with given io.ReadCloser.
+func NewReadCloserWithReadCloser(r io.ReadCloser, repeatable bool) (io.ReadCloser, error) {
+ content, err := ioutil.ReadAll(r)
+ if err != nil {
+ err = gerror.Wrapf(err, `ioutil.ReadAll failed`)
+ return nil, err
+ }
+ defer r.Close()
+ return &ReadCloser{
+ content: content,
+ repeatable: repeatable,
+ }, nil
+}
+
+// Read implements the io.ReadCloser interface.
+func (b *ReadCloser) Read(p []byte) (n int, err error) {
+ n = copy(p, b.content[b.index:])
+ b.index += n
+ if b.index >= len(b.content) {
+ // Make it repeatable reading.
+ if b.repeatable {
+ b.index = 0
+ }
+ return n, io.EOF
+ }
+ return n, nil
+}
+
+// Close implements the io.ReadCloser interface.
+func (b *ReadCloser) Close() error {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_is.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_is.go
new file mode 100644
index 000000000000..778d45ed9745
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_is.go
@@ -0,0 +1,99 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/empty"
+)
+
+// IsNil checks whether `value` is nil, especially for interface{} type value.
+func IsNil(value interface{}) bool {
+ return empty.IsNil(value)
+}
+
+// IsEmpty checks whether `value` is empty.
+func IsEmpty(value interface{}) bool {
+ return empty.IsEmpty(value)
+}
+
+// IsInt checks whether `value` is type of int.
+func IsInt(value interface{}) bool {
+ switch value.(type) {
+ case int, *int, int8, *int8, int16, *int16, int32, *int32, int64, *int64:
+ return true
+ }
+ return false
+}
+
+// IsUint checks whether `value` is type of uint.
+func IsUint(value interface{}) bool {
+ switch value.(type) {
+ case uint, *uint, uint8, *uint8, uint16, *uint16, uint32, *uint32, uint64, *uint64:
+ return true
+ }
+ return false
+}
+
+// IsFloat checks whether `value` is type of float.
+func IsFloat(value interface{}) bool {
+ switch value.(type) {
+ case float32, *float32, float64, *float64:
+ return true
+ }
+ return false
+}
+
+// IsSlice checks whether `value` is type of slice.
+func IsSlice(value interface{}) bool {
+ var (
+ reflectValue = reflect.ValueOf(value)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ }
+ switch reflectKind {
+ case reflect.Slice, reflect.Array:
+ return true
+ }
+ return false
+}
+
+// IsMap checks whether `value` is type of map.
+func IsMap(value interface{}) bool {
+ var (
+ reflectValue = reflect.ValueOf(value)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ }
+ switch reflectKind {
+ case reflect.Map:
+ return true
+ }
+ return false
+}
+
+// IsStruct checks whether `value` is type of struct.
+func IsStruct(value interface{}) bool {
+ var (
+ reflectValue = reflect.ValueOf(value)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Struct:
+ return true
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_list.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_list.go
new file mode 100644
index 000000000000..355ad9f8e7af
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_list.go
@@ -0,0 +1,37 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import "fmt"
+
+// ListToMapByKey converts `list` to a map[string]interface{} of which key is specified by `key`.
+// Note that the item value may be type of slice.
+func ListToMapByKey(list []map[string]interface{}, key string) map[string]interface{} {
+ var (
+ s = ""
+ m = make(map[string]interface{})
+ tempMap = make(map[string][]interface{})
+ hasMultiValues bool
+ )
+ for _, item := range list {
+ if k, ok := item[key]; ok {
+ s = fmt.Sprintf(`%v`, k)
+ tempMap[s] = append(tempMap[s], item)
+ if len(tempMap[s]) > 1 {
+ hasMultiValues = true
+ }
+ }
+ }
+ for k, v := range tempMap {
+ if hasMultiValues {
+ m[k] = v
+ } else {
+ m[k] = v[0]
+ }
+ }
+ return m
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_map.go
new file mode 100644
index 000000000000..fba7da77c851
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_map.go
@@ -0,0 +1,37 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.
+//
+// Note that this function might be of low performance.
+func MapPossibleItemByKey(data map[string]interface{}, key string) (foundKey string, foundValue interface{}) {
+ if len(data) == 0 {
+ return
+ }
+ if v, ok := data[key]; ok {
+ return key, v
+ }
+ // Loop checking.
+ for k, v := range data {
+ if EqualFoldWithoutChars(k, key) {
+ return k, v
+ }
+ }
+ return "", nil
+}
+
+// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.
+// It checks the key ignoring cases and symbols.
+//
+// Note that this function might be of low performance.
+func MapContainsPossibleKey(data map[string]interface{}, key string) bool {
+ if k, _ := MapPossibleItemByKey(data, key); k != "" {
+ return true
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_reflect.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_reflect.go
new file mode 100644
index 000000000000..f8c4df94ea34
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_reflect.go
@@ -0,0 +1,61 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import "reflect"
+
+type OriginValueAndKindOutput struct {
+ InputValue reflect.Value
+ InputKind reflect.Kind
+ OriginValue reflect.Value
+ OriginKind reflect.Kind
+}
+
+// OriginValueAndKind retrieves and returns the original reflect value and kind.
+func OriginValueAndKind(value interface{}) (out OriginValueAndKindOutput) {
+ if v, ok := value.(reflect.Value); ok {
+ out.InputValue = v
+ } else {
+ out.InputValue = reflect.ValueOf(value)
+ }
+ out.InputKind = out.InputValue.Kind()
+ out.OriginValue = out.InputValue
+ out.OriginKind = out.InputKind
+ for out.OriginKind == reflect.Ptr {
+ out.OriginValue = out.OriginValue.Elem()
+ out.OriginKind = out.OriginValue.Kind()
+ }
+ return
+}
+
+type OriginTypeAndKindOutput struct {
+ InputType reflect.Type
+ InputKind reflect.Kind
+ OriginType reflect.Type
+ OriginKind reflect.Kind
+}
+
+// OriginTypeAndKind retrieves and returns the original reflect type and kind.
+func OriginTypeAndKind(value interface{}) (out OriginTypeAndKindOutput) {
+ if reflectType, ok := value.(reflect.Type); ok {
+ out.InputType = reflectType
+ } else {
+ if reflectValue, ok := value.(reflect.Value); ok {
+ out.InputType = reflectValue.Type()
+ } else {
+ out.InputType = reflect.TypeOf(value)
+ }
+ }
+ out.InputKind = out.InputType.Kind()
+ out.OriginType = out.InputType
+ out.OriginKind = out.InputKind
+ for out.OriginKind == reflect.Ptr {
+ out.OriginType = out.OriginType.Elem()
+ out.OriginKind = out.OriginType.Kind()
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_str.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_str.go
new file mode 100644
index 000000000000..358d7d6855f7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/internal/utils/utils_str.go
@@ -0,0 +1,171 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package utils
+
+import (
+ "bytes"
+ "strings"
+)
+
+var (
+ // DefaultTrimChars are the characters which are stripped by Trim* functions in default.
+ DefaultTrimChars = string([]byte{
+ '\t', // Tab.
+ '\v', // Vertical tab.
+ '\n', // New line (line feed).
+ '\r', // Carriage return.
+ '\f', // New page.
+ ' ', // Ordinary space.
+ 0x00, // NUL-byte.
+ 0x85, // Delete.
+ 0xA0, // Non-breaking space.
+ })
+)
+
+// IsLetterUpper checks whether the given byte b is in upper case.
+func IsLetterUpper(b byte) bool {
+ if b >= byte('A') && b <= byte('Z') {
+ return true
+ }
+ return false
+}
+
+// IsLetterLower checks whether the given byte b is in lower case.
+func IsLetterLower(b byte) bool {
+ if b >= byte('a') && b <= byte('z') {
+ return true
+ }
+ return false
+}
+
+// IsLetter checks whether the given byte b is a letter.
+func IsLetter(b byte) bool {
+ return IsLetterUpper(b) || IsLetterLower(b)
+}
+
+// IsNumeric checks whether the given string s is numeric.
+// Note that float string like "123.456" is also numeric.
+func IsNumeric(s string) bool {
+ var (
+ dotCount = 0
+ length = len(s)
+ )
+ if length == 0 {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if s[i] == '-' && i == 0 {
+ continue
+ }
+ if s[i] == '.' {
+ dotCount++
+ if i > 0 && i < len(s)-1 {
+ continue
+ } else {
+ return false
+ }
+ }
+ if s[i] < '0' || s[i] > '9' {
+ return false
+ }
+ }
+ if dotCount > 1 {
+ return false
+ }
+ return true
+}
+
+// UcFirst returns a copy of the string s with the first letter mapped to its upper case.
+func UcFirst(s string) string {
+ if len(s) == 0 {
+ return s
+ }
+ if IsLetterLower(s[0]) {
+ return string(s[0]-32) + s[1:]
+ }
+ return s
+}
+
+// ReplaceByMap returns a copy of `origin`,
+// which is replaced by a map in unordered way, case-sensitively.
+func ReplaceByMap(origin string, replaces map[string]string) string {
+ for k, v := range replaces {
+ origin = strings.Replace(origin, k, v, -1)
+ }
+ return origin
+}
+
+// RemoveSymbols removes all symbols from string and lefts only numbers and letters.
+func RemoveSymbols(s string) string {
+ var b = make([]rune, 0, len(s))
+ for _, c := range s {
+ if c > 127 {
+ b = append(b, c)
+ } else if (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') {
+ b = append(b, c)
+ }
+ }
+ return string(b)
+}
+
+// EqualFoldWithoutChars checks string `s1` and `s2` equal case-insensitively,
+// with/without chars '-'/'_'/'.'/' '.
+func EqualFoldWithoutChars(s1, s2 string) bool {
+ return strings.EqualFold(RemoveSymbols(s1), RemoveSymbols(s2))
+}
+
+// SplitAndTrim splits string `str` by a string `delimiter` to an array,
+// and calls Trim to every element of this array. It ignores the elements
+// which are empty after Trim.
+func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
+ array := make([]string, 0)
+ for _, v := range strings.Split(str, delimiter) {
+ v = Trim(v, characterMask...)
+ if v != "" {
+ array = append(array, v)
+ }
+ }
+ return array
+}
+
+// Trim strips whitespace (or other characters) from the beginning and end of a string.
+// The optional parameter `characterMask` specifies the additional stripped characters.
+func Trim(str string, characterMask ...string) string {
+ trimChars := DefaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
+ }
+ return strings.Trim(str, trimChars)
+}
+
+// FormatCmdKey formats string `s` as command key using uniformed format.
+func FormatCmdKey(s string) string {
+ return strings.ToLower(strings.Replace(s, "_", ".", -1))
+}
+
+// FormatEnvKey formats string `s` as environment key using uniformed format.
+func FormatEnvKey(s string) string {
+ return strings.ToUpper(strings.Replace(s, ".", "_", -1))
+}
+
+// StripSlashes un-quotes a quoted string by AddSlashes.
+func StripSlashes(str string) string {
+ var buf bytes.Buffer
+ l, skip := len(str), false
+ for i, char := range str {
+ if skip {
+ skip = false
+ } else if char == '\\' {
+ if i+1 < l && str[i+1] == '\\' {
+ skip = true
+ }
+ continue
+ }
+ buf.WriteRune(char)
+ }
+ return buf.String()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient.go
new file mode 100644
index 000000000000..9219fa3b08e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient.go
@@ -0,0 +1,113 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gclient provides convenient http client functionalities.
+package gclient
+
+import (
+ "crypto/rand"
+ "crypto/tls"
+ "fmt"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/gogf/gf/v2"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/net/gsel"
+ "github.com/gogf/gf/v2/os/gfile"
+)
+
+// Client is the HTTP client for HTTP request management.
+type Client struct {
+ http.Client // Underlying HTTP Client.
+ header map[string]string // Custom header map.
+ cookies map[string]string // Custom cookie map.
+ prefix string // Prefix for request.
+ authUser string // HTTP basic authentication: user.
+ authPass string // HTTP basic authentication: pass.
+ retryCount int // Retry count when request fails.
+ retryInterval time.Duration // Retry interval when request fails.
+ middlewareHandler []HandlerFunc // Interceptor handlers
+ selectorBuilder gsel.Builder // Builder for request balance.
+}
+
+const (
+ httpProtocolName = `http`
+ httpParamFileHolder = `@file:`
+ httpRegexParamJson = `^[\w\[\]]+=.+`
+ httpRegexHeaderRaw = `^([\w\-]+):\s*(.+)`
+ httpHeaderHost = `Host`
+ httpHeaderCookie = `Cookie`
+ httpHeaderUserAgent = `User-Agent`
+ httpHeaderContentType = `Content-Type`
+ httpHeaderContentTypeJson = `application/json`
+ httpHeaderContentTypeXml = `application/xml`
+ httpHeaderContentTypeForm = `application/x-www-form-urlencoded`
+)
+
+var (
+ hostname, _ = os.Hostname()
+ defaultClientAgent = fmt.Sprintf(`GClient %s at %s`, gf.VERSION, hostname)
+)
+
+// New creates and returns a new HTTP client object.
+func New() *Client {
+ c := &Client{
+ Client: http.Client{
+ Transport: &http.Transport{
+ // No validation for https certification of the server in default.
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ DisableKeepAlives: true,
+ },
+ },
+ header: make(map[string]string),
+ cookies: make(map[string]string),
+ }
+ c.header[httpHeaderUserAgent] = defaultClientAgent
+ // It enables OpenTelemetry for client in default.
+ c.Use(internalMiddlewareTracing, internalMiddlewareDiscovery)
+ return c
+}
+
+// Clone deeply clones current client and returns a new one.
+func (c *Client) Clone() *Client {
+ newClient := New()
+ *newClient = *c
+ newClient.header = make(map[string]string)
+ newClient.cookies = make(map[string]string)
+ for k, v := range c.header {
+ newClient.header[k] = v
+ }
+ for k, v := range c.cookies {
+ newClient.cookies[k] = v
+ }
+ return newClient
+}
+
+// LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.
+func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {
+ crtPath, err := gfile.Search(crtFile)
+ if err != nil {
+ return nil, err
+ }
+ keyPath, err := gfile.Search(keyFile)
+ if err != nil {
+ return nil, err
+ }
+ crt, err := tls.LoadX509KeyPair(crtPath, keyPath)
+ if err != nil {
+ err = gerror.Wrapf(err, `tls.LoadX509KeyPair failed for certFile "%s", keyFile "%s"`, crtPath, keyPath)
+ return nil, err
+ }
+ tlsConfig := &tls.Config{}
+ tlsConfig.Certificates = []tls.Certificate{crt}
+ tlsConfig.Time = time.Now
+ tlsConfig.Rand = rand.Reader
+ return tlsConfig, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_bytes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_bytes.go
new file mode 100644
index 000000000000..bfdc85e41bf7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_bytes.go
@@ -0,0 +1,75 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// GetBytes sends a GET request, retrieves and returns the result content as bytes.
+func (c *Client) GetBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodGet, url, data...)
+}
+
+// PutBytes sends a PUT request, retrieves and returns the result content as bytes.
+func (c *Client) PutBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodPut, url, data...)
+}
+
+// PostBytes sends a POST request, retrieves and returns the result content as bytes.
+func (c *Client) PostBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodPost, url, data...)
+}
+
+// DeleteBytes sends a DELETE request, retrieves and returns the result content as bytes.
+func (c *Client) DeleteBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodDelete, url, data...)
+}
+
+// HeadBytes sends a HEAD request, retrieves and returns the result content as bytes.
+func (c *Client) HeadBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodHead, url, data...)
+}
+
+// PatchBytes sends a PATCH request, retrieves and returns the result content as bytes.
+func (c *Client) PatchBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodPatch, url, data...)
+}
+
+// ConnectBytes sends a CONNECT request, retrieves and returns the result content as bytes.
+func (c *Client) ConnectBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodConnect, url, data...)
+}
+
+// OptionsBytes sends a OPTIONS request, retrieves and returns the result content as bytes.
+func (c *Client) OptionsBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodOptions, url, data...)
+}
+
+// TraceBytes sends a TRACE request, retrieves and returns the result content as bytes.
+func (c *Client) TraceBytes(ctx context.Context, url string, data ...interface{}) []byte {
+ return c.RequestBytes(ctx, http.MethodTrace, url, data...)
+}
+
+// RequestBytes sends request using given HTTP method and data, retrieves returns the result
+// as bytes. It reads and closes the response object internally automatically.
+func (c *Client) RequestBytes(ctx context.Context, method string, url string, data ...interface{}) []byte {
+ response, err := c.DoRequest(ctx, method, url, data...)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ return nil
+ }
+ defer func() {
+ if err = response.Close(); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }()
+ return response.ReadAll()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_chain.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_chain.go
new file mode 100644
index 000000000000..a24e2c3dbce3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_chain.go
@@ -0,0 +1,114 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "time"
+)
+
+// Prefix is a chaining function,
+// which sets the URL prefix for next request of this client.
+func (c *Client) Prefix(prefix string) *Client {
+ newClient := c.Clone()
+ newClient.SetPrefix(prefix)
+ return newClient
+}
+
+// Header is a chaining function,
+// which sets custom HTTP headers with map for next request.
+func (c *Client) Header(m map[string]string) *Client {
+ newClient := c.Clone()
+ newClient.SetHeaderMap(m)
+ return newClient
+}
+
+// HeaderRaw is a chaining function,
+// which sets custom HTTP header using raw string for next request.
+func (c *Client) HeaderRaw(headers string) *Client {
+ newClient := c.Clone()
+ newClient.SetHeaderRaw(headers)
+ return newClient
+}
+
+// Cookie is a chaining function,
+// which sets cookie items with map for next request.
+func (c *Client) Cookie(m map[string]string) *Client {
+ newClient := c.Clone()
+ newClient.SetCookieMap(m)
+ return newClient
+}
+
+// ContentType is a chaining function,
+// which sets HTTP content type for the next request.
+func (c *Client) ContentType(contentType string) *Client {
+ newClient := c.Clone()
+ newClient.SetContentType(contentType)
+ return newClient
+}
+
+// ContentJson is a chaining function,
+// which sets the HTTP content type as "application/json" for the next request.
+//
+// Note that it also checks and encodes the parameter to JSON format automatically.
+func (c *Client) ContentJson() *Client {
+ newClient := c.Clone()
+ newClient.SetContentType(httpHeaderContentTypeJson)
+ return newClient
+}
+
+// ContentXml is a chaining function,
+// which sets the HTTP content type as "application/xml" for the next request.
+//
+// Note that it also checks and encodes the parameter to XML format automatically.
+func (c *Client) ContentXml() *Client {
+ newClient := c.Clone()
+ newClient.SetContentType(httpHeaderContentTypeXml)
+ return newClient
+}
+
+// Timeout is a chaining function,
+// which sets the timeout for next request.
+func (c *Client) Timeout(t time.Duration) *Client {
+ newClient := c.Clone()
+ newClient.SetTimeout(t)
+ return newClient
+}
+
+// BasicAuth is a chaining function,
+// which sets HTTP basic authentication information for next request.
+func (c *Client) BasicAuth(user, pass string) *Client {
+ newClient := c.Clone()
+ newClient.SetBasicAuth(user, pass)
+ return newClient
+}
+
+// Retry is a chaining function,
+// which sets retry count and interval when failure for next request.
+func (c *Client) Retry(retryCount int, retryInterval time.Duration) *Client {
+ newClient := c.Clone()
+ newClient.SetRetry(retryCount, retryInterval)
+ return newClient
+}
+
+// Proxy is a chaining function,
+// which sets proxy for next request.
+// Make sure you pass the correct `proxyURL`.
+// The correct pattern is like `http://USER:PASSWORD@IP:PORT` or `socks5://USER:PASSWORD@IP:PORT`.
+// Only `http` and `socks5` proxies are supported currently.
+func (c *Client) Proxy(proxyURL string) *Client {
+ newClient := c.Clone()
+ newClient.SetProxy(proxyURL)
+ return newClient
+}
+
+// RedirectLimit is a chaining function,
+// which sets the redirect limit the number of jumps for the request.
+func (c *Client) RedirectLimit(redirectLimit int) *Client {
+ newClient := c.Clone()
+ newClient.SetRedirectLimit(redirectLimit)
+ return newClient
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_config.go
new file mode 100644
index 000000000000..4ce29ef9488b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_config.go
@@ -0,0 +1,198 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "crypto/tls"
+ "net"
+ "net/http"
+ "net/http/cookiejar"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "golang.org/x/net/proxy"
+)
+
+// SetBrowserMode enables browser mode of the client.
+// When browser mode is enabled, it automatically saves and sends cookie content
+// from and to server.
+func (c *Client) SetBrowserMode(enabled bool) *Client {
+ if enabled {
+ jar, _ := cookiejar.New(nil)
+ c.Jar = jar
+ }
+ return c
+}
+
+// SetHeader sets a custom HTTP header pair for the client.
+func (c *Client) SetHeader(key, value string) *Client {
+ c.header[key] = value
+ return c
+}
+
+// SetHeaderMap sets custom HTTP headers with map.
+func (c *Client) SetHeaderMap(m map[string]string) *Client {
+ for k, v := range m {
+ c.header[k] = v
+ }
+ return c
+}
+
+// SetAgent sets the User-Agent header for client.
+func (c *Client) SetAgent(agent string) *Client {
+ c.header[httpHeaderUserAgent] = agent
+ return c
+}
+
+// SetContentType sets HTTP content type for the client.
+func (c *Client) SetContentType(contentType string) *Client {
+ c.header[httpHeaderContentType] = contentType
+ return c
+}
+
+// SetHeaderRaw sets custom HTTP header using raw string.
+func (c *Client) SetHeaderRaw(headers string) *Client {
+ for _, line := range gstr.SplitAndTrim(headers, "\n") {
+ array, _ := gregex.MatchString(httpRegexHeaderRaw, line)
+ if len(array) >= 3 {
+ c.header[array[1]] = array[2]
+ }
+ }
+ return c
+}
+
+// SetCookie sets a cookie pair for the client.
+func (c *Client) SetCookie(key, value string) *Client {
+ c.cookies[key] = value
+ return c
+}
+
+// SetCookieMap sets cookie items with map.
+func (c *Client) SetCookieMap(m map[string]string) *Client {
+ for k, v := range m {
+ c.cookies[k] = v
+ }
+ return c
+}
+
+// SetPrefix sets the request server URL prefix.
+func (c *Client) SetPrefix(prefix string) *Client {
+ c.prefix = prefix
+ return c
+}
+
+// SetTimeout sets the request timeout for the client.
+func (c *Client) SetTimeout(t time.Duration) *Client {
+ c.Client.Timeout = t
+ return c
+}
+
+// SetBasicAuth sets HTTP basic authentication information for the client.
+func (c *Client) SetBasicAuth(user, pass string) *Client {
+ c.authUser = user
+ c.authPass = pass
+ return c
+}
+
+// SetRetry sets retry count and interval.
+func (c *Client) SetRetry(retryCount int, retryInterval time.Duration) *Client {
+ c.retryCount = retryCount
+ c.retryInterval = retryInterval
+ return c
+}
+
+// SetRedirectLimit limit the number of jumps
+func (c *Client) SetRedirectLimit(redirectLimit int) *Client {
+ c.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+ if len(via) >= redirectLimit {
+ return http.ErrUseLastResponse
+ }
+ return nil
+ }
+ return c
+}
+
+// SetProxy set proxy for the client.
+// This func will do nothing when the parameter `proxyURL` is empty or in wrong pattern.
+// The correct pattern is like `http://USER:PASSWORD@IP:PORT` or `socks5://USER:PASSWORD@IP:PORT`.
+// Only `http` and `socks5` proxies are supported currently.
+func (c *Client) SetProxy(proxyURL string) {
+ if strings.TrimSpace(proxyURL) == "" {
+ return
+ }
+ _proxy, err := url.Parse(proxyURL)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ return
+ }
+ if _proxy.Scheme == httpProtocolName {
+ if v, ok := c.Transport.(*http.Transport); ok {
+ v.Proxy = http.ProxyURL(_proxy)
+ }
+ } else {
+ var auth = &proxy.Auth{}
+ user := _proxy.User.Username()
+ if user != "" {
+ auth.User = user
+ password, hasPassword := _proxy.User.Password()
+ if hasPassword && password != "" {
+ auth.Password = password
+ }
+ } else {
+ auth = nil
+ }
+ // refer to the source code, error is always nil
+ dialer, err := proxy.SOCKS5(
+ "tcp",
+ _proxy.Host,
+ auth,
+ &net.Dialer{
+ Timeout: c.Client.Timeout,
+ KeepAlive: c.Client.Timeout,
+ },
+ )
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ return
+ }
+ if v, ok := c.Transport.(*http.Transport); ok {
+ v.DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, e error) {
+ return dialer.Dial(network, addr)
+ }
+ }
+ // c.SetTimeout(10*time.Second)
+ }
+}
+
+// SetTLSKeyCrt sets the certificate and key file for TLS configuration of client.
+func (c *Client) SetTLSKeyCrt(crtFile, keyFile string) error {
+ tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
+ if err != nil {
+ return gerror.Wrap(err, "LoadKeyCrt failed")
+ }
+ if v, ok := c.Transport.(*http.Transport); ok {
+ tlsConfig.InsecureSkipVerify = true
+ v.TLSClientConfig = tlsConfig
+ return nil
+ }
+ return gerror.New(`cannot set TLSClientConfig for custom Transport of the client`)
+}
+
+// SetTLSConfig sets the TLS configuration of client.
+func (c *Client) SetTLSConfig(tlsConfig *tls.Config) error {
+ if v, ok := c.Transport.(*http.Transport); ok {
+ v.TLSClientConfig = tlsConfig
+ return nil
+ }
+ return gerror.New(`cannot set TLSClientConfig for custom Transport of the client`)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_content.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_content.go
new file mode 100644
index 000000000000..1a39c97a5c2e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_content.go
@@ -0,0 +1,72 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "net/http"
+)
+
+// GetContent is a convenience method for sending GET request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) GetContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodGet, url, data...))
+}
+
+// PutContent is a convenience method for sending PUT request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) PutContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodPut, url, data...))
+}
+
+// PostContent is a convenience method for sending POST request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) PostContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodPost, url, data...))
+}
+
+// DeleteContent is a convenience method for sending DELETE request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) DeleteContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodDelete, url, data...))
+}
+
+// HeadContent is a convenience method for sending HEAD request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) HeadContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodHead, url, data...))
+}
+
+// PatchContent is a convenience method for sending PATCH request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) PatchContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodPatch, url, data...))
+}
+
+// ConnectContent is a convenience method for sending CONNECT request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) ConnectContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodConnect, url, data...))
+}
+
+// OptionsContent is a convenience method for sending OPTIONS request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) OptionsContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodOptions, url, data...))
+}
+
+// TraceContent is a convenience method for sending TRACE request, which retrieves and returns
+// the result content and automatically closes response object.
+func (c *Client) TraceContent(ctx context.Context, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, http.MethodTrace, url, data...))
+}
+
+// RequestContent is a convenience method for sending custom http method request, which
+// retrieves and returns the result content and automatically closes response object.
+func (c *Client) RequestContent(ctx context.Context, method string, url string, data ...interface{}) string {
+ return string(c.RequestBytes(ctx, method, url, data...))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_discovery.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_discovery.go
new file mode 100644
index 000000000000..3d17443b9ad9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_discovery.go
@@ -0,0 +1,99 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/net/gsel"
+ "github.com/gogf/gf/v2/net/gsvc"
+ "github.com/gogf/gf/v2/os/gctx"
+)
+
+const (
+ discoveryMiddlewareHandled gctx.StrKey = `MiddlewareClientDiscoveryHandled`
+)
+
+type discoveryNode struct {
+ service *gsvc.Service
+ address string
+}
+
+func (n *discoveryNode) Service() *gsvc.Service {
+ return n.service
+}
+
+func (n *discoveryNode) Address() string {
+ return n.address
+}
+
+var (
+ clientSelectorMap = gmap.New(true)
+)
+
+// internalMiddlewareDiscovery is a client middleware that enables service discovery feature for client.
+func internalMiddlewareDiscovery(c *Client, r *http.Request) (response *Response, err error) {
+ var ctx = r.Context()
+ // Mark this request is handled by server tracing middleware,
+ // to avoid repeated handling by the same middleware.
+ if ctx.Value(discoveryMiddlewareHandled) != nil {
+ return c.Next(r)
+ }
+ if gsvc.GetRegistry() == nil {
+ return c.Next(r)
+ }
+ var service *gsvc.Service
+ service, err = gsvc.GetWithWatch(ctx, r.URL.Host, func(service *gsvc.Service) {
+ intlog.Printf(ctx, `http client watching service "%s" changed`, service.KeyWithoutEndpoints())
+ if v := clientSelectorMap.Get(service.KeyWithoutEndpoints()); v != nil {
+ if err = updateSelectorNodesByService(v.(gsel.Selector), service); err != nil {
+ intlog.Errorf(context.Background(), `%+v`, err)
+ }
+ }
+ })
+ if err != nil {
+ return nil, err
+ }
+ if service == nil {
+ return c.Next(r)
+ }
+ // Balancer.
+ var selectorMapKey = service.KeyWithoutEndpoints()
+ selector := clientSelectorMap.GetOrSetFuncLock(selectorMapKey, func() interface{} {
+ intlog.Printf(ctx, `http client create selector for service "%s"`, selectorMapKey)
+ return gsel.GetBuilder().Build()
+ }).(gsel.Selector)
+ // Update selector nodes.
+ if err = updateSelectorNodesByService(selector, service); err != nil {
+ return nil, err
+ }
+ // Pick one node from multiple addresses.
+ node, done, err := selector.Pick(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if done != nil {
+ defer done(ctx, gsel.DoneInfo{})
+ }
+ r.URL.Host = node.Address()
+ r.Host = node.Address()
+ return c.Next(r)
+}
+
+func updateSelectorNodesByService(selector gsel.Selector, service *gsvc.Service) error {
+ nodes := make([]gsel.Node, 0)
+ for _, address := range service.Endpoints {
+ nodes = append(nodes, &discoveryNode{
+ service: service,
+ address: address,
+ })
+ }
+ return selector.Update(nodes)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_dump.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_dump.go
new file mode 100644
index 000000000000..51750d05a421
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_dump.go
@@ -0,0 +1,88 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/http/httputil"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// dumpTextFormat is the format of the dumped raw string
+const dumpTextFormat = `+---------------------------------------------+
+| %s |
++---------------------------------------------+
+%s
+%s
+`
+
+// getResponseBody returns the text of the response body.
+func getResponseBody(res *http.Response) string {
+ if res.Body == nil {
+ return ""
+ }
+ bodyContent, _ := ioutil.ReadAll(res.Body)
+ res.Body = utils.NewReadCloser(bodyContent, true)
+ return string(bodyContent)
+}
+
+// RawRequest returns the raw content of the request.
+func (r *Response) RawRequest() string {
+ // Response can be nil.
+ if r == nil {
+ return ""
+ }
+ if r.request == nil {
+ return ""
+ }
+ // DumpRequestOut writes more request headers than DumpRequest, such as User-Agent.
+ bs, err := httputil.DumpRequestOut(r.request, false)
+ if err != nil {
+ intlog.Errorf(r.request.Context(), `%+v`, err)
+ return ""
+ }
+ return fmt.Sprintf(
+ dumpTextFormat,
+ "REQUEST ",
+ string(bs),
+ r.requestBody,
+ )
+}
+
+// RawResponse returns the raw content of the response.
+func (r *Response) RawResponse() string {
+ // Response might be nil.
+ if r == nil || r.Response == nil {
+ return ""
+ }
+ bs, err := httputil.DumpResponse(r.Response, false)
+ if err != nil {
+ intlog.Errorf(r.request.Context(), `%+v`, err)
+ return ""
+ }
+
+ return fmt.Sprintf(
+ dumpTextFormat,
+ "RESPONSE",
+ string(bs),
+ getResponseBody(r.Response),
+ )
+}
+
+// Raw returns the raw text of the request and the response.
+func (r *Response) Raw() string {
+ return fmt.Sprintf("%s\n%s", r.RawRequest(), r.RawResponse())
+}
+
+// RawDump outputs the raw text of the request and the response to stdout.
+func (r *Response) RawDump() {
+ fmt.Println(r.Raw())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_middleware.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_middleware.go
new file mode 100644
index 000000000000..010ba30bbcc8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_middleware.go
@@ -0,0 +1,50 @@
+package gclient
+
+import (
+ "net/http"
+
+ "github.com/gogf/gf/v2/os/gctx"
+)
+
+// HandlerFunc middleware handler func
+type HandlerFunc = func(c *Client, r *http.Request) (*Response, error)
+
+// clientMiddleware is the plugin for http client request workflow management.
+type clientMiddleware struct {
+ client *Client // http client.
+ handlers []HandlerFunc // mdl handlers.
+ handlerIndex int // current handler index.
+ resp *Response // save resp.
+ err error // save err.
+}
+
+const clientMiddlewareKey gctx.StrKey = "__clientMiddlewareKey"
+
+// Use adds one or more middleware handlers to client.
+func (c *Client) Use(handlers ...HandlerFunc) *Client {
+ c.middlewareHandler = append(c.middlewareHandler, handlers...)
+ return c
+}
+
+// Next calls the next middleware.
+// This should only be call in HandlerFunc.
+func (c *Client) Next(req *http.Request) (*Response, error) {
+ if v := req.Context().Value(clientMiddlewareKey); v != nil {
+ if m, ok := v.(*clientMiddleware); ok {
+ return m.Next(req)
+ }
+ }
+ return c.callRequest(req)
+}
+
+// Next calls the next middleware handler.
+func (m *clientMiddleware) Next(req *http.Request) (resp *Response, err error) {
+ if m.err != nil {
+ return m.resp, m.err
+ }
+ if m.handlerIndex < len(m.handlers) {
+ m.handlerIndex++
+ m.resp, m.err = m.handlers[m.handlerIndex](m.client, req)
+ }
+ return m.resp, m.err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_request.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_request.go
new file mode 100644
index 000000000000..2dbb26d10feb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_request.go
@@ -0,0 +1,353 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "bytes"
+ "context"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/httputil"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Get send GET request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Get(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodGet, url, data...)
+}
+
+// Put send PUT request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Put(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodPut, url, data...)
+}
+
+// Post sends request using HTTP method POST and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Post(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodPost, url, data...)
+}
+
+// Delete send DELETE request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Delete(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodDelete, url, data...)
+}
+
+// Head send HEAD request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Head(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodHead, url, data...)
+}
+
+// Patch send PATCH request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Patch(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodPatch, url, data...)
+}
+
+// Connect send CONNECT request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Connect(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodConnect, url, data...)
+}
+
+// Options send OPTIONS request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Options(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodOptions, url, data...)
+}
+
+// Trace send TRACE request and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) Trace(ctx context.Context, url string, data ...interface{}) (*Response, error) {
+ return c.DoRequest(ctx, http.MethodTrace, url, data...)
+}
+
+// PostForm issues a POST to the specified URL,
+// with data's keys and values URL-encoded as the request body.
+//
+// The Content-Type header is set to application/x-www-form-urlencoded.
+// To set other headers, use NewRequest and Client.Do.
+//
+// When err is nil, resp always contains a non-nil resp.Body.
+// Caller should close resp.Body when done reading from it.
+//
+// See the Client.Do method documentation for details on how redirects
+// are handled.
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and Client.Do.
+// Deprecated, use Post instead.
+func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
+ return nil, gerror.NewCode(
+ gcode.CodeNotSupported,
+ `PostForm is not supported, please use Post instead`,
+ )
+}
+
+// DoRequest sends request with given HTTP method and data and returns the response object.
+// Note that the response object MUST be closed if it'll never be used.
+//
+// Note that it uses "multipart/form-data" as its Content-Type if it contains file uploading,
+// else it uses "application/x-www-form-urlencoded". It also automatically detects the post
+// content for JSON format, and for that it automatically sets the Content-Type as
+// "application/json".
+func (c *Client) DoRequest(ctx context.Context, method, url string, data ...interface{}) (resp *Response, err error) {
+ req, err := c.prepareRequest(ctx, method, url, data...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Client middleware.
+ if len(c.middlewareHandler) > 0 {
+ mdlHandlers := make([]HandlerFunc, 0, len(c.middlewareHandler)+1)
+ mdlHandlers = append(mdlHandlers, c.middlewareHandler...)
+ mdlHandlers = append(mdlHandlers, func(cli *Client, r *http.Request) (*Response, error) {
+ return cli.callRequest(r)
+ })
+ ctx = context.WithValue(req.Context(), clientMiddlewareKey, &clientMiddleware{
+ client: c,
+ handlers: mdlHandlers,
+ handlerIndex: -1,
+ })
+ req = req.WithContext(ctx)
+ resp, err = c.Next(req)
+ } else {
+ resp, err = c.callRequest(req)
+ }
+ return resp, err
+}
+
+// prepareRequest verifies request parameters, builds and returns http request.
+func (c *Client) prepareRequest(ctx context.Context, method, url string, data ...interface{}) (req *http.Request, err error) {
+ method = strings.ToUpper(method)
+ if len(c.prefix) > 0 {
+ url = c.prefix + gstr.Trim(url)
+ }
+ if !gstr.ContainsI(url, httpProtocolName) {
+ url = httpProtocolName + `://` + url
+ }
+ var params string
+ if len(data) > 0 {
+ switch c.header[httpHeaderContentType] {
+ case httpHeaderContentTypeJson:
+ switch data[0].(type) {
+ case string, []byte:
+ params = gconv.String(data[0])
+ default:
+ if b, err := json.Marshal(data[0]); err != nil {
+ return nil, err
+ } else {
+ params = string(b)
+ }
+ }
+
+ case httpHeaderContentTypeXml:
+ switch data[0].(type) {
+ case string, []byte:
+ params = gconv.String(data[0])
+ default:
+ if b, err := gjson.New(data[0]).ToXml(); err != nil {
+ return nil, err
+ } else {
+ params = string(b)
+ }
+ }
+ default:
+ params = httputil.BuildParams(data[0])
+ }
+ }
+ if method == http.MethodGet {
+ var bodyBuffer *bytes.Buffer
+ if params != "" {
+ switch c.header[httpHeaderContentType] {
+ case
+ httpHeaderContentTypeJson,
+ httpHeaderContentTypeXml:
+ bodyBuffer = bytes.NewBuffer([]byte(params))
+ default:
+ // It appends the parameters to the url
+ // if http method is GET and Content-Type is not specified.
+ if gstr.Contains(url, "?") {
+ url = url + "&" + params
+ } else {
+ url = url + "?" + params
+ }
+ bodyBuffer = bytes.NewBuffer(nil)
+ }
+ } else {
+ bodyBuffer = bytes.NewBuffer(nil)
+ }
+ if req, err = http.NewRequest(method, url, bodyBuffer); err != nil {
+ err = gerror.Wrapf(err, `http.NewRequest failed with method "%s" and URL "%s"`, method, url)
+ return nil, err
+ }
+ } else {
+ if strings.Contains(params, httpParamFileHolder) {
+ // File uploading request.
+ var (
+ buffer = bytes.NewBuffer(nil)
+ writer = multipart.NewWriter(buffer)
+ )
+ for _, item := range strings.Split(params, "&") {
+ array := strings.Split(item, "=")
+ if len(array[1]) > 6 && strings.Compare(array[1][0:6], httpParamFileHolder) == 0 {
+ path := array[1][6:]
+ if !gfile.Exists(path) {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" does not exist`, path)
+ }
+ var (
+ file io.Writer
+ formFileName = gfile.Basename(path)
+ formFieldName = array[0]
+ )
+ if file, err = writer.CreateFormFile(formFieldName, formFileName); err != nil {
+ err = gerror.Wrapf(err, `CreateFormFile failed with "%s", "%s"`, formFieldName, formFileName)
+ return nil, err
+ } else {
+ var f *os.File
+ if f, err = gfile.Open(path); err != nil {
+ return nil, err
+ }
+ if _, err = io.Copy(file, f); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed from "%s" to form "%s"`, path, formFieldName)
+ _ = f.Close()
+ return nil, err
+ }
+ _ = f.Close()
+ }
+ } else {
+ var (
+ fieldName = array[0]
+ fieldValue = array[1]
+ )
+ if err = writer.WriteField(fieldName, fieldValue); err != nil {
+ err = gerror.Wrapf(err, `write form field failed with "%s", "%s"`, fieldName, fieldValue)
+ return nil, err
+ }
+ }
+ }
+ // Close finishes the multipart message and writes the trailing
+ // boundary end line to the output.
+ if err = writer.Close(); err != nil {
+ err = gerror.Wrapf(err, `form writer close failed`)
+ return nil, err
+ }
+
+ if req, err = http.NewRequest(method, url, buffer); err != nil {
+ err = gerror.Wrapf(err, `http.NewRequest failed for method "%s" and URL "%s"`, method, url)
+ return nil, err
+ } else {
+ req.Header.Set(httpHeaderContentType, writer.FormDataContentType())
+ }
+ } else {
+ // Normal request.
+ paramBytes := []byte(params)
+ if req, err = http.NewRequest(method, url, bytes.NewReader(paramBytes)); err != nil {
+ err = gerror.Wrapf(err, `http.NewRequest failed for method "%s" and URL "%s"`, method, url)
+ return nil, err
+ } else {
+ if v, ok := c.header[httpHeaderContentType]; ok {
+ // Custom Content-Type.
+ req.Header.Set(httpHeaderContentType, v)
+ } else if len(paramBytes) > 0 {
+ if (paramBytes[0] == '[' || paramBytes[0] == '{') && json.Valid(paramBytes) {
+ // Auto-detecting and setting the post content format: JSON.
+ req.Header.Set(httpHeaderContentType, httpHeaderContentTypeJson)
+ } else if gregex.IsMatchString(httpRegexParamJson, params) {
+ // If the parameters passed like "name=value", it then uses form type.
+ req.Header.Set(httpHeaderContentType, httpHeaderContentTypeForm)
+ }
+ }
+ }
+ }
+ }
+
+ // Context.
+ if ctx != nil {
+ req = req.WithContext(ctx)
+ }
+ // Custom header.
+ if len(c.header) > 0 {
+ for k, v := range c.header {
+ req.Header.Set(k, v)
+ }
+ }
+ // It's necessary set the req.Host if you want to custom the host value of the request.
+ // It uses the "Host" value from header if it's not empty.
+ if reqHeaderHost := req.Header.Get(httpHeaderHost); reqHeaderHost != "" {
+ req.Host = reqHeaderHost
+ }
+ // Custom Cookie.
+ if len(c.cookies) > 0 {
+ headerCookie := ""
+ for k, v := range c.cookies {
+ if len(headerCookie) > 0 {
+ headerCookie += ";"
+ }
+ headerCookie += k + "=" + v
+ }
+ if len(headerCookie) > 0 {
+ req.Header.Set(httpHeaderCookie, headerCookie)
+ }
+ }
+ // HTTP basic authentication.
+ if len(c.authUser) > 0 {
+ req.SetBasicAuth(c.authUser, c.authPass)
+ }
+ return req, nil
+}
+
+// callRequest sends request with give http.Request, and returns the responses object.
+// Note that the response object MUST be closed if it'll never be used.
+func (c *Client) callRequest(req *http.Request) (resp *Response, err error) {
+ resp = &Response{
+ request: req,
+ }
+ // Dump feature.
+ // The request body can be reused for dumping
+ // raw HTTP request-response procedure.
+ reqBodyContent, _ := ioutil.ReadAll(req.Body)
+ resp.requestBody = reqBodyContent
+ req.Body = utils.NewReadCloser(reqBodyContent, false)
+ for {
+ if resp.Response, err = c.Do(req); err != nil {
+ err = gerror.Wrapf(err, `request failed`)
+ // The response might not be nil when err != nil.
+ if resp.Response != nil {
+ _ = resp.Response.Body.Close()
+ }
+ if c.retryCount > 0 {
+ c.retryCount--
+ time.Sleep(c.retryInterval)
+ } else {
+ // return resp, err
+ break
+ }
+ } else {
+ break
+ }
+ }
+ return resp, err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_response.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_response.go
new file mode 100644
index 000000000000..dd3a3815fe33
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_response.go
@@ -0,0 +1,79 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "io/ioutil"
+ "net/http"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// Response is the struct for client request response.
+type Response struct {
+ *http.Response // Response is the underlying http.Response object of certain request.
+ request *http.Request // Request is the underlying http.Request object of certain request.
+ requestBody []byte // The body bytes of certain request, only available in Dump feature.
+ cookies map[string]string // Response cookies, which are only parsed once.
+}
+
+// initCookie initializes the cookie map attribute of Response.
+func (r *Response) initCookie() {
+ if r.cookies == nil {
+ r.cookies = make(map[string]string)
+ // Response might be nil.
+ if r != nil && r.Response != nil {
+ for _, v := range r.Cookies() {
+ r.cookies[v.Name] = v.Value
+ }
+ }
+ }
+}
+
+// GetCookie retrieves and returns the cookie value of specified `key`.
+func (r *Response) GetCookie(key string) string {
+ r.initCookie()
+ return r.cookies[key]
+}
+
+// GetCookieMap retrieves and returns a copy of current cookie values map.
+func (r *Response) GetCookieMap() map[string]string {
+ r.initCookie()
+ m := make(map[string]string, len(r.cookies))
+ for k, v := range r.cookies {
+ m[k] = v
+ }
+ return m
+}
+
+// ReadAll retrieves and returns the response content as []byte.
+func (r *Response) ReadAll() []byte {
+ // Response might be nil.
+ if r == nil || r.Response == nil {
+ return []byte{}
+ }
+ body, err := ioutil.ReadAll(r.Response.Body)
+ if err != nil {
+ intlog.Errorf(r.request.Context(), `%+v`, err)
+ return nil
+ }
+ return body
+}
+
+// ReadAllString retrieves and returns the response content as string.
+func (r *Response) ReadAllString() string {
+ return string(r.ReadAll())
+}
+
+// Close closes the response when it will never be used.
+func (r *Response) Close() error {
+ if r == nil || r.Response == nil || r.Response.Close {
+ return nil
+ }
+ r.Response.Close = true
+ return r.Response.Body.Close()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_tracing.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_tracing.go
new file mode 100644
index 000000000000..86a2828c77c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_tracing.go
@@ -0,0 +1,104 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptrace"
+
+ "github.com/gogf/gf/v2/os/gctx"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/propagation"
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2"
+ "github.com/gogf/gf/v2/internal/httputil"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/net/gtrace"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ tracingInstrumentName = "github.com/gogf/gf/v2/net/gclient.Client"
+ tracingAttrHttpAddressRemote = "http.address.remote"
+ tracingAttrHttpAddressLocal = "http.address.local"
+ tracingAttrHttpDnsStart = "http.dns.start"
+ tracingAttrHttpDnsDone = "http.dns.done"
+ tracingAttrHttpConnectStart = "http.connect.start"
+ tracingAttrHttpConnectDone = "http.connect.done"
+ tracingEventHttpRequest = "http.request"
+ tracingEventHttpRequestHeaders = "http.request.headers"
+ tracingEventHttpRequestBaggage = "http.request.baggage"
+ tracingEventHttpRequestBody = "http.request.body"
+ tracingEventHttpResponse = "http.response"
+ tracingEventHttpResponseHeaders = "http.response.headers"
+ tracingEventHttpResponseBody = "http.response.body"
+ tracingMiddlewareHandled gctx.StrKey = `MiddlewareClientTracingHandled`
+)
+
+// internalMiddlewareTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
+func internalMiddlewareTracing(c *Client, r *http.Request) (response *Response, err error) {
+ var ctx = r.Context()
+ // Mark this request is handled by server tracing middleware,
+ // to avoid repeated handling by the same middleware.
+ if ctx.Value(tracingMiddlewareHandled) != nil {
+ return c.Next(r)
+ }
+
+ ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)
+ tr := otel.GetTracerProvider().Tracer(
+ tracingInstrumentName,
+ trace.WithInstrumentationVersion(gf.VERSION),
+ )
+ ctx, span := tr.Start(r.Context(), r.URL.String(), trace.WithSpanKind(trace.SpanKindClient))
+ defer span.End()
+
+ span.SetAttributes(gtrace.CommonLabels()...)
+
+ // Inject tracing content into http header.
+ otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header))
+
+ // If it is now using default trace provider, it then does no complex tracing jobs.
+ if gtrace.IsUsingDefaultProvider() {
+ response, err = c.Next(r)
+ return
+ }
+
+ // Continue client handler executing.
+ response, err = c.Next(
+ r.WithContext(
+ httptrace.WithClientTrace(
+ ctx, newClientTrace(ctx, span, r),
+ ),
+ ),
+ )
+ if err != nil {
+ span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
+ }
+ if response == nil || response.Response == nil {
+ return
+ }
+
+ reqBodyContentBytes, _ := ioutil.ReadAll(response.Body)
+ response.Body = utils.NewReadCloser(reqBodyContentBytes, false)
+
+ span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
+ attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(response.Header))),
+ attribute.String(tracingEventHttpResponseBody, gstr.StrLimit(
+ string(reqBodyContentBytes),
+ gtrace.MaxContentLogSize(),
+ "...",
+ )),
+ ))
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_tracing_tracer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_tracing_tracer.go
new file mode 100644
index 000000000000..4966f1fb7218
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_tracing_tracer.go
@@ -0,0 +1,166 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptrace"
+ "net/textproto"
+ "strings"
+ "sync"
+
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/net/gtrace"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// clientTracer is used for implementing httptrace.ClientTrace.
+type clientTracer struct {
+ context.Context
+ span trace.Span
+ request *http.Request
+ requestBody []byte
+ headers map[string]interface{}
+ mtx sync.Mutex
+}
+
+// newClientTrace creates and returns object of newClientTrace.
+func newClientTrace(ctx context.Context, span trace.Span, request *http.Request) *httptrace.ClientTrace {
+ ct := &clientTracer{
+ Context: ctx,
+ span: span,
+ request: request,
+ headers: make(map[string]interface{}),
+ }
+
+ reqBodyContent, _ := ioutil.ReadAll(ct.request.Body)
+ ct.requestBody = reqBodyContent
+ ct.request.Body = utils.NewReadCloser(reqBodyContent, false)
+
+ return &httptrace.ClientTrace{
+ GetConn: ct.getConn,
+ GotConn: ct.gotConn,
+ PutIdleConn: ct.putIdleConn,
+ GotFirstResponseByte: ct.gotFirstResponseByte,
+ Got100Continue: ct.got100Continue,
+ Got1xxResponse: ct.got1xxResponse,
+ DNSStart: ct.dnsStart,
+ DNSDone: ct.dnsDone,
+ ConnectStart: ct.connectStart,
+ ConnectDone: ct.connectDone,
+ TLSHandshakeStart: ct.tlsHandshakeStart,
+ TLSHandshakeDone: ct.tlsHandshakeDone,
+ WroteHeaderField: ct.wroteHeaderField,
+ WroteHeaders: ct.wroteHeaders,
+ Wait100Continue: ct.wait100Continue,
+ WroteRequest: ct.wroteRequest,
+ }
+}
+
+func (ct *clientTracer) getConn(host string) {}
+
+func (ct *clientTracer) gotConn(info httptrace.GotConnInfo) {
+ ct.span.SetAttributes(
+ attribute.String(tracingAttrHttpAddressRemote, info.Conn.RemoteAddr().String()),
+ attribute.String(tracingAttrHttpAddressLocal, info.Conn.LocalAddr().String()),
+ )
+}
+
+func (ct *clientTracer) putIdleConn(err error) {
+ if err != nil {
+ ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
+ }
+}
+
+func (ct *clientTracer) dnsStart(info httptrace.DNSStartInfo) {
+ ct.span.SetAttributes(
+ attribute.String(tracingAttrHttpDnsStart, info.Host),
+ )
+}
+
+func (ct *clientTracer) dnsDone(info httptrace.DNSDoneInfo) {
+ var buffer strings.Builder
+ for _, v := range info.Addrs {
+ if buffer.Len() != 0 {
+ buffer.WriteString(",")
+ }
+ buffer.WriteString(v.String())
+ }
+ if info.Err != nil {
+ ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))
+ }
+ ct.span.SetAttributes(
+ attribute.String(tracingAttrHttpDnsDone, buffer.String()),
+ )
+}
+
+func (ct *clientTracer) connectStart(network, addr string) {
+ ct.span.SetAttributes(
+ attribute.String(tracingAttrHttpConnectStart, network+"@"+addr),
+ )
+}
+
+func (ct *clientTracer) connectDone(network, addr string, err error) {
+ if err != nil {
+ ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
+ }
+ ct.span.SetAttributes(
+ attribute.String(tracingAttrHttpConnectDone, network+"@"+addr),
+ )
+}
+
+func (ct *clientTracer) tlsHandshakeStart() {}
+
+func (ct *clientTracer) tlsHandshakeDone(_ tls.ConnectionState, err error) {
+ if err != nil {
+ ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
+ }
+}
+
+func (ct *clientTracer) wroteHeaderField(k string, v []string) {
+ if len(v) > 1 {
+ ct.headers[k] = v
+ } else {
+ ct.headers[k] = v[0]
+ }
+}
+
+func (ct *clientTracer) wroteHeaders() {}
+
+func (ct *clientTracer) wroteRequest(info httptrace.WroteRequestInfo) {
+ if info.Err != nil {
+ ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))
+ }
+
+ ct.span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
+ attribute.String(tracingEventHttpRequestHeaders, gconv.String(ct.headers)),
+ attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ct.Context).String()),
+ attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
+ string(ct.requestBody),
+ gtrace.MaxContentLogSize(),
+ "...",
+ )),
+ ))
+}
+
+func (ct *clientTracer) got100Continue() {}
+
+func (ct *clientTracer) wait100Continue() {}
+
+func (ct *clientTracer) gotFirstResponseByte() {}
+
+func (ct *clientTracer) got1xxResponse(code int, header textproto.MIMEHeader) error {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_var.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_var.go
new file mode 100644
index 000000000000..950f96ac04b1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_var.go
@@ -0,0 +1,80 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// GetVar sends a GET request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) GetVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodGet, url, data...)
+}
+
+// PutVar sends a PUT request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) PutVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodPut, url, data...)
+}
+
+// PostVar sends a POST request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) PostVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodPost, url, data...)
+}
+
+// DeleteVar sends a DELETE request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) DeleteVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodDelete, url, data...)
+}
+
+// HeadVar sends a HEAD request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) HeadVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodHead, url, data...)
+}
+
+// PatchVar sends a PATCH request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) PatchVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodPatch, url, data...)
+}
+
+// ConnectVar sends a CONNECT request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) ConnectVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodConnect, url, data...)
+}
+
+// OptionsVar sends a OPTIONS request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) OptionsVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodOptions, url, data...)
+}
+
+// TraceVar sends a TRACE request, retrieves and converts the result content to specified pointer.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) TraceVar(ctx context.Context, url string, data ...interface{}) *gvar.Var {
+ return c.RequestVar(ctx, http.MethodTrace, url, data...)
+}
+
+// RequestVar sends request using given HTTP method and data, retrieves converts the result
+// to specified pointer. It reads and closes the response object internally automatically.
+// The parameter `pointer` can be type of: struct/*struct/**struct/[]struct/[]*struct/*[]struct, etc.
+func (c *Client) RequestVar(ctx context.Context, method string, url string, data ...interface{}) *gvar.Var {
+ response, err := c.DoRequest(ctx, method, url, data...)
+ if err != nil {
+ return gvar.New(nil)
+ }
+ defer response.Close()
+ return gvar.New(response.ReadAll())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_websocket.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_websocket.go
new file mode 100644
index 000000000000..3bdb38f02196
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gclient/gclient_websocket.go
@@ -0,0 +1,30 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gclient
+
+import (
+ "net/http"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+// WebSocketClient wraps the underlying websocket client connection
+// and provides convenient functions.
+type WebSocketClient struct {
+ *websocket.Dialer
+}
+
+// NewWebSocket creates and returns a new WebSocketClient object.
+func NewWebSocket() *WebSocketClient {
+ return &WebSocketClient{
+ &websocket.Dialer{
+ Proxy: http.ProxyFromEnvironment,
+ HandshakeTimeout: 45 * time.Second,
+ },
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp.go
new file mode 100644
index 000000000000..4783fe6d79b3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp.go
@@ -0,0 +1,175 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package ghttp provides powerful http server and simple client implements.
+package ghttp
+
+import (
+ "net/http"
+ "reflect"
+ "time"
+
+ "github.com/gogf/gf/v2/net/gsvc"
+ "github.com/gorilla/websocket"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/os/gcache"
+ "github.com/gogf/gf/v2/os/gsession"
+ "github.com/gogf/gf/v2/protocol/goai"
+)
+
+type (
+ // Server wraps the http.Server and provides more rich features.
+ Server struct {
+ instance string // Instance name.
+ config ServerConfig // Configuration.
+ plugins []Plugin // Plugin array to extend server functionality.
+ servers []*gracefulServer // Underlying http.Server array.
+ serverCount *gtype.Int // Underlying http.Server count.
+ closeChan chan struct{} // Used for underlying server closing event notification.
+ serveTree map[string]interface{} // The route map tree.
+ serveCache *gcache.Cache // Server caches for internal usage.
+ routesMap map[string][]registeredRouteItem // Route map mainly for route dumps and repeated route checks.
+ statusHandlerMap map[string][]HandlerFunc // Custom status handler map.
+ sessionManager *gsession.Manager // Session manager.
+ openapi *goai.OpenApiV3 // The OpenApi specification management object.
+ service *gsvc.Service // The service for Registry.
+ }
+
+ // Router object.
+ Router struct {
+ Uri string // URI.
+ Method string // HTTP method
+ Domain string // Bound domain.
+ RegRule string // Parsed regular expression for route matching.
+ RegNames []string // Parsed router parameter names.
+ Priority int // Just for reference.
+ }
+
+ // RouterItem is just for route dumps.
+ RouterItem struct {
+ Handler *handlerItem // The handler.
+ Server string // Server name.
+ Address string // Listening address.
+ Domain string // Bound domain.
+ Type string // Router type.
+ Middleware string // Bound middleware.
+ Method string // Handler method name.
+ Route string // Route URI.
+ Priority int // Just for reference.
+ IsServiceHandler bool // Is service handler.
+ }
+
+ // HandlerFunc is request handler function.
+ HandlerFunc = func(r *Request)
+
+ // handlerFuncInfo contains the HandlerFunc address and its reflection type.
+ handlerFuncInfo struct {
+ Func HandlerFunc // Handler function address.
+ Type reflect.Type // Reflect type information for current handler, which is used for extension of handler feature.
+ Value reflect.Value // Reflect value information for current handler, which is used for extension of handler feature.
+ }
+
+ // handlerItem is the registered handler for route handling,
+ // including middleware and hook functions.
+ handlerItem struct {
+ Id int // Unique handler item id mark.
+ Name string // Handler name, which is automatically retrieved from runtime stack when registered.
+ Type string // Handler type: object/handler/middleware/hook.
+ Info handlerFuncInfo // Handler function information.
+ InitFunc HandlerFunc // Initialization function when request enters the object (only available for object register type).
+ ShutFunc HandlerFunc // Shutdown function when request leaves out the object (only available for object register type).
+ Middleware []HandlerFunc // Bound middleware array.
+ HookName string // Hook type name, only available for hook type.
+ Router *Router // Router object.
+ Source string // Registering source file `path:line`.
+ }
+
+ // handlerParsedItem is the item parsed from URL.Path.
+ handlerParsedItem struct {
+ Handler *handlerItem // Handler information.
+ Values map[string]string // Router values parsed from URL.Path.
+ }
+
+ // registeredRouteItem stores the information of the router and is used for route map.
+ registeredRouteItem struct {
+ Source string // Source file path and its line number.
+ Handler *handlerItem // Handler object.
+ }
+
+ // Listening file descriptor mapping.
+ // The key is either "http" or "https" and the value is its FD.
+ listenerFdMap = map[string]string
+)
+
+const (
+ HeaderXUrlPath = "x-url-path" // Used for custom route handler, which does not change URL.Path.
+ HookBeforeServe = "HOOK_BEFORE_SERVE" // Hook handler before route handler/file serving.
+ HookAfterServe = "HOOK_AFTER_SERVE" // Hook handler after route handler/file serving.
+ HookBeforeOutput = "HOOK_BEFORE_OUTPUT" // Hook handler before response output.
+ HookAfterOutput = "HOOK_AFTER_OUTPUT" // Hook handler after response output.
+ ServerStatusStopped = 0
+ ServerStatusRunning = 1
+ DefaultServerName = "default"
+ DefaultDomainName = "default"
+ HandlerTypeHandler = "handler"
+ HandlerTypeObject = "object"
+ HandlerTypeMiddleware = "middleware"
+ HandlerTypeHook = "hook"
+)
+
+const (
+ supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
+ defaultMethod = "ALL"
+ exceptionExit = "exit"
+ exceptionExitAll = "exit_all"
+ exceptionExitHook = "exit_hook"
+ routeCacheDuration = time.Hour
+ methodNameInit = "Init"
+ methodNameShut = "Shut"
+ ctxKeyForRequest = "gHttpRequestObject"
+ contentTypeXml = "text/xml"
+ contentTypeHtml = "text/html"
+ contentTypeJson = "application/json"
+ swaggerUIPackedPath = "/goframe/swaggerui"
+ responseTraceIDHeader = "Trace-ID"
+)
+
+var (
+ // methodsMap stores all supported HTTP method,
+ // it is used for quick HTTP method searching using map.
+ methodsMap = make(map[string]struct{})
+
+ // serverMapping stores more than one server instances for current process.
+ // The key is the name of the server, and the value is its instance.
+ serverMapping = gmap.NewStrAnyMap(true)
+
+ // serverRunning marks the running server count.
+ // If there is no successful server running or all servers' shutdown, this value is 0.
+ serverRunning = gtype.NewInt()
+
+ // wsUpGrader is the default up-grader configuration for websocket.
+ wsUpGrader = websocket.Upgrader{
+ // It does not check the origin in default, the application can do it itself.
+ CheckOrigin: func(r *http.Request) bool {
+ return true
+ },
+ }
+ // allDoneChan is the event for all server have done its serving and exit.
+ // It is used for process blocking purpose.
+ allDoneChan = make(chan struct{}, 1000)
+
+ // serverProcessInitialized is used for lazy initialization for server.
+ // The process can only be initialized once.
+ serverProcessInitialized = gtype.NewBool()
+
+ // gracefulEnabled is used for graceful reload feature, which is false in default.
+ gracefulEnabled = false
+
+ // defaultValueTags is the struct tag names for default value storing.
+ defaultValueTags = []string{"d", "default"}
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go
new file mode 100644
index 000000000000..406958701451
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_func.go
@@ -0,0 +1,57 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/httputil"
+)
+
+// BuildParams builds the request string for the http client. The `params` can be type of:
+// string/[]byte/map/struct/*struct.
+//
+// The optional parameter `noUrlEncode` specifies whether ignore the url encoding for the data.
+func BuildParams(params interface{}, noUrlEncode ...bool) (encodedParamStr string) {
+ return httputil.BuildParams(params, noUrlEncode...)
+}
+
+// niceCallFunc calls function `f` with exception capture logic.
+func niceCallFunc(f func()) {
+ defer func() {
+ if exception := recover(); exception != nil {
+ switch exception {
+ case exceptionExit, exceptionExitAll:
+ return
+
+ default:
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ // It's already an error that has stack info.
+ panic(v)
+ }
+ // Create a new error with stack info.
+ // Note that there's a skip pointing the start stacktrace
+ // of the real error point.
+ if v, ok := exception.(error); ok {
+ if gerror.Code(v) != gcode.CodeNil {
+ panic(v)
+ } else {
+ panic(gerror.WrapCodeSkip(
+ gcode.CodeInternalError, 1, v, "exception recovered",
+ ))
+ }
+ } else {
+ panic(gerror.NewCodeSkipf(
+ gcode.CodeInternalError, 1, "exception recovered: %+v", exception,
+ ))
+ }
+
+ }
+ }
+ }()
+ f()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_cors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_cors.go
new file mode 100644
index 000000000000..bcfe9b87410b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_cors.go
@@ -0,0 +1,13 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+// MiddlewareCORS is a middleware handler for CORS with default options.
+func MiddlewareCORS(r *Request) {
+ r.Response.CORSDefault()
+ r.Middleware.Next()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_handler_response.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_handler_response.go
new file mode 100644
index 000000000000..72193f40dbc7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_handler_response.go
@@ -0,0 +1,60 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+type DefaultHandlerResponse struct {
+ Code int `json:"code" dc:"Error code"`
+ Message string `json:"message" dc:"Error message"`
+ Data interface{} `json:"data" dc:"Result data for certain request according API definition"`
+}
+
+// MiddlewareHandlerResponse is the default middleware handling handler response object and its error.
+func MiddlewareHandlerResponse(r *Request) {
+ r.Middleware.Next()
+
+ // There's custom buffer content, it then exits current handler.
+ if r.Response.BufferLength() > 0 {
+ return
+ }
+
+ var (
+ err error
+ res interface{}
+ ctx = r.Context()
+ internalErr error
+ )
+ res, err = r.GetHandlerResponse()
+ if err != nil {
+ code := gerror.Code(err)
+ if code == gcode.CodeNil {
+ code = gcode.CodeInternalError
+ }
+ internalErr = r.Response.WriteJson(DefaultHandlerResponse{
+ Code: code.Code(),
+ Message: err.Error(),
+ Data: nil,
+ })
+ if internalErr != nil {
+ intlog.Errorf(ctx, `%+v`, internalErr)
+ }
+ return
+ }
+ internalErr = r.Response.WriteJson(DefaultHandlerResponse{
+ Code: gcode.CodeOK.Code(),
+ Message: "",
+ Data: res,
+ })
+ if internalErr != nil {
+ intlog.Errorf(ctx, `%+v`, internalErr)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_tracing.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_tracing.go
new file mode 100644
index 000000000000..1645a9ba196b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_middleware_tracing.go
@@ -0,0 +1,111 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+ "io/ioutil"
+
+ "github.com/gogf/gf/v2/os/gctx"
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/propagation"
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2"
+ "github.com/gogf/gf/v2/internal/httputil"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/net/gtrace"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ tracingInstrumentName = "github.com/gogf/gf/v2/net/ghttp.Server"
+ tracingEventHttpRequest = "http.request"
+ tracingEventHttpRequestHeaders = "http.request.headers"
+ tracingEventHttpRequestBaggage = "http.request.baggage"
+ tracingEventHttpRequestBody = "http.request.body"
+ tracingEventHttpResponse = "http.response"
+ tracingEventHttpResponseHeaders = "http.response.headers"
+ tracingEventHttpResponseBody = "http.response.body"
+ tracingMiddlewareHandled gctx.StrKey = `MiddlewareServerTracingHandled`
+)
+
+// internalMiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry.
+func internalMiddlewareServerTracing(r *Request) {
+ var (
+ ctx = r.Context()
+ )
+ // Mark this request is handled by server tracing middleware,
+ // to avoid repeated handling by the same middleware.
+ if ctx.Value(tracingMiddlewareHandled) != nil {
+ r.Middleware.Next()
+ return
+ }
+
+ ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)
+ var (
+ span trace.Span
+ tr = otel.GetTracerProvider().Tracer(
+ tracingInstrumentName,
+ trace.WithInstrumentationVersion(gf.VERSION),
+ )
+ )
+ ctx, span = tr.Start(
+ otel.GetTextMapPropagator().Extract(
+ ctx,
+ propagation.HeaderCarrier(r.Header),
+ ),
+ r.URL.String(),
+ trace.WithSpanKind(trace.SpanKindServer),
+ )
+ defer span.End()
+
+ span.SetAttributes(gtrace.CommonLabels()...)
+
+ // Inject tracing context.
+ r.SetCtx(ctx)
+
+ // If it is now using default trace provider, it then does no complex tracing jobs.
+ if gtrace.IsUsingDefaultProvider() {
+ r.Middleware.Next()
+ return
+ }
+
+ // Request content logging.
+ reqBodyContentBytes, _ := ioutil.ReadAll(r.Body)
+ r.Body = utils.NewReadCloser(reqBodyContentBytes, false)
+
+ span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
+ attribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))),
+ attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()),
+ attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
+ string(reqBodyContentBytes),
+ gtrace.MaxContentLogSize(),
+ "...",
+ )),
+ ))
+
+ // Continue executing.
+ r.Middleware.Next()
+
+ // Error logging.
+ if err := r.GetError(); err != nil {
+ span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
+ }
+ // Response content logging.
+ var resBodyContent = gstr.StrLimit(r.Response.BufferString(), gtrace.MaxContentLogSize(), "...")
+
+ span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
+ attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(r.Response.Header()))),
+ attribute.String(tracingEventHttpResponseBody, resBodyContent),
+ ))
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request.go
new file mode 100644
index 000000000000..a704d6b16472
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request.go
@@ -0,0 +1,272 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gsession"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gview"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/util/guid"
+)
+
+// Request is the context object for a request.
+type Request struct {
+ *http.Request
+ Server *Server // Server.
+ Cookie *Cookie // Cookie.
+ Session *gsession.Session // Session.
+ Response *Response // Corresponding Response of this request.
+ Router *Router // Matched Router for this request. Note that it's not available in HOOK handler.
+ EnterTime int64 // Request starting time in microseconds.
+ LeaveTime int64 // Request ending time in microseconds.
+ Middleware *middleware // Middleware manager.
+ StaticFile *staticFile // Static file object for static file serving.
+
+ // =================================================================================================================
+ // Private attributes for internal usage purpose.
+ // =================================================================================================================
+
+ context context.Context // Custom context for internal usage purpose.
+ handlers []*handlerParsedItem // All matched handlers containing handler, hook and middleware for this request.
+ handlerResponse handlerResponse // Handler response object and its error value for Request/Response handler.
+ hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
+ hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
+ parsedQuery bool // A bool marking whether the GET parameters parsed.
+ parsedBody bool // A bool marking whether the request body parsed.
+ parsedForm bool // A bool marking whether request Form parsed for HTTP method PUT, POST, PATCH.
+ paramsMap map[string]interface{} // Custom parameters map.
+ routerMap map[string]string // Router parameters map, which might be nil if there're no router parameters.
+ queryMap map[string]interface{} // Query parameters map, which is nil if there's no query string.
+ formMap map[string]interface{} // Form parameters map, which is nil if there's no form data from client.
+ bodyMap map[string]interface{} // Body parameters map, which might be nil if there're no body content.
+ error error // Current executing error of the request.
+ exitAll bool // A bool marking whether current request is exited.
+ parsedHost string // The parsed host name for current host used by GetHost function.
+ clientIp string // The parsed client ip for current host used by GetClientIp function.
+ bodyContent []byte // Request body content.
+ isFileRequest bool // A bool marking whether current request is file serving.
+ viewObject *gview.View // Custom template view engine object for this response.
+ viewParams gview.Params // Custom template view variables for this response.
+ originUrlPath string // Original URL path that passed from client.
+}
+
+type handlerResponse struct {
+ Object interface{}
+ Error error
+}
+
+// staticFile is the file struct for static file service.
+type staticFile struct {
+ File *gres.File // Resource file object.
+ Path string // File path.
+ IsDir bool // Is directory.
+}
+
+// newRequest creates and returns a new request object.
+func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
+ request := &Request{
+ Server: s,
+ Request: r,
+ Response: newResponse(s, w),
+ EnterTime: gtime.TimestampMilli(),
+ originUrlPath: r.URL.Path,
+ }
+ request.Cookie = GetCookie(request)
+ request.Session = s.sessionManager.New(
+ r.Context(),
+ request.GetSessionId(),
+ )
+ request.Response.Request = request
+ request.Middleware = &middleware{
+ request: request,
+ }
+ // Custom session id creating function.
+ err := request.Session.SetIdFunc(func(ttl time.Duration) string {
+ var (
+ address = request.RemoteAddr
+ header = fmt.Sprintf("%v", request.Header)
+ )
+ intlog.Print(r.Context(), address, header)
+ return guid.S([]byte(address), []byte(header))
+ })
+ if err != nil {
+ panic(err)
+ }
+ // Remove char '/' in the tail of URI.
+ if request.URL.Path != "/" {
+ for len(request.URL.Path) > 0 && request.URL.Path[len(request.URL.Path)-1] == '/' {
+ request.URL.Path = request.URL.Path[:len(request.URL.Path)-1]
+ }
+ }
+
+ // Default URI value if it's empty.
+ if request.URL.Path == "" {
+ request.URL.Path = "/"
+ }
+ return request
+}
+
+// WebSocket upgrades current request as a websocket request.
+// It returns a new WebSocket object if success, or the error if failure.
+// Note that the request should be a websocket request, or it will surely fail upgrading.
+func (r *Request) WebSocket() (*WebSocket, error) {
+ if conn, err := wsUpGrader.Upgrade(r.Response.Writer, r.Request, nil); err == nil {
+ return &WebSocket{
+ conn,
+ }, nil
+ } else {
+ return nil, err
+ }
+}
+
+// Exit exits executing of current HTTP handler.
+func (r *Request) Exit() {
+ panic(exceptionExit)
+}
+
+// ExitAll exits executing of current and following HTTP handlers.
+func (r *Request) ExitAll() {
+ r.exitAll = true
+ panic(exceptionExitAll)
+}
+
+// ExitHook exits executing of current and following HTTP HOOK handlers.
+func (r *Request) ExitHook() {
+ panic(exceptionExitHook)
+}
+
+// IsExited checks and returns whether current request is exited.
+func (r *Request) IsExited() bool {
+ return r.exitAll
+}
+
+// GetHeader retrieves and returns the header value with given `key`.
+func (r *Request) GetHeader(key string) string {
+ return r.Header.Get(key)
+}
+
+// GetHost returns current request host name, which might be a domain or an IP without port.
+func (r *Request) GetHost() string {
+ if len(r.parsedHost) == 0 {
+ array, _ := gregex.MatchString(`(.+):(\d+)`, r.Host)
+ if len(array) > 1 {
+ r.parsedHost = array[1]
+ } else {
+ r.parsedHost = r.Host
+ }
+ }
+ return r.parsedHost
+}
+
+// IsFileRequest checks and returns whether current request is serving file.
+func (r *Request) IsFileRequest() bool {
+ return r.isFileRequest
+}
+
+// IsAjaxRequest checks and returns whether current request is an AJAX request.
+func (r *Request) IsAjaxRequest() bool {
+ return strings.EqualFold(r.Header.Get("X-Requested-With"), "XMLHttpRequest")
+}
+
+// GetClientIp returns the client ip of this request without port.
+// Note that this ip address might be modified by client header.
+func (r *Request) GetClientIp() string {
+ if r.clientIp != "" {
+ return r.clientIp
+ }
+ realIps := r.Header.Get("X-Forwarded-For")
+ if realIps != "" && len(realIps) != 0 && !strings.EqualFold("unknown", realIps) {
+ ipArray := strings.Split(realIps, ",")
+ r.clientIp = ipArray[0]
+ }
+ if r.clientIp == "" {
+ r.clientIp = r.Header.Get("Proxy-Client-IP")
+ }
+ if r.clientIp == "" {
+ r.clientIp = r.Header.Get("WL-Proxy-Client-IP")
+ }
+ if r.clientIp == "" {
+ r.clientIp = r.Header.Get("HTTP_CLIENT_IP")
+ }
+ if r.clientIp == "" {
+ r.clientIp = r.Header.Get("HTTP_X_FORWARDED_FOR")
+ }
+ if r.clientIp == "" {
+ r.clientIp = r.Header.Get("X-Real-IP")
+ }
+ if r.clientIp == "" {
+ r.clientIp = r.GetRemoteIp()
+ }
+ return r.clientIp
+}
+
+// GetRemoteIp returns the ip from RemoteAddr.
+func (r *Request) GetRemoteIp() string {
+ array, _ := gregex.MatchString(`(.+):(\d+)`, r.RemoteAddr)
+ if len(array) > 1 {
+ return strings.Trim(array[1], "[]")
+ }
+ return r.RemoteAddr
+}
+
+// GetUrl returns current URL of this request.
+func (r *Request) GetUrl() string {
+ scheme := "http"
+ if r.TLS != nil {
+ scheme = "https"
+ }
+ return fmt.Sprintf(`%s://%s%s`, scheme, r.Host, r.URL.String())
+}
+
+// GetSessionId retrieves and returns session id from cookie or header.
+func (r *Request) GetSessionId() string {
+ id := r.Cookie.GetSessionId()
+ if id == "" {
+ id = r.Header.Get(r.Server.GetSessionIdName())
+ }
+ return id
+}
+
+// GetReferer returns referer of this request.
+func (r *Request) GetReferer() string {
+ return r.Header.Get("Referer")
+}
+
+// GetError returns the error occurs in the procedure of the request.
+// It returns nil if there's no error.
+func (r *Request) GetError() error {
+ return r.error
+}
+
+// SetError sets custom error for current request.
+func (r *Request) SetError(err error) {
+ r.error = err
+}
+
+// ReloadParam is used for modifying request parameter.
+// Sometimes, we want to modify request parameters through middleware, but directly modifying Request.Body
+// is invalid, so it clears the parsed* marks to make the parameters re-parsed.
+func (r *Request) ReloadParam() {
+ r.parsedBody = false
+ r.parsedForm = false
+ r.parsedQuery = false
+ r.bodyContent = nil
+}
+
+// GetHandlerResponse retrieves and returns the handler response object and its error.
+func (r *Request) GetHandlerResponse() (res interface{}, err error) {
+ return r.handlerResponse.Object, r.handlerResponse.Error
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_auth.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_auth.go
new file mode 100644
index 000000000000..017340812645
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_auth.go
@@ -0,0 +1,65 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/gogf/gf/v2/encoding/gbase64"
+)
+
+// BasicAuth enables the http basic authentication feature with given passport and password
+// and asks client for authentication. It returns true if authentication success, else returns
+// false if failure.
+func (r *Request) BasicAuth(user, pass string, tips ...string) bool {
+ auth := r.Header.Get("Authorization")
+ if auth == "" {
+ r.setBasicAuth(tips...)
+ return false
+ }
+ authArray := strings.SplitN(auth, " ", 2)
+ if len(authArray) != 2 {
+ r.Response.WriteStatus(http.StatusForbidden)
+ return false
+ }
+ switch authArray[0] {
+ case "Basic":
+ authBytes, err := gbase64.DecodeString(authArray[1])
+ if err != nil {
+ r.Response.WriteStatus(http.StatusForbidden, err.Error())
+ return false
+ }
+ authArray := strings.SplitN(string(authBytes), ":", 2)
+ if len(authArray) != 2 {
+ r.Response.WriteStatus(http.StatusForbidden)
+ return false
+ }
+ if authArray[0] != user || authArray[1] != pass {
+ r.setBasicAuth(tips...)
+ return false
+ }
+ return true
+
+ default:
+ r.Response.WriteStatus(http.StatusForbidden)
+ return false
+ }
+}
+
+// setBasicAuth sets the http basic authentication tips.
+func (r *Request) setBasicAuth(tips ...string) {
+ realm := ""
+ if len(tips) > 0 && tips[0] != "" {
+ realm = tips[0]
+ } else {
+ realm = "Need Login"
+ }
+ r.Response.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
+ r.Response.WriteHeader(http.StatusUnauthorized)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go
new file mode 100644
index 000000000000..3572d8d40ea2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_middleware.go
@@ -0,0 +1,172 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "net/http"
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// middleware is the plugin for request workflow management.
+type middleware struct {
+ served bool // Is the request served, which is used for checking response status 404.
+ request *Request // The request object pointer.
+ handlerIndex int // Index number for executing sequence purpose for handler items.
+ handlerMDIndex int // Index number for executing sequence purpose for bound middleware of handler item.
+}
+
+// Next calls the next workflow handler.
+// It's an important function controlling the workflow of the server request execution.
+func (m *middleware) Next() {
+ var item *handlerParsedItem
+ var loop = true
+ for loop {
+ // Check whether the request is exited.
+ if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {
+ break
+ }
+ item = m.request.handlers[m.handlerIndex]
+ // Filter the HOOK handlers, which are designed to be called in another standalone procedure.
+ if item.Handler.Type == HandlerTypeHook {
+ m.handlerIndex++
+ continue
+ }
+ // Current router switching.
+ m.request.Router = item.Handler.Router
+
+ // Router values switching.
+ m.request.routerMap = item.Values
+
+ gutil.TryCatch(func() {
+ // Execute bound middleware array of the item if it's not empty.
+ if m.handlerMDIndex < len(item.Handler.Middleware) {
+ md := item.Handler.Middleware[m.handlerMDIndex]
+ m.handlerMDIndex++
+ niceCallFunc(func() {
+ md(m.request)
+ })
+ loop = false
+ return
+ }
+ m.handlerIndex++
+
+ switch item.Handler.Type {
+ // Service object.
+ case HandlerTypeObject:
+ m.served = true
+ if m.request.IsExited() {
+ break
+ }
+ if item.Handler.InitFunc != nil {
+ niceCallFunc(func() {
+ item.Handler.InitFunc(m.request)
+ })
+ }
+ if !m.request.IsExited() {
+ m.callHandlerFunc(item.Handler.Info)
+ }
+ if !m.request.IsExited() && item.Handler.ShutFunc != nil {
+ niceCallFunc(func() {
+ item.Handler.ShutFunc(m.request)
+ })
+ }
+
+ // Service handler.
+ case HandlerTypeHandler:
+ m.served = true
+ if m.request.IsExited() {
+ break
+ }
+ niceCallFunc(func() {
+ m.callHandlerFunc(item.Handler.Info)
+ })
+
+ // Global middleware array.
+ case HandlerTypeMiddleware:
+ niceCallFunc(func() {
+ item.Handler.Info.Func(m.request)
+ })
+ // It does not continue calling next middleware after another middleware done.
+ // There should be a "Next" function to be called in the middleware in order to manage the workflow.
+ loop = false
+ }
+ }, func(exception error) {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ // It's already an error that has stack info.
+ m.request.error = v
+ } else {
+ // Create a new error with stack info.
+ // Note that there's a skip pointing the start stacktrace
+ // of the real error point.
+ m.request.error = gerror.WrapCodeSkip(gcode.CodeInternalError, 1, exception, "")
+ }
+ m.request.Response.WriteStatus(http.StatusInternalServerError, exception)
+ loop = false
+ })
+ }
+ // Check the http status code after all handler and middleware done.
+ if m.request.IsExited() || m.handlerIndex >= len(m.request.handlers) {
+ if m.request.Response.Status == 0 {
+ if m.request.Middleware.served {
+ m.request.Response.WriteHeader(http.StatusOK)
+ } else {
+ m.request.Response.WriteHeader(http.StatusNotFound)
+ }
+ }
+ }
+}
+
+func (m *middleware) callHandlerFunc(funcInfo handlerFuncInfo) {
+ niceCallFunc(func() {
+ if funcInfo.Func != nil {
+ funcInfo.Func(m.request)
+ } else {
+ var inputValues = []reflect.Value{
+ reflect.ValueOf(m.request.Context()),
+ }
+ if funcInfo.Type.NumIn() == 2 {
+ var (
+ inputObject reflect.Value
+ )
+ if funcInfo.Type.In(1).Kind() == reflect.Ptr {
+ inputObject = reflect.New(funcInfo.Type.In(1).Elem())
+ m.request.handlerResponse.Error = m.request.Parse(inputObject.Interface())
+ } else {
+ inputObject = reflect.New(funcInfo.Type.In(1).Elem()).Elem()
+ m.request.handlerResponse.Error = m.request.Parse(inputObject.Addr().Interface())
+ }
+ if m.request.handlerResponse.Error != nil {
+ return
+ }
+ inputValues = append(inputValues, inputObject)
+ }
+
+ // Call handler with dynamic created parameter values.
+ results := funcInfo.Value.Call(inputValues)
+ switch len(results) {
+ case 1:
+ if !results[0].IsNil() {
+ if err, ok := results[0].Interface().(error); ok {
+ m.request.handlerResponse.Error = err
+ }
+ }
+
+ case 2:
+ m.request.handlerResponse.Object = results[0].Interface()
+ if !results[1].IsNil() {
+ if err, ok := results[1].Interface().(error); ok {
+ m.request.handlerResponse.Error = err
+ }
+ }
+ }
+ }
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param.go
new file mode 100644
index 000000000000..2a3be9873884
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param.go
@@ -0,0 +1,360 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "mime/multipart"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/encoding/gurl"
+ "github.com/gogf/gf/v2/encoding/gxml"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gvalid"
+)
+
+const (
+ parseTypeRequest = 0
+ parseTypeQuery = 1
+ parseTypeForm = 2
+)
+
+var (
+ // xmlHeaderBytes is the most common XML format header.
+ xmlHeaderBytes = []byte(" 0 {
+ // Trim space/new line characters.
+ body = bytes.TrimSpace(body)
+ // JSON format checks.
+ if body[0] == '{' && body[len(body)-1] == '}' {
+ _ = json.UnmarshalUseNumber(body, &r.bodyMap)
+ }
+ // XML format checks.
+ if len(body) > 5 && bytes.EqualFold(body[:5], xmlHeaderBytes) {
+ r.bodyMap, _ = gxml.DecodeWithoutRoot(body)
+ }
+ if body[0] == '<' && body[len(body)-1] == '>' {
+ r.bodyMap, _ = gxml.DecodeWithoutRoot(body)
+ }
+ // Default parameters decoding.
+ if r.bodyMap == nil {
+ r.bodyMap, _ = gstr.Parse(r.GetBodyString())
+ }
+ }
+}
+
+// parseForm parses the request form for HTTP method PUT, POST, PATCH.
+// The form data is pared into r.formMap.
+//
+// Note that if the form was parsed firstly, the request body would be cleared and empty.
+func (r *Request) parseForm() {
+ if r.parsedForm {
+ return
+ }
+ r.parsedForm = true
+ // There's no data posted.
+ if r.ContentLength == 0 {
+ return
+ }
+ if contentType := r.Header.Get("Content-Type"); contentType != "" {
+ var err error
+ if gstr.Contains(contentType, "multipart/") {
+ // multipart/form-data, multipart/mixed
+ if err = r.ParseMultipartForm(r.Server.config.FormParsingMemory); err != nil {
+ panic(gerror.WrapCode(gcode.CodeInvalidRequest, err, "r.ParseMultipartForm failed"))
+ }
+ } else if gstr.Contains(contentType, "form") {
+ // application/x-www-form-urlencoded
+ if err = r.Request.ParseForm(); err != nil {
+ panic(gerror.WrapCode(gcode.CodeInvalidRequest, err, "r.Request.ParseForm failed"))
+ }
+ }
+ if len(r.PostForm) > 0 {
+ // Re-parse the form data using united parsing way.
+ params := ""
+ for name, values := range r.PostForm {
+ // Invalid parameter name.
+ // Only allow chars of: '\w', '[', ']', '-'.
+ if !gregex.IsMatchString(`^[\w\-\[\]]+$`, name) && len(r.PostForm) == 1 {
+ // It might be JSON/XML content.
+ if s := gstr.Trim(name + strings.Join(values, " ")); len(s) > 0 {
+ if s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' {
+ r.bodyContent = []byte(s)
+ params = ""
+ break
+ }
+ }
+ }
+ if len(values) == 1 {
+ if len(params) > 0 {
+ params += "&"
+ }
+ params += name + "=" + gurl.Encode(values[0])
+ } else {
+ if len(name) > 2 && name[len(name)-2:] == "[]" {
+ name = name[:len(name)-2]
+ for _, v := range values {
+ if len(params) > 0 {
+ params += "&"
+ }
+ params += name + "[]=" + gurl.Encode(v)
+ }
+ } else {
+ if len(params) > 0 {
+ params += "&"
+ }
+ params += name + "=" + gurl.Encode(values[len(values)-1])
+ }
+ }
+ }
+ if params != "" {
+ if r.formMap, err = gstr.Parse(params); err != nil {
+ panic(gerror.WrapCode(gcode.CodeInvalidParameter, err, "Parse request parameters failed"))
+ }
+ }
+ }
+ }
+ // It parses the request body without checking the Content-Type.
+ if r.formMap == nil {
+ if r.Method != "GET" {
+ r.parseBody()
+ }
+ if len(r.bodyMap) > 0 {
+ r.formMap = r.bodyMap
+ }
+ }
+}
+
+// GetMultipartForm parses and returns the form as multipart form.
+func (r *Request) GetMultipartForm() *multipart.Form {
+ r.parseForm()
+ return r.MultipartForm
+}
+
+// GetMultipartFiles parses and returns the post files array.
+// Note that the request form should be type of multipart.
+func (r *Request) GetMultipartFiles(name string) []*multipart.FileHeader {
+ form := r.GetMultipartForm()
+ if form == nil {
+ return nil
+ }
+ if v := form.File[name]; len(v) > 0 {
+ return v
+ }
+ // Support "name[]" as array parameter.
+ if v := form.File[name+"[]"]; len(v) > 0 {
+ return v
+ }
+ // Support "name[0]","name[1]","name[2]", etc. as array parameter.
+ var (
+ key = ""
+ files = make([]*multipart.FileHeader, 0)
+ )
+ for i := 0; ; i++ {
+ key = fmt.Sprintf(`%s[%d]`, name, i)
+ if v := form.File[key]; len(v) > 0 {
+ files = append(files, v[0])
+ } else {
+ break
+ }
+ }
+ if len(files) > 0 {
+ return files
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_ctx.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_ctx.go
new file mode 100644
index 000000000000..7c4760b5653b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_ctx.go
@@ -0,0 +1,65 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/os/gctx"
+)
+
+// RequestFromCtx retrieves and returns the Request object from context.
+func RequestFromCtx(ctx context.Context) *Request {
+ if v := ctx.Value(ctxKeyForRequest); v != nil {
+ return v.(*Request)
+ }
+ return nil
+}
+
+// Context is alias for function GetCtx.
+// This function overwrites the http.Request.Context function.
+// See GetCtx.
+func (r *Request) Context() context.Context {
+ if r.context == nil {
+ // DO NOT use the http context as it will be canceled after request done,
+ // which makes the asynchronous goroutine encounter "context canceled" error.
+ // r.context = r.Request.Context()
+ r.context = gctx.New()
+ }
+ // Inject Request object into context.
+ if RequestFromCtx(r.context) == nil {
+ r.context = context.WithValue(r.context, ctxKeyForRequest, r)
+ }
+ return r.context
+}
+
+// GetCtx retrieves and returns the request's context.
+func (r *Request) GetCtx() context.Context {
+ return r.Context()
+}
+
+// SetCtx custom context for current request.
+func (r *Request) SetCtx(ctx context.Context) {
+ r.context = ctx
+}
+
+// GetCtxVar retrieves and returns a Var with given key name.
+// The optional parameter `def` specifies the default value of the Var if given `key`
+// does not exist in the context.
+func (r *Request) GetCtxVar(key interface{}, def ...interface{}) *gvar.Var {
+ value := r.Context().Value(key)
+ if value == nil && len(def) > 0 {
+ value = def[0]
+ }
+ return gvar.New(value)
+}
+
+// SetCtxVar sets custom parameter to context with key-value pair.
+func (r *Request) SetCtxVar(key interface{}, value interface{}) {
+ r.context = context.WithValue(r.Context(), key, value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_file.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_file.go
new file mode 100644
index 000000000000..0b624cb764f7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_file.go
@@ -0,0 +1,136 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "io"
+ "mime/multipart"
+ "strconv"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+// UploadFile wraps the multipart uploading file with more and convenient features.
+type UploadFile struct {
+ *multipart.FileHeader
+ ctx context.Context
+}
+
+// UploadFiles is array type for *UploadFile.
+type UploadFiles []*UploadFile
+
+// Save saves the single uploading file to directory path and returns the saved file name.
+//
+// The parameter `dirPath` should be a directory path or it returns error.
+//
+// Note that it will OVERWRITE the target file if there's already a same name file exist.
+func (f *UploadFile) Save(dirPath string, randomlyRename ...bool) (filename string, err error) {
+ if f == nil {
+ return "", gerror.NewCode(
+ gcode.CodeMissingParameter,
+ "file is empty, maybe you retrieve it from invalid field name or form enctype",
+ )
+ }
+ if !gfile.Exists(dirPath) {
+ if err = gfile.Mkdir(dirPath); err != nil {
+ return
+ }
+ } else if !gfile.IsDir(dirPath) {
+ return "", gerror.NewCode(gcode.CodeInvalidParameter, `parameter "dirPath" should be a directory path`)
+ }
+
+ file, err := f.Open()
+ if err != nil {
+ err = gerror.Wrapf(err, `UploadFile.Open failed`)
+ return "", err
+ }
+ defer file.Close()
+
+ name := gfile.Basename(f.Filename)
+ if len(randomlyRename) > 0 && randomlyRename[0] {
+ name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
+ name = name + gfile.Ext(f.Filename)
+ }
+ filePath := gfile.Join(dirPath, name)
+ newFile, err := gfile.Create(filePath)
+ if err != nil {
+ return "", err
+ }
+ defer newFile.Close()
+ intlog.Printf(f.ctx, `save upload file: %s`, filePath)
+ if _, err = io.Copy(newFile, file); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed from "%s" to "%s"`, f.Filename, filePath)
+ return "", err
+ }
+ return gfile.Basename(filePath), nil
+}
+
+// Save saves all uploading files to specified directory path and returns the saved file names.
+//
+// The parameter `dirPath` should be a directory path or it returns error.
+//
+// The parameter `randomlyRename` specifies whether randomly renames all the file names.
+func (fs UploadFiles) Save(dirPath string, randomlyRename ...bool) (filenames []string, err error) {
+ if len(fs) == 0 {
+ return nil, gerror.NewCode(
+ gcode.CodeMissingParameter,
+ "file array is empty, maybe you retrieve it from invalid field name or form enctype",
+ )
+ }
+ for _, f := range fs {
+ if filename, err := f.Save(dirPath, randomlyRename...); err != nil {
+ return filenames, err
+ } else {
+ filenames = append(filenames, filename)
+ }
+ }
+ return
+}
+
+// GetUploadFile retrieves and returns the uploading file with specified form name.
+// This function is used for retrieving single uploading file object, which is
+// uploaded using multipart form content type.
+//
+// It returns nil if retrieving failed or no form file with given name posted.
+//
+// Note that the `name` is the file field name of the multipart form from client.
+func (r *Request) GetUploadFile(name string) *UploadFile {
+ uploadFiles := r.GetUploadFiles(name)
+ if len(uploadFiles) > 0 {
+ return uploadFiles[0]
+ }
+ return nil
+}
+
+// GetUploadFiles retrieves and returns multiple uploading files with specified form name.
+// This function is used for retrieving multiple uploading file objects, which are
+// uploaded using multipart form content type.
+//
+// It returns nil if retrieving failed or no form file with given name posted.
+//
+// Note that the `name` is the file field name of the multipart form from client.
+func (r *Request) GetUploadFiles(name string) UploadFiles {
+ multipartFiles := r.GetMultipartFiles(name)
+ if len(multipartFiles) > 0 {
+ uploadFiles := make(UploadFiles, len(multipartFiles))
+ for k, v := range multipartFiles {
+ uploadFiles[k] = &UploadFile{
+ ctx: r.Context(),
+ FileHeader: v,
+ }
+ }
+ return uploadFiles
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_form.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_form.go
new file mode 100644
index 000000000000..4cb710e9cb66
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_form.go
@@ -0,0 +1,109 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// SetForm sets custom form value with key-value pair.
+func (r *Request) SetForm(key string, value interface{}) {
+ r.parseForm()
+ if r.formMap == nil {
+ r.formMap = make(map[string]interface{})
+ }
+ r.formMap[key] = value
+}
+
+// GetForm retrieves and returns parameter `key` from form.
+// It returns `def` if `key` does not exist in the form and `def` is given, or else it returns nil.
+func (r *Request) GetForm(key string, def ...interface{}) *gvar.Var {
+ r.parseForm()
+ if len(r.formMap) > 0 {
+ if v, ok := r.formMap[key]; ok {
+ return gvar.New(v)
+ }
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// GetFormMap retrieves and returns all form parameters passed from client as map.
+// The parameter `kvMap` specifies the keys retrieving from client parameters,
+// the associated values are the default values if the client does not pass.
+func (r *Request) GetFormMap(kvMap ...map[string]interface{}) map[string]interface{} {
+ r.parseForm()
+ if len(kvMap) > 0 && kvMap[0] != nil {
+ if len(r.formMap) == 0 {
+ return kvMap[0]
+ }
+ m := make(map[string]interface{}, len(kvMap[0]))
+ for k, defValue := range kvMap[0] {
+ if postValue, ok := r.formMap[k]; ok {
+ m[k] = postValue
+ } else {
+ m[k] = defValue
+ }
+ }
+ return m
+ } else {
+ return r.formMap
+ }
+}
+
+// GetFormMapStrStr retrieves and returns all form parameters passed from client as map[string]string.
+// The parameter `kvMap` specifies the keys retrieving from client parameters, the associated values
+// are the default values if the client does not pass.
+func (r *Request) GetFormMapStrStr(kvMap ...map[string]interface{}) map[string]string {
+ formMap := r.GetFormMap(kvMap...)
+ if len(formMap) > 0 {
+ m := make(map[string]string, len(formMap))
+ for k, v := range formMap {
+ m[k] = gconv.String(v)
+ }
+ return m
+ }
+ return nil
+}
+
+// GetFormMapStrVar retrieves and returns all form parameters passed from client as map[string]*gvar.Var.
+// The parameter `kvMap` specifies the keys retrieving from client parameters, the associated values
+// are the default values if the client does not pass.
+func (r *Request) GetFormMapStrVar(kvMap ...map[string]interface{}) map[string]*gvar.Var {
+ formMap := r.GetFormMap(kvMap...)
+ if len(formMap) > 0 {
+ m := make(map[string]*gvar.Var, len(formMap))
+ for k, v := range formMap {
+ m[k] = gvar.New(v)
+ }
+ return m
+ }
+ return nil
+}
+
+// GetFormStruct retrieves all form parameters passed from client and converts them to
+// given struct object. Note that the parameter `pointer` is a pointer to the struct object.
+// The optional parameter `mapping` is used to specify the key to attribute mapping.
+func (r *Request) GetFormStruct(pointer interface{}, mapping ...map[string]string) error {
+ _, err := r.doGetFormStruct(pointer, mapping...)
+ return err
+}
+
+func (r *Request) doGetFormStruct(pointer interface{}, mapping ...map[string]string) (data map[string]interface{}, err error) {
+ r.parseForm()
+ data = r.formMap
+ if data == nil {
+ data = map[string]interface{}{}
+ }
+ if err = r.mergeDefaultStructValue(data, pointer); err != nil {
+ return data, nil
+ }
+ return data, gconv.Struct(data, pointer, mapping...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_page.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_page.go
new file mode 100644
index 000000000000..8feda30eb9cd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_page.go
@@ -0,0 +1,72 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gpage"
+)
+
+// GetPage creates and returns the pagination object for given `totalSize` and `pageSize`.
+// NOTE THAT the page parameter name from client is constantly defined as gpage.DefaultPageName
+// for simplification and convenience.
+func (r *Request) GetPage(totalSize, pageSize int) *gpage.Page {
+ // It must have Router object attribute.
+ if r.Router == nil {
+ panic("Router object not found")
+ }
+ var (
+ url = *r.URL
+ urlTemplate = url.Path
+ uriHasPageName = false
+ )
+ // Check the page variable in the URI.
+ if len(r.Router.RegNames) > 0 {
+ for _, name := range r.Router.RegNames {
+ if name == gpage.DefaultPageName {
+ uriHasPageName = true
+ break
+ }
+ }
+ if uriHasPageName {
+ if match, err := gregex.MatchString(r.Router.RegRule, url.Path); err == nil && len(match) > 0 {
+ if len(match) > len(r.Router.RegNames) {
+ urlTemplate = r.Router.Uri
+ for i, name := range r.Router.RegNames {
+ rule := fmt.Sprintf(`[:\*]%s|\{%s\}`, name, name)
+ if name == gpage.DefaultPageName {
+ urlTemplate, err = gregex.ReplaceString(rule, gpage.DefaultPagePlaceHolder, urlTemplate)
+ } else {
+ urlTemplate, err = gregex.ReplaceString(rule, match[i+1], urlTemplate)
+ }
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+ } else {
+ panic(err)
+ }
+ }
+ }
+ // Check the page variable in the query string.
+ if !uriHasPageName {
+ values := url.Query()
+ values.Set(gpage.DefaultPageName, gpage.DefaultPagePlaceHolder)
+ url.RawQuery = values.Encode()
+ // Replace the encoded "{.page}" to original "{.page}".
+ url.RawQuery = gstr.Replace(url.RawQuery, "%7B.page%7D", "{.page}")
+ }
+ if url.RawQuery != "" {
+ urlTemplate += "?" + url.RawQuery
+ }
+
+ return gpage.New(totalSize, pageSize, r.Get(gpage.DefaultPageName).Int(), urlTemplate)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_param.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_param.go
new file mode 100644
index 000000000000..1cb86c985d44
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_param.go
@@ -0,0 +1,40 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "github.com/gogf/gf/v2/container/gvar"
+
+// SetParam sets custom parameter with key-value pair.
+func (r *Request) SetParam(key string, value interface{}) {
+ if r.paramsMap == nil {
+ r.paramsMap = make(map[string]interface{})
+ }
+ r.paramsMap[key] = value
+}
+
+// SetParamMap sets custom parameter with key-value pair map.
+func (r *Request) SetParamMap(data map[string]interface{}) {
+ if r.paramsMap == nil {
+ r.paramsMap = make(map[string]interface{})
+ }
+ for k, v := range data {
+ r.paramsMap[k] = v
+ }
+}
+
+// GetParam returns custom parameter with given name `key`.
+// It returns `def` if `key` does not exist.
+// It returns nil if `def` is not passed.
+func (r *Request) GetParam(key string, def ...interface{}) *gvar.Var {
+ if r.paramsMap != nil {
+ return gvar.New(r.paramsMap[key])
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_query.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_query.go
new file mode 100644
index 000000000000..70ed03f1d97e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_query.go
@@ -0,0 +1,148 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// SetQuery sets custom query value with key-value pair.
+func (r *Request) SetQuery(key string, value interface{}) {
+ r.parseQuery()
+ if r.queryMap == nil {
+ r.queryMap = make(map[string]interface{})
+ }
+ r.queryMap[key] = value
+}
+
+// GetQuery retrieves and returns parameter with given name `key` from query string
+// and request body. It returns `def` if `key` does not exist in the query and `def` is given,
+// or else it returns nil.
+//
+// Note that if there are multiple parameters with the same name, the parameters are retrieved
+// and overwrote in order of priority: query > body.
+func (r *Request) GetQuery(key string, def ...interface{}) *gvar.Var {
+ r.parseQuery()
+ if len(r.queryMap) > 0 {
+ if v, ok := r.queryMap[key]; ok {
+ return gvar.New(v)
+ }
+ }
+ if r.Method == "GET" {
+ r.parseBody()
+ }
+ if len(r.bodyMap) > 0 {
+ if v, ok := r.bodyMap[key]; ok {
+ return gvar.New(v)
+ }
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// GetQueryMap retrieves and returns all parameters passed from client using HTTP GET method
+// as map. The parameter `kvMap` specifies the keys retrieving from client parameters,
+// the associated values are the default values if the client does not pass.
+//
+// Note that if there are multiple parameters with the same name, the parameters are retrieved and overwrote
+// in order of priority: query > body.
+func (r *Request) GetQueryMap(kvMap ...map[string]interface{}) map[string]interface{} {
+ r.parseQuery()
+ if r.Method == "GET" {
+ r.parseBody()
+ }
+ var m map[string]interface{}
+ if len(kvMap) > 0 && kvMap[0] != nil {
+ if len(r.queryMap) == 0 && len(r.bodyMap) == 0 {
+ return kvMap[0]
+ }
+ m = make(map[string]interface{}, len(kvMap[0]))
+ if len(r.bodyMap) > 0 {
+ for k, v := range kvMap[0] {
+ if postValue, ok := r.bodyMap[k]; ok {
+ m[k] = postValue
+ } else {
+ m[k] = v
+ }
+ }
+ }
+ if len(r.queryMap) > 0 {
+ for k, v := range kvMap[0] {
+ if postValue, ok := r.queryMap[k]; ok {
+ m[k] = postValue
+ } else {
+ m[k] = v
+ }
+ }
+ }
+ } else {
+ m = make(map[string]interface{}, len(r.queryMap)+len(r.bodyMap))
+ for k, v := range r.bodyMap {
+ m[k] = v
+ }
+ for k, v := range r.queryMap {
+ m[k] = v
+ }
+ }
+ return m
+}
+
+// GetQueryMapStrStr retrieves and returns all parameters passed from client using HTTP GET method
+// as map[string]string. The parameter `kvMap` specifies the keys
+// retrieving from client parameters, the associated values are the default values if the client
+// does not pass.
+func (r *Request) GetQueryMapStrStr(kvMap ...map[string]interface{}) map[string]string {
+ queryMap := r.GetQueryMap(kvMap...)
+ if len(queryMap) > 0 {
+ m := make(map[string]string, len(queryMap))
+ for k, v := range queryMap {
+ m[k] = gconv.String(v)
+ }
+ return m
+ }
+ return nil
+}
+
+// GetQueryMapStrVar retrieves and returns all parameters passed from client using HTTP GET method
+// as map[string]*gvar.Var. The parameter `kvMap` specifies the keys
+// retrieving from client parameters, the associated values are the default values if the client
+// does not pass.
+func (r *Request) GetQueryMapStrVar(kvMap ...map[string]interface{}) map[string]*gvar.Var {
+ queryMap := r.GetQueryMap(kvMap...)
+ if len(queryMap) > 0 {
+ m := make(map[string]*gvar.Var, len(queryMap))
+ for k, v := range queryMap {
+ m[k] = gvar.New(v)
+ }
+ return m
+ }
+ return nil
+}
+
+// GetQueryStruct retrieves all parameters passed from client using HTTP GET method
+// and converts them to given struct object. Note that the parameter `pointer` is a pointer
+// to the struct object. The optional parameter `mapping` is used to specify the key to
+// attribute mapping.
+func (r *Request) GetQueryStruct(pointer interface{}, mapping ...map[string]string) error {
+ _, err := r.doGetQueryStruct(pointer, mapping...)
+ return err
+}
+
+func (r *Request) doGetQueryStruct(pointer interface{}, mapping ...map[string]string) (data map[string]interface{}, err error) {
+ r.parseQuery()
+ data = r.GetQueryMap()
+ if data == nil {
+ data = map[string]interface{}{}
+ }
+ if err = r.mergeDefaultStructValue(data, pointer); err != nil {
+ return data, nil
+ }
+ return data, gconv.Struct(data, pointer, mapping...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_request.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_request.go
new file mode 100644
index 000000000000..035ba2c72cfe
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_request.go
@@ -0,0 +1,203 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// GetRequest retrieves and returns the parameter named `key` passed from client and
+// custom params as interface{}, no matter what HTTP method the client is using. The
+// parameter `def` specifies the default value if the `key` does not exist.
+//
+// GetRequest is one of the most commonly used functions for retrieving parameters.
+//
+// Note that if there are multiple parameters with the same name, the parameters are
+// retrieved and overwrote in order of priority: router < query < body < form < custom.
+func (r *Request) GetRequest(key string, def ...interface{}) *gvar.Var {
+ value := r.GetParam(key)
+ if value == nil {
+ value = r.GetForm(key)
+ }
+ if value == nil {
+ r.parseBody()
+ if len(r.bodyMap) > 0 {
+ if v := r.bodyMap[key]; v != nil {
+ value = gvar.New(v)
+ }
+ }
+ }
+ if value == nil {
+ value = r.GetQuery(key)
+ }
+ if value == nil {
+ value = r.GetRouter(key)
+ }
+ if value != nil {
+ return value
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// GetRequestMap retrieves and returns all parameters passed from client and custom params
+// as map, no matter what HTTP method the client is using. The parameter `kvMap` specifies
+// the keys retrieving from client parameters, the associated values are the default values
+// if the client does not pass the according keys.
+//
+// GetRequestMap is one of the most commonly used functions for retrieving parameters.
+//
+// Note that if there are multiple parameters with the same name, the parameters are retrieved
+// and overwrote in order of priority: router < query < body < form < custom.
+func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]interface{} {
+ r.parseQuery()
+ r.parseForm()
+ r.parseBody()
+ var (
+ ok, filter bool
+ )
+ var length int
+ if len(kvMap) > 0 && kvMap[0] != nil {
+ length = len(kvMap[0])
+ filter = true
+ } else {
+ length = len(r.routerMap) + len(r.queryMap) + len(r.formMap) + len(r.bodyMap) + len(r.paramsMap)
+ }
+ m := make(map[string]interface{}, length)
+ for k, v := range r.routerMap {
+ if filter {
+ if _, ok = kvMap[0][k]; !ok {
+ continue
+ }
+ }
+ m[k] = v
+ }
+ for k, v := range r.queryMap {
+ if filter {
+ if _, ok = kvMap[0][k]; !ok {
+ continue
+ }
+ }
+ m[k] = v
+ }
+ for k, v := range r.formMap {
+ if filter {
+ if _, ok = kvMap[0][k]; !ok {
+ continue
+ }
+ }
+ m[k] = v
+ }
+ for k, v := range r.bodyMap {
+ if filter {
+ if _, ok = kvMap[0][k]; !ok {
+ continue
+ }
+ }
+ m[k] = v
+ }
+ for k, v := range r.paramsMap {
+ if filter {
+ if _, ok = kvMap[0][k]; !ok {
+ continue
+ }
+ }
+ m[k] = v
+ }
+ // Check none exist parameters and assign it with default value.
+ if filter {
+ for k, v := range kvMap[0] {
+ if _, ok = m[k]; !ok {
+ m[k] = v
+ }
+ }
+ }
+ return m
+}
+
+// GetRequestMapStrStr retrieves and returns all parameters passed from client and custom
+// params as map[string]string, no matter what HTTP method the client is using. The parameter
+// `kvMap` specifies the keys retrieving from client parameters, the associated values are the
+// default values if the client does not pass.
+func (r *Request) GetRequestMapStrStr(kvMap ...map[string]interface{}) map[string]string {
+ requestMap := r.GetRequestMap(kvMap...)
+ if len(requestMap) > 0 {
+ m := make(map[string]string, len(requestMap))
+ for k, v := range requestMap {
+ m[k] = gconv.String(v)
+ }
+ return m
+ }
+ return nil
+}
+
+// GetRequestMapStrVar retrieves and returns all parameters passed from client and custom
+// params as map[string]*gvar.Var, no matter what HTTP method the client is using. The parameter
+// `kvMap` specifies the keys retrieving from client parameters, the associated values are the
+// default values if the client does not pass.
+func (r *Request) GetRequestMapStrVar(kvMap ...map[string]interface{}) map[string]*gvar.Var {
+ requestMap := r.GetRequestMap(kvMap...)
+ if len(requestMap) > 0 {
+ m := make(map[string]*gvar.Var, len(requestMap))
+ for k, v := range requestMap {
+ m[k] = gvar.New(v)
+ }
+ return m
+ }
+ return nil
+}
+
+// GetRequestStruct retrieves all parameters passed from client and custom params no matter
+// what HTTP method the client is using, and converts them to given struct object. Note that
+// the parameter `pointer` is a pointer to the struct object.
+// The optional parameter `mapping` is used to specify the key to attribute mapping.
+func (r *Request) GetRequestStruct(pointer interface{}, mapping ...map[string]string) error {
+ _, err := r.doGetRequestStruct(pointer, mapping...)
+ return err
+}
+
+func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string]string) (data map[string]interface{}, err error) {
+ data = r.GetRequestMap()
+ if data == nil {
+ data = map[string]interface{}{}
+ }
+ if err = r.mergeDefaultStructValue(data, pointer); err != nil {
+ return data, nil
+ }
+ return data, gconv.Struct(data, pointer, mapping...)
+}
+
+// mergeDefaultStructValue merges the request parameters with default values from struct tag definition.
+func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error {
+ tagFields, err := gstructs.TagFields(pointer, defaultValueTags)
+ if err != nil {
+ return err
+ }
+ if len(tagFields) > 0 {
+ var (
+ foundKey string
+ foundValue interface{}
+ )
+ for _, field := range tagFields {
+ foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
+ if foundKey == "" {
+ data[field.Name()] = field.TagValue
+ } else {
+ if empty.IsEmpty(foundValue) {
+ data[foundKey] = field.TagValue
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_router.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_router.go
new file mode 100644
index 000000000000..37db2f11a67a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_param_router.go
@@ -0,0 +1,35 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "github.com/gogf/gf/v2/container/gvar"
+
+// GetRouterMap retrieves and returns a copy of router map.
+func (r *Request) GetRouterMap() map[string]string {
+ if r.routerMap != nil {
+ m := make(map[string]string, len(r.routerMap))
+ for k, v := range r.routerMap {
+ m[k] = v
+ }
+ return m
+ }
+ return nil
+}
+
+// GetRouter retrieves and returns the router value with given key name `key`.
+// It returns `def` if `key` does not exist.
+func (r *Request) GetRouter(key string, def ...interface{}) *gvar.Var {
+ if r.routerMap != nil {
+ if v, ok := r.routerMap[key]; ok {
+ return gvar.New(v)
+ }
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_view.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_view.go
new file mode 100644
index 000000000000..143ecc701bb5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_request_view.go
@@ -0,0 +1,44 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "github.com/gogf/gf/v2/os/gview"
+
+// SetView sets template view engine object for this request.
+func (r *Request) SetView(view *gview.View) {
+ r.viewObject = view
+}
+
+// GetView returns the template view engine object for this request.
+func (r *Request) GetView() *gview.View {
+ view := r.viewObject
+ if view == nil {
+ view = r.Server.config.View
+ }
+ if view == nil {
+ view = gview.Instance()
+ }
+ return view
+}
+
+// Assigns binds multiple template variables to current request.
+func (r *Request) Assigns(data gview.Params) {
+ if r.viewParams == nil {
+ r.viewParams = make(gview.Params, len(data))
+ }
+ for k, v := range data {
+ r.viewParams[k] = v
+ }
+}
+
+// Assign binds a template variable to current request.
+func (r *Request) Assign(key string, value interface{}) {
+ if r.viewParams == nil {
+ r.viewParams = make(gview.Params)
+ }
+ r.viewParams[key] = value
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response.go
new file mode 100644
index 000000000000..eb6f89ef13b3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response.go
@@ -0,0 +1,151 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package ghttp
+
+import (
+ "bytes"
+ "fmt"
+ "net/http"
+
+ "github.com/gogf/gf/v2/net/gtrace"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gres"
+)
+
+// Response is the http response manager.
+// Note that it implements the http.ResponseWriter interface with buffering feature.
+type Response struct {
+ *ResponseWriter // Underlying ResponseWriter.
+ Server *Server // Parent server.
+ Writer *ResponseWriter // Alias of ResponseWriter.
+ Request *Request // According request.
+}
+
+// newResponse creates and returns a new Response object.
+func newResponse(s *Server, w http.ResponseWriter) *Response {
+ r := &Response{
+ Server: s,
+ ResponseWriter: &ResponseWriter{
+ writer: w,
+ buffer: bytes.NewBuffer(nil),
+ },
+ }
+ r.Writer = r.ResponseWriter
+ return r
+}
+
+// ServeFile serves the file to the response.
+func (r *Response) ServeFile(path string, allowIndex ...bool) {
+ var (
+ serveFile *staticFile
+ )
+ if file := gres.Get(path); file != nil {
+ serveFile = &staticFile{
+ File: file,
+ IsDir: file.FileInfo().IsDir(),
+ }
+ } else {
+ path, _ = gfile.Search(path)
+ if path == "" {
+ r.WriteStatus(http.StatusNotFound)
+ return
+ }
+ serveFile = &staticFile{Path: path}
+ }
+ r.Server.serveFile(r.Request, serveFile, allowIndex...)
+}
+
+// ServeFileDownload serves file downloading to the response.
+func (r *Response) ServeFileDownload(path string, name ...string) {
+ var (
+ serveFile *staticFile
+ downloadName = ""
+ )
+
+ if len(name) > 0 {
+ downloadName = name[0]
+ }
+ if file := gres.Get(path); file != nil {
+ serveFile = &staticFile{
+ File: file,
+ IsDir: file.FileInfo().IsDir(),
+ }
+ if downloadName == "" {
+ downloadName = gfile.Basename(file.Name())
+ }
+ } else {
+ path, _ = gfile.Search(path)
+ if path == "" {
+ r.WriteStatus(http.StatusNotFound)
+ return
+ }
+ serveFile = &staticFile{Path: path}
+ if downloadName == "" {
+ downloadName = gfile.Basename(path)
+ }
+ }
+ r.Header().Set("Content-Type", "application/force-download")
+ r.Header().Set("Accept-Ranges", "bytes")
+ r.Header().Set("Content-Disposition", fmt.Sprintf(`attachment;filename="%s"`, downloadName))
+ r.Server.serveFile(r.Request, serveFile)
+}
+
+// RedirectTo redirects client to another location.
+// The optional parameter `code` specifies the http status code for redirecting,
+// which commonly can be 301 or 302. It's 302 in default.
+func (r *Response) RedirectTo(location string, code ...int) {
+ r.Header().Set("Location", location)
+ if len(code) > 0 {
+ r.WriteHeader(code[0])
+ } else {
+ r.WriteHeader(http.StatusFound)
+ }
+ r.Request.Exit()
+}
+
+// RedirectBack redirects client back to referer.
+// The optional parameter `code` specifies the http status code for redirecting,
+// which commonly can be 301 or 302. It's 302 in default.
+func (r *Response) RedirectBack(code ...int) {
+ r.RedirectTo(r.Request.GetReferer(), code...)
+}
+
+// Buffer returns the buffered content as []byte.
+func (r *Response) Buffer() []byte {
+ return r.buffer.Bytes()
+}
+
+// BufferString returns the buffered content as string.
+func (r *Response) BufferString() string {
+ return r.buffer.String()
+}
+
+// BufferLength returns the length of the buffered content.
+func (r *Response) BufferLength() int {
+ return r.buffer.Len()
+}
+
+// SetBuffer overwrites the buffer with `data`.
+func (r *Response) SetBuffer(data []byte) {
+ r.buffer.Reset()
+ r.buffer.Write(data)
+}
+
+// ClearBuffer clears the response buffer.
+func (r *Response) ClearBuffer() {
+ r.buffer.Reset()
+}
+
+// Flush outputs the buffer content to the client and clears the buffer.
+func (r *Response) Flush() {
+ r.Header().Set(responseTraceIDHeader, gtrace.GetTraceID(r.Request.Context()))
+ if r.Server.config.ServerAgent != "" {
+ r.Header().Set("Server", r.Server.config.ServerAgent)
+ }
+ r.Writer.Flush()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_cors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_cors.go
new file mode 100644
index 000000000000..d18fbc9b5d54
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_cors.go
@@ -0,0 +1,137 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package ghttp
+
+import (
+ "net/http"
+ "net/url"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// CORSOptions is the options for CORS feature.
+// See https://www.w3.org/TR/cors/ .
+type CORSOptions struct {
+ AllowDomain []string // Used for allowing requests from custom domains
+ AllowOrigin string // Access-Control-Allow-Origin
+ AllowCredentials string // Access-Control-Allow-Credentials
+ ExposeHeaders string // Access-Control-Expose-Headers
+ MaxAge int // Access-Control-Max-Age
+ AllowMethods string // Access-Control-Allow-Methods
+ AllowHeaders string // Access-Control-Allow-Headers
+}
+
+var (
+ // defaultAllowHeaders is the default allowed headers for CORS.
+ // It's defined another map for better header key searching performance.
+ defaultAllowHeaders = "Origin,Content-Type,Accept,User-Agent,Cookie,Authorization,X-Auth-Token,X-Requested-With"
+ defaultAllowHeadersMap = make(map[string]struct{})
+)
+
+func init() {
+ array := gstr.SplitAndTrim(defaultAllowHeaders, ",")
+ for _, header := range array {
+ defaultAllowHeadersMap[header] = struct{}{}
+ }
+}
+
+// DefaultCORSOptions returns the default CORS options,
+// which allows any cross-domain request.
+func (r *Response) DefaultCORSOptions() CORSOptions {
+ options := CORSOptions{
+ AllowOrigin: "*",
+ AllowMethods: supportedHttpMethods,
+ AllowCredentials: "true",
+ AllowHeaders: defaultAllowHeaders,
+ MaxAge: 3628800,
+ }
+ // Allow all client's custom headers in default.
+ if headers := r.Request.Header.Get("Access-Control-Request-Headers"); headers != "" {
+ array := gstr.SplitAndTrim(headers, ",")
+ for _, header := range array {
+ if _, ok := defaultAllowHeadersMap[header]; !ok {
+ options.AllowHeaders += "," + header
+ }
+ }
+ }
+ // Allow all anywhere origin in default.
+ if origin := r.Request.Header.Get("Origin"); origin != "" {
+ options.AllowOrigin = origin
+ } else if referer := r.Request.Referer(); referer != "" {
+ if p := gstr.PosR(referer, "/", 6); p != -1 {
+ options.AllowOrigin = referer[:p]
+ } else {
+ options.AllowOrigin = referer
+ }
+ }
+ return options
+}
+
+// CORS sets custom CORS options.
+// See https://www.w3.org/TR/cors/ .
+func (r *Response) CORS(options CORSOptions) {
+ if r.CORSAllowedOrigin(options) {
+ r.Header().Set("Access-Control-Allow-Origin", options.AllowOrigin)
+ }
+ if options.AllowCredentials != "" {
+ r.Header().Set("Access-Control-Allow-Credentials", options.AllowCredentials)
+ }
+ if options.ExposeHeaders != "" {
+ r.Header().Set("Access-Control-Expose-Headers", options.ExposeHeaders)
+ }
+ if options.MaxAge != 0 {
+ r.Header().Set("Access-Control-Max-Age", gconv.String(options.MaxAge))
+ }
+ if options.AllowMethods != "" {
+ r.Header().Set("Access-Control-Allow-Methods", options.AllowMethods)
+ }
+ if options.AllowHeaders != "" {
+ r.Header().Set("Access-Control-Allow-Headers", options.AllowHeaders)
+ }
+ // No continue service handling if it's OPTIONS request.
+ // Note that there's special checks in previous router searching,
+ // so if it goes to here it means there's already serving handler exist.
+ if gstr.Equal(r.Request.Method, "OPTIONS") {
+ if r.Status == 0 {
+ r.Status = http.StatusOK
+ }
+ // No continue serving.
+ r.Request.ExitAll()
+ }
+}
+
+// CORSAllowedOrigin CORSAllowed checks whether the current request origin is allowed cross-domain.
+func (r *Response) CORSAllowedOrigin(options CORSOptions) bool {
+ if options.AllowDomain == nil {
+ return true
+ }
+ origin := r.Request.Header.Get("Origin")
+ if origin == "" {
+ return true
+ }
+ parsed, err := url.Parse(origin)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `url.Parse failed for URL "%s"`, origin)
+ return false
+ }
+ for _, v := range options.AllowDomain {
+ if gstr.IsSubDomain(parsed.Host, v) {
+ return true
+ }
+ }
+ return false
+}
+
+// CORSDefault sets CORS with default CORS options,
+// which allows any cross-domain request.
+func (r *Response) CORSDefault() {
+ r.CORS(r.DefaultCORSOptions())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_view.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_view.go
new file mode 100644
index 000000000000..ed733c998003
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_view.go
@@ -0,0 +1,102 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package ghttp
+
+import (
+ "github.com/gogf/gf/v2/os/gcfg"
+ "github.com/gogf/gf/v2/os/gview"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gmode"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// WriteTpl parses and responses given template file.
+// The parameter `params` specifies the template variables for parsing.
+func (r *Response) WriteTpl(tpl string, params ...gview.Params) error {
+ r.Header().Set("Content-Type", contentTypeHtml)
+ b, err := r.ParseTpl(tpl, params...)
+ if err != nil {
+ if !gmode.IsProduct() {
+ r.Write("Template Parsing Error: " + err.Error())
+ }
+ return err
+ }
+ r.Write(b)
+ return nil
+}
+
+// WriteTplDefault parses and responses the default template file.
+// The parameter `params` specifies the template variables for parsing.
+func (r *Response) WriteTplDefault(params ...gview.Params) error {
+ r.Header().Set("Content-Type", contentTypeHtml)
+ b, err := r.ParseTplDefault(params...)
+ if err != nil {
+ if !gmode.IsProduct() {
+ r.Write("Template Parsing Error: " + err.Error())
+ }
+ return err
+ }
+ r.Write(b)
+ return nil
+}
+
+// WriteTplContent parses and responses the template content.
+// The parameter `params` specifies the template variables for parsing.
+func (r *Response) WriteTplContent(content string, params ...gview.Params) error {
+ r.Header().Set("Content-Type", contentTypeHtml)
+ b, err := r.ParseTplContent(content, params...)
+ if err != nil {
+ if !gmode.IsProduct() {
+ r.Write("Template Parsing Error: " + err.Error())
+ }
+ return err
+ }
+ r.Write(b)
+ return nil
+}
+
+// ParseTpl parses given template file `tpl` with given template variables `params`
+// and returns the parsed template content.
+func (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) {
+ return r.Request.GetView().Parse(r.Request.Context(), tpl, r.buildInVars(params...))
+}
+
+// ParseTplDefault parses the default template file with params.
+func (r *Response) ParseTplDefault(params ...gview.Params) (string, error) {
+ return r.Request.GetView().ParseDefault(r.Request.Context(), r.buildInVars(params...))
+}
+
+// ParseTplContent parses given template file `file` with given template parameters `params`
+// and returns the parsed template content.
+func (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) {
+ return r.Request.GetView().ParseContent(r.Request.Context(), content, r.buildInVars(params...))
+}
+
+// buildInVars merges build-in variables into `params` and returns the new template variables.
+// TODO performance improving.
+func (r *Response) buildInVars(params ...map[string]interface{}) map[string]interface{} {
+ m := gutil.MapMergeCopy(r.Request.viewParams)
+ if len(params) > 0 {
+ gutil.MapMerge(m, params[0])
+ }
+ // Retrieve custom template variables from request object.
+ sessionMap := gconv.MapDeep(r.Request.Session.MustData())
+ gutil.MapMerge(m, map[string]interface{}{
+ "Form": r.Request.GetFormMap(),
+ "Query": r.Request.GetQueryMap(),
+ "Request": r.Request.GetMap(),
+ "Cookie": r.Request.Cookie.Map(),
+ "Session": sessionMap,
+ })
+ // Note that it should assign no Config variable to template
+ // if there's no configuration file.
+ if v, _ := gcfg.Instance().Data(r.Request.Context()); len(v) > 0 {
+ m["Config"] = v
+ }
+ return m
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_write.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_write.go
new file mode 100644
index 000000000000..e7923e3520bb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_write.go
@@ -0,0 +1,220 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package ghttp
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Write writes `content` to the response buffer.
+func (r *Response) Write(content ...interface{}) {
+ if r.hijacked || len(content) == 0 {
+ return
+ }
+ if r.Status == 0 {
+ r.Status = http.StatusOK
+ }
+ for _, v := range content {
+ switch value := v.(type) {
+ case []byte:
+ r.buffer.Write(value)
+ case string:
+ r.buffer.WriteString(value)
+ default:
+ r.buffer.WriteString(gconv.String(v))
+ }
+ }
+}
+
+// WriteExit writes `content` to the response buffer and exits executing of current handler.
+// The "Exit" feature is commonly used to replace usage of return statement in the handler,
+// for convenience.
+func (r *Response) WriteExit(content ...interface{}) {
+ r.Write(content...)
+ r.Request.Exit()
+}
+
+// WriteOver overwrites the response buffer with `content`.
+func (r *Response) WriteOver(content ...interface{}) {
+ r.ClearBuffer()
+ r.Write(content...)
+}
+
+// WriteOverExit overwrites the response buffer with `content` and exits executing
+// of current handler. The "Exit" feature is commonly used to replace usage of return
+// statement in the handler, for convenience.
+func (r *Response) WriteOverExit(content ...interface{}) {
+ r.WriteOver(content...)
+ r.Request.Exit()
+}
+
+// Writef writes the response with fmt.Sprintf.
+func (r *Response) Writef(format string, params ...interface{}) {
+ r.Write(fmt.Sprintf(format, params...))
+}
+
+// WritefExit writes the response with fmt.Sprintf and exits executing of current handler.
+// The "Exit" feature is commonly used to replace usage of return statement in the handler,
+// for convenience.
+func (r *Response) WritefExit(format string, params ...interface{}) {
+ r.Writef(format, params...)
+ r.Request.Exit()
+}
+
+// Writeln writes the response with `content` and new line.
+func (r *Response) Writeln(content ...interface{}) {
+ if len(content) == 0 {
+ r.Write("\n")
+ return
+ }
+ r.Write(append(content, "\n")...)
+}
+
+// WritelnExit writes the response with `content` and new line and exits executing
+// of current handler. The "Exit" feature is commonly used to replace usage of return
+// statement in the handler, for convenience.
+func (r *Response) WritelnExit(content ...interface{}) {
+ r.Writeln(content...)
+ r.Request.Exit()
+}
+
+// Writefln writes the response with fmt.Sprintf and new line.
+func (r *Response) Writefln(format string, params ...interface{}) {
+ r.Writeln(fmt.Sprintf(format, params...))
+}
+
+// WriteflnExit writes the response with fmt.Sprintf and new line and exits executing
+// of current handler. The "Exit" feature is commonly used to replace usage of return
+// statement in the handler, for convenience.
+func (r *Response) WriteflnExit(format string, params ...interface{}) {
+ r.Writefln(format, params...)
+ r.Request.Exit()
+}
+
+// WriteJson writes `content` to the response with JSON format.
+func (r *Response) WriteJson(content interface{}) error {
+ r.Header().Set("Content-Type", contentTypeJson)
+ // If given string/[]byte, response it directly to client.
+ switch content.(type) {
+ case string, []byte:
+ r.Write(gconv.String(content))
+ return nil
+ }
+ // Else use json.Marshal function to encode the parameter.
+ if b, err := json.Marshal(content); err != nil {
+ return err
+ } else {
+ r.Write(b)
+ }
+ return nil
+}
+
+// WriteJsonExit writes `content` to the response with JSON format and exits executing
+// of current handler if success. The "Exit" feature is commonly used to replace usage of
+// return statement in the handler, for convenience.
+func (r *Response) WriteJsonExit(content interface{}) error {
+ if err := r.WriteJson(content); err != nil {
+ return err
+ }
+ r.Request.Exit()
+ return nil
+}
+
+// WriteJsonP writes `content` to the response with JSONP format.
+//
+// Note that there should be a "callback" parameter in the request for JSONP format.
+func (r *Response) WriteJsonP(content interface{}) error {
+ r.Header().Set("Content-Type", contentTypeJson)
+ // If given string/[]byte, response it directly to client.
+ switch content.(type) {
+ case string, []byte:
+ r.Write(gconv.String(content))
+ return nil
+ }
+ // Else use json.Marshal function to encode the parameter.
+ if b, err := json.Marshal(content); err != nil {
+ return err
+ } else {
+ // r.Header().Set("Content-Type", "application/json")
+ if callback := r.Request.Get("callback").String(); callback != "" {
+ buffer := []byte(callback)
+ buffer = append(buffer, byte('('))
+ buffer = append(buffer, b...)
+ buffer = append(buffer, byte(')'))
+ r.Write(buffer)
+ } else {
+ r.Write(b)
+ }
+ }
+ return nil
+}
+
+// WriteJsonPExit writes `content` to the response with JSONP format and exits executing
+// of current handler if success. The "Exit" feature is commonly used to replace usage of
+// return statement in the handler, for convenience.
+//
+// Note that there should be a "callback" parameter in the request for JSONP format.
+func (r *Response) WriteJsonPExit(content interface{}) error {
+ if err := r.WriteJsonP(content); err != nil {
+ return err
+ }
+ r.Request.Exit()
+ return nil
+}
+
+// WriteXml writes `content` to the response with XML format.
+func (r *Response) WriteXml(content interface{}, rootTag ...string) error {
+ r.Header().Set("Content-Type", contentTypeXml)
+ // If given string/[]byte, response it directly to client.
+ switch content.(type) {
+ case string, []byte:
+ r.Write(gconv.String(content))
+ return nil
+ }
+ if b, err := gjson.New(content).ToXml(rootTag...); err != nil {
+ return err
+ } else {
+ r.Write(b)
+ }
+ return nil
+}
+
+// WriteXmlExit writes `content` to the response with XML format and exits executing
+// of current handler if success. The "Exit" feature is commonly used to replace usage
+// of return statement in the handler, for convenience.
+func (r *Response) WriteXmlExit(content interface{}, rootTag ...string) error {
+ if err := r.WriteXml(content, rootTag...); err != nil {
+ return err
+ }
+ r.Request.Exit()
+ return nil
+}
+
+// WriteStatus writes HTTP `status` and `content` to the response.
+// Note that do not set Content-Type header here.
+func (r *Response) WriteStatus(status int, content ...interface{}) {
+ r.WriteHeader(status)
+ if len(content) > 0 {
+ r.Write(content...)
+ } else {
+ r.Write(http.StatusText(status))
+ }
+}
+
+// WriteStatusExit writes HTTP `status` and `content` to the response and exits executing
+// of current handler if success. The "Exit" feature is commonly used to replace usage of
+// return statement in the handler, for convenience.
+func (r *Response) WriteStatusExit(status int, content ...interface{}) {
+ r.WriteStatus(status, content...)
+ r.Request.Exit()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_writer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_writer.go
new file mode 100644
index 000000000000..5a8781a02954
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_response_writer.go
@@ -0,0 +1,70 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package ghttp
+
+import (
+ "bufio"
+ "bytes"
+ "net"
+ "net/http"
+)
+
+// ResponseWriter is the custom writer for http response.
+type ResponseWriter struct {
+ Status int // HTTP status.
+ writer http.ResponseWriter // The underlying ResponseWriter.
+ buffer *bytes.Buffer // The output buffer.
+ hijacked bool // Mark this request is hijacked or not.
+ wroteHeader bool // Is header wrote or not, avoiding error: superfluous/multiple response.WriteHeader call.
+}
+
+// RawWriter returns the underlying ResponseWriter.
+func (w *ResponseWriter) RawWriter() http.ResponseWriter {
+ return w.writer
+}
+
+// Header implements the interface function of http.ResponseWriter.Header.
+func (w *ResponseWriter) Header() http.Header {
+ return w.writer.Header()
+}
+
+// Write implements the interface function of http.ResponseWriter.Write.
+func (w *ResponseWriter) Write(data []byte) (int, error) {
+ w.buffer.Write(data)
+ return len(data), nil
+}
+
+// WriteHeader implements the interface of http.ResponseWriter.WriteHeader.
+func (w *ResponseWriter) WriteHeader(status int) {
+ w.Status = status
+}
+
+// Hijack implements the interface function of http.Hijacker.Hijack.
+func (w *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ w.hijacked = true
+ return w.writer.(http.Hijacker).Hijack()
+}
+
+// Flush outputs the buffer to client and clears the buffer.
+func (w *ResponseWriter) Flush() {
+ if w.hijacked {
+ return
+ }
+ if w.Status != 0 && !w.wroteHeader {
+ w.wroteHeader = true
+ w.writer.WriteHeader(w.Status)
+ }
+ // Default status text output.
+ if w.Status != http.StatusOK && w.buffer.Len() == 0 {
+ w.buffer.WriteString(http.StatusText(w.Status))
+ }
+ if w.buffer.Len() > 0 {
+ w.writer.Write(w.buffer.Bytes())
+ w.buffer.Reset()
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server.go
new file mode 100644
index 000000000000..f036c121db62
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server.go
@@ -0,0 +1,621 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "net/http"
+ "os"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/olekukonko/tablewriter"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/debug/gdebug"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/net/ghttp/internal/swaggerui"
+ "github.com/gogf/gf/v2/os/gcache"
+ "github.com/gogf/gf/v2/os/genv"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/os/gproc"
+ "github.com/gogf/gf/v2/os/gsession"
+ "github.com/gogf/gf/v2/os/gtimer"
+ "github.com/gogf/gf/v2/protocol/goai"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+func init() {
+ // Initialize the methods map.
+ for _, v := range strings.Split(supportedHttpMethods, ",") {
+ methodsMap[v] = struct{}{}
+ }
+}
+
+// serverProcessInit initializes some process configurations, which can only be done once.
+func serverProcessInit() {
+ var ctx = context.TODO()
+ if !serverProcessInitialized.Cas(false, true) {
+ return
+ }
+ // This means it is a restart server, it should kill its parent before starting its listening,
+ // to avoid duplicated port listening in two processes.
+ if !genv.Get(adminActionRestartEnvKey).IsEmpty() {
+ if p, err := os.FindProcess(gproc.PPid()); err == nil {
+ if err = p.Kill(); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ if _, err = p.Wait(); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ } else {
+ glog.Error(ctx, err)
+ }
+ }
+
+ // Signal handler.
+ go handleProcessSignal()
+
+ // Process message handler.
+ // It's enabled only graceful feature is enabled.
+ if gracefulEnabled {
+ intlog.Printf(ctx, "%d: graceful reload feature is enabled", gproc.Pid())
+ go handleProcessMessage()
+ } else {
+ intlog.Printf(ctx, "%d: graceful reload feature is disabled", gproc.Pid())
+ }
+
+ // It's an ugly calling for better initializing the main package path
+ // in source development environment. It is useful only be used in main goroutine.
+ // It fails retrieving the main package path in asynchronous goroutines.
+ gfile.MainPkgPath()
+}
+
+// GetServer creates and returns a server instance using given name and default configurations.
+// Note that the parameter `name` should be unique for different servers. It returns an existing
+// server instance if given `name` is already existing in the server mapping.
+func GetServer(name ...interface{}) *Server {
+ serverName := DefaultServerName
+ if len(name) > 0 && name[0] != "" {
+ serverName = gconv.String(name[0])
+ }
+ if s := serverMapping.Get(serverName); s != nil {
+ return s.(*Server)
+ }
+ s := &Server{
+ instance: serverName,
+ plugins: make([]Plugin, 0),
+ servers: make([]*gracefulServer, 0),
+ closeChan: make(chan struct{}, 10000),
+ serverCount: gtype.NewInt(),
+ statusHandlerMap: make(map[string][]HandlerFunc),
+ serveTree: make(map[string]interface{}),
+ serveCache: gcache.New(),
+ routesMap: make(map[string][]registeredRouteItem),
+ openapi: goai.New(),
+ }
+ // Initialize the server using default configurations.
+ if err := s.SetConfig(NewConfig()); err != nil {
+ panic(gerror.WrapCode(gcode.CodeInvalidConfiguration, err, ""))
+ }
+ // Record the server to internal server mapping by name.
+ serverMapping.Set(serverName, s)
+ // It enables OpenTelemetry for server in default.
+ s.Use(internalMiddlewareServerTracing)
+ return s
+}
+
+// Start starts listening on configured port.
+// This function does not block the process, you can use function Wait blocking the process.
+func (s *Server) Start() error {
+ var ctx = context.TODO()
+
+ // Swagger UI.
+ if s.config.SwaggerPath != "" {
+ swaggerui.Init()
+ s.AddStaticPath(s.config.SwaggerPath, swaggerUIPackedPath)
+ s.BindHookHandler(s.config.SwaggerPath+"/*", HookBeforeServe, s.swaggerUI)
+ s.Logger().Debugf(
+ ctx,
+ `swagger ui is serving at address: %s%s/`,
+ s.getListenAddress(),
+ s.config.SwaggerPath,
+ )
+ }
+
+ // OpenApi specification json producing handler.
+ if s.config.OpenApiPath != "" {
+ s.BindHandler(s.config.OpenApiPath, s.openapiSpec)
+ s.Logger().Infof(
+ ctx,
+ `openapi specification is serving at address: %s%s`,
+ s.getListenAddress(),
+ s.config.OpenApiPath,
+ )
+ } else {
+ if s.config.SwaggerPath != "" {
+ s.Logger().Warning(
+ ctx,
+ `openapi specification is disabled but swagger ui is serving, which might make no sense`,
+ )
+ } else {
+ s.Logger().Info(
+ ctx,
+ `openapi specification is disabled`,
+ )
+ }
+ }
+ // Register group routes.
+ s.handlePreBindItems(ctx)
+
+ // Server process initialization, which can only be initialized once.
+ serverProcessInit()
+
+ // Server can only be run once.
+ if s.Status() == ServerStatusRunning {
+ return gerror.NewCode(gcode.CodeInvalidOperation, "server is already running")
+ }
+
+ // Logging path setting check.
+ if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
+ if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
+ return err
+ }
+ }
+ // Default session storage.
+ if s.config.SessionStorage == nil {
+ path := ""
+ if s.config.SessionPath != "" {
+ path = gfile.Join(s.config.SessionPath, s.config.Name)
+ if !gfile.Exists(path) {
+ if err := gfile.Mkdir(path); err != nil {
+ return gerror.Wrapf(err, `mkdir failed for "%s"`, path)
+ }
+ }
+ }
+ s.config.SessionStorage = gsession.NewStorageFile(path)
+ }
+ // Initialize session manager when start running.
+ s.sessionManager = gsession.New(
+ s.config.SessionMaxAge,
+ s.config.SessionStorage,
+ )
+
+ // PProf feature.
+ if s.config.PProfEnabled {
+ s.EnablePProf(s.config.PProfPattern)
+ }
+
+ // Default HTTP handler.
+ if s.config.Handler == nil {
+ s.config.Handler = s.ServeHTTP
+ }
+
+ // Install external plugins.
+ for _, p := range s.plugins {
+ if err := p.Install(s); err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+ }
+ // Check the group routes again.
+ s.handlePreBindItems(ctx)
+
+ // If there's no route registered and no static service enabled,
+ // it then returns an error of invalid usage of server.
+ if len(s.routesMap) == 0 && !s.config.FileServerEnabled {
+ return gerror.NewCode(
+ gcode.CodeInvalidOperation,
+ `there's no route set or static feature enabled, did you forget import the router?`,
+ )
+ }
+
+ // Start the HTTP server.
+ reloaded := false
+ fdMapStr := genv.Get(adminActionReloadEnvKey).String()
+ if len(fdMapStr) > 0 {
+ sfm := bufferToServerFdMap([]byte(fdMapStr))
+ if v, ok := sfm[s.config.Name]; ok {
+ s.startServer(v)
+ reloaded = true
+ }
+ }
+ if !reloaded {
+ s.startServer(nil)
+ }
+
+ // If this is a child process, it then notifies its parent exit.
+ if gproc.IsChild() {
+ gtimer.SetTimeout(ctx, time.Duration(s.config.GracefulTimeout)*time.Second, func(ctx context.Context) {
+ if err := gproc.Send(gproc.PPid(), []byte("exit"), adminGProcCommGroup); err != nil {
+ intlog.Errorf(ctx, `server error in process communication: %+v`, err)
+ }
+ })
+ }
+ s.initOpenApi()
+ s.doServiceRegister()
+ s.dumpRouterMap()
+ return nil
+}
+
+func (s *Server) getListenAddress() string {
+ var (
+ array = gstr.SplitAndTrim(s.config.Address, ":")
+ host = `127.0.0.1`
+ port = 0
+ )
+ if len(array) > 1 {
+ host = array[0]
+ port = gconv.Int(array[1])
+ } else {
+ port = gconv.Int(array[0])
+ }
+ return fmt.Sprintf(`http://%s:%d`, host, port)
+}
+
+// DumpRouterMap dumps the router map to the log.
+func (s *Server) dumpRouterMap() {
+ var (
+ ctx = context.TODO()
+ routes = s.GetRoutes()
+ headers = []string{"SERVER", "DOMAIN", "ADDRESS", "METHOD", "ROUTE", "HANDLER", "MIDDLEWARE"}
+ isJustDefaultServerAndDomain = true
+ )
+ for _, item := range routes {
+ if item.Server != DefaultServerName || item.Domain != DefaultDomainName {
+ isJustDefaultServerAndDomain = false
+ break
+ }
+ }
+ if isJustDefaultServerAndDomain {
+ headers = []string{"ADDRESS", "METHOD", "ROUTE", "HANDLER", "MIDDLEWARE"}
+ }
+ if s.config.DumpRouterMap && len(routes) > 0 {
+ buffer := bytes.NewBuffer(nil)
+ table := tablewriter.NewWriter(buffer)
+ table.SetHeader(headers)
+ table.SetRowLine(true)
+ table.SetBorder(false)
+ table.SetCenterSeparator("|")
+
+ for _, item := range routes {
+ var (
+ data = make([]string, 0)
+ handlerName = gstr.TrimRightStr(item.Handler.Name, "-fm")
+ middlewares = gstr.SplitAndTrim(item.Middleware, ",")
+ )
+ for k, v := range middlewares {
+ middlewares[k] = gstr.TrimRightStr(v, "-fm")
+ }
+ item.Middleware = gstr.Join(middlewares, "\n")
+ if isJustDefaultServerAndDomain {
+ data = append(
+ data,
+ item.Address,
+ item.Method,
+ item.Route,
+ handlerName,
+ item.Middleware,
+ )
+ } else {
+ data = append(
+ data,
+ item.Server,
+ item.Domain,
+ item.Address,
+ item.Method,
+ item.Route,
+ handlerName,
+ item.Middleware,
+ )
+ }
+ table.Append(data)
+ }
+ table.Render()
+ s.config.Logger.Header(false).Printf(ctx, "\n%s", buffer.String())
+ }
+}
+
+// GetOpenApi returns the OpenApi specification management object of current server.
+func (s *Server) GetOpenApi() *goai.OpenApiV3 {
+ return s.openapi
+}
+
+// GetRoutes retrieves and returns the router array.
+func (s *Server) GetRoutes() []RouterItem {
+ var (
+ m = make(map[string]*garray.SortedArray)
+ address = s.config.Address
+ )
+ if s.config.HTTPSAddr != "" {
+ if len(address) > 0 {
+ address += ","
+ }
+ address += "tls" + s.config.HTTPSAddr
+ }
+ for k, registeredItems := range s.routesMap {
+ array, _ := gregex.MatchString(`(.*?)%([A-Z]+):(.+)@(.+)`, k)
+ for index, registeredItem := range registeredItems {
+ item := RouterItem{
+ Server: s.config.Name,
+ Address: address,
+ Domain: array[4],
+ Type: registeredItem.Handler.Type,
+ Middleware: array[1],
+ Method: array[2],
+ Route: array[3],
+ Priority: len(registeredItems) - index - 1,
+ Handler: registeredItem.Handler,
+ }
+ switch item.Handler.Type {
+ case HandlerTypeObject, HandlerTypeHandler:
+ item.IsServiceHandler = true
+
+ case HandlerTypeMiddleware:
+ item.Middleware = "GLOBAL MIDDLEWARE"
+ }
+ if len(item.Handler.Middleware) > 0 {
+ for _, v := range item.Handler.Middleware {
+ if item.Middleware != "" {
+ item.Middleware += ","
+ }
+ item.Middleware += gdebug.FuncName(v)
+ }
+ }
+ // If the domain does not exist in the dump map, it creates the map.
+ // The value of the map is a custom sorted array.
+ if _, ok := m[item.Domain]; !ok {
+ // Sort in ASC order.
+ m[item.Domain] = garray.NewSortedArray(func(v1, v2 interface{}) int {
+ item1 := v1.(RouterItem)
+ item2 := v2.(RouterItem)
+ r := 0
+ if r = strings.Compare(item1.Domain, item2.Domain); r == 0 {
+ if r = strings.Compare(item1.Route, item2.Route); r == 0 {
+ if r = strings.Compare(item1.Method, item2.Method); r == 0 {
+ if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type != HandlerTypeMiddleware {
+ return -1
+ } else if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type == HandlerTypeMiddleware {
+ return 1
+ } else if r = strings.Compare(item1.Middleware, item2.Middleware); r == 0 {
+ r = item2.Priority - item1.Priority
+ }
+ }
+ }
+ }
+ return r
+ })
+ }
+ m[item.Domain].Add(item)
+ }
+ }
+
+ routerArray := make([]RouterItem, 0, 128)
+ for _, array := range m {
+ for _, v := range array.Slice() {
+ routerArray = append(routerArray, v.(RouterItem))
+ }
+ }
+ return routerArray
+}
+
+// Run starts server listening in blocking way.
+// It's commonly used for single server situation.
+func (s *Server) Run() {
+ var ctx = context.TODO()
+
+ if err := s.Start(); err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+ // Blocking using channel.
+ <-s.closeChan
+ // Remove plugins.
+ if len(s.plugins) > 0 {
+ for _, p := range s.plugins {
+ intlog.Printf(ctx, `remove plugin: %s`, p.Name())
+ if err := p.Remove(); err != nil {
+ intlog.Errorf(ctx, "%+v", err)
+ }
+ }
+ }
+ s.doServiceDeregister()
+ s.Logger().Infof(ctx, "pid[%d]: all servers shutdown", gproc.Pid())
+}
+
+// Wait blocks to wait for all servers done.
+// It's commonly used in multiple server situation.
+func Wait() {
+ var ctx = context.TODO()
+
+ <-allDoneChan
+ // Remove plugins.
+ serverMapping.Iterator(func(k string, v interface{}) bool {
+ s := v.(*Server)
+ if len(s.plugins) > 0 {
+ for _, p := range s.plugins {
+ intlog.Printf(ctx, `remove plugin: %s`, p.Name())
+ if err := p.Remove(); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ }
+ return true
+ })
+ glog.Infof(ctx, "pid[%d]: all servers shutdown", gproc.Pid())
+}
+
+// startServer starts the underlying server listening.
+func (s *Server) startServer(fdMap listenerFdMap) {
+ var (
+ ctx = context.TODO()
+ httpsEnabled bool
+ )
+ // HTTPS
+ if s.config.TLSConfig != nil || (s.config.HTTPSCertPath != "" && s.config.HTTPSKeyPath != "") {
+ if len(s.config.HTTPSAddr) == 0 {
+ if len(s.config.Address) > 0 {
+ s.config.HTTPSAddr = s.config.Address
+ s.config.Address = ""
+ } else {
+ s.config.HTTPSAddr = defaultHttpsAddr
+ }
+ }
+ httpsEnabled = len(s.config.HTTPSAddr) > 0
+ var array []string
+ if v, ok := fdMap["https"]; ok && len(v) > 0 {
+ array = strings.Split(v, ",")
+ } else {
+ array = strings.Split(s.config.HTTPSAddr, ",")
+ }
+ for _, v := range array {
+ if len(v) == 0 {
+ continue
+ }
+ var (
+ fd = 0
+ itemFunc = v
+ addrAndFd = strings.Split(v, "#")
+ )
+ if len(addrAndFd) > 1 {
+ itemFunc = addrAndFd[0]
+ // The Windows OS does not support socket file descriptor passing
+ // from parent process.
+ if runtime.GOOS != "windows" {
+ fd = gconv.Int(addrAndFd[1])
+ }
+ }
+ if fd > 0 {
+ s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
+ } else {
+ s.servers = append(s.servers, s.newGracefulServer(itemFunc))
+ }
+ s.servers[len(s.servers)-1].isHttps = true
+ }
+ }
+ // HTTP
+ if !httpsEnabled && len(s.config.Address) == 0 {
+ s.config.Address = defaultHttpAddr
+ }
+ var array []string
+ if v, ok := fdMap["http"]; ok && len(v) > 0 {
+ array = strings.Split(v, ",")
+ } else {
+ array = strings.Split(s.config.Address, ",")
+ }
+ for _, v := range array {
+ if len(v) == 0 {
+ continue
+ }
+ var (
+ fd = 0
+ itemFunc = v
+ addrAndFd = strings.Split(v, "#")
+ )
+ if len(addrAndFd) > 1 {
+ itemFunc = addrAndFd[0]
+ // The Windows OS does not support socket file descriptor passing
+ // from parent process.
+ if runtime.GOOS != "windows" {
+ fd = gconv.Int(addrAndFd[1])
+ }
+ }
+ if fd > 0 {
+ s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
+ } else {
+ s.servers = append(s.servers, s.newGracefulServer(itemFunc))
+ }
+ }
+ // Start listening asynchronously.
+ serverRunning.Add(1)
+ for _, v := range s.servers {
+ go func(server *gracefulServer) {
+ s.serverCount.Add(1)
+ var err error
+ if server.isHttps {
+ err = server.ListenAndServeTLS(s.config.HTTPSCertPath, s.config.HTTPSKeyPath, s.config.TLSConfig)
+ } else {
+ err = server.ListenAndServe()
+ }
+ // The process exits if the server is closed with none closing error.
+ if err != nil && !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+ // If all the underlying servers' shutdown, the process exits.
+ if s.serverCount.Add(-1) < 1 {
+ s.closeChan <- struct{}{}
+ if serverRunning.Add(-1) < 1 {
+ serverMapping.Remove(s.instance)
+ allDoneChan <- struct{}{}
+ }
+ }
+ }(v)
+ }
+}
+
+// Status retrieves and returns the server status.
+func (s *Server) Status() int {
+ if serverRunning.Val() == 0 {
+ return ServerStatusStopped
+ }
+ // If any underlying server is running, the server status is running.
+ for _, v := range s.servers {
+ if v.status == ServerStatusRunning {
+ return ServerStatusRunning
+ }
+ }
+ return ServerStatusStopped
+}
+
+// getListenerFdMap retrieves and returns the socket file descriptors.
+// The key of the returned map is "http" and "https".
+func (s *Server) getListenerFdMap() map[string]string {
+ m := map[string]string{
+ "https": "",
+ "http": "",
+ }
+ for _, v := range s.servers {
+ str := v.address + "#" + gconv.String(v.Fd()) + ","
+ if v.isHttps {
+ if len(m["https"]) > 0 {
+ m["https"] += ","
+ }
+ m["https"] += str
+ } else {
+ if len(m["http"]) > 0 {
+ m["http"] += ","
+ }
+ m["http"] += str
+ }
+ }
+ return m
+}
+
+// GetListenedPort retrieves and returns one port which is listened by current server.
+func (s *Server) GetListenedPort() int {
+ ports := s.GetListenedPorts()
+ if len(ports) > 0 {
+ return ports[0]
+ }
+ return 0
+}
+
+// GetListenedPorts retrieves and returns the ports which are listened by current server.
+func (s *Server) GetListenedPorts() []int {
+ ports := make([]int, 0)
+ for _, server := range s.servers {
+ ports = append(ports, server.GetListenedPort())
+ }
+ return ports
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin.go
new file mode 100644
index 000000000000..e84d8d886396
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin.go
@@ -0,0 +1,100 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gproc"
+ "github.com/gogf/gf/v2/os/gtimer"
+ "github.com/gogf/gf/v2/os/gview"
+)
+
+// utilAdmin is the controller for administration.
+type utilAdmin struct{}
+
+// Index shows the administration page.
+func (p *utilAdmin) Index(r *Request) {
+ data := map[string]interface{}{
+ "pid": gproc.Pid(),
+ "path": gfile.SelfPath(),
+ "uri": strings.TrimRight(r.URL.Path, "/"),
+ }
+ buffer, _ := gview.ParseContent(r.Context(), `
+
+
+ GoFrame Web Server Admin
+
+
+ Pid: {{.pid}}
+ File Path: {{.path}}
+ Restart
+ Shutdown
+
+
+ `, data)
+ r.Response.Write(buffer)
+}
+
+// Restart restarts all the servers in the process.
+func (p *utilAdmin) Restart(r *Request) {
+ var (
+ ctx = r.Context()
+ err error
+ )
+ // Custom start binary path when this process exits.
+ path := r.GetQuery("newExeFilePath").String()
+ if path == "" {
+ path = gfile.SelfPath()
+ }
+ if len(path) > 0 {
+ err = RestartAllServer(ctx, path)
+ } else {
+ err = RestartAllServer(ctx)
+ }
+ if err == nil {
+ r.Response.WriteExit("server restarted")
+ } else {
+ r.Response.WriteExit(err.Error())
+ }
+}
+
+// Shutdown shuts down all the servers.
+func (p *utilAdmin) Shutdown(r *Request) {
+ gtimer.SetTimeout(r.Context(), time.Second, func(ctx context.Context) {
+ // It shuts down the server after 1 second, which is not triggered by system signal,
+ // to ensure the response successfully to the client.
+ _ = r.Server.Shutdown()
+ })
+ r.Response.WriteExit("server shutdown")
+}
+
+// EnableAdmin enables the administration feature for the process.
+// The optional parameter `pattern` specifies the URI for the administration page.
+func (s *Server) EnableAdmin(pattern ...string) {
+ p := "/debug/admin"
+ if len(pattern) > 0 {
+ p = pattern[0]
+ }
+ s.BindObject(p, &utilAdmin{})
+}
+
+// Shutdown shuts down current server.
+func (s *Server) Shutdown() error {
+ var (
+ ctx = context.TODO()
+ )
+ // Only shut down current servers.
+ // It may have multiple underlying http servers.
+ for _, v := range s.servers {
+ v.close(ctx)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_process.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_process.go
new file mode 100644
index 000000000000..a02ab0eb1c21
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_process.go
@@ -0,0 +1,306 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/os/gproc"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gtimer"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ // Allow executing management command after server starts after this interval in milliseconds.
+ adminActionIntervalLimit = 2000
+ adminActionNone = 0
+ adminActionRestarting = 1
+ adminActionShuttingDown = 2
+ adminActionReloadEnvKey = "GF_SERVER_RELOAD"
+ adminActionRestartEnvKey = "GF_SERVER_RESTART"
+ adminGProcCommGroup = "GF_GPROC_HTTP_SERVER"
+)
+
+var (
+ // serverActionLocker is the locker for server administration operations.
+ serverActionLocker sync.Mutex
+
+ // serverActionLastTime is timestamp in milliseconds of last administration operation.
+ serverActionLastTime = gtype.NewInt64(gtime.TimestampMilli())
+
+ // serverProcessStatus is the server status for operation of current process.
+ serverProcessStatus = gtype.NewInt()
+)
+
+// RestartAllServer restarts all the servers of the process.
+// The optional parameter `newExeFilePath` specifies the new binary file for creating process.
+func RestartAllServer(ctx context.Context, newExeFilePath ...string) error {
+ if !gracefulEnabled {
+ return gerror.NewCode(gcode.CodeInvalidOperation, "graceful reload feature is disabled")
+ }
+ serverActionLocker.Lock()
+ defer serverActionLocker.Unlock()
+ if err := checkProcessStatus(); err != nil {
+ return err
+ }
+ if err := checkActionFrequency(); err != nil {
+ return err
+ }
+ return restartWebServers(ctx, "", newExeFilePath...)
+}
+
+// ShutdownAllServer shuts down all servers of current process.
+func ShutdownAllServer(ctx context.Context) error {
+ serverActionLocker.Lock()
+ defer serverActionLocker.Unlock()
+ if err := checkProcessStatus(); err != nil {
+ return err
+ }
+ if err := checkActionFrequency(); err != nil {
+ return err
+ }
+ shutdownWebServers(ctx)
+ return nil
+}
+
+// checkProcessStatus checks the server status of current process.
+func checkProcessStatus() error {
+ status := serverProcessStatus.Val()
+ if status > 0 {
+ switch status {
+ case adminActionRestarting:
+ return gerror.NewCode(gcode.CodeInvalidOperation, "server is restarting")
+
+ case adminActionShuttingDown:
+ return gerror.NewCode(gcode.CodeInvalidOperation, "server is shutting down")
+ }
+ }
+ return nil
+}
+
+// checkActionFrequency checks the operation frequency.
+// It returns error if it is too frequency.
+func checkActionFrequency() error {
+ interval := gtime.TimestampMilli() - serverActionLastTime.Val()
+ if interval < adminActionIntervalLimit {
+ return gerror.NewCodef(
+ gcode.CodeInvalidOperation,
+ "too frequent action, please retry in %d ms",
+ adminActionIntervalLimit-interval,
+ )
+ }
+ serverActionLastTime.Set(gtime.TimestampMilli())
+ return nil
+}
+
+// forkReloadProcess creates a new child process and copies the fd to child process.
+func forkReloadProcess(ctx context.Context, newExeFilePath ...string) error {
+ var (
+ path = os.Args[0]
+ )
+ if len(newExeFilePath) > 0 {
+ path = newExeFilePath[0]
+ }
+ var (
+ p = gproc.NewProcess(path, os.Args, os.Environ())
+ sfm = getServerFdMap()
+ )
+ for name, m := range sfm {
+ for fdk, fdv := range m {
+ if len(fdv) > 0 {
+ s := ""
+ for _, item := range gstr.SplitAndTrim(fdv, ",") {
+ array := strings.Split(item, "#")
+ fd := uintptr(gconv.Uint(array[1]))
+ if fd > 0 {
+ s += fmt.Sprintf("%s#%d,", array[0], 3+len(p.ExtraFiles))
+ p.ExtraFiles = append(p.ExtraFiles, os.NewFile(fd, ""))
+ } else {
+ s += fmt.Sprintf("%s#%d,", array[0], 0)
+ }
+ }
+ sfm[name][fdk] = strings.TrimRight(s, ",")
+ }
+ }
+ }
+ buffer, _ := gjson.Encode(sfm)
+ p.Env = append(p.Env, adminActionReloadEnvKey+"="+string(buffer))
+ if _, err := p.Start(); err != nil {
+ glog.Errorf(
+ ctx,
+ "%d: fork process failed, error:%s, %s",
+ gproc.Pid(), err.Error(), string(buffer),
+ )
+ return err
+ }
+ return nil
+}
+
+// forkRestartProcess creates a new server process.
+func forkRestartProcess(ctx context.Context, newExeFilePath ...string) error {
+ var (
+ path = os.Args[0]
+ )
+ if len(newExeFilePath) > 0 {
+ path = newExeFilePath[0]
+ }
+ if err := os.Unsetenv(adminActionReloadEnvKey); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ env := os.Environ()
+ env = append(env, adminActionRestartEnvKey+"=1")
+ p := gproc.NewProcess(path, os.Args, env)
+ if _, err := p.Start(); err != nil {
+ glog.Errorf(
+ ctx,
+ `%d: fork process failed, error:%s, are you running using "go run"?`,
+ gproc.Pid(), err.Error(),
+ )
+ return err
+ }
+ return nil
+}
+
+// getServerFdMap returns all the servers name to file descriptor mapping as map.
+func getServerFdMap() map[string]listenerFdMap {
+ sfm := make(map[string]listenerFdMap)
+ serverMapping.RLockFunc(func(m map[string]interface{}) {
+ for k, v := range m {
+ sfm[k] = v.(*Server).getListenerFdMap()
+ }
+ })
+ return sfm
+}
+
+// bufferToServerFdMap converts binary content to fd map.
+func bufferToServerFdMap(buffer []byte) map[string]listenerFdMap {
+ sfm := make(map[string]listenerFdMap)
+ if len(buffer) > 0 {
+ j, _ := gjson.LoadContent(buffer)
+ for k, _ := range j.Var().Map() {
+ m := make(map[string]string)
+ for k, v := range j.Get(k).Map() {
+ m[k] = gconv.String(v)
+ }
+ sfm[k] = m
+ }
+ }
+ return sfm
+}
+
+// restartWebServers restarts all servers.
+func restartWebServers(ctx context.Context, signal string, newExeFilePath ...string) error {
+ serverProcessStatus.Set(adminActionRestarting)
+ if runtime.GOOS == "windows" {
+ if len(signal) > 0 {
+ // Controlled by signal.
+ forceCloseWebServers(ctx)
+ if err := forkRestartProcess(ctx, newExeFilePath...); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ } else {
+ // Controlled by web page.
+ // It should ensure the response wrote to client and then close all servers gracefully.
+ gtimer.SetTimeout(ctx, time.Second, func(ctx context.Context) {
+ forceCloseWebServers(ctx)
+ if err := forkRestartProcess(ctx, newExeFilePath...); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ })
+ }
+ } else {
+ if err := forkReloadProcess(ctx, newExeFilePath...); err != nil {
+ glog.Printf(ctx, "%d: server restarts failed", gproc.Pid())
+ serverProcessStatus.Set(adminActionNone)
+ return err
+ } else {
+ if len(signal) > 0 {
+ glog.Printf(ctx, "%d: server restarting by signal: %s", gproc.Pid(), signal)
+ } else {
+ glog.Printf(ctx, "%d: server restarting by web admin", gproc.Pid())
+ }
+ }
+ }
+ return nil
+}
+
+// shutdownWebServers shuts down all servers.
+func shutdownWebServers(ctx context.Context, signal ...string) {
+ serverProcessStatus.Set(adminActionShuttingDown)
+ if len(signal) > 0 {
+ glog.Printf(ctx, "%d: server shutting down by signal: %s", gproc.Pid(), signal[0])
+ forceCloseWebServers(ctx)
+ allDoneChan <- struct{}{}
+ } else {
+ glog.Printf(ctx, "%d: server shutting down by api", gproc.Pid())
+ gtimer.SetTimeout(ctx, time.Second, func(ctx context.Context) {
+ forceCloseWebServers(ctx)
+ allDoneChan <- struct{}{}
+ })
+ }
+}
+
+// shutdownWebServersGracefully gracefully shuts down all servers.
+func shutdownWebServersGracefully(ctx context.Context, signal ...string) {
+ if len(signal) > 0 {
+ glog.Printf(ctx, "%d: server gracefully shutting down by signal: %s", gproc.Pid(), signal[0])
+ } else {
+ glog.Printf(ctx, "%d: server gracefully shutting down by api", gproc.Pid())
+ }
+ serverMapping.RLockFunc(func(m map[string]interface{}) {
+ for _, v := range m {
+ for _, s := range v.(*Server).servers {
+ s.shutdown(ctx)
+ }
+ }
+ })
+}
+
+// forceCloseWebServers forced shuts down all servers.
+func forceCloseWebServers(ctx context.Context) {
+ serverMapping.RLockFunc(func(m map[string]interface{}) {
+ for _, v := range m {
+ for _, s := range v.(*Server).servers {
+ s.close(ctx)
+ }
+ }
+ })
+}
+
+// handleProcessMessage receives and handles the message from processes,
+// which are commonly used for graceful reloading feature.
+func handleProcessMessage() {
+ var (
+ ctx = context.TODO()
+ )
+ for {
+ if msg := gproc.Receive(adminGProcCommGroup); msg != nil {
+ if bytes.EqualFold(msg.Data, []byte("exit")) {
+ intlog.Printf(ctx, "%d: process message: exit", gproc.Pid())
+ shutdownWebServersGracefully(ctx)
+ allDoneChan <- struct{}{}
+ intlog.Printf(ctx, "%d: process message: exit done", gproc.Pid())
+ return
+ }
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_unix.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_unix.go
new file mode 100644
index 000000000000..b98b1d40d3d6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_unix.go
@@ -0,0 +1,65 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+//go:build !windows
+// +build !windows
+
+package ghttp
+
+import (
+ "context"
+ "os"
+ "os/signal"
+ "syscall"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// procSignalChan is the channel for listening the signal.
+var procSignalChan = make(chan os.Signal)
+
+// handleProcessSignal handles all signal from system.
+func handleProcessSignal() {
+ var (
+ ctx = context.TODO()
+ sig os.Signal
+ )
+ signal.Notify(
+ procSignalChan,
+ syscall.SIGINT,
+ syscall.SIGQUIT,
+ syscall.SIGKILL,
+ syscall.SIGTERM,
+ syscall.SIGABRT,
+ syscall.SIGUSR1,
+ syscall.SIGUSR2,
+ )
+ for {
+ sig = <-procSignalChan
+ intlog.Printf(ctx, `signal received: %s`, sig.String())
+ switch sig {
+ // Shutdown the servers.
+ case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGABRT:
+ shutdownWebServers(ctx, sig.String())
+ return
+
+ // Shutdown the servers gracefully.
+ // Especially from K8S when running server in POD.
+ case syscall.SIGTERM:
+ shutdownWebServersGracefully(ctx, sig.String())
+ return
+
+ // Restart the servers.
+ case syscall.SIGUSR1:
+ if err := restartWebServers(ctx, sig.String()); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ return
+
+ default:
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_windows.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_windows.go
new file mode 100644
index 000000000000..2a514493d15a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_admin_windows.go
@@ -0,0 +1,15 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+//go:build windows
+// +build windows
+
+package ghttp
+
+// registerSignalHandler does nothing on windows platform.
+func handleProcessSignal() {
+
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config.go
new file mode 100644
index 000000000000..099358983fbd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config.go
@@ -0,0 +1,495 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "crypto/tls"
+ "net/http"
+ "strconv"
+ "time"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/net/gtcp"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gsession"
+ "github.com/gogf/gf/v2/os/gview"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ defaultHttpAddr = ":80" // Default listening port for HTTP.
+ defaultHttpsAddr = ":443" // Default listening port for HTTPS.
+ UriTypeDefault = 0 // Method names to URI converting type, which converts name to its lower case and joins the words using char '-'.
+ UriTypeFullName = 1 // Method names to URI converting type, which does no converting to the method name.
+ UriTypeAllLower = 2 // Method names to URI converting type, which converts name to its lower case.
+ UriTypeCamel = 3 // Method names to URI converting type, which converts name to its camel case.
+)
+
+// ServerConfig is the HTTP Server configuration manager.
+type ServerConfig struct {
+ // ======================================================================================================
+ // Basic.
+ // ======================================================================================================
+
+ // Service name, which is for service registry and discovery.
+ Name string `json:"name"`
+
+ // Address specifies the server listening address like "port" or ":port",
+ // multiple addresses joined using ','.
+ Address string `json:"address"`
+
+ // HTTPSAddr specifies the HTTPS addresses, multiple addresses joined using char ','.
+ HTTPSAddr string `json:"httpsAddr"`
+
+ // HTTPSCertPath specifies certification file path for HTTPS service.
+ HTTPSCertPath string `json:"httpsCertPath"`
+
+ // HTTPSKeyPath specifies the key file path for HTTPS service.
+ HTTPSKeyPath string `json:"httpsKeyPath"`
+
+ // TLSConfig optionally provides a TLS configuration for use
+ // by ServeTLS and ListenAndServeTLS. Note that this value is
+ // cloned by ServeTLS and ListenAndServeTLS, so it's not
+ // possible to modify the configuration with methods like
+ // tls.Config.SetSessionTicketKeys. To use
+ // SetSessionTicketKeys, use Server.Serve with a TLS Listener
+ // instead.
+ TLSConfig *tls.Config `json:"tlsConfig"`
+
+ // Handler the handler for HTTP request.
+ Handler func(w http.ResponseWriter, r *http.Request) `json:"-"`
+
+ // ReadTimeout is the maximum duration for reading the entire
+ // request, including the body.
+ //
+ // Because ReadTimeout does not let Handlers make per-request
+ // decisions on each request body's acceptable deadline or
+ // upload rate, most users will prefer to use
+ // ReadHeaderTimeout. It is valid to use them both.
+ ReadTimeout time.Duration `json:"readTimeout"`
+
+ // WriteTimeout is the maximum duration before timing out
+ // writes of the response. It is reset whenever a new
+ // request's header is read. Like ReadTimeout, it does not
+ // let Handlers make decisions on a per-request basis.
+ WriteTimeout time.Duration `json:"writeTimeout"`
+
+ // IdleTimeout is the maximum amount of time to wait for the
+ // next request when keep-alives are enabled. If IdleTimeout
+ // is zero, the value of ReadTimeout is used. If both are
+ // zero, there is no timeout.
+ IdleTimeout time.Duration `json:"idleTimeout"`
+
+ // MaxHeaderBytes controls the maximum number of bytes the
+ // server will read parsing the request header's keys and
+ // values, including the request line. It does not limit the
+ // size of the request body.
+ //
+ // It can be configured in configuration file using string like: 1m, 10m, 500kb etc.
+ // It's 10240 bytes in default.
+ MaxHeaderBytes int `json:"maxHeaderBytes"`
+
+ // KeepAlive enables HTTP keep-alive.
+ KeepAlive bool `json:"keepAlive"`
+
+ // ServerAgent specifies the server agent information, which is wrote to
+ // HTTP response header as "Server".
+ ServerAgent string `json:"serverAgent"`
+
+ // View specifies the default template view object for the server.
+ View *gview.View `json:"view"`
+
+ // ======================================================================================================
+ // Static.
+ // ======================================================================================================
+
+ // Rewrites specifies the URI rewrite rules map.
+ Rewrites map[string]string `json:"rewrites"`
+
+ // IndexFiles specifies the index files for static folder.
+ IndexFiles []string `json:"indexFiles"`
+
+ // IndexFolder specifies if listing sub-files when requesting folder.
+ // The server responses HTTP status code 403 if it is false.
+ IndexFolder bool `json:"indexFolder"`
+
+ // ServerRoot specifies the root directory for static service.
+ ServerRoot string `json:"serverRoot"`
+
+ // SearchPaths specifies additional searching directories for static service.
+ SearchPaths []string `json:"searchPaths"`
+
+ // StaticPaths specifies URI to directory mapping array.
+ StaticPaths []staticPathItem `json:"staticPaths"`
+
+ // FileServerEnabled is the global switch for static service.
+ // It is automatically set enabled if any static path is set.
+ FileServerEnabled bool `json:"fileServerEnabled"`
+
+ // ======================================================================================================
+ // Cookie.
+ // ======================================================================================================
+
+ // CookieMaxAge specifies the max TTL for cookie items.
+ CookieMaxAge time.Duration `json:"cookieMaxAge"`
+
+ // CookiePath specifies cookie path.
+ // It also affects the default storage for session id.
+ CookiePath string `json:"cookiePath"`
+
+ // CookieDomain specifies cookie domain.
+ // It also affects the default storage for session id.
+ CookieDomain string `json:"cookieDomain"`
+
+ // ======================================================================================================
+ // Session.
+ // ======================================================================================================
+
+ // SessionIdName specifies the session id name.
+ SessionIdName string `json:"sessionIdName"`
+
+ // SessionMaxAge specifies max TTL for session items.
+ SessionMaxAge time.Duration `json:"sessionMaxAge"`
+
+ // SessionPath specifies the session storage directory path for storing session files.
+ // It only makes sense if the session storage is type of file storage.
+ SessionPath string `json:"sessionPath"`
+
+ // SessionStorage specifies the session storage.
+ SessionStorage gsession.Storage `json:"sessionStorage"`
+
+ // SessionCookieMaxAge specifies the cookie ttl for session id.
+ // If it is set 0, it means it expires along with browser session.
+ SessionCookieMaxAge time.Duration `json:"sessionCookieMaxAge"`
+
+ // SessionCookieOutput specifies whether automatic outputting session id to cookie.
+ SessionCookieOutput bool `json:"sessionCookieOutput"`
+
+ // ======================================================================================================
+ // Logging.
+ // ======================================================================================================
+
+ Logger *glog.Logger `json:"logger"` // Logger specifies the logger for server.
+ LogPath string `json:"logPath"` // LogPath specifies the directory for storing logging files.
+ LogLevel string `json:"logLevel"` // LogLevel specifies the logging level for logger.
+ LogStdout bool `json:"logStdout"` // LogStdout specifies whether printing logging content to stdout.
+ ErrorStack bool `json:"errorStack"` // ErrorStack specifies whether logging stack information when error.
+ ErrorLogEnabled bool `json:"errorLogEnabled"` // ErrorLogEnabled enables error logging content to files.
+ ErrorLogPattern string `json:"errorLogPattern"` // ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log
+ AccessLogEnabled bool `json:"accessLogEnabled"` // AccessLogEnabled enables access logging content to files.
+ AccessLogPattern string `json:"accessLogPattern"` // AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log
+
+ // ======================================================================================================
+ // PProf.
+ // ======================================================================================================
+
+ PProfEnabled bool `json:"pprofEnabled"` // PProfEnabled enables PProf feature.
+ PProfPattern string `json:"pprofPattern"` // PProfPattern specifies the PProf service pattern for router.
+
+ // ======================================================================================================
+ // API & Swagger.
+ // ======================================================================================================
+
+ OpenApiPath string `json:"openapiPath"` // OpenApiPath specifies the OpenApi specification file path.
+ SwaggerPath string `json:"swaggerPath"` // SwaggerPath specifies the swagger UI path for route registering.
+
+ // ======================================================================================================
+ // Other.
+ // ======================================================================================================
+
+ // ClientMaxBodySize specifies the max body size limit in bytes for client request.
+ // It can be configured in configuration file using string like: 1m, 10m, 500kb etc.
+ // It's `8MB` in default.
+ ClientMaxBodySize int64 `json:"clientMaxBodySize"`
+
+ // FormParsingMemory specifies max memory buffer size in bytes which can be used for
+ // parsing multimedia form.
+ // It can be configured in configuration file using string like: 1m, 10m, 500kb etc.
+ // It's 1MB in default.
+ FormParsingMemory int64 `json:"formParsingMemory"`
+
+ // NameToUriType specifies the type for converting struct method name to URI when
+ // registering routes.
+ NameToUriType int `json:"nameToUriType"`
+
+ // RouteOverWrite allows to overwrite the route if duplicated.
+ RouteOverWrite bool `json:"routeOverWrite"`
+
+ // DumpRouterMap specifies whether automatically dumps router map when server starts.
+ DumpRouterMap bool `json:"dumpRouterMap"`
+
+ // Graceful enables graceful reload feature for all servers of the process.
+ Graceful bool `json:"graceful"`
+
+ // GracefulTimeout set the maximum survival time (seconds) of the parent process.
+ GracefulTimeout uint8 `json:"gracefulTimeout"`
+}
+
+// NewConfig creates and returns a ServerConfig object with default configurations.
+// Note that, do not define this default configuration to local package variable, as there are
+// some pointer attributes that may be shared in different servers.
+func NewConfig() ServerConfig {
+ return ServerConfig{
+ Name: DefaultServerName,
+ Address: ":0",
+ HTTPSAddr: "",
+ Handler: nil,
+ ReadTimeout: 60 * time.Second,
+ WriteTimeout: 0, // No timeout.
+ IdleTimeout: 60 * time.Second,
+ MaxHeaderBytes: 10240, // 10KB
+ KeepAlive: true,
+ IndexFiles: []string{"index.html", "index.htm"},
+ IndexFolder: false,
+ ServerAgent: "GoFrame HTTP Server",
+ ServerRoot: "",
+ StaticPaths: make([]staticPathItem, 0),
+ FileServerEnabled: false,
+ CookieMaxAge: time.Hour * 24 * 365,
+ CookiePath: "/",
+ CookieDomain: "",
+ SessionIdName: "gfsessionid",
+ SessionPath: gsession.DefaultStorageFilePath,
+ SessionMaxAge: time.Hour * 24,
+ SessionCookieOutput: true,
+ SessionCookieMaxAge: time.Hour * 24,
+ Logger: glog.New(),
+ LogLevel: "all",
+ LogStdout: true,
+ ErrorStack: true,
+ ErrorLogEnabled: true,
+ ErrorLogPattern: "error-{Ymd}.log",
+ AccessLogEnabled: false,
+ AccessLogPattern: "access-{Ymd}.log",
+ DumpRouterMap: true,
+ ClientMaxBodySize: 8 * 1024 * 1024, // 8MB
+ FormParsingMemory: 1024 * 1024, // 1MB
+ Rewrites: make(map[string]string),
+ Graceful: false,
+ GracefulTimeout: 2, // seconds
+ }
+}
+
+// ConfigFromMap creates and returns a ServerConfig object with given map and
+// default configuration object.
+func ConfigFromMap(m map[string]interface{}) (ServerConfig, error) {
+ config := NewConfig()
+ if err := gconv.Struct(m, &config); err != nil {
+ return config, err
+ }
+ return config, nil
+}
+
+// SetConfigWithMap sets the configuration for the server using map.
+func (s *Server) SetConfigWithMap(m map[string]interface{}) error {
+ // The m now is a shallow copy of m.
+ // Any changes to m does not affect the original one.
+ // A little tricky, isn't it?
+ m = gutil.MapCopy(m)
+ // Allow setting the size configuration items using string size like:
+ // 1m, 100mb, 512kb, etc.
+ if k, v := gutil.MapPossibleItemByKey(m, "MaxHeaderBytes"); k != "" {
+ m[k] = gfile.StrToSize(gconv.String(v))
+ }
+ if k, v := gutil.MapPossibleItemByKey(m, "ClientMaxBodySize"); k != "" {
+ m[k] = gfile.StrToSize(gconv.String(v))
+ }
+ if k, v := gutil.MapPossibleItemByKey(m, "FormParsingMemory"); k != "" {
+ m[k] = gfile.StrToSize(gconv.String(v))
+ }
+ // Update the current configuration object.
+ // It only updates the configured keys not all the object.
+ if err := gconv.Struct(m, &s.config); err != nil {
+ return err
+ }
+ return s.SetConfig(s.config)
+}
+
+// SetConfig sets the configuration for the server.
+func (s *Server) SetConfig(c ServerConfig) error {
+ s.config = c
+ // Address, check and use a random free port.
+ array := gstr.Split(s.config.Address, ":")
+ if s.config.Address == "" || len(array) < 2 || array[1] == "0" {
+ s.config.Address = gstr.Join([]string{
+ array[0], gconv.String(gtcp.MustGetFreePort()),
+ }, ":")
+ }
+ // Static.
+ if c.ServerRoot != "" {
+ s.SetServerRoot(c.ServerRoot)
+ }
+ if len(c.SearchPaths) > 0 {
+ paths := c.SearchPaths
+ c.SearchPaths = []string{}
+ for _, v := range paths {
+ s.AddSearchPath(v)
+ }
+ }
+ // HTTPS.
+ if c.TLSConfig == nil && c.HTTPSCertPath != "" {
+ s.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath)
+ }
+ // Logging.
+ if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
+ if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
+ return err
+ }
+ }
+ if err := s.config.Logger.SetLevelStr(s.config.LogLevel); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ gracefulEnabled = c.Graceful
+ intlog.Printf(context.TODO(), "SetConfig: %+v", s.config)
+ return nil
+}
+
+// SetAddr sets the listening address for the server.
+// The address is like ':80', '0.0.0.0:80', '127.0.0.1:80', '180.18.99.10:80', etc.
+func (s *Server) SetAddr(address string) {
+ s.config.Address = address
+}
+
+// SetPort sets the listening ports for the server.
+// The listening ports can be multiple like: SetPort(80, 8080).
+func (s *Server) SetPort(port ...int) {
+ if len(port) > 0 {
+ s.config.Address = ""
+ for _, v := range port {
+ if len(s.config.Address) > 0 {
+ s.config.Address += ","
+ }
+ s.config.Address += ":" + strconv.Itoa(v)
+ }
+ }
+}
+
+// SetHTTPSAddr sets the HTTPS listening ports for the server.
+func (s *Server) SetHTTPSAddr(address string) {
+ s.config.HTTPSAddr = address
+}
+
+// SetHTTPSPort sets the HTTPS listening ports for the server.
+// The listening ports can be multiple like: SetHTTPSPort(443, 500).
+func (s *Server) SetHTTPSPort(port ...int) {
+ if len(port) > 0 {
+ s.config.HTTPSAddr = ""
+ for _, v := range port {
+ if len(s.config.HTTPSAddr) > 0 {
+ s.config.HTTPSAddr += ","
+ }
+ s.config.HTTPSAddr += ":" + strconv.Itoa(v)
+ }
+ }
+}
+
+// EnableHTTPS enables HTTPS with given certification and key files for the server.
+// The optional parameter `tlsConfig` specifies custom TLS configuration.
+func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config) {
+ var ctx = context.TODO()
+ certFileRealPath := gfile.RealPath(certFile)
+ if certFileRealPath == "" {
+ certFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + certFile)
+ if certFileRealPath == "" {
+ certFileRealPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + certFile)
+ }
+ }
+ // Resource.
+ if certFileRealPath == "" && gres.Contains(certFile) {
+ certFileRealPath = certFile
+ }
+ if certFileRealPath == "" {
+ s.Logger().Fatalf(ctx, `EnableHTTPS failed: certFile "%s" does not exist`, certFile)
+ }
+ keyFileRealPath := gfile.RealPath(keyFile)
+ if keyFileRealPath == "" {
+ keyFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + keyFile)
+ if keyFileRealPath == "" {
+ keyFileRealPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + keyFile)
+ }
+ }
+ // Resource.
+ if keyFileRealPath == "" && gres.Contains(keyFile) {
+ keyFileRealPath = keyFile
+ }
+ if keyFileRealPath == "" {
+ s.Logger().Fatal(ctx, `EnableHTTPS failed: keyFile "%s" does not exist`, keyFile)
+ }
+ s.config.HTTPSCertPath = certFileRealPath
+ s.config.HTTPSKeyPath = keyFileRealPath
+ if len(tlsConfig) > 0 {
+ s.config.TLSConfig = tlsConfig[0]
+ }
+}
+
+// SetTLSConfig sets custom TLS configuration and enables HTTPS feature for the server.
+func (s *Server) SetTLSConfig(tlsConfig *tls.Config) {
+ s.config.TLSConfig = tlsConfig
+}
+
+// SetReadTimeout sets the ReadTimeout for the server.
+func (s *Server) SetReadTimeout(t time.Duration) {
+ s.config.ReadTimeout = t
+}
+
+// SetWriteTimeout sets the WriteTimeout for the server.
+func (s *Server) SetWriteTimeout(t time.Duration) {
+ s.config.WriteTimeout = t
+}
+
+// SetIdleTimeout sets the IdleTimeout for the server.
+func (s *Server) SetIdleTimeout(t time.Duration) {
+ s.config.IdleTimeout = t
+}
+
+// SetMaxHeaderBytes sets the MaxHeaderBytes for the server.
+func (s *Server) SetMaxHeaderBytes(b int) {
+ s.config.MaxHeaderBytes = b
+}
+
+// SetServerAgent sets the ServerAgent for the server.
+func (s *Server) SetServerAgent(agent string) {
+ s.config.ServerAgent = agent
+}
+
+// SetKeepAlive sets the KeepAlive for the server.
+func (s *Server) SetKeepAlive(enabled bool) {
+ s.config.KeepAlive = enabled
+}
+
+// SetView sets the View for the server.
+func (s *Server) SetView(view *gview.View) {
+ s.config.View = view
+}
+
+// GetName returns the name of the server.
+func (s *Server) GetName() string {
+ return s.config.Name
+}
+
+// SetName sets the name for the server.
+func (s *Server) SetName(name string) {
+ s.config.Name = name
+}
+
+// SetHandler sets the request handler for server.
+func (s *Server) SetHandler(h func(w http.ResponseWriter, r *http.Request)) {
+ s.config.Handler = h
+}
+
+// GetHandler returns the request handler of the server.
+func (s *Server) GetHandler() func(w http.ResponseWriter, r *http.Request) {
+ if s.config.Handler == nil {
+ return s.ServeHTTP
+ }
+ return s.config.Handler
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_cookie.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_cookie.go
new file mode 100644
index 000000000000..26646202814c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_cookie.go
@@ -0,0 +1,41 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "time"
+)
+
+// SetCookieMaxAge sets the CookieMaxAge for server.
+func (s *Server) SetCookieMaxAge(ttl time.Duration) {
+ s.config.CookieMaxAge = ttl
+}
+
+// SetCookiePath sets the CookiePath for server.
+func (s *Server) SetCookiePath(path string) {
+ s.config.CookiePath = path
+}
+
+// SetCookieDomain sets the CookieDomain for server.
+func (s *Server) SetCookieDomain(domain string) {
+ s.config.CookieDomain = domain
+}
+
+// GetCookieMaxAge returns the CookieMaxAge of server.
+func (s *Server) GetCookieMaxAge() time.Duration {
+ return s.config.CookieMaxAge
+}
+
+// GetCookiePath returns the CookiePath of server.
+func (s *Server) GetCookiePath() string {
+ return s.config.CookiePath
+}
+
+// GetCookieDomain returns CookieDomain of server.
+func (s *Server) GetCookieDomain() string {
+ return s.config.CookieDomain
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_logging.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_logging.go
new file mode 100644
index 000000000000..f3e566b397e7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_logging.go
@@ -0,0 +1,77 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "github.com/gogf/gf/v2/os/glog"
+
+// SetLogPath sets the log path for server.
+// It logs content to file only if the log path is set.
+func (s *Server) SetLogPath(path string) error {
+ if len(path) == 0 {
+ return nil
+ }
+ s.config.LogPath = path
+ s.config.ErrorLogEnabled = true
+ s.config.AccessLogEnabled = true
+ if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
+ if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SetLogger sets the logger for logging responsibility.
+// Note that it cannot be set in runtime as there may be concurrent safety issue.
+func (s *Server) SetLogger(logger *glog.Logger) {
+ s.config.Logger = logger
+}
+
+// Logger is alias of GetLogger.
+func (s *Server) Logger() *glog.Logger {
+ return s.config.Logger
+}
+
+// SetLogLevel sets logging level by level string.
+func (s *Server) SetLogLevel(level string) {
+ s.config.LogLevel = level
+}
+
+// SetLogStdout sets whether output the logging content to stdout.
+func (s *Server) SetLogStdout(enabled bool) {
+ s.config.LogStdout = enabled
+}
+
+// SetAccessLogEnabled enables/disables the access log.
+func (s *Server) SetAccessLogEnabled(enabled bool) {
+ s.config.AccessLogEnabled = enabled
+}
+
+// SetErrorLogEnabled enables/disables the error log.
+func (s *Server) SetErrorLogEnabled(enabled bool) {
+ s.config.ErrorLogEnabled = enabled
+}
+
+// SetErrorStack enables/disables the error stack feature.
+func (s *Server) SetErrorStack(enabled bool) {
+ s.config.ErrorStack = enabled
+}
+
+// GetLogPath returns the log path.
+func (s *Server) GetLogPath() string {
+ return s.config.LogPath
+}
+
+// IsAccessLogEnabled checks whether the access log enabled.
+func (s *Server) IsAccessLogEnabled() bool {
+ return s.config.AccessLogEnabled
+}
+
+// IsErrorLogEnabled checks whether the error log enabled.
+func (s *Server) IsErrorLogEnabled() bool {
+ return s.config.ErrorLogEnabled
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_mess.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_mess.go
new file mode 100644
index 000000000000..23d23e8b3452
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_mess.go
@@ -0,0 +1,38 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+// SetNameToUriType sets the NameToUriType for server.
+func (s *Server) SetNameToUriType(t int) {
+ s.config.NameToUriType = t
+}
+
+// SetDumpRouterMap sets the DumpRouterMap for server.
+// If DumpRouterMap is enabled, it automatically dumps the route map when server starts.
+func (s *Server) SetDumpRouterMap(enabled bool) {
+ s.config.DumpRouterMap = enabled
+}
+
+// SetClientMaxBodySize sets the ClientMaxBodySize for server.
+func (s *Server) SetClientMaxBodySize(maxSize int64) {
+ s.config.ClientMaxBodySize = maxSize
+}
+
+// SetFormParsingMemory sets the FormParsingMemory for server.
+func (s *Server) SetFormParsingMemory(maxMemory int64) {
+ s.config.FormParsingMemory = maxMemory
+}
+
+// SetSwaggerPath sets the SwaggerPath for server.
+func (s *Server) SetSwaggerPath(path string) {
+ s.config.SwaggerPath = path
+}
+
+// SetOpenApiPath sets the OpenApiPath for server.
+func (s *Server) SetOpenApiPath(path string) {
+ s.config.OpenApiPath = path
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_route.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_route.go
new file mode 100644
index 000000000000..1fcde0eb5e8c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_route.go
@@ -0,0 +1,24 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+// SetRewrite sets rewrites for static URI for server.
+func (s *Server) SetRewrite(uri string, rewrite string) {
+ s.config.Rewrites[uri] = rewrite
+}
+
+// SetRewriteMap sets the rewrite map for server.
+func (s *Server) SetRewriteMap(rewrites map[string]string) {
+ for k, v := range rewrites {
+ s.config.Rewrites[k] = v
+ }
+}
+
+// SetRouteOverWrite sets the RouteOverWrite for server.
+func (s *Server) SetRouteOverWrite(enabled bool) {
+ s.config.RouteOverWrite = enabled
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_session.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_session.go
new file mode 100644
index 000000000000..a9c25abafc4b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_session.go
@@ -0,0 +1,53 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "time"
+
+ "github.com/gogf/gf/v2/os/gsession"
+)
+
+// SetSessionMaxAge sets the SessionMaxAge for server.
+func (s *Server) SetSessionMaxAge(ttl time.Duration) {
+ s.config.SessionMaxAge = ttl
+}
+
+// SetSessionIdName sets the SessionIdName for server.
+func (s *Server) SetSessionIdName(name string) {
+ s.config.SessionIdName = name
+}
+
+// SetSessionStorage sets the SessionStorage for server.
+func (s *Server) SetSessionStorage(storage gsession.Storage) {
+ s.config.SessionStorage = storage
+}
+
+// SetSessionCookieOutput sets the SetSessionCookieOutput for server.
+func (s *Server) SetSessionCookieOutput(enabled bool) {
+ s.config.SessionCookieOutput = enabled
+}
+
+// SetSessionCookieMaxAge sets the SessionCookieMaxAge for server.
+func (s *Server) SetSessionCookieMaxAge(maxAge time.Duration) {
+ s.config.SessionCookieMaxAge = maxAge
+}
+
+// GetSessionMaxAge returns the SessionMaxAge of server.
+func (s *Server) GetSessionMaxAge() time.Duration {
+ return s.config.SessionMaxAge
+}
+
+// GetSessionIdName returns the SessionIdName of server.
+func (s *Server) GetSessionIdName() string {
+ return s.config.SessionIdName
+}
+
+// GetSessionCookieMaxAge returns the SessionCookieMaxAge of server.
+func (s *Server) GetSessionCookieMaxAge() time.Duration {
+ return s.config.SessionCookieMaxAge
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_static.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_static.go
new file mode 100644
index 000000000000..b2b7042d5385
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_config_static.go
@@ -0,0 +1,133 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Static Searching Priority: Resource > ServerPaths > ServerRoot > SearchPath
+
+package ghttp
+
+import (
+ "context"
+ "strings"
+
+ "github.com/gogf/gf/v2/os/gres"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// staticPathItem is the item struct for static path configuration.
+type staticPathItem struct {
+ prefix string // The router URI.
+ path string // The static path.
+}
+
+// SetIndexFiles sets the index files for server.
+func (s *Server) SetIndexFiles(indexFiles []string) {
+ s.config.IndexFiles = indexFiles
+}
+
+// GetIndexFiles retrieves and returns the index files from server.
+func (s *Server) GetIndexFiles() []string {
+ return s.config.IndexFiles
+}
+
+// SetIndexFolder enables/disables listing the sub-files if requesting a directory.
+func (s *Server) SetIndexFolder(enabled bool) {
+ s.config.IndexFolder = enabled
+}
+
+// SetFileServerEnabled enables/disables the static file service.
+// It's the main switch for the static file service. When static file service configuration
+// functions like SetServerRoot, AddSearchPath and AddStaticPath are called, this configuration
+// is automatically enabled.
+func (s *Server) SetFileServerEnabled(enabled bool) {
+ s.config.FileServerEnabled = enabled
+}
+
+// SetServerRoot sets the document root for static service.
+func (s *Server) SetServerRoot(root string) {
+ var (
+ ctx = context.TODO()
+ realPath = root
+ )
+ if !gres.Contains(realPath) {
+ if p, err := gfile.Search(root); err != nil {
+ s.Logger().Fatalf(ctx, `SetServerRoot failed: %+v`, err)
+ } else {
+ realPath = p
+ }
+ }
+ s.Logger().Debug(ctx, "SetServerRoot path:", realPath)
+ s.config.SearchPaths = []string{strings.TrimRight(realPath, gfile.Separator)}
+ s.config.FileServerEnabled = true
+}
+
+// AddSearchPath add searching directory path for static file service.
+func (s *Server) AddSearchPath(path string) {
+ var (
+ ctx = context.TODO()
+ realPath = path
+ )
+ if !gres.Contains(realPath) {
+ if p, err := gfile.Search(path); err != nil {
+ s.Logger().Fatalf(ctx, `AddSearchPath failed: %+v`, err)
+ } else {
+ realPath = p
+ }
+ }
+ s.config.SearchPaths = append(s.config.SearchPaths, realPath)
+ s.config.FileServerEnabled = true
+}
+
+// AddStaticPath sets the uri to static directory path mapping for static file service.
+func (s *Server) AddStaticPath(prefix string, path string) {
+ var (
+ ctx = context.TODO()
+ realPath = path
+ )
+ if !gres.Contains(realPath) {
+ if p, err := gfile.Search(path); err != nil {
+ s.Logger().Fatalf(ctx, `AddStaticPath failed: %+v`, err)
+ } else {
+ realPath = p
+ }
+ }
+ addItem := staticPathItem{
+ prefix: prefix,
+ path: realPath,
+ }
+ if len(s.config.StaticPaths) > 0 {
+ s.config.StaticPaths = append(s.config.StaticPaths, addItem)
+ // Sort the array by length of prefix from short to long.
+ array := garray.NewSortedArray(func(v1, v2 interface{}) int {
+ s1 := gconv.String(v1)
+ s2 := gconv.String(v2)
+ r := len(s2) - len(s1)
+ if r == 0 {
+ r = strings.Compare(s1, s2)
+ }
+ return r
+ })
+ for _, v := range s.config.StaticPaths {
+ array.Add(v.prefix)
+ }
+ // Add the items to paths by previous sorted slice.
+ paths := make([]staticPathItem, 0)
+ for _, v := range array.Slice() {
+ for _, item := range s.config.StaticPaths {
+ if strings.EqualFold(gconv.String(v), item.prefix) {
+ paths = append(paths, item)
+ break
+ }
+ }
+ }
+ s.config.StaticPaths = paths
+ } else {
+ s.config.StaticPaths = []staticPathItem{addItem}
+ }
+ s.config.FileServerEnabled = true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_cookie.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_cookie.go
new file mode 100644
index 000000000000..8275593d9c2a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_cookie.go
@@ -0,0 +1,186 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "net/http"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// Cookie for HTTP COOKIE management.
+type Cookie struct {
+ data map[string]*cookieItem // Underlying cookie items.
+ server *Server // Belonged HTTP server
+ request *Request // Belonged HTTP request.
+ response *Response // Belonged HTTP response.
+}
+
+// cookieItem is the item stored in Cookie.
+type cookieItem struct {
+ *http.Cookie // Underlying cookie items.
+ FromClient bool // Mark this cookie received from client.
+}
+
+// GetCookie creates or retrieves a cookie object with given request.
+// It retrieves and returns an existing cookie object if it already exists with given request.
+// It creates and returns a new cookie object if it does not exist with given request.
+func GetCookie(r *Request) *Cookie {
+ if r.Cookie != nil {
+ return r.Cookie
+ }
+ return &Cookie{
+ request: r,
+ server: r.Server,
+ }
+}
+
+// init does lazy initialization for cookie object.
+func (c *Cookie) init() {
+ if c.data != nil {
+ return
+ }
+ c.data = make(map[string]*cookieItem)
+ c.response = c.request.Response
+ // DO NOT ADD ANY DEFAULT COOKIE DOMAIN!
+ // if c.request.Server.GetCookieDomain() == "" {
+ // c.request.Server.GetCookieDomain() = c.request.GetHost()
+ // }
+ for _, v := range c.request.Cookies() {
+ c.data[v.Name] = &cookieItem{
+ Cookie: v,
+ FromClient: true,
+ }
+ }
+}
+
+// Map returns the cookie items as map[string]string.
+func (c *Cookie) Map() map[string]string {
+ c.init()
+ m := make(map[string]string)
+ for k, v := range c.data {
+ m[k] = v.Value
+ }
+ return m
+}
+
+// Contains checks if given key exists and not expired in cookie.
+func (c *Cookie) Contains(key string) bool {
+ c.init()
+ if r, ok := c.data[key]; ok {
+ if r.Expires.IsZero() || r.Expires.After(time.Now()) {
+ return true
+ }
+ }
+ return false
+}
+
+// Set sets cookie item with default domain, path and expiration age.
+func (c *Cookie) Set(key, value string) {
+ c.SetCookie(
+ key,
+ value,
+ c.request.Server.GetCookieDomain(),
+ c.request.Server.GetCookiePath(),
+ c.request.Server.GetCookieMaxAge(),
+ )
+}
+
+// SetCookie sets cookie item with given domain, path and expiration age.
+// The optional parameter `httpOnly` specifies if the cookie item is only available in HTTP,
+// which is usually empty.
+func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, httpOnly ...bool) {
+ c.init()
+ isHttpOnly := false
+ if len(httpOnly) > 0 {
+ isHttpOnly = httpOnly[0]
+ }
+ httpCookie := &http.Cookie{
+ Name: key,
+ Value: value,
+ Path: path,
+ Domain: domain,
+ HttpOnly: isHttpOnly,
+ }
+ if maxAge != 0 {
+ httpCookie.Expires = time.Now().Add(maxAge)
+ }
+ c.data[key] = &cookieItem{
+ Cookie: httpCookie,
+ }
+}
+
+// SetHttpCookie sets cookie with *http.Cookie.
+func (c *Cookie) SetHttpCookie(httpCookie *http.Cookie) {
+ c.init()
+ c.data[httpCookie.Name] = &cookieItem{
+ Cookie: httpCookie,
+ }
+}
+
+// GetSessionId retrieves and returns the session id from cookie.
+func (c *Cookie) GetSessionId() string {
+ return c.Get(c.server.GetSessionIdName()).String()
+}
+
+// SetSessionId sets session id in the cookie.
+func (c *Cookie) SetSessionId(id string) {
+ c.SetCookie(
+ c.server.GetSessionIdName(),
+ id,
+ c.request.Server.GetCookieDomain(),
+ c.request.Server.GetCookiePath(),
+ c.server.GetSessionCookieMaxAge(),
+ )
+}
+
+// Get retrieves and returns the value with specified key.
+// It returns `def` if specified key does not exist and `def` is given.
+func (c *Cookie) Get(key string, def ...string) *gvar.Var {
+ c.init()
+ if r, ok := c.data[key]; ok {
+ if r.Expires.IsZero() || r.Expires.After(time.Now()) {
+ return gvar.New(r.Value)
+ }
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// Remove deletes specified key and its value from cookie using default domain and path.
+// It actually tells the http client that the cookie is expired, do not send it to server next time.
+func (c *Cookie) Remove(key string) {
+ c.SetCookie(
+ key,
+ "",
+ c.request.Server.GetCookieDomain(),
+ c.request.Server.GetCookiePath(),
+ -24*time.Hour,
+ )
+}
+
+// RemoveCookie deletes specified key and its value from cookie using given domain and path.
+// It actually tells the http client that the cookie is expired, do not send it to server next time.
+func (c *Cookie) RemoveCookie(key, domain, path string) {
+ c.SetCookie(key, "", domain, path, -24*time.Hour)
+}
+
+// Flush outputs the cookie items to client.
+func (c *Cookie) Flush() {
+ if len(c.data) == 0 {
+ return
+ }
+ for _, v := range c.data {
+ if v.FromClient {
+ continue
+ }
+ http.SetCookie(c.response.Writer, v.Cookie)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_domain.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_domain.go
new file mode 100644
index 000000000000..74a77c4a1656
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_domain.go
@@ -0,0 +1,157 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "strings"
+)
+
+// Domain is used for route register for domains.
+type Domain struct {
+ server *Server // Belonged server
+ domains map[string]struct{} // Support multiple domains.
+}
+
+// Domain creates and returns a domain object for management for one or more domains.
+func (s *Server) Domain(domains string) *Domain {
+ d := &Domain{
+ server: s,
+ domains: make(map[string]struct{}),
+ }
+ for _, v := range strings.Split(domains, ",") {
+ d.domains[strings.TrimSpace(v)] = struct{}{}
+ }
+ return d
+}
+
+func (d *Domain) BindHandler(pattern string, handler interface{}) {
+ for domain, _ := range d.domains {
+ d.server.BindHandler(pattern+"@"+domain, handler)
+ }
+}
+
+func (d *Domain) doBindHandler(ctx context.Context, in doBindHandlerInput) {
+ for domain, _ := range d.domains {
+ d.server.doBindHandler(ctx, doBindHandlerInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern + "@" + domain,
+ FuncInfo: in.FuncInfo,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ })
+ }
+}
+
+func (d *Domain) BindObject(pattern string, obj interface{}, methods ...string) {
+ for domain, _ := range d.domains {
+ d.server.BindObject(pattern+"@"+domain, obj, methods...)
+ }
+}
+
+func (d *Domain) doBindObject(ctx context.Context, in doBindObjectInput) {
+ for domain, _ := range d.domains {
+ d.server.doBindObject(ctx, doBindObjectInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern + "@" + domain,
+ Object: in.Object,
+ Method: in.Method,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ })
+ }
+}
+
+func (d *Domain) BindObjectMethod(pattern string, obj interface{}, method string) {
+ for domain, _ := range d.domains {
+ d.server.BindObjectMethod(pattern+"@"+domain, obj, method)
+ }
+}
+
+func (d *Domain) doBindObjectMethod(ctx context.Context, in doBindObjectMethodInput) {
+ for domain, _ := range d.domains {
+ d.server.doBindObjectMethod(ctx, doBindObjectMethodInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern + "@" + domain,
+ Object: in.Object,
+ Method: in.Method,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ })
+ }
+}
+
+func (d *Domain) BindObjectRest(pattern string, obj interface{}) {
+ for domain, _ := range d.domains {
+ d.server.BindObjectRest(pattern+"@"+domain, obj)
+ }
+}
+
+func (d *Domain) doBindObjectRest(ctx context.Context, in doBindObjectInput) {
+ for domain, _ := range d.domains {
+ d.server.doBindObjectRest(ctx, doBindObjectInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern + "@" + domain,
+ Object: in.Object,
+ Method: in.Method,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ })
+ }
+}
+
+func (d *Domain) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
+ for domain, _ := range d.domains {
+ d.server.BindHookHandler(pattern+"@"+domain, hook, handler)
+ }
+}
+
+func (d *Domain) doBindHookHandler(ctx context.Context, in doBindHookHandlerInput) {
+ for domain, _ := range d.domains {
+ d.server.doBindHookHandler(ctx, doBindHookHandlerInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern + "@" + domain,
+ HookName: in.HookName,
+ Handler: in.Handler,
+ Source: in.Source,
+ })
+ }
+}
+
+func (d *Domain) BindHookHandlerByMap(pattern string, hookmap map[string]HandlerFunc) {
+ for domain, _ := range d.domains {
+ d.server.BindHookHandlerByMap(pattern+"@"+domain, hookmap)
+ }
+}
+
+func (d *Domain) BindStatusHandler(status int, handler HandlerFunc) {
+ for domain, _ := range d.domains {
+ d.server.addStatusHandler(d.server.statusHandlerKey(status, domain), handler)
+ }
+}
+
+func (d *Domain) BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {
+ for k, v := range handlerMap {
+ d.BindStatusHandler(k, v)
+ }
+}
+
+func (d *Domain) BindMiddleware(pattern string, handlers ...HandlerFunc) {
+ for domain, _ := range d.domains {
+ d.server.BindMiddleware(pattern+"@"+domain, handlers...)
+ }
+}
+
+func (d *Domain) BindMiddlewareDefault(handlers ...HandlerFunc) {
+ for domain, _ := range d.domains {
+ d.server.BindMiddleware(defaultMiddlewarePattern+"@"+domain, handlers...)
+ }
+}
+
+func (d *Domain) Use(handlers ...HandlerFunc) {
+ d.BindMiddlewareDefault(handlers...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_error_logger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_error_logger.go
new file mode 100644
index 000000000000..7bc89a079ea7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_error_logger.go
@@ -0,0 +1,25 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "bytes"
+ "context"
+
+ "github.com/gogf/gf/v2/os/glog"
+)
+
+// errorLogger is the error logging logger for underlying net/http.Server.
+type errorLogger struct {
+ logger *glog.Logger
+}
+
+// Write implements the io.Writer interface.
+func (l *errorLogger) Write(p []byte) (n int, err error) {
+ l.logger.Skip(1).Error(context.TODO(), string(bytes.TrimRight(p, "\r\n")))
+ return len(p), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_graceful.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_graceful.go
new file mode 100644
index 000000000000..1eaad532132c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_graceful.go
@@ -0,0 +1,238 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "crypto/tls"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "sync"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gproc"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// gracefulServer wraps the net/http.Server with graceful reload/restart feature.
+type gracefulServer struct {
+ server *Server // Belonged server.
+ fd uintptr // File descriptor for passing to child process when graceful reload.
+ address string // Listening address like:":80", ":8080".
+ httpServer *http.Server // Underlying http.Server.
+ rawListener net.Listener // Underlying net.Listener.
+ rawLnMu sync.RWMutex // Concurrent safety mutex for `rawListener`.
+ listener net.Listener // Wrapped net.Listener.
+ isHttps bool // Is HTTPS.
+ status int // Status of current server.
+}
+
+// newGracefulServer creates and returns a graceful http server with given address.
+// The optional parameter `fd` specifies the file descriptor which is passed from parent server.
+func (s *Server) newGracefulServer(address string, fd ...int) *gracefulServer {
+ // Change port to address like: 80 -> :80
+ if gstr.IsNumeric(address) {
+ address = ":" + address
+ }
+ gs := &gracefulServer{
+ server: s,
+ address: address,
+ httpServer: s.newHttpServer(address),
+ }
+ if len(fd) > 0 && fd[0] > 0 {
+ gs.fd = uintptr(fd[0])
+ }
+ return gs
+}
+
+// newGracefulServer creates and returns an underlying http.Server with given address.
+func (s *Server) newHttpServer(address string) *http.Server {
+ server := &http.Server{
+ Addr: address,
+ Handler: http.HandlerFunc(s.config.Handler),
+ ReadTimeout: s.config.ReadTimeout,
+ WriteTimeout: s.config.WriteTimeout,
+ IdleTimeout: s.config.IdleTimeout,
+ MaxHeaderBytes: s.config.MaxHeaderBytes,
+ ErrorLog: log.New(&errorLogger{logger: s.config.Logger}, "", 0),
+ }
+ server.SetKeepAlivesEnabled(s.config.KeepAlive)
+ return server
+}
+
+// ListenAndServe starts listening on configured address.
+func (s *gracefulServer) ListenAndServe() error {
+ ln, err := s.getNetListener()
+ if err != nil {
+ return err
+ }
+ s.listener = ln
+ s.setRawListener(ln)
+ return s.doServe(context.TODO())
+}
+
+// Fd retrieves and returns the file descriptor of current server.
+// It is available ony in *nix like operating systems like: linux, unix, darwin.
+func (s *gracefulServer) Fd() uintptr {
+ if ln := s.getRawListener(); ln != nil {
+ file, err := ln.(*net.TCPListener).File()
+ if err == nil {
+ return file.Fd()
+ }
+ }
+ return 0
+}
+
+// setFd sets the file descriptor for current server.
+func (s *gracefulServer) setFd(fd int) {
+ s.fd = uintptr(fd)
+}
+
+// ListenAndServeTLS starts listening on configured address with HTTPS.
+// The parameter `certFile` and `keyFile` specify the necessary certification and key files for HTTPS.
+// The optional parameter `tlsConfig` specifies the custom TLS configuration.
+func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error {
+ var (
+ ctx = context.TODO()
+ config *tls.Config
+ )
+ if len(tlsConfig) > 0 && tlsConfig[0] != nil {
+ config = tlsConfig[0]
+ } else if s.httpServer.TLSConfig != nil {
+ config = s.httpServer.TLSConfig
+ } else {
+ config = &tls.Config{}
+ }
+ if config.NextProtos == nil {
+ config.NextProtos = []string{"http/1.1"}
+ }
+ var err error
+ if len(config.Certificates) == 0 {
+ config.Certificates = make([]tls.Certificate, 1)
+ if gres.Contains(certFile) {
+ config.Certificates[0], err = tls.X509KeyPair(
+ gres.GetContent(certFile),
+ gres.GetContent(keyFile),
+ )
+ } else {
+ config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+ }
+
+ }
+ if err != nil {
+ return gerror.Wrapf(err, `open certFile "%s" and keyFile "%s" failed`, certFile, keyFile)
+ }
+ ln, err := s.getNetListener()
+ if err != nil {
+ return err
+ }
+
+ s.listener = tls.NewListener(ln, config)
+ s.setRawListener(ln)
+ return s.doServe(ctx)
+}
+
+// GetListenedPort retrieves and returns one port which is listened by current server.
+func (s *gracefulServer) GetListenedPort() int {
+ if ln := s.getRawListener(); ln != nil {
+ return ln.Addr().(*net.TCPAddr).Port
+ }
+ return 0
+}
+
+// getProto retrieves and returns the proto string of current server.
+func (s *gracefulServer) getProto() string {
+ proto := "http"
+ if s.isHttps {
+ proto = "https"
+ }
+ return proto
+}
+
+// doServe starts the serving.
+func (s *gracefulServer) doServe(ctx context.Context) error {
+ action := "started"
+ if s.fd != 0 {
+ action = "reloaded"
+ }
+ s.server.Logger().Infof(
+ ctx,
+ `pid[%d]: %s server %s listening on [%s]`,
+ gproc.Pid(), s.getProto(), action, s.address,
+ )
+ s.status = ServerStatusRunning
+ err := s.httpServer.Serve(s.listener)
+ s.status = ServerStatusStopped
+ return err
+}
+
+// getNetListener retrieves and returns the wrapped net.Listener.
+func (s *gracefulServer) getNetListener() (net.Listener, error) {
+ var (
+ ln net.Listener
+ err error
+ )
+ if s.fd > 0 {
+ f := os.NewFile(s.fd, "")
+ ln, err = net.FileListener(f)
+ if err != nil {
+ err = gerror.Wrapf(err, "%d: net.FileListener failed", gproc.Pid())
+ return nil, err
+ }
+ } else {
+ ln, err = net.Listen("tcp", s.httpServer.Addr)
+ if err != nil {
+ err = gerror.Wrapf(err, "%d: net.Listen failed", gproc.Pid())
+ }
+ }
+ return ln, err
+}
+
+// shutdown shuts down the server gracefully.
+func (s *gracefulServer) shutdown(ctx context.Context) {
+ if s.status == ServerStatusStopped {
+ return
+ }
+ if err := s.httpServer.Shutdown(context.Background()); err != nil {
+ s.server.Logger().Errorf(
+ ctx,
+ "%d: %s server [%s] shutdown error: %v",
+ gproc.Pid(), s.getProto(), s.address, err,
+ )
+ }
+}
+
+// setRawListener sets `rawListener` with given net.Listener.
+func (s *gracefulServer) setRawListener(ln net.Listener) {
+ s.rawLnMu.Lock()
+ defer s.rawLnMu.Unlock()
+ s.rawListener = ln
+}
+
+// setRawListener returns the `rawListener` of current server.
+func (s *gracefulServer) getRawListener() net.Listener {
+ s.rawLnMu.RLock()
+ defer s.rawLnMu.RUnlock()
+ return s.rawListener
+}
+
+// close shuts down the server forcibly.
+func (s *gracefulServer) close(ctx context.Context) {
+ if s.status == ServerStatusStopped {
+ return
+ }
+ if err := s.httpServer.Close(); err != nil {
+ s.server.Logger().Errorf(
+ ctx,
+ "%d: %s server [%s] closed error: %v",
+ gproc.Pid(), s.getProto(), s.address, err,
+ )
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_handler.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_handler.go
new file mode 100644
index 000000000000..89b9697cbf2e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_handler.go
@@ -0,0 +1,348 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "net/http"
+ "os"
+ "sort"
+ "strings"
+
+ "github.com/gogf/gf/v2/encoding/ghtml"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gspath"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// ServeHTTP is the default handler for http request.
+// It should not create new goroutine handling the request as
+// it's called by am already created new goroutine from http.Server.
+//
+// This function also make serve implementing the interface of http.Handler.
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // Max body size limit.
+ if s.config.ClientMaxBodySize > 0 {
+ r.Body = http.MaxBytesReader(w, r.Body, s.config.ClientMaxBodySize)
+ }
+
+ // Rewrite feature checks.
+ if len(s.config.Rewrites) > 0 {
+ if rewrite, ok := s.config.Rewrites[r.URL.Path]; ok {
+ r.URL.Path = rewrite
+ }
+ }
+
+ // Create a new request object.
+ request := newRequest(s, r, w)
+
+ defer func() {
+ request.LeaveTime = gtime.TimestampMilli()
+ // error log handling.
+ if request.error != nil {
+ s.handleErrorLog(request.error, request)
+ } else {
+ if exception := recover(); exception != nil {
+ request.Response.WriteStatus(http.StatusInternalServerError)
+ if v, ok := exception.(error); ok {
+ if code := gerror.Code(v); code != gcode.CodeNil {
+ s.handleErrorLog(v, request)
+ } else {
+ s.handleErrorLog(gerror.WrapCodeSkip(gcode.CodeInternalError, 1, v, ""), request)
+ }
+ } else {
+ s.handleErrorLog(gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception), request)
+ }
+ }
+ }
+ // access log handling.
+ s.handleAccessLog(request)
+ // Close the session, which automatically update the TTL
+ // of the session if it exists.
+ if err := request.Session.Close(); err != nil {
+ intlog.Errorf(request.Context(), `%+v`, err)
+ }
+
+ // Close the request and response body
+ // to release the file descriptor in time.
+ err := request.Request.Body.Close()
+ if err != nil {
+ intlog.Errorf(request.Context(), `%+v`, err)
+ }
+ if request.Request.Response != nil {
+ err = request.Request.Response.Body.Close()
+ if err != nil {
+ intlog.Errorf(request.Context(), `%+v`, err)
+ }
+ }
+ }()
+
+ // ============================================================
+ // Priority:
+ // Static File > Dynamic Service > Static Directory
+ // ============================================================
+
+ // Search the static file with most high priority,
+ // which also handle the index files feature.
+ if s.config.FileServerEnabled {
+ request.StaticFile = s.searchStaticFile(r.URL.Path)
+ if request.StaticFile != nil {
+ request.isFileRequest = true
+ }
+ }
+
+ // Search the dynamic service handler.
+ request.handlers, request.hasHookHandler, request.hasServeHandler = s.getHandlersWithCache(request)
+
+ // Check the service type static or dynamic for current request.
+ if request.StaticFile != nil && request.StaticFile.IsDir && request.hasServeHandler {
+ request.isFileRequest = false
+ }
+
+ // HOOK - BeforeServe
+ s.callHookHandler(HookBeforeServe, request)
+
+ // Core serving handling.
+ if !request.IsExited() {
+ if request.isFileRequest {
+ // Static file service.
+ s.serveFile(request, request.StaticFile)
+ } else {
+ if len(request.handlers) > 0 {
+ // Dynamic service.
+ request.Middleware.Next()
+ } else {
+ if request.StaticFile != nil && request.StaticFile.IsDir {
+ // Serve the directory.
+ s.serveFile(request, request.StaticFile)
+ } else {
+ if len(request.Response.Header()) == 0 &&
+ request.Response.Status == 0 &&
+ request.Response.BufferLength() == 0 {
+ request.Response.WriteHeader(http.StatusNotFound)
+ }
+ }
+ }
+ }
+ }
+
+ // HOOK - AfterServe
+ if !request.IsExited() {
+ s.callHookHandler(HookAfterServe, request)
+ }
+
+ // HOOK - BeforeOutput
+ if !request.IsExited() {
+ s.callHookHandler(HookBeforeOutput, request)
+ }
+
+ // HTTP status checking.
+ if request.Response.Status == 0 {
+ if request.StaticFile != nil || request.Middleware.served || request.Response.buffer.Len() > 0 {
+ request.Response.WriteHeader(http.StatusOK)
+ } else {
+ request.Response.WriteHeader(http.StatusNotFound)
+ }
+ }
+ // HTTP status handler.
+ if request.Response.Status != http.StatusOK {
+ statusFuncArray := s.getStatusHandler(request.Response.Status, request)
+ for _, f := range statusFuncArray {
+ // Call custom status handler.
+ niceCallFunc(func() {
+ f(request)
+ })
+ if request.IsExited() {
+ break
+ }
+ }
+ }
+
+ // Automatically set the session id to cookie
+ // if it creates a new session id in this request
+ // and SessionCookieOutput is enabled.
+ if s.config.SessionCookieOutput &&
+ request.Session.IsDirty() &&
+ request.Session.MustId() != request.GetSessionId() {
+ request.Cookie.SetSessionId(request.Session.MustId())
+ }
+ // Output the cookie content to client.
+ request.Cookie.Flush()
+ // Output the buffer content to client.
+ request.Response.Flush()
+ // HOOK - AfterOutput
+ if !request.IsExited() {
+ s.callHookHandler(HookAfterOutput, request)
+ }
+}
+
+// searchStaticFile searches the file with given URI.
+// It returns a file struct specifying the file information.
+func (s *Server) searchStaticFile(uri string) *staticFile {
+ var (
+ file *gres.File
+ path string
+ dir bool
+ )
+ // Firstly search the StaticPaths mapping.
+ if len(s.config.StaticPaths) > 0 {
+ for _, item := range s.config.StaticPaths {
+ if len(uri) >= len(item.prefix) && strings.EqualFold(item.prefix, uri[0:len(item.prefix)]) {
+ // To avoid case like: /static/style -> /static/style.css
+ if len(uri) > len(item.prefix) && uri[len(item.prefix)] != '/' {
+ continue
+ }
+ file = gres.GetWithIndex(item.path+uri[len(item.prefix):], s.config.IndexFiles)
+ if file != nil {
+ return &staticFile{
+ File: file,
+ IsDir: file.FileInfo().IsDir(),
+ }
+ }
+ path, dir = gspath.Search(item.path, uri[len(item.prefix):], s.config.IndexFiles...)
+ if path != "" {
+ return &staticFile{
+ Path: path,
+ IsDir: dir,
+ }
+ }
+
+ }
+ }
+ }
+ // Secondly search the root and searching paths.
+ if len(s.config.SearchPaths) > 0 {
+ for _, p := range s.config.SearchPaths {
+ file = gres.GetWithIndex(p+uri, s.config.IndexFiles)
+ if file != nil {
+ return &staticFile{
+ File: file,
+ IsDir: file.FileInfo().IsDir(),
+ }
+ }
+ if path, dir = gspath.Search(p, uri, s.config.IndexFiles...); path != "" {
+ return &staticFile{
+ Path: path,
+ IsDir: dir,
+ }
+ }
+ }
+ }
+ // Lastly search the resource manager.
+ if len(s.config.StaticPaths) == 0 && len(s.config.SearchPaths) == 0 {
+ if file = gres.GetWithIndex(uri, s.config.IndexFiles); file != nil {
+ return &staticFile{
+ File: file,
+ IsDir: file.FileInfo().IsDir(),
+ }
+ }
+ }
+ return nil
+}
+
+// serveFile serves the static file for client.
+// The optional parameter `allowIndex` specifies if allowing directory listing if `f` is directory.
+func (s *Server) serveFile(r *Request, f *staticFile, allowIndex ...bool) {
+ // Use resource file from memory.
+ if f.File != nil {
+ if f.IsDir {
+ if s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) {
+ s.listDir(r, f.File)
+ } else {
+ r.Response.WriteStatus(http.StatusForbidden)
+ }
+ } else {
+ info := f.File.FileInfo()
+ r.Response.wroteHeader = true
+ http.ServeContent(r.Response.Writer.RawWriter(), r.Request, info.Name(), info.ModTime(), f.File)
+ }
+ return
+ }
+ // Use file from dist.
+ file, err := os.Open(f.Path)
+ if err != nil {
+ r.Response.WriteStatus(http.StatusForbidden)
+ return
+ }
+ defer file.Close()
+
+ // Clear the response buffer before file serving.
+ // It ignores all custom buffer content and uses the file content.
+ r.Response.ClearBuffer()
+
+ info, _ := file.Stat()
+ if info.IsDir() {
+ if s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) {
+ s.listDir(r, file)
+ } else {
+ r.Response.WriteStatus(http.StatusForbidden)
+ }
+ } else {
+ r.Response.wroteHeader = true
+ http.ServeContent(r.Response.Writer.RawWriter(), r.Request, info.Name(), info.ModTime(), file)
+ }
+}
+
+// listDir lists the sub files of specified directory as HTML content to client.
+func (s *Server) listDir(r *Request, f http.File) {
+ files, err := f.Readdir(-1)
+ if err != nil {
+ r.Response.WriteStatus(http.StatusInternalServerError, "Error reading directory")
+ return
+ }
+ // The folder type has the most priority than file.
+ sort.Slice(files, func(i, j int) bool {
+ if files[i].IsDir() && !files[j].IsDir() {
+ return true
+ }
+ if !files[i].IsDir() && files[j].IsDir() {
+ return false
+ }
+ return files[i].Name() < files[j].Name()
+ })
+ if r.Response.Header().Get("Content-Type") == "" {
+ r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
+ }
+ r.Response.Write(``)
+ r.Response.Write(``)
+ r.Response.Write(``)
+ r.Response.Write(``)
+ r.Response.Write(``)
+ r.Response.Writef(`Index of %s `, r.URL.Path)
+ r.Response.Writef(` `)
+ r.Response.Write(``)
+ if r.URL.Path != "/" {
+ r.Response.Write(``)
+ r.Response.Writef(`.. `, gfile.Dir(r.URL.Path))
+ r.Response.Write(` `)
+ }
+ name := ""
+ size := ""
+ prefix := gstr.TrimRight(r.URL.Path, "/")
+ for _, file := range files {
+ name = file.Name()
+ size = gfile.FormatSize(file.Size())
+ if file.IsDir() {
+ name += "/"
+ size = "-"
+ }
+ r.Response.Write(``)
+ r.Response.Writef(`%s `, prefix, name, ghtml.SpecialChars(name))
+ r.Response.Writef(`%s `, gtime.New(file.ModTime()).ISO8601())
+ r.Response.Writef(`%s `, size)
+ r.Response.Write(` `)
+ }
+ r.Response.Write(`
`)
+ r.Response.Write(``)
+ r.Response.Write(``)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_log.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_log.go
new file mode 100644
index 000000000000..7743f1f230a3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_log.go
@@ -0,0 +1,73 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// handleAccessLog handles the access logging for server.
+func (s *Server) handleAccessLog(r *Request) {
+ if !s.IsAccessLogEnabled() {
+ return
+ }
+ scheme := "http"
+ if r.TLS != nil {
+ scheme = "https"
+ }
+ s.Logger().File(s.config.AccessLogPattern).
+ Stdout(s.config.LogStdout).
+ Printf(
+ r.Context(),
+ `%d "%s %s %s %s %s" %.3f, %s, "%s", "%s"`,
+ r.Response.Status, r.Method, scheme, r.Host, r.URL.String(), r.Proto,
+ float64(r.LeaveTime-r.EnterTime)/1000,
+ r.GetClientIp(), r.Referer(), r.UserAgent(),
+ )
+}
+
+// handleErrorLog handles the error logging for server.
+func (s *Server) handleErrorLog(err error, r *Request) {
+ // It does nothing if error logging is custom disabled.
+ if !s.IsErrorLogEnabled() {
+ return
+ }
+ var (
+ code = gerror.Code(err)
+ scheme = "http"
+ codeDetail = code.Detail()
+ codeDetailStr string
+ )
+ if r.TLS != nil {
+ scheme = "https"
+ }
+ if codeDetail != nil {
+ codeDetailStr = gstr.Replace(fmt.Sprintf(`%+v`, codeDetail), "\n", " ")
+ }
+ content := fmt.Sprintf(
+ `%d "%s %s %s %s %s" %.3f, %s, "%s", "%s", %d, "%s", "%+v"`,
+ r.Response.Status, r.Method, scheme, r.Host, r.URL.String(), r.Proto,
+ float64(r.LeaveTime-r.EnterTime)/1000,
+ r.GetClientIp(), r.Referer(), r.UserAgent(),
+ code.Code(), code.Message(), codeDetailStr,
+ )
+ if s.config.ErrorStack {
+ if stack := gerror.Stack(err); stack != "" {
+ content += "\nStack:\n" + stack
+ } else {
+ content += ", " + err.Error()
+ }
+ } else {
+ content += ", " + err.Error()
+ }
+ s.Logger().File(s.config.ErrorLogPattern).
+ Stdout(s.config.LogStdout).
+ Print(r.Context(), content)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_openapi.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_openapi.go
new file mode 100644
index 000000000000..035063f04340
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_openapi.go
@@ -0,0 +1,63 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/protocol/goai"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// initOpenApi generates api specification using OpenApiV3 protocol.
+func (s *Server) initOpenApi() {
+ if s.config.OpenApiPath == "" {
+ return
+ }
+ var (
+ ctx = context.TODO()
+ err error
+ method string
+ )
+ for _, item := range s.GetRoutes() {
+ switch item.Type {
+ case HandlerTypeMiddleware, HandlerTypeHook:
+ continue
+ }
+ method = item.Method
+ if gstr.Equal(method, defaultMethod) {
+ method = ""
+ }
+ if item.Handler.Info.Func == nil {
+ err = s.openapi.Add(goai.AddInput{
+ Path: item.Route,
+ Method: method,
+ Object: item.Handler.Info.Value.Interface(),
+ })
+ if err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+ }
+ }
+}
+
+// openapiSpec is a build-in handler automatic producing for openapi specification json file.
+func (s *Server) openapiSpec(r *Request) {
+ var (
+ err error
+ )
+ if s.config.OpenApiPath == "" {
+ r.Response.Write(`OpenApi specification file producing is disabled`)
+ } else {
+ err = r.Response.WriteJson(s.openapi)
+ }
+
+ if err != nil {
+ intlog.Errorf(r.Context(), `%+v`, err)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_plugin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_plugin.go
new file mode 100644
index 000000000000..ce97e7f9b37b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_plugin.go
@@ -0,0 +1,22 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+// Plugin is the interface for server plugin.
+type Plugin interface {
+ Name() string // Name returns the name of the plugin.
+ Author() string // Author returns the author of the plugin.
+ Version() string // Version returns the version of the plugin, like "v1.0.0".
+ Description() string // Description returns the description of the plugin.
+ Install(s *Server) error // Install installs the plugin before server starts.
+ Remove() error // Remove removes the plugin.
+}
+
+// Plugin adds plugin to server.
+func (s *Server) Plugin(plugin ...Plugin) {
+ s.plugins = append(s.plugins, plugin...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_pprof.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_pprof.go
new file mode 100644
index 000000000000..632feb6c8859
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_pprof.go
@@ -0,0 +1,128 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ netpprof "net/http/pprof"
+ runpprof "runtime/pprof"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gview"
+)
+
+// utilPProf is the PProf interface implementer.
+type utilPProf struct{}
+
+const (
+ defaultPProfServerName = "pprof-server"
+ defaultPProfPattern = "/debug/pprof"
+)
+
+// StartPProfServer starts and runs a new server for pprof.
+func StartPProfServer(port int, pattern ...string) {
+ s := GetServer(defaultPProfServerName)
+ s.EnablePProf()
+ s.SetPort(port)
+ s.Run()
+}
+
+// EnablePProf enables PProf feature for server.
+func (s *Server) EnablePProf(pattern ...string) {
+ s.Domain(DefaultDomainName).EnablePProf(pattern...)
+}
+
+// EnablePProf enables PProf feature for server of specified domain.
+func (d *Domain) EnablePProf(pattern ...string) {
+ p := defaultPProfPattern
+ if len(pattern) > 0 && pattern[0] != "" {
+ p = pattern[0]
+ }
+ up := &utilPProf{}
+ _, _, uri, _ := d.server.parsePattern(p)
+ uri = strings.TrimRight(uri, "/")
+ d.Group(uri, func(group *RouterGroup) {
+ group.ALL("/*action", up.Index)
+ group.ALL("/cmdline", up.Cmdline)
+ group.ALL("/profile", up.Profile)
+ group.ALL("/symbol", up.Symbol)
+ group.ALL("/trace", up.Trace)
+ })
+}
+
+// Index shows the PProf index page.
+func (p *utilPProf) Index(r *Request) {
+ var (
+ ctx = r.Context()
+ profiles = runpprof.Profiles()
+ action = r.Get("action").String()
+ data = map[string]interface{}{
+ "uri": strings.TrimRight(r.URL.Path, "/") + "/",
+ "profiles": profiles,
+ }
+ )
+ if len(action) == 0 {
+ buffer, _ := gview.ParseContent(r.Context(), `
+
+
+ GoFrame PProf
+
+ {{$uri := .uri}}
+
+ profiles:
+
+ {{range .profiles}}
+
+ {{.Count}}
+ {{.Name}}
+
+ {{end}}
+
+ full goroutine stack dump
+
+
+ `, data)
+ r.Response.Write(buffer)
+ return
+ }
+ for _, p := range profiles {
+ if p.Name() == action {
+ if err := p.WriteTo(r.Response.Writer, r.GetRequest("debug").Int()); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ break
+ }
+ }
+}
+
+// Cmdline responds with the running program's
+// command line, with arguments separated by NUL bytes.
+// The package initialization registers it as /debug/pprof/cmdline.
+func (p *utilPProf) Cmdline(r *Request) {
+ netpprof.Cmdline(r.Response.Writer, r.Request)
+}
+
+// Profile responds with the pprof-formatted cpu profile.
+// Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified.
+// The package initialization registers it as /debug/pprof/profile.
+func (p *utilPProf) Profile(r *Request) {
+ netpprof.Profile(r.Response.Writer, r.Request)
+}
+
+// Symbol looks up the program counters listed in the request,
+// responding with a table mapping program counters to function names.
+// The package initialization registers it as /debug/pprof/symbol.
+func (p *utilPProf) Symbol(r *Request) {
+ netpprof.Symbol(r.Response.Writer, r.Request)
+}
+
+// Trace responds with the execution trace in binary form.
+// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
+// The package initialization registers it as /debug/pprof/trace.
+func (p *utilPProf) Trace(r *Request) {
+ netpprof.Trace(r.Response.Writer, r.Request)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_registry.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_registry.go
new file mode 100644
index 000000000000..32b3e9cef693
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_registry.go
@@ -0,0 +1,69 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/net/gipv4"
+ "github.com/gogf/gf/v2/net/gsvc"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// doServiceRegister registers current service to Registry.
+func (s *Server) doServiceRegister() {
+ if gsvc.GetRegistry() == nil {
+ return
+ }
+ var (
+ ctx = context.Background()
+ protocol = `http`
+ insecure = true
+ address = s.config.Address
+ )
+ if address == "" {
+ address = s.config.HTTPSAddr
+ }
+ var (
+ array = gstr.Split(address, ":")
+ ip = array[0]
+ port = array[1]
+ )
+ if ip == "" {
+ ip = gipv4.MustGetIntranetIp()
+ }
+ if s.config.TLSConfig != nil {
+ protocol = `https`
+ insecure = false
+ }
+ metadata := gsvc.Metadata{
+ gsvc.MDProtocol: protocol,
+ gsvc.MDInsecure: insecure,
+ }
+ s.service = &gsvc.Service{
+ Name: s.GetName(),
+ Endpoints: []string{fmt.Sprintf(`%s:%s`, ip, port)},
+ Metadata: metadata,
+ }
+ s.Logger().Debugf(ctx, `service register: %+v`, s.service)
+ if err := gsvc.Register(ctx, s.service); err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+}
+
+// doServiceDeregister de-registers current service from Registry.
+func (s *Server) doServiceDeregister() {
+ if gsvc.GetRegistry() == nil {
+ return
+ }
+ var ctx = context.Background()
+ s.Logger().Debugf(ctx, `service deregister: %+v`, s.service)
+ if err := gsvc.Deregister(ctx, s.service); err != nil {
+ s.Logger().Errorf(ctx, `%+v`, err)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router.go
new file mode 100644
index 000000000000..1fdcd5629b5c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router.go
@@ -0,0 +1,426 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/debug/gdebug"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/protocol/goai"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gmeta"
+)
+
+const (
+ stackFilterKey = "/net/ghttp/ghttp"
+)
+
+var (
+ // handlerIdGenerator is handler item id generator.
+ handlerIdGenerator = gtype.NewInt()
+)
+
+// routerMapKey creates and returns an unique router key for given parameters.
+// This key is used for Server.routerMap attribute, which is mainly for checks for
+// repeated router registering.
+func (s *Server) routerMapKey(hook, method, path, domain string) string {
+ return hook + "%" + s.serveHandlerKey(method, path, domain)
+}
+
+// parsePattern parses the given pattern to domain, method and path variable.
+func (s *Server) parsePattern(pattern string) (domain, method, path string, err error) {
+ path = strings.TrimSpace(pattern)
+ domain = DefaultDomainName
+ method = defaultMethod
+ if array, err := gregex.MatchString(`([a-zA-Z]+):(.+)`, pattern); len(array) > 1 && err == nil {
+ path = strings.TrimSpace(array[2])
+ if v := strings.TrimSpace(array[1]); v != "" {
+ method = v
+ }
+ }
+ if array, err := gregex.MatchString(`(.+)@([\w\.\-]+)`, path); len(array) > 1 && err == nil {
+ path = strings.TrimSpace(array[1])
+ if v := strings.TrimSpace(array[2]); v != "" {
+ domain = v
+ }
+ }
+ if path == "" {
+ err = gerror.NewCode(gcode.CodeInvalidParameter, "invalid pattern: URI should not be empty")
+ }
+ if path != "/" {
+ path = strings.TrimRight(path, "/")
+ }
+ return
+}
+
+type setHandlerInput struct {
+ Prefix string
+ Pattern string
+ HandlerItem *handlerItem
+}
+
+// setHandler creates router item with given handler and pattern and registers the handler to the router tree.
+// The router tree can be treated as a multilayer hash table, please refer to the comment in following codes.
+// This function is called during server starts up, which cares little about the performance. What really cares
+// is the well-designed router storage structure for router searching when the request is under serving.
+func (s *Server) setHandler(ctx context.Context, in setHandlerInput) {
+ var (
+ prefix = in.Prefix
+ pattern = in.Pattern
+ handler = in.HandlerItem
+ )
+ if handler.Name == "" {
+ handler.Name = runtime.FuncForPC(handler.Info.Value.Pointer()).Name()
+ }
+ handler.Id = handlerIdGenerator.Add(1)
+ if handler.Source == "" {
+ _, file, line := gdebug.CallerWithFilter([]string{utils.StackFilterKeyForGoFrame})
+ handler.Source = fmt.Sprintf(`%s:%d`, file, line)
+ }
+ domain, method, uri, err := s.parsePattern(pattern)
+ if err != nil {
+ s.Logger().Fatalf(ctx, `invalid pattern "%s", %+v`, pattern, err)
+ return
+ }
+
+ // Change the registered route according meta info from its request structure.
+ if handler.Info.Type != nil && handler.Info.Type.NumIn() == 2 {
+ var (
+ objectReq = reflect.New(handler.Info.Type.In(1))
+ )
+ if v := gmeta.Get(objectReq, goai.TagNamePath); !v.IsEmpty() {
+ uri = v.String()
+ }
+ if v := gmeta.Get(objectReq, goai.TagNameMethod); !v.IsEmpty() {
+ method = v.String()
+ }
+ if v := gmeta.Get(objectReq, goai.TagNameDomain); !v.IsEmpty() {
+ domain = v.String()
+ }
+ }
+
+ // Prefix for URI feature.
+ if prefix != "" {
+ uri = prefix + "/" + strings.TrimLeft(uri, "/")
+ }
+ uri = strings.TrimRight(uri, "/")
+ if uri == "" {
+ uri = "/"
+ }
+
+ if len(uri) == 0 || uri[0] != '/' {
+ s.Logger().Fatalf(ctx, `invalid pattern "%s", URI should lead with '/'`, pattern)
+ return
+ }
+
+ // Repeated router checks, this feature can be disabled by server configuration.
+ routerKey := s.routerMapKey(handler.HookName, method, uri, domain)
+ if !s.config.RouteOverWrite {
+ switch handler.Type {
+ case HandlerTypeHandler, HandlerTypeObject:
+ if item, ok := s.routesMap[routerKey]; ok {
+ s.Logger().Fatalf(
+ ctx,
+ `duplicated route registry "%s" at %s , already registered at %s`,
+ pattern, handler.Source, item[0].Source,
+ )
+ return
+ }
+ }
+ }
+ // Create a new router by given parameter.
+ handler.Router = &Router{
+ Uri: uri,
+ Domain: domain,
+ Method: strings.ToUpper(method),
+ Priority: strings.Count(uri[1:], "/"),
+ }
+ handler.Router.RegRule, handler.Router.RegNames = s.patternToRegular(uri)
+
+ if _, ok := s.serveTree[domain]; !ok {
+ s.serveTree[domain] = make(map[string]interface{})
+ }
+ // List array, very important for router registering.
+ // There may be multiple lists adding into this array when searching from root to leaf.
+ lists := make([]*glist.List, 0)
+ array := ([]string)(nil)
+ if strings.EqualFold("/", uri) {
+ array = []string{"/"}
+ } else {
+ array = strings.Split(uri[1:], "/")
+ }
+ // Multilayer hash table:
+ // 1. Each node of the table is separated by URI path which is split by char '/'.
+ // 2. The key "*fuzz" specifies this node is a fuzzy node, which has no certain name.
+ // 3. The key "*list" is the list item of the node, MOST OF THE NODES HAVE THIS ITEM,
+ // especially the fuzzy node. NOTE THAT the fuzzy node must have the "*list" item,
+ // and the leaf node also has "*list" item. If the node is not a fuzzy node either
+ // a leaf, it neither has "*list" item.
+ // 2. The "*list" item is a list containing registered router items ordered by their
+ // priorities from high to low.
+ // 3. There may be repeated router items in the router lists. The lists' priorities
+ // from root to leaf are from low to high.
+ p := s.serveTree[domain]
+ for i, part := range array {
+ // Ignore empty URI part, like: /user//index
+ if part == "" {
+ continue
+ }
+ // Check if it's a fuzzy node.
+ if gregex.IsMatchString(`^[:\*]|\{[\w\.\-]+\}|\*`, part) {
+ part = "*fuzz"
+ // If it's a fuzzy node, it creates a "*list" item - which is a list - in the hash map.
+ // All the sub router items from this fuzzy node will also be added to its "*list" item.
+ if v, ok := p.(map[string]interface{})["*list"]; !ok {
+ newListForFuzzy := glist.New()
+ p.(map[string]interface{})["*list"] = newListForFuzzy
+ lists = append(lists, newListForFuzzy)
+ } else {
+ lists = append(lists, v.(*glist.List))
+ }
+ }
+ // Make a new bucket for current node.
+ if _, ok := p.(map[string]interface{})[part]; !ok {
+ p.(map[string]interface{})[part] = make(map[string]interface{})
+ }
+ // Loop to next bucket.
+ p = p.(map[string]interface{})[part]
+ // The leaf is a hash map and must have an item named "*list", which contains the router item.
+ // The leaf can be furthermore extended by adding more ket-value pairs into its map.
+ // Note that the `v != "*fuzz"` comparison is required as the list might be added in the former
+ // fuzzy checks.
+ if i == len(array)-1 && part != "*fuzz" {
+ if v, ok := p.(map[string]interface{})["*list"]; !ok {
+ leafList := glist.New()
+ p.(map[string]interface{})["*list"] = leafList
+ lists = append(lists, leafList)
+ } else {
+ lists = append(lists, v.(*glist.List))
+ }
+ }
+ }
+ // It iterates the list array of `lists`, compares priorities and inserts the new router item in
+ // the proper position of each list. The priority of the list is ordered from high to low.
+ item := (*handlerItem)(nil)
+ for _, l := range lists {
+ pushed := false
+ for e := l.Front(); e != nil; e = e.Next() {
+ item = e.Value.(*handlerItem)
+ // Checks the priority whether inserting the route item before current item,
+ // which means it has higher priority.
+ if s.compareRouterPriority(handler, item) {
+ l.InsertBefore(e, handler)
+ pushed = true
+ goto end
+ }
+ }
+ end:
+ // Just push back in default.
+ if !pushed {
+ l.PushBack(handler)
+ }
+ }
+ // Initialize the route map item.
+ if _, ok := s.routesMap[routerKey]; !ok {
+ s.routesMap[routerKey] = make([]registeredRouteItem, 0)
+ }
+
+ routeItem := registeredRouteItem{
+ Source: handler.Source,
+ Handler: handler,
+ }
+ switch handler.Type {
+ case HandlerTypeHandler, HandlerTypeObject:
+ // Overwrite the route.
+ s.routesMap[routerKey] = []registeredRouteItem{routeItem}
+ default:
+ // Append the route.
+ s.routesMap[routerKey] = append(s.routesMap[routerKey], routeItem)
+ }
+}
+
+// compareRouterPriority compares the priority between `newItem` and `oldItem`. It returns true
+// if `newItem`'s priority is higher than `oldItem`, else it returns false. The higher priority
+// item will be inserted into the router list before the other one.
+//
+// Comparison rules:
+// 1. The middleware has the most high priority.
+// 2. URI: The deeper, the higher (simply check the count of char '/' in the URI).
+// 3. Route type: {xxx} > :xxx > *xxx.
+func (s *Server) compareRouterPriority(newItem *handlerItem, oldItem *handlerItem) bool {
+ // If they're all type of middleware, the priority is according their registered sequence.
+ if newItem.Type == HandlerTypeMiddleware && oldItem.Type == HandlerTypeMiddleware {
+ return false
+ }
+ // The middleware has the most high priority.
+ if newItem.Type == HandlerTypeMiddleware && oldItem.Type != HandlerTypeMiddleware {
+ return true
+ }
+ // URI: The deeper, the higher (simply check the count of char '/' in the URI).
+ if newItem.Router.Priority > oldItem.Router.Priority {
+ return true
+ }
+ if newItem.Router.Priority < oldItem.Router.Priority {
+ return false
+ }
+
+ // Compare the length of their URI,
+ // but the fuzzy and named parts of the URI are not calculated to the result.
+
+ // Example:
+ // /admin-goods-{page} > /admin-{page}
+ // /{hash}.{type} > /{hash}
+ var uriNew, uriOld string
+ uriNew, _ = gregex.ReplaceString(`\{[^/]+?\}`, "", newItem.Router.Uri)
+ uriOld, _ = gregex.ReplaceString(`\{[^/]+?\}`, "", oldItem.Router.Uri)
+ uriNew, _ = gregex.ReplaceString(`:[^/]+?`, "", uriNew)
+ uriOld, _ = gregex.ReplaceString(`:[^/]+?`, "", uriOld)
+ uriNew, _ = gregex.ReplaceString(`\*[^/]*`, "", uriNew) // Replace "/*" and "/*any".
+ uriOld, _ = gregex.ReplaceString(`\*[^/]*`, "", uriOld) // Replace "/*" and "/*any".
+ if len(uriNew) > len(uriOld) {
+ return true
+ }
+ if len(uriNew) < len(uriOld) {
+ return false
+ }
+
+ // Route type checks: {xxx} > :xxx > *xxx.
+ // Example:
+ // /name/act > /{name}/:act
+ var (
+ fuzzyCountFieldNew int
+ fuzzyCountFieldOld int
+ fuzzyCountNameNew int
+ fuzzyCountNameOld int
+ fuzzyCountAnyNew int
+ fuzzyCountAnyOld int
+ fuzzyCountTotalNew int
+ fuzzyCountTotalOld int
+ )
+ for _, v := range newItem.Router.Uri {
+ switch v {
+ case '{':
+ fuzzyCountFieldNew++
+ case ':':
+ fuzzyCountNameNew++
+ case '*':
+ fuzzyCountAnyNew++
+ }
+ }
+ for _, v := range oldItem.Router.Uri {
+ switch v {
+ case '{':
+ fuzzyCountFieldOld++
+ case ':':
+ fuzzyCountNameOld++
+ case '*':
+ fuzzyCountAnyOld++
+ }
+ }
+ fuzzyCountTotalNew = fuzzyCountFieldNew + fuzzyCountNameNew + fuzzyCountAnyNew
+ fuzzyCountTotalOld = fuzzyCountFieldOld + fuzzyCountNameOld + fuzzyCountAnyOld
+ if fuzzyCountTotalNew < fuzzyCountTotalOld {
+ return true
+ }
+ if fuzzyCountTotalNew > fuzzyCountTotalOld {
+ return false
+ }
+
+ // If the counts of their fuzzy rules equal.
+
+ // Eg: /name/{act} > /name/:act
+ if fuzzyCountFieldNew > fuzzyCountFieldOld {
+ return true
+ }
+ if fuzzyCountFieldNew < fuzzyCountFieldOld {
+ return false
+ }
+ // Eg: /name/:act > /name/*act
+ if fuzzyCountNameNew > fuzzyCountNameOld {
+ return true
+ }
+ if fuzzyCountNameNew < fuzzyCountNameOld {
+ return false
+ }
+
+ // It then compares the accuracy of their http method,
+ // the more accurate the more priority.
+ if newItem.Router.Method != defaultMethod {
+ return true
+ }
+ if oldItem.Router.Method != defaultMethod {
+ return true
+ }
+
+ // If they have different router type,
+ // the new router item has more priority than the other one.
+ if newItem.Type == HandlerTypeHandler || newItem.Type == HandlerTypeObject {
+ return true
+ }
+
+ // Other situations, like HOOK items,
+ // the old router item has more priority than the other one.
+ return false
+}
+
+// patternToRegular converts route rule to according regular expression.
+func (s *Server) patternToRegular(rule string) (regular string, names []string) {
+ if len(rule) < 2 {
+ return rule, nil
+ }
+ regular = "^"
+ array := strings.Split(rule[1:], "/")
+ for _, v := range array {
+ if len(v) == 0 {
+ continue
+ }
+ switch v[0] {
+ case ':':
+ if len(v) > 1 {
+ regular += `/([^/]+)`
+ names = append(names, v[1:])
+ } else {
+ regular += `/[^/]+`
+ }
+ case '*':
+ if len(v) > 1 {
+ regular += `/{0,1}(.*)`
+ names = append(names, v[1:])
+ } else {
+ regular += `/{0,1}.*`
+ }
+ default:
+ // Special chars replacement.
+ v = gstr.ReplaceByMap(v, map[string]string{
+ `.`: `\.`,
+ `+`: `\+`,
+ `*`: `.*`,
+ })
+ s, _ := gregex.ReplaceStringFunc(`\{[\w\.\-]+\}`, v, func(s string) string {
+ names = append(names, s[1:len(s)-1])
+ return `([^/]+)`
+ })
+ if strings.EqualFold(s, v) {
+ regular += "/" + v
+ } else {
+ regular += "/" + s
+ }
+ }
+ }
+ regular += `$`
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_group.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_group.go
new file mode 100644
index 000000000000..75535c02b79d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_group.go
@@ -0,0 +1,429 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+
+ "github.com/gogf/gf/v2/debug/gdebug"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type (
+ // RouterGroup is a group wrapping multiple routes and middleware.
+ RouterGroup struct {
+ parent *RouterGroup // Parent group.
+ server *Server // Server.
+ domain *Domain // Domain.
+ prefix string // Prefix for sub-route.
+ middleware []HandlerFunc // Middleware array.
+ }
+
+ // preBindItem is item for lazy registering feature of router group. preBindItem is not really registered
+ // to server when route function of the group called but is lazily registered when server starts.
+ preBindItem struct {
+ group *RouterGroup
+ bindType string
+ pattern string
+ object interface{} // Can be handler, controller or object.
+ params []interface{} // Extra parameters for route registering depending on the type.
+ source string // Handler is register at certain source file path:line.
+ bound bool // Is this item bound to server.
+ }
+)
+
+const (
+ groupBindTypeHandler = "HANDLER"
+ groupBindTypeRest = "REST"
+ groupBindTypeHook = "HOOK"
+ groupBindTypeMiddleware = "MIDDLEWARE"
+)
+
+var (
+ preBindItems = make([]*preBindItem, 0, 64)
+)
+
+// handlePreBindItems is called when server starts, which does really route registering to the server.
+func (s *Server) handlePreBindItems(ctx context.Context) {
+ if len(preBindItems) == 0 {
+ return
+ }
+ for _, item := range preBindItems {
+ if item.bound {
+ continue
+ }
+ // Handle the items of current server.
+ if item.group.server != nil && item.group.server != s {
+ continue
+ }
+ if item.group.domain != nil && item.group.domain.server != s {
+ continue
+ }
+ item.group.doBindRoutersToServer(ctx, item)
+ item.bound = true
+ }
+}
+
+// Group creates and returns a RouterGroup object.
+func (s *Server) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {
+ if len(prefix) > 0 && prefix[0] != '/' {
+ prefix = "/" + prefix
+ }
+ if prefix == "/" {
+ prefix = ""
+ }
+ group := &RouterGroup{
+ server: s,
+ prefix: prefix,
+ }
+ if len(groups) > 0 {
+ for _, v := range groups {
+ v(group)
+ }
+ }
+ return group
+}
+
+// Group creates and returns a RouterGroup object, which is bound to a specified domain.
+func (d *Domain) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {
+ if len(prefix) > 0 && prefix[0] != '/' {
+ prefix = "/" + prefix
+ }
+ if prefix == "/" {
+ prefix = ""
+ }
+ routerGroup := &RouterGroup{
+ domain: d,
+ server: d.server,
+ prefix: prefix,
+ }
+ if len(groups) > 0 {
+ for _, nestedGroup := range groups {
+ nestedGroup(routerGroup)
+ }
+ }
+ return routerGroup
+}
+
+// Group creates and returns a sub-group of current router group.
+func (g *RouterGroup) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {
+ if prefix == "/" {
+ prefix = ""
+ }
+ group := &RouterGroup{
+ parent: g,
+ server: g.server,
+ domain: g.domain,
+ prefix: prefix,
+ }
+ if len(g.middleware) > 0 {
+ group.middleware = make([]HandlerFunc, len(g.middleware))
+ copy(group.middleware, g.middleware)
+ }
+ if len(groups) > 0 {
+ for _, v := range groups {
+ v(group)
+ }
+ }
+ return group
+}
+
+// Clone returns a new router group which is a clone of current group.
+func (g *RouterGroup) Clone() *RouterGroup {
+ newGroup := &RouterGroup{
+ parent: g.parent,
+ server: g.server,
+ domain: g.domain,
+ prefix: g.prefix,
+ middleware: make([]HandlerFunc, len(g.middleware)),
+ }
+ copy(newGroup.middleware, g.middleware)
+ return newGroup
+}
+
+// Bind does batch route registering feature for router group.
+func (g *RouterGroup) Bind(handlerOrObject ...interface{}) *RouterGroup {
+ var (
+ ctx = context.TODO()
+ group = g.Clone()
+ )
+ for _, v := range handlerOrObject {
+ var (
+ item = v
+ originValueAndKind = utils.OriginValueAndKind(item)
+ )
+
+ switch originValueAndKind.OriginKind {
+ case reflect.Func, reflect.Struct:
+ group = group.preBindToLocalArray(
+ groupBindTypeHandler,
+ "/",
+ item,
+ )
+ default:
+ g.server.Logger().Fatalf(ctx, "invalid bind parameter type: %v", originValueAndKind.InputValue.Type())
+ }
+ }
+ return group
+}
+
+// ALL registers a http handler to given route pattern and all http methods.
+func (g *RouterGroup) ALL(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(
+ groupBindTypeHandler,
+ defaultMethod+":"+pattern,
+ object,
+ params...,
+ )
+}
+
+// ALLMap registers http handlers for http methods using map.
+func (g *RouterGroup) ALLMap(m map[string]interface{}) {
+ for pattern, object := range m {
+ g.ALL(pattern, object)
+ }
+}
+
+// Map registers http handlers for http methods using map.
+func (g *RouterGroup) Map(m map[string]interface{}) {
+ for pattern, object := range m {
+ g.preBindToLocalArray(groupBindTypeHandler, pattern, object)
+ }
+}
+
+// GET registers a http handler to given route pattern and http method: GET.
+func (g *RouterGroup) GET(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "GET:"+pattern, object, params...)
+}
+
+// PUT registers a http handler to given route pattern and http method: PUT.
+func (g *RouterGroup) PUT(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "PUT:"+pattern, object, params...)
+}
+
+// POST registers a http handler to given route pattern and http method: POST.
+func (g *RouterGroup) POST(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "POST:"+pattern, object, params...)
+}
+
+// DELETE registers a http handler to given route pattern and http method: DELETE.
+func (g *RouterGroup) DELETE(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "DELETE:"+pattern, object, params...)
+}
+
+// PATCH registers a http handler to given route pattern and http method: PATCH.
+func (g *RouterGroup) PATCH(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "PATCH:"+pattern, object, params...)
+}
+
+// HEAD registers a http handler to given route pattern and http method: HEAD.
+func (g *RouterGroup) HEAD(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "HEAD:"+pattern, object, params...)
+}
+
+// CONNECT registers a http handler to given route pattern and http method: CONNECT.
+func (g *RouterGroup) CONNECT(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "CONNECT:"+pattern, object, params...)
+}
+
+// OPTIONS registers a http handler to given route pattern and http method: OPTIONS.
+func (g *RouterGroup) OPTIONS(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "OPTIONS:"+pattern, object, params...)
+}
+
+// TRACE registers a http handler to given route pattern and http method: TRACE.
+func (g *RouterGroup) TRACE(pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, "TRACE:"+pattern, object, params...)
+}
+
+// REST registers a http handler to given route pattern according to REST rule.
+func (g *RouterGroup) REST(pattern string, object interface{}) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeRest, pattern, object)
+}
+
+// Hook registers a hook to given route pattern.
+func (g *RouterGroup) Hook(pattern string, hook string, handler HandlerFunc) *RouterGroup {
+ return g.Clone().preBindToLocalArray(groupBindTypeHandler, pattern, handler, hook)
+}
+
+// Middleware binds one or more middleware to the router group.
+func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup {
+ g.middleware = append(g.middleware, handlers...)
+ return g
+}
+
+// preBindToLocalArray adds the route registering parameters to internal variable array for lazily registering feature.
+func (g *RouterGroup) preBindToLocalArray(bindType string, pattern string, object interface{}, params ...interface{}) *RouterGroup {
+ _, file, line := gdebug.CallerWithFilter([]string{utils.StackFilterKeyForGoFrame})
+ preBindItems = append(preBindItems, &preBindItem{
+ group: g,
+ bindType: bindType,
+ pattern: pattern,
+ object: object,
+ params: params,
+ source: fmt.Sprintf(`%s:%d`, file, line),
+ })
+ return g
+}
+
+// getPrefix returns the route prefix of the group, which recursively retrieves its parent's prefixo.
+func (g *RouterGroup) getPrefix() string {
+ prefix := g.prefix
+ parent := g.parent
+ for parent != nil {
+ prefix = parent.prefix + prefix
+ parent = parent.parent
+ }
+ return prefix
+}
+
+// doBindRoutersToServer does really register for the group.
+func (g *RouterGroup) doBindRoutersToServer(ctx context.Context, item *preBindItem) *RouterGroup {
+ var (
+ bindType = item.bindType
+ pattern = item.pattern
+ object = item.object
+ params = item.params
+ source = item.source
+ )
+ prefix := g.getPrefix()
+ // Route check.
+ if len(prefix) > 0 {
+ domain, method, path, err := g.server.parsePattern(pattern)
+ if err != nil {
+ g.server.Logger().Fatalf(ctx, "invalid route pattern: %s", pattern)
+ }
+ // If there is already a domain, unset the domain field in the pattern.
+ if g.domain != nil {
+ domain = ""
+ }
+ if bindType == groupBindTypeRest {
+ pattern = path
+ } else {
+ pattern = g.server.serveHandlerKey(
+ method, path, domain,
+ )
+ }
+ }
+ // Filter repeated char '/'.
+ pattern = gstr.Replace(pattern, "//", "/")
+
+ // Convert params to string array.
+ extras := gconv.Strings(params)
+
+ // Check whether it's a hook handler.
+ if _, ok := object.(HandlerFunc); ok && len(extras) > 0 {
+ bindType = groupBindTypeHook
+ }
+ switch bindType {
+ case groupBindTypeHandler:
+ if reflect.ValueOf(object).Kind() == reflect.Func {
+ funcInfo, err := g.server.checkAndCreateFuncInfo(object, "", "", "")
+ if err != nil {
+ g.server.Logger().Fatal(ctx, err.Error())
+ return g
+ }
+ in := doBindHandlerInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ FuncInfo: funcInfo,
+ Middleware: g.middleware,
+ Source: source,
+ }
+ if g.domain != nil {
+ g.domain.doBindHandler(ctx, in)
+ } else {
+ g.server.doBindHandler(ctx, in)
+ }
+ } else {
+ if len(extras) > 0 {
+ if gstr.Contains(extras[0], ",") {
+ in := doBindObjectInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ Object: object,
+ Method: extras[0],
+ Middleware: g.middleware,
+ Source: source,
+ }
+ if g.domain != nil {
+ g.domain.doBindObject(ctx, in)
+ } else {
+ g.server.doBindObject(ctx, in)
+ }
+ } else {
+ in := doBindObjectMethodInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ Object: object,
+ Method: extras[0],
+ Middleware: g.middleware,
+ Source: source,
+ }
+ if g.domain != nil {
+ g.domain.doBindObjectMethod(ctx, in)
+ } else {
+ g.server.doBindObjectMethod(ctx, in)
+ }
+ }
+ } else {
+ in := doBindObjectInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ Object: object,
+ Method: "",
+ Middleware: g.middleware,
+ Source: source,
+ }
+ // At last, it treats the `object` as Object registering type.
+ if g.domain != nil {
+ g.domain.doBindObject(ctx, in)
+ } else {
+ g.server.doBindObject(ctx, in)
+ }
+ }
+ }
+
+ case groupBindTypeRest:
+ in := doBindObjectInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ Object: object,
+ Method: "",
+ Middleware: g.middleware,
+ Source: source,
+ }
+ if g.domain != nil {
+ g.domain.doBindObjectRest(ctx, in)
+ } else {
+ g.server.doBindObjectRest(ctx, in)
+ }
+
+ case groupBindTypeHook:
+ if handler, ok := object.(HandlerFunc); ok {
+ in := doBindHookHandlerInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ HookName: extras[0],
+ Handler: handler,
+ Source: source,
+ }
+ if g.domain != nil {
+ g.domain.doBindHookHandler(ctx, in)
+ } else {
+ g.server.doBindHookHandler(ctx, in)
+ }
+ } else {
+ g.server.Logger().Fatalf(ctx, "invalid hook handler for pattern: %s", pattern)
+ }
+ }
+ return g
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_hook.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_hook.go
new file mode 100644
index 000000000000..6c53b05d015d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_hook.go
@@ -0,0 +1,117 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "net/http"
+ "reflect"
+
+ "github.com/gogf/gf/v2/debug/gdebug"
+)
+
+// BindHookHandler registers handler for specified hook.
+func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
+ s.doBindHookHandler(context.TODO(), doBindHookHandlerInput{
+ Prefix: "",
+ Pattern: pattern,
+ HookName: hook,
+ Handler: handler,
+ Source: "",
+ })
+}
+
+type doBindHookHandlerInput struct {
+ Prefix string
+ Pattern string
+ HookName string
+ Handler HandlerFunc
+ Source string
+}
+
+func (s *Server) doBindHookHandler(ctx context.Context, in doBindHookHandlerInput) {
+ s.setHandler(
+ ctx,
+ setHandlerInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern,
+ HandlerItem: &handlerItem{
+ Type: HandlerTypeHook,
+ Name: gdebug.FuncPath(in.Handler),
+ Info: handlerFuncInfo{
+ Func: in.Handler,
+ Type: reflect.TypeOf(in.Handler),
+ },
+ HookName: in.HookName,
+ Source: in.Source,
+ },
+ },
+ )
+}
+
+func (s *Server) BindHookHandlerByMap(pattern string, hookMap map[string]HandlerFunc) {
+ for k, v := range hookMap {
+ s.BindHookHandler(pattern, k, v)
+ }
+}
+
+// callHookHandler calls the hook handler by their registered sequences.
+func (s *Server) callHookHandler(hook string, r *Request) {
+ if !r.hasHookHandler {
+ return
+ }
+ hookItems := r.getHookHandlers(hook)
+ if len(hookItems) > 0 {
+ // Backup the old router variable map.
+ oldRouterMap := r.routerMap
+ for _, item := range hookItems {
+ r.routerMap = item.Values
+ // DO NOT USE the router of the hook handler,
+ // which can overwrite the router of serving handler.
+ // r.Router = item.handler.router
+ if err := s.niceCallHookHandler(item.Handler.Info.Func, r); err != nil {
+ switch err {
+ case exceptionExit:
+ break
+ case exceptionExitAll:
+ fallthrough
+ case exceptionExitHook:
+ return
+ default:
+ r.Response.WriteStatus(http.StatusInternalServerError, err)
+ panic(err)
+ }
+ }
+ }
+ // Restore the old router variable map.
+ r.routerMap = oldRouterMap
+ }
+}
+
+// getHookHandlers retrieves and returns the hook handlers of specified hook.
+func (r *Request) getHookHandlers(hook string) []*handlerParsedItem {
+ parsedItems := make([]*handlerParsedItem, 0, 4)
+ for _, v := range r.handlers {
+ if v.Handler.HookName != hook {
+ continue
+ }
+ item := v
+ parsedItems = append(parsedItems, item)
+ }
+ return parsedItems
+}
+
+// niceCallHookHandler nicely calls the hook handler function,
+// which means it automatically catches and returns the possible panic error to
+// avoid goroutine crash.
+func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}) {
+ defer func() {
+ err = recover()
+ }()
+ f(r)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_middleware.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_middleware.go
new file mode 100644
index 000000000000..74a3d483ab1b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_middleware.go
@@ -0,0 +1,72 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "reflect"
+
+ "github.com/gogf/gf/v2/debug/gdebug"
+)
+
+const (
+ // The default route pattern for global middleware.
+ defaultMiddlewarePattern = "/*"
+)
+
+// BindMiddleware registers one or more global middleware to the server.
+// Global middleware can be used standalone without service handler, which intercepts all dynamic requests
+// before or after service handler. The parameter `pattern` specifies what route pattern the middleware intercepts,
+// which is usually a "fuzzy" pattern like "/:name", "/*any" or "/{field}".
+func (s *Server) BindMiddleware(pattern string, handlers ...HandlerFunc) {
+ var (
+ ctx = context.TODO()
+ )
+ for _, handler := range handlers {
+ s.setHandler(ctx, setHandlerInput{
+ Prefix: "",
+ Pattern: pattern,
+ HandlerItem: &handlerItem{
+ Type: HandlerTypeMiddleware,
+ Name: gdebug.FuncPath(handler),
+ Info: handlerFuncInfo{
+ Func: handler,
+ Type: reflect.TypeOf(handler),
+ },
+ },
+ })
+ }
+}
+
+// BindMiddlewareDefault registers one or more global middleware to the server using default pattern "/*".
+// Global middleware can be used standalone without service handler, which intercepts all dynamic requests
+// before or after service handler.
+func (s *Server) BindMiddlewareDefault(handlers ...HandlerFunc) {
+ var (
+ ctx = context.TODO()
+ )
+ for _, handler := range handlers {
+ s.setHandler(ctx, setHandlerInput{
+ Prefix: "",
+ Pattern: defaultMiddlewarePattern,
+ HandlerItem: &handlerItem{
+ Type: HandlerTypeMiddleware,
+ Name: gdebug.FuncPath(handler),
+ Info: handlerFuncInfo{
+ Func: handler,
+ Type: reflect.TypeOf(handler),
+ },
+ },
+ })
+ }
+}
+
+// Use is alias of BindMiddlewareDefault.
+// See BindMiddlewareDefault.
+func (s *Server) Use(handlers ...HandlerFunc) {
+ s.BindMiddlewareDefault(handlers...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_serve.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_serve.go
new file mode 100644
index 000000000000..58318341c33c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_router_serve.go
@@ -0,0 +1,262 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+// handlerCacheItem is an item just for internal router searching cache.
+type handlerCacheItem struct {
+ parsedItems []*handlerParsedItem
+ hasHook bool
+ hasServe bool
+}
+
+// serveHandlerKey creates and returns a handler key for router.
+func (s *Server) serveHandlerKey(method, path, domain string) string {
+ if len(domain) > 0 {
+ domain = "@" + domain
+ }
+ if method == "" {
+ return path + strings.ToLower(domain)
+ }
+ return strings.ToUpper(method) + ":" + path + strings.ToLower(domain)
+}
+
+// getHandlersWithCache searches the router item with cache feature for given request.
+func (s *Server) getHandlersWithCache(r *Request) (parsedItems []*handlerParsedItem, hasHook, hasServe bool) {
+ var (
+ ctx = r.Context()
+ method = r.Method
+ path = r.URL.Path
+ host = r.GetHost()
+ )
+ // Special http method OPTIONS handling.
+ // It searches the handler with the request method instead of OPTIONS method.
+ if method == http.MethodOptions {
+ if v := r.Request.Header.Get("Access-Control-Request-Method"); v != "" {
+ method = v
+ }
+ }
+ // Search and cache the router handlers.
+ if xUrlPath := r.Header.Get(HeaderXUrlPath); xUrlPath != "" {
+ path = xUrlPath
+ }
+ var handlerKey = s.serveHandlerKey(method, path, host)
+ value, err := s.serveCache.GetOrSetFunc(ctx, handlerKey, func(ctx context.Context) (interface{}, error) {
+ parsedItems, hasHook, hasServe = s.searchHandlers(method, path, host)
+ if parsedItems != nil {
+ return &handlerCacheItem{parsedItems, hasHook, hasServe}, nil
+ }
+ return nil, nil
+ }, routeCacheDuration)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ if value != nil {
+ item := value.Val().(*handlerCacheItem)
+ return item.parsedItems, item.hasHook, item.hasServe
+ }
+ return
+}
+
+// searchHandlers retrieves and returns the routers with given parameters.
+// Note that the returned routers contain serving handler, middleware handlers and hook handlers.
+func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*handlerParsedItem, hasHook, hasServe bool) {
+ if len(path) == 0 {
+ return nil, false, false
+ }
+ // In case of double '/' URI, for example:
+ // /user//index, //user/index, //user//index//
+ var previousIsSep = false
+ for i := 0; i < len(path); {
+ if path[i] == '/' {
+ if previousIsSep {
+ path = path[:i] + path[i+1:]
+ continue
+ } else {
+ previousIsSep = true
+ }
+ } else {
+ previousIsSep = false
+ }
+ i++
+ }
+ // Split the URL.path to separate parts.
+ var array []string
+ if strings.EqualFold("/", path) {
+ array = []string{"/"}
+ } else {
+ array = strings.Split(path[1:], "/")
+ }
+ var (
+ lastMiddlewareElem *glist.Element
+ parsedItemList = glist.New()
+ repeatHandlerCheckMap = make(map[int]struct{}, 16)
+ )
+
+ // Default domain has the most priority when iteration.
+ for _, domainItem := range []string{DefaultDomainName, domain} {
+ p, ok := s.serveTree[domainItem]
+ if !ok {
+ continue
+ }
+ // Make a list array with capacity of 16.
+ lists := make([]*glist.List, 0, 16)
+ for i, part := range array {
+ // Add all list of each node to the list array.
+ if v, ok := p.(map[string]interface{})["*list"]; ok {
+ lists = append(lists, v.(*glist.List))
+ }
+ if v, ok := p.(map[string]interface{})[part]; ok {
+ // Loop to the next node by certain key name.
+ p = v
+ if i == len(array)-1 {
+ if v, ok := p.(map[string]interface{})["*list"]; ok {
+ lists = append(lists, v.(*glist.List))
+ break
+ }
+ }
+ } else if v, ok := p.(map[string]interface{})["*fuzz"]; ok {
+ // Loop to the next node by fuzzy node item.
+ p = v
+ }
+ if i == len(array)-1 {
+ // It here also checks the fuzzy item,
+ // for rule case like: "/user/*action" matches to "/user".
+ if v, ok := p.(map[string]interface{})["*fuzz"]; ok {
+ p = v
+ }
+ // The leaf must have a list item. It adds the list to the list array.
+ if v, ok := p.(map[string]interface{})["*list"]; ok {
+ lists = append(lists, v.(*glist.List))
+ }
+ }
+ }
+
+ // OK, let's loop the result list array, adding the handler item to the result handler result array.
+ // As the tail of the list array has the most priority, it iterates the list array from its tail to head.
+ for i := len(lists) - 1; i >= 0; i-- {
+ for e := lists[i].Front(); e != nil; e = e.Next() {
+ item := e.Value.(*handlerItem)
+ // Filter repeated handler item, especially the middleware and hook handlers.
+ // It is necessary, do not remove this checks logic unless you really know how it is necessary.
+ if _, ok := repeatHandlerCheckMap[item.Id]; ok {
+ continue
+ } else {
+ repeatHandlerCheckMap[item.Id] = struct{}{}
+ }
+ // Serving handler can only be added to the handler array just once.
+ if hasServe {
+ switch item.Type {
+ case HandlerTypeHandler, HandlerTypeObject:
+ continue
+ }
+ }
+ if item.Router.Method == defaultMethod || item.Router.Method == method {
+ // Note the rule having no fuzzy rules: len(match) == 1
+ if match, err := gregex.MatchString(item.Router.RegRule, path); err == nil && len(match) > 0 {
+ parsedItem := &handlerParsedItem{item, nil}
+ // If the rule contains fuzzy names,
+ // it needs paring the URL to retrieve the values for the names.
+ if len(item.Router.RegNames) > 0 {
+ if len(match) > len(item.Router.RegNames) {
+ parsedItem.Values = make(map[string]string)
+ // It there repeated names, it just overwrites the same one.
+ for i, name := range item.Router.RegNames {
+ parsedItem.Values[name] = match[i+1]
+ }
+ }
+ }
+ switch item.Type {
+ // The serving handler can be only added just once.
+ case HandlerTypeHandler, HandlerTypeObject:
+ hasServe = true
+ parsedItemList.PushBack(parsedItem)
+
+ // The middleware is inserted before the serving handler.
+ // If there are multiple middleware, they're inserted into the result list by their registering order.
+ // The middleware is also executed by their registered order.
+ case HandlerTypeMiddleware:
+ if lastMiddlewareElem == nil {
+ lastMiddlewareElem = parsedItemList.PushFront(parsedItem)
+ } else {
+ lastMiddlewareElem = parsedItemList.InsertAfter(lastMiddlewareElem, parsedItem)
+ }
+
+ // HOOK handler, just push it back to the list.
+ case HandlerTypeHook:
+ hasHook = true
+ parsedItemList.PushBack(parsedItem)
+
+ default:
+ panic(gerror.Newf(`invalid handler type %s`, item.Type))
+ }
+ }
+ }
+ }
+ }
+ }
+ if parsedItemList.Len() > 0 {
+ index := 0
+ parsedItems = make([]*handlerParsedItem, parsedItemList.Len())
+ for e := parsedItemList.Front(); e != nil; e = e.Next() {
+ parsedItems[index] = e.Value.(*handlerParsedItem)
+ index++
+ }
+ }
+ return
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (item handlerItem) MarshalJSON() ([]byte, error) {
+ switch item.Type {
+ case HandlerTypeHook:
+ return json.Marshal(
+ fmt.Sprintf(
+ `%s %s:%s (%s)`,
+ item.Router.Uri,
+ item.Router.Domain,
+ item.Router.Method,
+ item.HookName,
+ ),
+ )
+ case HandlerTypeMiddleware:
+ return json.Marshal(
+ fmt.Sprintf(
+ `%s %s:%s (MIDDLEWARE)`,
+ item.Router.Uri,
+ item.Router.Domain,
+ item.Router.Method,
+ ),
+ )
+ default:
+ return json.Marshal(
+ fmt.Sprintf(
+ `%s %s:%s`,
+ item.Router.Uri,
+ item.Router.Domain,
+ item.Router.Method,
+ ),
+ )
+ }
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (item handlerParsedItem) MarshalJSON() ([]byte, error) {
+ return json.Marshal(item.Handler)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_service_handler.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_service_handler.go
new file mode 100644
index 000000000000..4b5ffa8f0bfe
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_service_handler.go
@@ -0,0 +1,211 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "bytes"
+ "context"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// BindHandler registers a handler function to server with given pattern.
+//
+// Note that the parameter `handler` can be type of:
+// 1. func(*ghttp.Request)
+// 2. func(context.Context, BizRequest)(BizResponse, error)
+func (s *Server) BindHandler(pattern string, handler interface{}) {
+ var (
+ ctx = context.TODO()
+ )
+ funcInfo, err := s.checkAndCreateFuncInfo(handler, "", "", "")
+ if err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+ s.doBindHandler(ctx, doBindHandlerInput{
+ Prefix: "",
+ Pattern: pattern,
+ FuncInfo: funcInfo,
+ Middleware: nil,
+ Source: "",
+ })
+}
+
+type doBindHandlerInput struct {
+ Prefix string
+ Pattern string
+ FuncInfo handlerFuncInfo
+ Middleware []HandlerFunc
+ Source string
+}
+
+// doBindHandler registers a handler function to server with given pattern.
+//
+// The parameter `pattern` is like:
+// /user/list, put:/user, delete:/user, post:/user@goframe.org
+func (s *Server) doBindHandler(ctx context.Context, in doBindHandlerInput) {
+ s.setHandler(ctx, setHandlerInput{
+ Prefix: in.Prefix,
+ Pattern: in.Pattern,
+ HandlerItem: &handlerItem{
+ Type: HandlerTypeHandler,
+ Info: in.FuncInfo,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ },
+ })
+}
+
+// bindHandlerByMap registers handlers to server using map.
+func (s *Server) bindHandlerByMap(ctx context.Context, prefix string, m map[string]*handlerItem) {
+ for pattern, handler := range m {
+ s.setHandler(ctx, setHandlerInput{
+ Prefix: prefix,
+ Pattern: pattern,
+ HandlerItem: handler,
+ })
+ }
+}
+
+// mergeBuildInNameToPattern merges build-in names into the pattern according to the following
+// rules, and the built-in names are named like "{.xxx}".
+// Rule 1: The URI in pattern contains the {.struct} keyword, it then replaces the keyword with the struct name;
+// Rule 2: The URI in pattern contains the {.method} keyword, it then replaces the keyword with the method name;
+// Rule 2: If Rule 1 is not met, it then adds the method name directly to the URI in the pattern;
+//
+// The parameter `allowAppend` specifies whether allowing appending method name to the tail of pattern.
+func (s *Server) mergeBuildInNameToPattern(pattern string, structName, methodName string, allowAppend bool) string {
+ structName = s.nameToUri(structName)
+ methodName = s.nameToUri(methodName)
+ pattern = strings.Replace(pattern, "{.struct}", structName, -1)
+ if strings.Index(pattern, "{.method}") != -1 {
+ return strings.Replace(pattern, "{.method}", methodName, -1)
+ }
+ if !allowAppend {
+ return pattern
+ }
+ // Check domain parameter.
+ array := strings.Split(pattern, "@")
+ uri := array[0]
+ uri = strings.TrimRight(uri, "/") + "/" + methodName
+ // Append the domain parameter to URI.
+ if len(array) > 1 {
+ return uri + "@" + array[1]
+ }
+ return uri
+}
+
+// nameToUri converts the given name to URL format using following rules:
+// Rule 0: Convert all method names to lowercase, add char '-' between words.
+// Rule 1: Do not convert the method name, construct the URI with the original method name.
+// Rule 2: Convert all method names to lowercase, no connecting symbols between words.
+// Rule 3: Use camel case naming.
+func (s *Server) nameToUri(name string) string {
+ switch s.config.NameToUriType {
+ case UriTypeFullName:
+ return name
+
+ case UriTypeAllLower:
+ return strings.ToLower(name)
+
+ case UriTypeCamel:
+ part := bytes.NewBuffer(nil)
+ if gstr.IsLetterUpper(name[0]) {
+ part.WriteByte(name[0] + 32)
+ } else {
+ part.WriteByte(name[0])
+ }
+ part.WriteString(name[1:])
+ return part.String()
+
+ case UriTypeDefault:
+ fallthrough
+
+ default:
+ part := bytes.NewBuffer(nil)
+ for i := 0; i < len(name); i++ {
+ if i > 0 && gstr.IsLetterUpper(name[i]) {
+ part.WriteByte('-')
+ }
+ if gstr.IsLetterUpper(name[i]) {
+ part.WriteByte(name[i] + 32)
+ } else {
+ part.WriteByte(name[i])
+ }
+ }
+ return part.String()
+ }
+}
+
+func (s *Server) checkAndCreateFuncInfo(f interface{}, pkgPath, structName, methodName string) (info handlerFuncInfo, err error) {
+ handlerFunc, ok := f.(HandlerFunc)
+ if !ok {
+ reflectType := reflect.TypeOf(f)
+ if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
+ if pkgPath != "" {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid handler: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" or "func(context.Context, BizRequest)(BizResponse, error)" is required`,
+ pkgPath, structName, methodName, reflect.TypeOf(f).String(),
+ )
+ } else {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid handler: defined as "%s", but "func(*ghttp.Request)" or "func(context.Context, BizRequest)(BizResponse, error)" is required`,
+ reflect.TypeOf(f).String(),
+ )
+ }
+ return
+ }
+
+ if reflectType.In(0).String() != "context.Context" {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid handler: defined as "%s", but the first input parameter should be type of "context.Context"`,
+ reflect.TypeOf(f).String(),
+ )
+ return
+ }
+
+ if reflectType.Out(1).String() != "error" {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid handler: defined as "%s", but the last output parameter should be type of "error"`,
+ reflect.TypeOf(f).String(),
+ )
+ return
+ }
+
+ // The request struct should be named as `xxxReq`.
+ if !gstr.HasSuffix(reflectType.In(1).String(), `Req`) {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid struct naming for request: defined as "%s", but it should be named with "Req" suffix like "xxxReq"`,
+ reflectType.In(1).String(),
+ )
+ return
+ }
+
+ // The response struct should be named as `xxxRes`.
+ if !gstr.HasSuffix(reflectType.Out(0).String(), `Res`) {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid struct naming for response: defined as "%s", but it should be named with "Res" suffix like "xxxRes"`,
+ reflectType.Out(0).String(),
+ )
+ return
+ }
+ }
+ info.Func = handlerFunc
+ info.Type = reflect.TypeOf(f)
+ info.Value = reflect.ValueOf(f)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_service_object.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_service_object.go
new file mode 100644
index 000000000000..543492e3455a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_service_object.go
@@ -0,0 +1,303 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// BindObject registers object to server routes with given pattern.
+//
+// The optional parameter `method` is used to specify the method to be registered, which
+// supports multiple method names, multiple methods are separated by char ',', case-sensitive.
+func (s *Server) BindObject(pattern string, object interface{}, method ...string) {
+ var (
+ bindMethod = ""
+ )
+ if len(method) > 0 {
+ bindMethod = method[0]
+ }
+ s.doBindObject(context.TODO(), doBindObjectInput{
+ Prefix: "",
+ Pattern: pattern,
+ Object: object,
+ Method: bindMethod,
+ Middleware: nil,
+ Source: "",
+ })
+}
+
+// BindObjectMethod registers specified method of object to server routes with given pattern.
+//
+// The optional parameter `method` is used to specify the method to be registered, which
+// does not supports multiple method names but only one, case-sensitive.
+func (s *Server) BindObjectMethod(pattern string, object interface{}, method string) {
+ s.doBindObjectMethod(context.TODO(), doBindObjectMethodInput{
+ Prefix: "",
+ Pattern: pattern,
+ Object: object,
+ Method: method,
+ Middleware: nil,
+ Source: "",
+ })
+}
+
+// BindObjectRest registers object in REST API styles to server with specified pattern.
+func (s *Server) BindObjectRest(pattern string, object interface{}) {
+ s.doBindObjectRest(context.TODO(), doBindObjectInput{
+ Prefix: "",
+ Pattern: pattern,
+ Object: object,
+ Method: "",
+ Middleware: nil,
+ Source: "",
+ })
+}
+
+type doBindObjectInput struct {
+ Prefix string
+ Pattern string
+ Object interface{}
+ Method string
+ Middleware []HandlerFunc
+ Source string
+}
+
+func (s *Server) doBindObject(ctx context.Context, in doBindObjectInput) {
+ // Convert input method to map for convenience and high performance searching purpose.
+ var (
+ methodMap map[string]bool
+ )
+ if len(in.Method) > 0 {
+ methodMap = make(map[string]bool)
+ for _, v := range strings.Split(in.Method, ",") {
+ methodMap[strings.TrimSpace(v)] = true
+ }
+ }
+ // If the `method` in `pattern` is `defaultMethod`,
+ // it removes for convenience for next statement control.
+ domain, method, path, err := s.parsePattern(in.Pattern)
+ if err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ return
+ }
+ if strings.EqualFold(method, defaultMethod) {
+ in.Pattern = s.serveHandlerKey("", path, domain)
+ }
+ var (
+ handlerMap = make(map[string]*handlerItem)
+ reflectValue = reflect.ValueOf(in.Object)
+ reflectType = reflectValue.Type()
+ initFunc func(*Request)
+ shutFunc func(*Request)
+ )
+ // If given `object` is not pointer, it then creates a temporary one,
+ // of which the value is `reflectValue`.
+ // It then can retrieve all the methods both of struct/*struct.
+ if reflectValue.Kind() == reflect.Struct {
+ newValue := reflect.New(reflectType)
+ newValue.Elem().Set(reflectValue)
+ reflectValue = newValue
+ reflectType = reflectValue.Type()
+ }
+ structName := reflectType.Elem().Name()
+ if reflectValue.MethodByName("Init").IsValid() {
+ initFunc = reflectValue.MethodByName("Init").Interface().(func(*Request))
+ }
+ if reflectValue.MethodByName("Shut").IsValid() {
+ shutFunc = reflectValue.MethodByName("Shut").Interface().(func(*Request))
+ }
+ pkgPath := reflectType.Elem().PkgPath()
+ pkgName := gfile.Basename(pkgPath)
+ for i := 0; i < reflectValue.NumMethod(); i++ {
+ methodName := reflectType.Method(i).Name
+ if methodMap != nil && !methodMap[methodName] {
+ continue
+ }
+ if methodName == "Init" || methodName == "Shut" {
+ continue
+ }
+ objName := gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), "")
+ if objName[0] == '*' {
+ objName = fmt.Sprintf(`(%s)`, objName)
+ }
+
+ funcInfo, err := s.checkAndCreateFuncInfo(reflectValue.Method(i).Interface(), pkgPath, objName, methodName)
+ if err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+
+ key := s.mergeBuildInNameToPattern(in.Pattern, structName, methodName, true)
+ handlerMap[key] = &handlerItem{
+ Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
+ Type: HandlerTypeObject,
+ Info: funcInfo,
+ InitFunc: initFunc,
+ ShutFunc: shutFunc,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ }
+ // If there's "Index" method, then an additional route is automatically added
+ // to match the main URI, for example:
+ // If pattern is "/user", then "/user" and "/user/index" are both automatically
+ // registered.
+ //
+ // Note that if there's built-in variables in pattern, this route will not be added
+ // automatically.
+ if strings.EqualFold(methodName, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, in.Pattern) {
+ p := gstr.PosRI(key, "/index")
+ k := key[0:p] + key[p+6:]
+ if len(k) == 0 || k[0] == '@' {
+ k = "/" + k
+ }
+ handlerMap[k] = &handlerItem{
+ Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
+ Type: HandlerTypeObject,
+ Info: funcInfo,
+ InitFunc: initFunc,
+ ShutFunc: shutFunc,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ }
+ }
+ }
+ s.bindHandlerByMap(ctx, in.Prefix, handlerMap)
+}
+
+type doBindObjectMethodInput struct {
+ Prefix string
+ Pattern string
+ Object interface{}
+ Method string
+ Middleware []HandlerFunc
+ Source string
+}
+
+func (s *Server) doBindObjectMethod(ctx context.Context, in doBindObjectMethodInput) {
+ var (
+ handlerMap = make(map[string]*handlerItem)
+ reflectValue = reflect.ValueOf(in.Object)
+ reflectType = reflectValue.Type()
+ initFunc func(*Request)
+ shutFunc func(*Request)
+ )
+ // If given `object` is not pointer, it then creates a temporary one,
+ // of which the value is `v`.
+ if reflectValue.Kind() == reflect.Struct {
+ newValue := reflect.New(reflectType)
+ newValue.Elem().Set(reflectValue)
+ reflectValue = newValue
+ reflectType = reflectValue.Type()
+ }
+ var (
+ structName = reflectType.Elem().Name()
+ methodName = strings.TrimSpace(in.Method)
+ methodValue = reflectValue.MethodByName(methodName)
+ )
+ if !methodValue.IsValid() {
+ s.Logger().Fatalf(ctx, "invalid method name: %s", methodName)
+ return
+ }
+ if reflectValue.MethodByName("Init").IsValid() {
+ initFunc = reflectValue.MethodByName("Init").Interface().(func(*Request))
+ }
+ if reflectValue.MethodByName("Shut").IsValid() {
+ shutFunc = reflectValue.MethodByName("Shut").Interface().(func(*Request))
+ }
+ var (
+ pkgPath = reflectType.Elem().PkgPath()
+ pkgName = gfile.Basename(pkgPath)
+ objName = gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), "")
+ )
+ if objName[0] == '*' {
+ objName = fmt.Sprintf(`(%s)`, objName)
+ }
+
+ funcInfo, err := s.checkAndCreateFuncInfo(methodValue.Interface(), pkgPath, objName, methodName)
+ if err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+
+ key := s.mergeBuildInNameToPattern(in.Pattern, structName, methodName, false)
+ handlerMap[key] = &handlerItem{
+ Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
+ Type: HandlerTypeObject,
+ Info: funcInfo,
+ InitFunc: initFunc,
+ ShutFunc: shutFunc,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ }
+
+ s.bindHandlerByMap(ctx, in.Prefix, handlerMap)
+}
+
+func (s *Server) doBindObjectRest(ctx context.Context, in doBindObjectInput) {
+ var (
+ handlerMap = make(map[string]*handlerItem)
+ reflectValue = reflect.ValueOf(in.Object)
+ reflectType = reflectValue.Type()
+ initFunc func(*Request)
+ shutFunc func(*Request)
+ )
+ // If given `object` is not pointer, it then creates a temporary one,
+ // of which the value is `v`.
+ if reflectValue.Kind() == reflect.Struct {
+ newValue := reflect.New(reflectType)
+ newValue.Elem().Set(reflectValue)
+ reflectValue = newValue
+ reflectType = reflectValue.Type()
+ }
+ structName := reflectType.Elem().Name()
+ if reflectValue.MethodByName(methodNameInit).IsValid() {
+ initFunc = reflectValue.MethodByName(methodNameInit).Interface().(func(*Request))
+ }
+ if reflectValue.MethodByName(methodNameShut).IsValid() {
+ shutFunc = reflectValue.MethodByName(methodNameShut).Interface().(func(*Request))
+ }
+ pkgPath := reflectType.Elem().PkgPath()
+ for i := 0; i < reflectValue.NumMethod(); i++ {
+ methodName := reflectType.Method(i).Name
+ if _, ok := methodsMap[strings.ToUpper(methodName)]; !ok {
+ continue
+ }
+ pkgName := gfile.Basename(pkgPath)
+ objName := gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), "")
+ if objName[0] == '*' {
+ objName = fmt.Sprintf(`(%s)`, objName)
+ }
+
+ funcInfo, err := s.checkAndCreateFuncInfo(
+ reflectValue.Method(i).Interface(),
+ pkgPath,
+ objName,
+ methodName,
+ )
+ if err != nil {
+ s.Logger().Fatalf(ctx, `%+v`, err)
+ }
+
+ key := s.mergeBuildInNameToPattern(methodName+":"+in.Pattern, structName, methodName, false)
+ handlerMap[key] = &handlerItem{
+ Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
+ Type: HandlerTypeObject,
+ Info: funcInfo,
+ InitFunc: initFunc,
+ ShutFunc: shutFunc,
+ Middleware: in.Middleware,
+ Source: in.Source,
+ }
+ }
+ s.bindHandlerByMap(ctx, in.Prefix, handlerMap)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_session.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_session.go
new file mode 100644
index 000000000000..3477dd2edfbb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_session.go
@@ -0,0 +1,13 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "github.com/gogf/gf/v2/os/gsession"
+
+// Session is actually a alias of gsession.Session,
+// which is bound to a single request.
+type Session = gsession.Session
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_status.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_status.go
new file mode 100644
index 000000000000..3fbd146b4bc3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_status.go
@@ -0,0 +1,48 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "fmt"
+)
+
+// getStatusHandler retrieves and returns the handler for given status code.
+func (s *Server) getStatusHandler(status int, r *Request) []HandlerFunc {
+ domains := []string{r.GetHost(), DefaultDomainName}
+ for _, domain := range domains {
+ if f, ok := s.statusHandlerMap[s.statusHandlerKey(status, domain)]; ok {
+ return f
+ }
+ }
+ return nil
+}
+
+// addStatusHandler sets the handler for given status code.
+// The parameter `pattern` is like: domain#status
+func (s *Server) addStatusHandler(pattern string, handler HandlerFunc) {
+ if s.statusHandlerMap[pattern] == nil {
+ s.statusHandlerMap[pattern] = make([]HandlerFunc, 0)
+ }
+ s.statusHandlerMap[pattern] = append(s.statusHandlerMap[pattern], handler)
+}
+
+// statusHandlerKey creates and returns key for given status and domain.
+func (s *Server) statusHandlerKey(status int, domain string) string {
+ return fmt.Sprintf("%s#%d", domain, status)
+}
+
+// BindStatusHandler registers handler for given status code.
+func (s *Server) BindStatusHandler(status int, handler HandlerFunc) {
+ s.addStatusHandler(s.statusHandlerKey(status, DefaultDomainName), handler)
+}
+
+// BindStatusHandlerByMap registers handler for given status code using map.
+func (s *Server) BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {
+ for k, v := range handlerMap {
+ s.BindStatusHandler(k, v)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_swagger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_swagger.go
new file mode 100644
index 000000000000..ea0cd34fc7fa
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_swagger.go
@@ -0,0 +1,42 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import (
+ "net/http"
+
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+const (
+ swaggerUIDefaultURL = `https://petstore.swagger.io/v2/swagger.json`
+)
+
+// swaggerUI is a build-in hook handler for replace default swagger json URL to local openapi json file path.
+// This handler makes sense only if the openapi specification automatic producing configuration is enabled.
+func (s *Server) swaggerUI(r *Request) {
+ if s.config.OpenApiPath == "" {
+ return
+ }
+ var (
+ indexFileName = `index.html`
+ )
+ if r.StaticFile != nil && r.StaticFile.File != nil && gfile.Basename(r.StaticFile.File.Name()) == indexFileName {
+ if gfile.Basename(r.URL.Path) != indexFileName && r.originUrlPath[len(r.originUrlPath)-1] != '/' {
+ r.Response.Header().Set("Location", r.originUrlPath+"/")
+ r.Response.WriteHeader(http.StatusMovedPermanently)
+ r.ExitAll()
+ }
+ r.Response.Write(gstr.Replace(
+ string(r.StaticFile.File.Content()),
+ swaggerUIDefaultURL,
+ s.config.OpenApiPath,
+ ))
+ r.ExitAll()
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_util.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_util.go
new file mode 100644
index 000000000000..f9a3ea8e1e2b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_util.go
@@ -0,0 +1,23 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "net/http"
+
+// WrapF is a helper function for wrapping http.HandlerFunc and returns a ghttp.HandlerFunc.
+func WrapF(f http.HandlerFunc) HandlerFunc {
+ return func(r *Request) {
+ f(r.Response.Writer, r.Request)
+ }
+}
+
+// WrapH is a helper function for wrapping http.Handler and returns a ghttp.HandlerFunc.
+func WrapH(h http.Handler) HandlerFunc {
+ return func(r *Request) {
+ h.ServeHTTP(r.Response.Writer, r.Request)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_websocket.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_websocket.go
new file mode 100644
index 000000000000..2dbde255e912
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/ghttp_server_websocket.go
@@ -0,0 +1,37 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package ghttp
+
+import "github.com/gorilla/websocket"
+
+// WebSocket wraps the underlying websocket connection
+// and provides convenient functions.
+type WebSocket struct {
+ *websocket.Conn
+}
+
+const (
+ // WsMsgText TextMessage denotes a text data message. The text message payload is
+ // interpreted as UTF-8 encoded text data.
+ WsMsgText = websocket.TextMessage
+
+ // WsMsgBinary BinaryMessage denotes a binary data message.
+ WsMsgBinary = websocket.BinaryMessage
+
+ // WsMsgClose CloseMessage denotes a close control message. The optional message
+ // payload contains a numeric code and text. Use the FormatCloseMessage
+ // function to format a close message payload.
+ WsMsgClose = websocket.CloseMessage
+
+ // WsMsgPing PingMessage denotes a ping control message. The optional message payload
+ // is UTF-8 encoded text.
+ WsMsgPing = websocket.PingMessage
+
+ // WsMsgPong PongMessage denotes a pong control message. The optional message payload
+ // is UTF-8 encoded text.
+ WsMsgPong = websocket.PongMessage
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/internal/swaggerui/swaggerui-packed.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/internal/swaggerui/swaggerui-packed.go
new file mode 100644
index 000000000000..ed9e1c36f9fc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/internal/swaggerui/swaggerui-packed.go
@@ -0,0 +1,9 @@
+package swaggerui
+
+import "github.com/gogf/gf/v2/os/gres"
+
+func Init() {
+ if err := gres.Add("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"); err != nil {
+ panic("add binary content to resource manager failed: " + err.Error())
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/internal/swaggerui/swaggerui.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/internal/swaggerui/swaggerui.go
new file mode 100644
index 000000000000..1d5ac769c3f6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/ghttp/internal/swaggerui/swaggerui.go
@@ -0,0 +1,11 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package swaggerui provides packed swagger ui static files using resource manager.
+//
+// Files from: https://github.com/swagger-api/swagger-ui
+// Pack command: gf pack swagger-ui swaggerui-packed.go -n=swaggerui -p=/goframe/swaggerui
+package swaggerui
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4.go
new file mode 100644
index 000000000000..ea52f913145a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4.go
@@ -0,0 +1,60 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+// Package gipv4 provides useful API for IPv4 address handling.
+package gipv4
+
+import (
+ "encoding/binary"
+ "fmt"
+ "net"
+ "strconv"
+
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+// Ip2long converts ip address to an uint32 integer.
+func Ip2long(ip string) uint32 {
+ netIp := net.ParseIP(ip)
+ if netIp == nil {
+ return 0
+ }
+ return binary.BigEndian.Uint32(netIp.To4())
+}
+
+// Long2ip converts an uint32 integer ip address to its string type address.
+func Long2ip(long uint32) string {
+ ipByte := make([]byte, 4)
+ binary.BigEndian.PutUint32(ipByte, long)
+ return net.IP(ipByte).String()
+}
+
+// Validate checks whether given `ip` a valid IPv4 address.
+func Validate(ip string) bool {
+ return gregex.IsMatchString(`^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$`, ip)
+}
+
+// ParseAddress parses `address` to its ip and port.
+// Eg: 192.168.1.1:80 -> 192.168.1.1, 80
+func ParseAddress(address string) (string, int) {
+ match, err := gregex.MatchString(`^(.+):(\d+)$`, address)
+ if err == nil {
+ i, _ := strconv.Atoi(match[2])
+ return match[1], i
+ }
+ return "", 0
+}
+
+// GetSegment returns the segment of given ip address.
+// Eg: 192.168.2.102 -> 192.168.2
+func GetSegment(ip string) string {
+ match, err := gregex.MatchString(`^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$`, ip)
+ if err != nil || len(match) < 4 {
+ return ""
+ }
+ return fmt.Sprintf("%s.%s.%s", match[1], match[2], match[3])
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_ip.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_ip.go
new file mode 100644
index 000000000000..be381edfdfd3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_ip.go
@@ -0,0 +1,147 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gipv4
+
+import (
+ "net"
+ "strconv"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// GetIpArray retrieves and returns all the ip of current host.
+func GetIpArray() (ips []string, err error) {
+ interfaceAddr, err := net.InterfaceAddrs()
+ if err != nil {
+ err = gerror.Wrap(err, `net.InterfaceAddrs failed`)
+ return nil, err
+ }
+ for _, address := range interfaceAddr {
+ ipNet, isValidIpNet := address.(*net.IPNet)
+ if isValidIpNet && !ipNet.IP.IsLoopback() {
+ if ipNet.IP.To4() != nil {
+ ips = append(ips, ipNet.IP.String())
+ }
+ }
+ }
+ return ips, nil
+}
+
+// MustGetIntranetIp performs as GetIntranetIp, but it panics if any error occurs.
+func MustGetIntranetIp() string {
+ ip, err := GetIntranetIp()
+ if err != nil {
+ panic(err)
+ }
+ return ip
+}
+
+// GetIntranetIp retrieves and returns the first intranet ip of current machine.
+func GetIntranetIp() (ip string, err error) {
+ ips, err := GetIntranetIpArray()
+ if err != nil {
+ return "", err
+ }
+ if len(ips) == 0 {
+ return "", gerror.New("no intranet ip found")
+ }
+ return ips[0], nil
+}
+
+// GetIntranetIpArray retrieves and returns the intranet ip list of current machine.
+func GetIntranetIpArray() (ips []string, err error) {
+ var (
+ addresses []net.Addr
+ interFaces []net.Interface
+ )
+ interFaces, err = net.Interfaces()
+ if err != nil {
+ err = gerror.Wrap(err, `net.Interfaces failed`)
+ return ips, err
+ }
+ for _, interFace := range interFaces {
+ if interFace.Flags&net.FlagUp == 0 {
+ // interface down
+ continue
+ }
+ if interFace.Flags&net.FlagLoopback != 0 {
+ // loop back interface
+ continue
+ }
+ // ignore warden bridge
+ if strings.HasPrefix(interFace.Name, "w-") {
+ continue
+ }
+ addresses, err = interFace.Addrs()
+ if err != nil {
+ err = gerror.Wrap(err, `interFace.Addrs failed`)
+ return ips, err
+ }
+ for _, addr := range addresses {
+ var ip net.IP
+ switch v := addr.(type) {
+ case *net.IPNet:
+ ip = v.IP
+ case *net.IPAddr:
+ ip = v.IP
+ }
+
+ if ip == nil || ip.IsLoopback() {
+ continue
+ }
+ ip = ip.To4()
+ if ip == nil {
+ // not an ipv4 address
+ continue
+ }
+ ipStr := ip.String()
+ if IsIntranet(ipStr) {
+ ips = append(ips, ipStr)
+ }
+ }
+ }
+ return ips, nil
+}
+
+// IsIntranet checks and returns whether given ip an intranet ip.
+//
+// Local: 127.0.0.1
+// A: 10.0.0.0--10.255.255.255
+// B: 172.16.0.0--172.31.255.255
+// C: 192.168.0.0--192.168.255.255
+func IsIntranet(ip string) bool {
+ if ip == "127.0.0.1" {
+ return true
+ }
+ array := strings.Split(ip, ".")
+ if len(array) != 4 {
+ return false
+ }
+ // A
+ if array[0] == "10" || (array[0] == "192" && array[1] == "168") {
+ return true
+ }
+ // C
+ if array[0] == "192" && array[1] == "168" {
+ return true
+ }
+ // B
+ if array[0] == "172" {
+ second, err := strconv.ParseInt(array[1], 10, 64)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.ParseInt failed for string "%s"`, array[1])
+ return false
+ }
+ if second >= 16 && second <= 31 {
+ return true
+ }
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_lookup.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_lookup.go
new file mode 100644
index 000000000000..f6aed4b0f414
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_lookup.go
@@ -0,0 +1,52 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gipv4
+
+import (
+ "net"
+ "strings"
+)
+
+// GetHostByName returns the IPv4 address corresponding to a given Internet host name.
+func GetHostByName(hostname string) (string, error) {
+ ips, err := net.LookupIP(hostname)
+ if ips != nil {
+ for _, v := range ips {
+ if v.To4() != nil {
+ return v.String(), nil
+ }
+ }
+ return "", nil
+ }
+ return "", err
+}
+
+// GetHostsByName returns a list of IPv4 addresses corresponding to a given Internet
+// host name.
+func GetHostsByName(hostname string) ([]string, error) {
+ ips, err := net.LookupIP(hostname)
+ if ips != nil {
+ var ipStrings []string
+ for _, v := range ips {
+ if v.To4() != nil {
+ ipStrings = append(ipStrings, v.String())
+ }
+ }
+ return ipStrings, nil
+ }
+ return nil, err
+}
+
+// GetNameByAddr returns the Internet host name corresponding to a given IP address.
+func GetNameByAddr(ipAddress string) (string, error) {
+ names, err := net.LookupAddr(ipAddress)
+ if names != nil {
+ return strings.TrimRight(names[0], "."), nil
+ }
+ return "", err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_mac.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_mac.go
new file mode 100644
index 000000000000..a09520554d0d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv4/gipv4_mac.go
@@ -0,0 +1,43 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gipv4
+
+import (
+ "net"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// GetMac retrieves and returns the first mac address of current host.
+func GetMac() (mac string, err error) {
+ macs, err := GetMacArray()
+ if err != nil {
+ return "", err
+ }
+ if len(macs) > 0 {
+ return macs[0], nil
+ }
+ return "", nil
+}
+
+// GetMacArray retrieves and returns all the mac address of current host.
+func GetMacArray() (macs []string, err error) {
+ netInterfaces, err := net.Interfaces()
+ if err != nil {
+ err = gerror.Wrap(err, `net.Interfaces failed`)
+ return nil, err
+ }
+ for _, netInterface := range netInterfaces {
+ macAddr := netInterface.HardwareAddr.String()
+ if len(macAddr) == 0 {
+ continue
+ }
+ macs = append(macs, macAddr)
+ }
+ return macs, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv6/gipv6.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv6/gipv6.go
new file mode 100644
index 000000000000..146307c38450
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gipv6/gipv6.go
@@ -0,0 +1,15 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gipv6 provides useful API for IPv6 address handling.
+package gipv6
+
+import "github.com/gogf/gf/v2/text/gregex"
+
+// Validate checks whether given `ip` a valid IPv6 address.
+func Validate(ip string) bool {
+ return gregex.IsMatchString(`^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}$|^:((:[\da-fA-F]{1,4}){1,6}|:)$|^[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,5}|:)$|^([\da-fA-F]{1,4}:){2}((:[\da-fA-F]{1,4}){1,4}|:)$|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]{1,4}){1,3}|:)$|^([\da-fA-F]{1,4}:){4}((:[\da-fA-F]{1,4}){1,2}|:)$|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?$|^([\da-fA-F]{1,4}:){6}:$`, ip)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel.go
new file mode 100644
index 000000000000..3b6d1249a8c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel.go
@@ -0,0 +1,85 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gsel provides selector definition and implements.
+package gsel
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/net/gsvc"
+)
+
+// Builder creates and returns selector in runtime.
+type Builder interface {
+ Build() Selector
+}
+
+// Selector for service balancer.
+type Selector interface {
+ // Pick selects and returns service.
+ Pick(ctx context.Context) (node Node, done DoneFunc, err error)
+
+ // Update updates services into Selector.
+ Update(nodes []Node) error
+}
+
+// Node is node interface.
+type Node interface {
+ Service() *gsvc.Service
+ Address() string
+}
+
+// DoneFunc is callback function when RPC invoke done.
+type DoneFunc func(ctx context.Context, di DoneInfo)
+
+// DoneInfo contains additional information for done.
+type DoneInfo struct {
+ // Err is the rpc error the RPC finished with. It could be nil.
+ Err error
+
+ // Trailer contains the metadata from the RPC's trailer, if present.
+ Trailer DoneInfoMD
+
+ // BytesSent indicates if any bytes have been sent to the server.
+ BytesSent bool
+
+ // BytesReceived indicates if any byte has been received from the server.
+ BytesReceived bool
+
+ // ServerLoad is the load received from server. It's usually sent as part of
+ // trailing metadata.
+ //
+ // The only supported type now is *orca_v1.LoadReport.
+ ServerLoad interface{}
+}
+
+// DoneInfoMD is a mapping from metadata keys to value array.
+// Users should use the following two convenience functions New and Pairs to generate MD.
+type DoneInfoMD interface {
+ // Len returns the number of items in md.
+ Len() int
+
+ // Get obtains the values for a given key.
+ //
+ // k is converted to lowercase before searching in md.
+ Get(k string) []string
+
+ // Set sets the value of a given key with a slice of values.
+ //
+ // k is converted to lowercase before storing in md.
+ Set(key string, values ...string)
+
+ // Append adds the values to key k, not overwriting what was already stored at
+ // that key.
+ //
+ // k is converted to lowercase before storing in md.
+ Append(k string, values ...string)
+
+ // Delete removes the values for a given key k which is converted to lowercase
+ // before removing it from md.
+ Delete(k string)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder.go
new file mode 100644
index 000000000000..31035a343df6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder.go
@@ -0,0 +1,20 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+// defaultBuilder is the default Builder for globally used purpose.
+var defaultBuilder = NewBuilderRoundRobin()
+
+// SetBuilder sets the default builder for globally used purpose.
+func SetBuilder(builder Builder) {
+ defaultBuilder = builder
+}
+
+// GetBuilder returns the default builder for globally used purpose.
+func GetBuilder() Builder {
+ return defaultBuilder
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_least_connection.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_least_connection.go
new file mode 100644
index 000000000000..d13b8c70b46e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_least_connection.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+type builderLeastConnection struct{}
+
+func NewBuilderLeastConnection() Builder {
+ return &builderLeastConnection{}
+}
+
+func (*builderLeastConnection) Build() Selector {
+ return NewSelectorLeastConnection()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_random.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_random.go
new file mode 100644
index 000000000000..49448f033a25
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_random.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+type builderRandom struct{}
+
+func NewBuilderRandom() Builder {
+ return &builderRandom{}
+}
+
+func (*builderRandom) Build() Selector {
+ return NewSelectorRandom()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_round_robin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_round_robin.go
new file mode 100644
index 000000000000..bff17a337125
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_round_robin.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+type builderRoundRobin struct{}
+
+func NewBuilderRoundRobin() Builder {
+ return &builderRoundRobin{}
+}
+
+func (*builderRoundRobin) Build() Selector {
+ return NewSelectorRoundRobin()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_weight.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_weight.go
new file mode 100644
index 000000000000..a2d3b6b8fb9c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_builder_weight.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+type builderWeight struct{}
+
+func NewBuilderWeight() Builder {
+ return &builderWeight{}
+}
+
+func (*builderWeight) Build() Selector {
+ return NewSelectorWeight()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_least_connection.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_least_connection.go
new file mode 100644
index 000000000000..2a8625726833
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_least_connection.go
@@ -0,0 +1,69 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+import (
+ "context"
+ "sync"
+
+ "github.com/gogf/gf/v2/container/gtype"
+)
+
+const SelectorLeastConnection = "BalancerLeastConnection"
+
+type selectorLeastConnection struct {
+ mu sync.RWMutex
+ nodes []*leastConnectionNode
+}
+
+type leastConnectionNode struct {
+ Node
+ inflight *gtype.Int
+}
+
+func NewSelectorLeastConnection() Selector {
+ return &selectorLeastConnection{
+ nodes: make([]*leastConnectionNode, 0),
+ }
+}
+
+func (s *selectorLeastConnection) Update(nodes []Node) error {
+ var newNodes []*leastConnectionNode
+ for _, v := range nodes {
+ node := v
+ newNodes = append(newNodes, &leastConnectionNode{
+ Node: node,
+ inflight: gtype.NewInt(),
+ })
+ }
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.nodes = newNodes
+ return nil
+}
+
+func (s *selectorLeastConnection) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+ var pickedNode *leastConnectionNode
+ if len(s.nodes) == 1 {
+ pickedNode = s.nodes[0]
+ } else {
+ for _, v := range s.nodes {
+ if pickedNode == nil {
+ pickedNode = v
+ } else if v.inflight.Val() < pickedNode.inflight.Val() {
+ pickedNode = v
+ }
+ }
+ }
+ pickedNode.inflight.Add(1)
+ done = func(ctx context.Context, di DoneInfo) {
+ pickedNode.inflight.Add(-1)
+ }
+ return pickedNode.Node, done, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_random.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_random.go
new file mode 100644
index 000000000000..466f306749a7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_random.go
@@ -0,0 +1,43 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+import (
+ "context"
+ "sync"
+
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+const SelectorRandom = "BalancerRandom"
+
+type selectorRandom struct {
+ mu sync.RWMutex
+ nodes []Node
+}
+
+func NewSelectorRandom() Selector {
+ return &selectorRandom{
+ nodes: make([]Node, 0),
+ }
+}
+
+func (s *selectorRandom) Update(nodes []Node) error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.nodes = nodes
+ return nil
+}
+
+func (s *selectorRandom) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+ if len(s.nodes) == 0 {
+ return nil, nil, nil
+ }
+ return s.nodes[grand.Intn(len(s.nodes))], nil, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_round_robin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_round_robin.go
new file mode 100644
index 000000000000..8f82bf920c0b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_round_robin.go
@@ -0,0 +1,41 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+import (
+ "context"
+ "sync"
+)
+
+const SelectorRoundRobin = "BalancerRoundRobin"
+
+type selectorRoundRobin struct {
+ mu sync.RWMutex
+ nodes []Node
+ next int
+}
+
+func NewSelectorRoundRobin() Selector {
+ return &selectorRoundRobin{
+ nodes: make([]Node, 0),
+ }
+}
+
+func (s *selectorRoundRobin) Update(nodes []Node) error {
+ s.mu.Lock()
+ s.nodes = nodes
+ s.mu.Unlock()
+ return nil
+}
+
+func (s *selectorRoundRobin) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+ node = s.nodes[s.next]
+ s.next = (s.next + 1) % len(s.nodes)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_weight.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_weight.go
new file mode 100644
index 000000000000..bbbf59d125e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsel/gsel_selector_weight.go
@@ -0,0 +1,55 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsel
+
+import (
+ "context"
+ "sync"
+
+ "github.com/gogf/gf/v2/net/gsvc"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+const SelectorWeight = "BalancerWeight"
+
+type selectorWeight struct {
+ mu sync.RWMutex
+ nodes []Node
+}
+
+func NewSelectorWeight() Selector {
+ return &selectorWeight{
+ nodes: make([]Node, 0),
+ }
+}
+
+func (s *selectorWeight) Update(nodes []Node) error {
+ var newNodes []Node
+ for _, v := range nodes {
+ node := v
+ for i := 0; i < s.getWeight(node); i++ {
+ newNodes = append(newNodes, node)
+ }
+ }
+ s.mu.Lock()
+ s.nodes = newNodes
+ s.mu.Unlock()
+ return nil
+}
+
+func (s *selectorWeight) Pick(ctx context.Context) (node Node, done DoneFunc, err error) {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+ if len(s.nodes) == 0 {
+ return nil, nil, nil
+ }
+ return s.nodes[grand.Intn(len(s.nodes))], nil, nil
+}
+
+func (s *selectorWeight) getWeight(node Node) int {
+ return node.Service().Metadata.Get(gsvc.MDWeight).Int()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc.go
new file mode 100644
index 000000000000..da86aaf440e3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc.go
@@ -0,0 +1,115 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gsvc provides service registry and discovery definition.
+package gsvc
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Registry interface for service.
+type Registry interface {
+ Registrar
+ Discovery
+}
+
+// Registrar interface for service registrar.
+type Registrar interface {
+ // Register registers `service` to Registry.
+ Register(ctx context.Context, service *Service) error
+
+ // Deregister off-lines and removes `service` from Registry.
+ Deregister(ctx context.Context, service *Service) error
+}
+
+// Discovery interface for service discovery.
+type Discovery interface {
+ // Search searches and returns services with specified condition.
+ Search(ctx context.Context, in SearchInput) ([]*Service, error)
+
+ // Watch watches specified condition changes.
+ Watch(ctx context.Context, key string) (Watcher, error)
+}
+
+// Watcher interface for service.
+type Watcher interface {
+ // Proceed proceeds watch in blocking way.
+ Proceed() ([]*Service, error)
+
+ // Close closes the watcher.
+ Close() error
+}
+
+// Service definition.
+type Service struct {
+ Prefix string // Service prefix.
+ Deployment string // Service deployment name, eg: dev, qa, staging, prod, etc.
+ Namespace string // Service Namespace, to indicate different service in the same environment with the same Name.
+ Name string // Name for the service.
+ Version string // Service version, eg: v1.0.0, v2.1.1, etc.
+ Endpoints []string // Service Endpoints, pattern: IP:port, eg: 192.168.1.2:8000.
+ Metadata Metadata // Custom data for this service, which can be set using JSON by environment or command-line.
+}
+
+// Metadata stores custom key-value pairs.
+type Metadata map[string]interface{}
+
+// SearchInput is the input for service searching.
+type SearchInput struct {
+ Prefix string // Service prefix.
+ Deployment string // Service deployment name, eg: dev, qa, staging, prod, etc.
+ Namespace string // Service Namespace, to indicate different service in the same environment with the same Name.
+ Name string // Name for the service.
+ Version string // Service version, eg: v1.0.0, v2.1.1, etc.}
+}
+
+// WatchInput is the input for service watching.
+type WatchInput struct {
+ Prefix string // Service prefix.
+ Deployment string // Service deployment name, eg: dev, qa, staging, prod, etc.
+ Namespace string // Service Namespace, to indicate different service in the same environment with the same Name.
+ Name string // Name for the service.
+ Version string // Service version, eg: v1.0.0, v2.1.1, etc.}
+}
+
+const (
+ Schema = `services`
+ DefaultPrefix = `services`
+ DefaultDeployment = `default`
+ DefaultNamespace = `default`
+ DefaultVersion = `latest`
+ EnvPrefix = `GF_GSVC_PREFIX`
+ EnvDeployment = `GF_GSVC_DEPLOYMENT`
+ EnvNamespace = `GF_GSVC_NAMESPACE`
+ EnvName = `GF_GSVC_Name`
+ EnvVersion = `GF_GSVC_VERSION`
+ MDProtocol = `protocol`
+ MDInsecure = `insecure`
+ MDWeight = `weight`
+ defaultTimeout = 5 * time.Second
+)
+
+var (
+ defaultRegistry Registry
+)
+
+// SetRegistry sets the default Registry implements as your own implemented interface.
+func SetRegistry(registry Registry) {
+ if registry == nil {
+ panic(gerror.New(`invalid Registry value "nil" given`))
+ }
+ defaultRegistry = registry
+}
+
+// GetRegistry returns the default Registry that is previously set.
+// It returns nil if no Registry is set.
+func GetRegistry() Registry {
+ return defaultRegistry
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_discovery.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_discovery.go
new file mode 100644
index 000000000000..aba2f538aab6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_discovery.go
@@ -0,0 +1,107 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsvc
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+var (
+ watchedServiceMap = gmap.New(true)
+)
+
+type ServiceWatch func(service *Service)
+
+func Get(ctx context.Context, name string) (service *Service, err error) {
+ return GetWithWatch(ctx, name, nil)
+}
+
+func GetWithWatch(ctx context.Context, name string, watch ServiceWatch) (service *Service, err error) {
+ v := watchedServiceMap.GetOrSetFuncLock(name, func() interface{} {
+ var (
+ s = NewServiceWithName(name)
+ services []*Service
+ watcher Watcher
+ )
+ services, err = Search(ctx, SearchInput{
+ Prefix: s.Prefix,
+ Deployment: s.Deployment,
+ Namespace: s.Namespace,
+ Name: s.Name,
+ Version: s.Version,
+ })
+ if err != nil {
+ return nil
+ }
+ if len(services) == 0 {
+ err = gerror.NewCodef(gcode.CodeNotFound, `service not found with name "%s"`, name)
+ return nil
+ }
+ service = services[0]
+ // Watch the service changes in goroutine.
+ watcher, err = Watch(ctx, service.KeyWithoutEndpoints())
+ if err != nil {
+ return nil
+ }
+ go watchAndUpdateService(watcher, service, watch)
+ return service
+ })
+ if v != nil {
+ service = v.(*Service)
+ }
+ return
+}
+
+func watchAndUpdateService(watcher Watcher, service *Service, watchFunc ServiceWatch) {
+ var (
+ ctx = context.Background()
+ err error
+ services []*Service
+ )
+ for {
+ time.Sleep(time.Second)
+ services, err = watcher.Proceed()
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ continue
+ }
+ if len(services) > 0 {
+ watchedServiceMap.Set(service.Name, services[0])
+ if watchFunc != nil {
+ gutil.TryCatch(func() {
+ watchFunc(services[0])
+ }, func(exception error) {
+ intlog.Errorf(ctx, `%+v`, exception)
+ })
+ }
+ }
+ }
+}
+
+// Search searches and returns services with specified condition.
+func Search(ctx context.Context, in SearchInput) ([]*Service, error) {
+ if defaultRegistry == nil {
+ return nil, gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)
+ }
+ ctx, _ = context.WithTimeout(ctx, defaultTimeout)
+ return defaultRegistry.Search(ctx, in)
+}
+
+// Watch watches specified condition changes.
+func Watch(ctx context.Context, key string) (Watcher, error) {
+ if defaultRegistry == nil {
+ return nil, gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)
+ }
+ return defaultRegistry.Watch(ctx, key)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_metadata.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_metadata.go
new file mode 100644
index 000000000000..015c4432a8d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_metadata.go
@@ -0,0 +1,24 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsvc
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// Set sets key-value pair into metadata.
+func (m Metadata) Set(key string, value string) {
+ m[key] = value
+}
+
+// Get retrieves and returns value of specified key as gvar.
+func (m Metadata) Get(key string) *gvar.Var {
+ if v, ok := m[key]; ok {
+ return gvar.New(v)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_registry.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_registry.go
new file mode 100644
index 000000000000..a73d5e9d6849
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_registry.go
@@ -0,0 +1,34 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsvc
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Register registers `service` to default registry..
+func Register(ctx context.Context, service *Service) error {
+ if defaultRegistry == nil {
+ return gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)
+ }
+ ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
+ defer cancel()
+ return defaultRegistry.Register(ctx, service)
+}
+
+// Deregister removes `service` from default registry.
+func Deregister(ctx context.Context, service *Service) error {
+ if defaultRegistry == nil {
+ return gerror.NewCodef(gcode.CodeNotImplemented, `no Registry is registered`)
+ }
+ ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
+ defer cancel()
+ return defaultRegistry.Deregister(ctx, service)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_search.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_search.go
new file mode 100644
index 000000000000..4f9263b7f8f2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_search.go
@@ -0,0 +1,28 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsvc
+
+// Key formats and returns a string for prefix searching purpose.
+func (s *SearchInput) Key() string {
+ keyPrefix := ""
+ if s.Prefix != "" {
+ keyPrefix += "/" + s.Prefix
+ }
+ if s.Deployment != "" {
+ keyPrefix += "/" + s.Deployment
+ if s.Namespace != "" {
+ keyPrefix += "/" + s.Namespace
+ if s.Name != "" {
+ keyPrefix += "/" + s.Name
+ if s.Version != "" {
+ keyPrefix += "/" + s.Version
+ }
+ }
+ }
+ }
+ return keyPrefix
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_service.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_service.go
new file mode 100644
index 000000000000..f8e0db3e6c27
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gsvc/gsvc_service.go
@@ -0,0 +1,116 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsvc
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcmd"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+const (
+ separator = "/"
+)
+
+// NewServiceWithName creates and returns service from `name`.
+func NewServiceWithName(name string) (s *Service) {
+ s = &Service{
+ Name: name,
+ Metadata: make(Metadata),
+ }
+ s.autoFillDefaultAttributes()
+ return s
+}
+
+// NewServiceWithKV creates and returns service from `key` and `value`.
+func NewServiceWithKV(key, value []byte) (s *Service, err error) {
+ array := gstr.Split(gstr.Trim(string(key), separator), separator)
+ if len(array) < 6 {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid service key "%s"`, key)
+ }
+ s = &Service{
+ Prefix: array[0],
+ Deployment: array[1],
+ Namespace: array[2],
+ Name: array[3],
+ Version: array[4],
+ Endpoints: gstr.Split(array[5], ","),
+ Metadata: make(Metadata),
+ }
+ s.autoFillDefaultAttributes()
+ if len(value) > 0 {
+ if err = gjson.Unmarshal(value, &s.Metadata); err != nil {
+ return nil, gerror.WrapCodef(gcode.CodeInvalidParameter, err, `invalid service value "%s"`, value)
+ }
+ }
+ return s, nil
+}
+
+// Key formats the service information and returns the Service as registering key.
+func (s *Service) Key() string {
+ serviceNameUnique := s.KeyWithoutEndpoints()
+ serviceNameUnique += separator + gstr.Join(s.Endpoints, ",")
+ return serviceNameUnique
+}
+
+// KeyWithSchema formats the service information and returns the Service as dialing target key.
+func (s *Service) KeyWithSchema() string {
+ return fmt.Sprintf(`%s://%s`, Schema, s.Key())
+}
+
+// KeyWithoutEndpoints formats the service information and returns a string as unique name of service.
+func (s *Service) KeyWithoutEndpoints() string {
+ s.autoFillDefaultAttributes()
+ return "/" + gstr.Join([]string{
+ s.Prefix,
+ s.Deployment,
+ s.Namespace,
+ s.Name,
+ s.Version,
+ }, separator)
+}
+
+func (s *Service) Value() string {
+ b, err := gjson.Marshal(s.Metadata)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ return string(b)
+}
+
+// Address returns the first endpoint of Service.
+// Eg: 192.168.1.12:9000.
+func (s *Service) Address() string {
+ if len(s.Endpoints) == 0 {
+ return ""
+ }
+ return s.Endpoints[0]
+}
+
+func (s *Service) autoFillDefaultAttributes() {
+ if s.Prefix == "" {
+ s.Prefix = gcmd.GetOptWithEnv(EnvPrefix, DefaultPrefix).String()
+ }
+ if s.Deployment == "" {
+ s.Deployment = gcmd.GetOptWithEnv(EnvDeployment, DefaultDeployment).String()
+ }
+ if s.Namespace == "" {
+ s.Namespace = gcmd.GetOptWithEnv(EnvNamespace, DefaultNamespace).String()
+ }
+ if s.Version == "" {
+ s.Version = gcmd.GetOptWithEnv(EnvVersion, DefaultVersion).String()
+ }
+ if s.Name == "" {
+ s.Name = gcmd.GetOptWithEnv(EnvName).String()
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp.go
new file mode 100644
index 000000000000..75b58f6eb64b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtcp provides TCP server and client implementations.
+package gtcp
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_conn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_conn.go
new file mode 100644
index 000000000000..92eb5a5ce9bd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_conn.go
@@ -0,0 +1,314 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
+ "io"
+ "net"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Conn is the TCP connection object.
+type Conn struct {
+ net.Conn // Underlying TCP connection object.
+ reader *bufio.Reader // Buffer reader for connection.
+ receiveDeadline time.Time // Timeout point for reading.
+ sendDeadline time.Time // Timeout point for writing.
+ receiveBufferWait time.Duration // Interval duration for reading buffer.
+}
+
+const (
+ // Default interval for reading buffer.
+ receiveAllWaitTimeout = time.Millisecond
+)
+
+// NewConn creates and returns a new connection with given address.
+func NewConn(addr string, timeout ...time.Duration) (*Conn, error) {
+ if conn, err := NewNetConn(addr, timeout...); err == nil {
+ return NewConnByNetConn(conn), nil
+ } else {
+ return nil, err
+ }
+}
+
+// NewConnTLS creates and returns a new TLS connection
+// with given address and TLS configuration.
+func NewConnTLS(addr string, tlsConfig *tls.Config) (*Conn, error) {
+ if conn, err := NewNetConnTLS(addr, tlsConfig); err == nil {
+ return NewConnByNetConn(conn), nil
+ } else {
+ return nil, err
+ }
+}
+
+// NewConnKeyCrt creates and returns a new TLS connection
+// with given address and TLS certificate and key files.
+func NewConnKeyCrt(addr, crtFile, keyFile string) (*Conn, error) {
+ if conn, err := NewNetConnKeyCrt(addr, crtFile, keyFile); err == nil {
+ return NewConnByNetConn(conn), nil
+ } else {
+ return nil, err
+ }
+}
+
+// NewConnByNetConn creates and returns a TCP connection object with given net.Conn object.
+func NewConnByNetConn(conn net.Conn) *Conn {
+ return &Conn{
+ Conn: conn,
+ reader: bufio.NewReader(conn),
+ receiveDeadline: time.Time{},
+ sendDeadline: time.Time{},
+ receiveBufferWait: receiveAllWaitTimeout,
+ }
+}
+
+// Send writes data to remote address.
+func (c *Conn) Send(data []byte, retry ...Retry) error {
+ for {
+ if _, err := c.Write(data); err != nil {
+ // Connection closed.
+ if err == io.EOF {
+ return err
+ }
+ // Still failed even after retrying.
+ if len(retry) == 0 || retry[0].Count == 0 {
+ err = gerror.Wrap(err, `Write data failed`)
+ return err
+ }
+ if len(retry) > 0 {
+ retry[0].Count--
+ if retry[0].Interval == 0 {
+ retry[0].Interval = defaultRetryInternal
+ }
+ time.Sleep(retry[0].Interval)
+ }
+ } else {
+ return nil
+ }
+ }
+}
+
+// Recv receives and returns data from the connection.
+//
+// Note that,
+// 1. If length = 0, which means it receives the data from current buffer and returns immediately.
+// 2. If length < 0, which means it receives all data from connection and returns it until no data
+// from connection. Developers should notice the package parsing yourself if you decide receiving
+// all data from buffer.
+// 3. If length > 0, which means it blocks reading data from connection until length size was received.
+// It is the most commonly used length value for data receiving.
+func (c *Conn) Recv(length int, retry ...Retry) ([]byte, error) {
+ var (
+ err error // Reading error.
+ size int // Reading size.
+ index int // Received size.
+ buffer []byte // Buffer object.
+ bufferWait bool // Whether buffer reading timeout set.
+ )
+ if length > 0 {
+ buffer = make([]byte, length)
+ } else {
+ buffer = make([]byte, defaultReadBufferSize)
+ }
+
+ for {
+ if length < 0 && index > 0 {
+ bufferWait = true
+ if err = c.SetReadDeadline(time.Now().Add(c.receiveBufferWait)); err != nil {
+ err = gerror.Wrap(err, `SetReadDeadline for connection failed`)
+ return nil, err
+ }
+ }
+ size, err = c.reader.Read(buffer[index:])
+ if size > 0 {
+ index += size
+ if length > 0 {
+ // It reads til `length` size if `length` is specified.
+ if index == length {
+ break
+ }
+ } else {
+ if index >= defaultReadBufferSize {
+ // If it exceeds the buffer size, it then automatically increases its buffer size.
+ buffer = append(buffer, make([]byte, defaultReadBufferSize)...)
+ } else {
+ // It returns immediately if received size is lesser than buffer size.
+ if !bufferWait {
+ break
+ }
+ }
+ }
+ }
+ if err != nil {
+ // Connection closed.
+ if err == io.EOF {
+ break
+ }
+ // Re-set the timeout when reading data.
+ if bufferWait && isTimeout(err) {
+ if err = c.SetReadDeadline(c.receiveDeadline); err != nil {
+ err = gerror.Wrap(err, `SetReadDeadline for connection failed`)
+ return nil, err
+ }
+ err = nil
+ break
+ }
+ if len(retry) > 0 {
+ // It fails even it retried.
+ if retry[0].Count == 0 {
+ break
+ }
+ retry[0].Count--
+ if retry[0].Interval == 0 {
+ retry[0].Interval = defaultRetryInternal
+ }
+ time.Sleep(retry[0].Interval)
+ continue
+ }
+ break
+ }
+ // Just read once from buffer.
+ if length == 0 {
+ break
+ }
+ }
+ return buffer[:index], err
+}
+
+// RecvLine reads data from the connection until reads char '\n'.
+// Note that the returned result does not contain the last char '\n'.
+func (c *Conn) RecvLine(retry ...Retry) ([]byte, error) {
+ var (
+ err error
+ buffer []byte
+ data = make([]byte, 0)
+ )
+ for {
+ buffer, err = c.Recv(1, retry...)
+ if len(buffer) > 0 {
+ if buffer[0] == '\n' {
+ data = append(data, buffer[:len(buffer)-1]...)
+ break
+ } else {
+ data = append(data, buffer...)
+ }
+ }
+ if err != nil {
+ break
+ }
+ }
+ return data, err
+}
+
+// RecvTill reads data from the connection until reads bytes `til`.
+// Note that the returned result contains the last bytes `til`.
+func (c *Conn) RecvTill(til []byte, retry ...Retry) ([]byte, error) {
+ var (
+ err error
+ buffer []byte
+ data = make([]byte, 0)
+ length = len(til)
+ )
+ for {
+ buffer, err = c.Recv(1, retry...)
+ if len(buffer) > 0 {
+ if length > 0 &&
+ len(data) >= length-1 &&
+ buffer[0] == til[length-1] &&
+ bytes.EqualFold(data[len(data)-length+1:], til[:length-1]) {
+ data = append(data, buffer...)
+ break
+ } else {
+ data = append(data, buffer...)
+ }
+ }
+ if err != nil {
+ break
+ }
+ }
+ return data, err
+}
+
+// RecvWithTimeout reads data from the connection with timeout.
+func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
+ if err = c.SetReceiveDeadline(time.Now().Add(timeout)); err != nil {
+ return nil, err
+ }
+ defer c.SetReceiveDeadline(time.Time{})
+ data, err = c.Recv(length, retry...)
+ return
+}
+
+// SendWithTimeout writes data to the connection with timeout.
+func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
+ if err = c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+ defer c.SetSendDeadline(time.Time{})
+ err = c.Send(data, retry...)
+ return
+}
+
+// SendRecv writes data to the connection and blocks reading response.
+func (c *Conn) SendRecv(data []byte, length int, retry ...Retry) ([]byte, error) {
+ if err := c.Send(data, retry...); err == nil {
+ return c.Recv(length, retry...)
+ } else {
+ return nil, err
+ }
+}
+
+// SendRecvWithTimeout writes data to the connection and reads response with timeout.
+func (c *Conn) SendRecvWithTimeout(data []byte, length int, timeout time.Duration, retry ...Retry) ([]byte, error) {
+ if err := c.Send(data, retry...); err == nil {
+ return c.RecvWithTimeout(length, timeout, retry...)
+ } else {
+ return nil, err
+ }
+}
+
+func (c *Conn) SetDeadline(t time.Time) (err error) {
+ if err = c.Conn.SetDeadline(t); err == nil {
+ c.receiveDeadline = t
+ c.sendDeadline = t
+ }
+ if err != nil {
+ err = gerror.Wrapf(err, `SetDeadline for connection failed with "%s"`, t)
+ }
+ return err
+}
+
+func (c *Conn) SetReceiveDeadline(t time.Time) (err error) {
+ if err = c.SetReadDeadline(t); err == nil {
+ c.receiveDeadline = t
+ }
+ if err != nil {
+ err = gerror.Wrapf(err, `SetReadDeadline for connection failed with "%s"`, t)
+ }
+ return err
+}
+
+func (c *Conn) SetSendDeadline(t time.Time) (err error) {
+ if err = c.SetWriteDeadline(t); err == nil {
+ c.sendDeadline = t
+ }
+ if err != nil {
+ err = gerror.Wrapf(err, `SetWriteDeadline for connection failed with "%s"`, t)
+ }
+ return err
+}
+
+// SetReceiveBufferWait sets the buffer waiting timeout when reading all data from connection.
+// The waiting duration cannot be too long which might delay receiving data from remote address.
+func (c *Conn) SetReceiveBufferWait(bufferWaitDuration time.Duration) {
+ c.receiveBufferWait = bufferWaitDuration
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_conn_pkg.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_conn_pkg.go
new file mode 100644
index 000000000000..f54ff88ce461
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_conn_pkg.go
@@ -0,0 +1,182 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import (
+ "encoding/binary"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+const (
+ pkgHeaderSizeDefault = 2 // Header size for simple package protocol.
+ pkgHeaderSizeMax = 4 // Max header size for simple package protocol.
+)
+
+// PkgOption is package option for simple protocol.
+type PkgOption struct {
+ // HeaderSize is used to mark the data length for next data receiving.
+ // It's 2 bytes in default, 4 bytes max, which stands for the max data length
+ // from 65535 to 4294967295 bytes.
+ HeaderSize int
+
+ // MaxDataSize is the data field size in bytes for data length validation.
+ // If it's not manually set, it'll automatically be set correspondingly with the HeaderSize.
+ MaxDataSize int
+
+ // Retry policy when operation fails.
+ Retry Retry
+}
+
+// SendPkg send data using simple package protocol.
+//
+// Simple package protocol: DataLength(24bit)|DataField(variant)。
+//
+// Note that,
+// 1. The DataLength is the length of DataField, which does not contain the header size.
+// 2. The integer bytes of the package are encoded using BigEndian order.
+func (c *Conn) SendPkg(data []byte, option ...PkgOption) error {
+ pkgOption, err := getPkgOption(option...)
+ if err != nil {
+ return err
+ }
+ length := len(data)
+ if length > pkgOption.MaxDataSize {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `data too long, data size %d exceeds allowed max data size %d`,
+ length, pkgOption.MaxDataSize,
+ )
+ }
+ offset := pkgHeaderSizeMax - pkgOption.HeaderSize
+ buffer := make([]byte, pkgHeaderSizeMax+len(data))
+ binary.BigEndian.PutUint32(buffer[0:], uint32(length))
+ copy(buffer[pkgHeaderSizeMax:], data)
+ if pkgOption.Retry.Count > 0 {
+ return c.Send(buffer[offset:], pkgOption.Retry)
+ }
+ return c.Send(buffer[offset:])
+}
+
+// SendPkgWithTimeout writes data to connection with timeout using simple package protocol.
+func (c *Conn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) {
+ if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+ defer c.SetSendDeadline(time.Time{})
+ err = c.SendPkg(data, option...)
+ return
+}
+
+// SendRecvPkg writes data to connection and blocks reading response using simple package protocol.
+func (c *Conn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) {
+ if err := c.SendPkg(data, option...); err == nil {
+ return c.RecvPkg(option...)
+ } else {
+ return nil, err
+ }
+}
+
+// SendRecvPkgWithTimeout writes data to connection and reads response with timeout using simple package protocol.
+func (c *Conn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {
+ if err := c.SendPkg(data, option...); err == nil {
+ return c.RecvPkgWithTimeout(timeout, option...)
+ } else {
+ return nil, err
+ }
+}
+
+// RecvPkg receives data from connection using simple package protocol.
+func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error) {
+ var (
+ buffer []byte
+ length int
+ )
+ pkgOption, err := getPkgOption(option...)
+ if err != nil {
+ return nil, err
+ }
+ // Header field.
+ buffer, err = c.Recv(pkgOption.HeaderSize, pkgOption.Retry)
+ if err != nil {
+ return nil, err
+ }
+ switch pkgOption.HeaderSize {
+ case 1:
+ // It fills with zero if the header size is lesser than 4 bytes (uint32).
+ length = int(binary.BigEndian.Uint32([]byte{0, 0, 0, buffer[0]}))
+ case 2:
+ length = int(binary.BigEndian.Uint32([]byte{0, 0, buffer[0], buffer[1]}))
+ case 3:
+ length = int(binary.BigEndian.Uint32([]byte{0, buffer[0], buffer[1], buffer[2]}))
+ default:
+ length = int(binary.BigEndian.Uint32([]byte{buffer[0], buffer[1], buffer[2], buffer[3]}))
+ }
+ // It here validates the size of the package.
+ // It clears the buffer and returns error immediately if it validates failed.
+ if length < 0 || length > pkgOption.MaxDataSize {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid package size %d`, length)
+ }
+ // Empty package.
+ if length == 0 {
+ return nil, nil
+ }
+ // Data field.
+ return c.Recv(length, pkgOption.Retry)
+}
+
+// RecvPkgWithTimeout reads data from connection with timeout using simple package protocol.
+func (c *Conn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) {
+ if err := c.SetReceiveDeadline(time.Now().Add(timeout)); err != nil {
+ return nil, err
+ }
+ defer c.SetReceiveDeadline(time.Time{})
+ data, err = c.RecvPkg(option...)
+ return
+}
+
+// getPkgOption wraps and returns the PkgOption.
+// If no option given, it returns a new option with default value.
+func getPkgOption(option ...PkgOption) (*PkgOption, error) {
+ pkgOption := PkgOption{}
+ if len(option) > 0 {
+ pkgOption = option[0]
+ }
+ if pkgOption.HeaderSize == 0 {
+ pkgOption.HeaderSize = pkgHeaderSizeDefault
+ }
+ if pkgOption.HeaderSize > pkgHeaderSizeMax {
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `package header size %d definition exceeds max header size %d`,
+ pkgOption.HeaderSize, pkgHeaderSizeMax,
+ )
+ }
+ if pkgOption.MaxDataSize == 0 {
+ switch pkgOption.HeaderSize {
+ case 1:
+ pkgOption.MaxDataSize = 0xFF
+ case 2:
+ pkgOption.MaxDataSize = 0xFFFF
+ case 3:
+ pkgOption.MaxDataSize = 0xFFFFFF
+ case 4:
+ // math.MaxInt32 not math.MaxUint32
+ pkgOption.MaxDataSize = 0x7FFFFFFF
+ }
+ }
+ if pkgOption.MaxDataSize > 0x7FFFFFFF {
+ return nil, gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `package data size %d definition exceeds allowed max data size %d`,
+ pkgOption.MaxDataSize, 0x7FFFFFFF,
+ )
+ }
+ return &pkgOption, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_func.go
new file mode 100644
index 000000000000..78848cea8ae2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_func.go
@@ -0,0 +1,230 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import (
+ "crypto/rand"
+ "crypto/tls"
+ "net"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gfile"
+)
+
+const (
+ defaultConnTimeout = 30 * time.Second // Default connection timeout.
+ defaultRetryInternal = 100 * time.Millisecond // Default retry interval.
+ defaultReadBufferSize = 128 // (Byte) Buffer size for reading.
+)
+
+type Retry struct {
+ Count int // Retry count.
+ Interval time.Duration // Retry interval.
+}
+
+// NewNetConn creates and returns a net.Conn with given address like "127.0.0.1:80".
+// The optional parameter `timeout` specifies the timeout for dialing connection.
+func NewNetConn(address string, timeout ...time.Duration) (net.Conn, error) {
+ var (
+ network = `tcp`
+ duration = defaultConnTimeout
+ )
+ if len(timeout) > 0 {
+ duration = timeout[0]
+ }
+ conn, err := net.DialTimeout(network, address, duration)
+ if err != nil {
+ err = gerror.Wrapf(
+ err,
+ `net.DialTimeout failed with network "%s", address "%s", timeout "%s"`,
+ network, address, duration,
+ )
+ }
+ return conn, err
+}
+
+// NewNetConnTLS creates and returns a TLS net.Conn with given address like "127.0.0.1:80".
+// The optional parameter `timeout` specifies the timeout for dialing connection.
+func NewNetConnTLS(address string, tlsConfig *tls.Config, timeout ...time.Duration) (net.Conn, error) {
+ var (
+ network = `tcp`
+ dialer = &net.Dialer{
+ Timeout: defaultConnTimeout,
+ }
+ )
+ if len(timeout) > 0 {
+ dialer.Timeout = timeout[0]
+ }
+ conn, err := tls.DialWithDialer(dialer, network, address, tlsConfig)
+ if err != nil {
+ err = gerror.Wrapf(
+ err,
+ `tls.DialWithDialer failed with network "%s", address "%s", timeout "%s", tlsConfig "%v"`,
+ network, address, dialer.Timeout, tlsConfig,
+ )
+ }
+ return conn, err
+}
+
+// NewNetConnKeyCrt creates and returns a TLS net.Conn with given TLS certificate and key files
+// and address like "127.0.0.1:80". The optional parameter `timeout` specifies the timeout for
+// dialing connection.
+func NewNetConnKeyCrt(addr, crtFile, keyFile string, timeout ...time.Duration) (net.Conn, error) {
+ tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
+ if err != nil {
+ return nil, err
+ }
+ return NewNetConnTLS(addr, tlsConfig, timeout...)
+}
+
+// Send creates connection to `address`, writes `data` to the connection and then closes the connection.
+// The optional parameter `retry` specifies the retry policy when fails in writing data.
+func Send(address string, data []byte, retry ...Retry) error {
+ conn, err := NewConn(address)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return conn.Send(data, retry...)
+}
+
+// SendRecv creates connection to `address`, writes `data` to the connection, receives response
+// and then closes the connection.
+//
+// The parameter `length` specifies the bytes count waiting to receive. It receives all buffer content
+// and returns if `length` is -1.
+//
+// The optional parameter `retry` specifies the retry policy when fails in writing data.
+func SendRecv(address string, data []byte, length int, retry ...Retry) ([]byte, error) {
+ conn, err := NewConn(address)
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+ return conn.SendRecv(data, length, retry...)
+}
+
+// SendWithTimeout does Send logic with writing timeout limitation.
+func SendWithTimeout(address string, data []byte, timeout time.Duration, retry ...Retry) error {
+ conn, err := NewConn(address)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return conn.SendWithTimeout(data, timeout, retry...)
+}
+
+// SendRecvWithTimeout does SendRecv logic with reading timeout limitation.
+func SendRecvWithTimeout(address string, data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
+ conn, err := NewConn(address)
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+ return conn.SendRecvWithTimeout(data, receive, timeout, retry...)
+}
+
+// isTimeout checks whether given `err` is a timeout error.
+func isTimeout(err error) bool {
+ if err == nil {
+ return false
+ }
+ if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
+ return true
+ }
+ return false
+}
+
+// LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.
+func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {
+ crtPath, err := gfile.Search(crtFile)
+ if err != nil {
+ return nil, err
+ }
+ keyPath, err := gfile.Search(keyFile)
+ if err != nil {
+ return nil, err
+ }
+ crt, err := tls.LoadX509KeyPair(crtPath, keyPath)
+ if err != nil {
+ return nil, gerror.Wrapf(err,
+ `tls.LoadX509KeyPair failed for certFile "%s" and keyFile "%s"`,
+ crtPath, keyPath,
+ )
+ }
+ tlsConfig := &tls.Config{}
+ tlsConfig.Certificates = []tls.Certificate{crt}
+ tlsConfig.Time = time.Now
+ tlsConfig.Rand = rand.Reader
+ return tlsConfig, nil
+}
+
+// MustGetFreePort performs as GetFreePort, but it panics is any error occurs.
+func MustGetFreePort() int {
+ port, err := GetFreePort()
+ if err != nil {
+ panic(err)
+ }
+ return port
+}
+
+// GetFreePort retrieves and returns a port that is free.
+func GetFreePort() (port int, err error) {
+ var (
+ network = `tcp`
+ address = `:0`
+ )
+ resolvedAddr, err := net.ResolveTCPAddr(network, address)
+ if err != nil {
+ return 0, gerror.Wrapf(
+ err,
+ `net.ResolveTCPAddr failed for network "%s", address "%s"`,
+ network, address,
+ )
+ }
+ l, err := net.ListenTCP(network, resolvedAddr)
+ if err != nil {
+ return 0, gerror.Wrapf(
+ err,
+ `net.ListenTCP failed for network "%s", address "%s"`,
+ network, resolvedAddr.String(),
+ )
+ }
+ port = l.Addr().(*net.TCPAddr).Port
+ err = l.Close()
+ return
+}
+
+// GetFreePorts retrieves and returns specified number of ports that are free.
+func GetFreePorts(count int) (ports []int, err error) {
+ var (
+ network = `tcp`
+ address = `:0`
+ )
+ for i := 0; i < count; i++ {
+ resolvedAddr, err := net.ResolveTCPAddr(network, address)
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.ResolveTCPAddr failed for network "%s", address "%s"`,
+ network, address,
+ )
+ }
+ l, err := net.ListenTCP(network, resolvedAddr)
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.ListenTCP failed for network "%s", address "%s"`,
+ network, resolvedAddr.String(),
+ )
+ }
+ ports = append(ports, l.Addr().(*net.TCPAddr).Port)
+ _ = l.Close()
+ }
+ return ports, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_func_pkg.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_func_pkg.go
new file mode 100644
index 000000000000..39a3754b1192
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_func_pkg.go
@@ -0,0 +1,53 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import "time"
+
+// SendPkg sends a package containing `data` to `address` and closes the connection.
+// The optional parameter `option` specifies the package options for sending.
+func SendPkg(address string, data []byte, option ...PkgOption) error {
+ conn, err := NewConn(address)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return conn.SendPkg(data, option...)
+}
+
+// SendRecvPkg sends a package containing `data` to `address`, receives the response
+// and closes the connection. The optional parameter `option` specifies the package options for sending.
+func SendRecvPkg(address string, data []byte, option ...PkgOption) ([]byte, error) {
+ conn, err := NewConn(address)
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+ return conn.SendRecvPkg(data, option...)
+}
+
+// SendPkgWithTimeout sends a package containing `data` to `address` with timeout limitation
+// and closes the connection. The optional parameter `option` specifies the package options for sending.
+func SendPkgWithTimeout(address string, data []byte, timeout time.Duration, option ...PkgOption) error {
+ conn, err := NewConn(address)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return conn.SendPkgWithTimeout(data, timeout, option...)
+}
+
+// SendRecvPkgWithTimeout sends a package containing `data` to `address`, receives the response with timeout limitation
+// and closes the connection. The optional parameter `option` specifies the package options for sending.
+func SendRecvPkgWithTimeout(address string, data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {
+ conn, err := NewConn(address)
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+ return conn.SendRecvPkgWithTimeout(data, timeout, option...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_pool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_pool.go
new file mode 100644
index 000000000000..bbfe192db9df
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_pool.go
@@ -0,0 +1,162 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import (
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gpool"
+)
+
+// PoolConn is a connection with pool feature for TCP.
+// Note that it is NOT a pool or connection manager, it is just a TCP connection object.
+type PoolConn struct {
+ *Conn // Underlying connection object.
+ pool *gpool.Pool // Connection pool, which is not a real connection pool, but a connection reusable pool.
+ status int // Status of current connection, which is used to mark this connection usable or not.
+}
+
+const (
+ defaultPoolExpire = 10 * time.Second // Default TTL for connection in the pool.
+ connStatusUnknown = 0 // Means it is unknown it's connective or not.
+ connStatusActive = 1 // Means it is now connective.
+ connStatusError = 2 // Means it should be closed and removed from pool.
+)
+
+var (
+ // addressPoolMap is a mapping for address to its pool object.
+ addressPoolMap = gmap.NewStrAnyMap(true)
+)
+
+// NewPoolConn creates and returns a connection with pool feature.
+func NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) {
+ v := addressPoolMap.GetOrSetFuncLock(addr, func() interface{} {
+ var pool *gpool.Pool
+ pool = gpool.New(defaultPoolExpire, func() (interface{}, error) {
+ if conn, err := NewConn(addr, timeout...); err == nil {
+ return &PoolConn{conn, pool, connStatusActive}, nil
+ } else {
+ return nil, err
+ }
+ })
+ return pool
+ })
+ value, err := v.(*gpool.Pool).Get()
+ if err != nil {
+ return nil, err
+ }
+ return value.(*PoolConn), nil
+}
+
+// Close puts back the connection to the pool if it's active,
+// or closes the connection if it's not active.
+//
+// Note that, if `c` calls Close function closing itself, `c` can not
+// be used again.
+func (c *PoolConn) Close() error {
+ if c.pool != nil && c.status == connStatusActive {
+ c.status = connStatusUnknown
+ c.pool.Put(c)
+ } else {
+ return c.Conn.Close()
+ }
+ return nil
+}
+
+// Send writes data to the connection. It retrieves a new connection from its pool if it fails
+// writing data.
+func (c *PoolConn) Send(data []byte, retry ...Retry) error {
+ err := c.Conn.Send(data, retry...)
+ if err != nil && c.status == connStatusUnknown {
+ if v, e := c.pool.Get(); e == nil {
+ c.Conn = v.(*PoolConn).Conn
+ err = c.Send(data, retry...)
+ } else {
+ err = e
+ }
+ }
+ if err != nil {
+ c.status = connStatusError
+ } else {
+ c.status = connStatusActive
+ }
+ return err
+}
+
+// Recv receives data from the connection.
+func (c *PoolConn) Recv(length int, retry ...Retry) ([]byte, error) {
+ data, err := c.Conn.Recv(length, retry...)
+ if err != nil {
+ c.status = connStatusError
+ } else {
+ c.status = connStatusActive
+ }
+ return data, err
+}
+
+// RecvLine reads data from the connection until reads char '\n'.
+// Note that the returned result does not contain the last char '\n'.
+func (c *PoolConn) RecvLine(retry ...Retry) ([]byte, error) {
+ data, err := c.Conn.RecvLine(retry...)
+ if err != nil {
+ c.status = connStatusError
+ } else {
+ c.status = connStatusActive
+ }
+ return data, err
+}
+
+// RecvTill reads data from the connection until reads bytes `til`.
+// Note that the returned result contains the last bytes `til`.
+func (c *PoolConn) RecvTill(til []byte, retry ...Retry) ([]byte, error) {
+ data, err := c.Conn.RecvTill(til, retry...)
+ if err != nil {
+ c.status = connStatusError
+ } else {
+ c.status = connStatusActive
+ }
+ return data, err
+}
+
+// RecvWithTimeout reads data from the connection with timeout.
+func (c *PoolConn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
+ if err := c.SetReceiveDeadline(time.Now().Add(timeout)); err != nil {
+ return nil, err
+ }
+ defer c.SetReceiveDeadline(time.Time{})
+ data, err = c.Recv(length, retry...)
+ return
+}
+
+// SendWithTimeout writes data to the connection with timeout.
+func (c *PoolConn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
+ if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+ defer c.SetSendDeadline(time.Time{})
+ err = c.Send(data, retry...)
+ return
+}
+
+// SendRecv writes data to the connection and blocks reading response.
+func (c *PoolConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
+ if err := c.Send(data, retry...); err == nil {
+ return c.Recv(receive, retry...)
+ } else {
+ return nil, err
+ }
+}
+
+// SendRecvWithTimeout writes data to the connection and reads response with timeout.
+func (c *PoolConn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
+ if err := c.Send(data, retry...); err == nil {
+ return c.RecvWithTimeout(receive, timeout, retry...)
+ } else {
+ return nil, err
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_pool_pkg.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_pool_pkg.go
new file mode 100644
index 000000000000..1e1eb2f640c4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_pool_pkg.go
@@ -0,0 +1,80 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import (
+ "time"
+)
+
+// SendPkg sends a package containing `data` to the connection.
+// The optional parameter `option` specifies the package options for sending.
+func (c *PoolConn) SendPkg(data []byte, option ...PkgOption) (err error) {
+ if err = c.Conn.SendPkg(data, option...); err != nil && c.status == connStatusUnknown {
+ if v, e := c.pool.NewFunc(); e == nil {
+ c.Conn = v.(*PoolConn).Conn
+ err = c.Conn.SendPkg(data, option...)
+ } else {
+ err = e
+ }
+ }
+ if err != nil {
+ c.status = connStatusError
+ } else {
+ c.status = connStatusActive
+ }
+ return err
+}
+
+// RecvPkg receives package from connection using simple package protocol.
+// The optional parameter `option` specifies the package options for receiving.
+func (c *PoolConn) RecvPkg(option ...PkgOption) ([]byte, error) {
+ data, err := c.Conn.RecvPkg(option...)
+ if err != nil {
+ c.status = connStatusError
+ } else {
+ c.status = connStatusActive
+ }
+ return data, err
+}
+
+// RecvPkgWithTimeout reads data from connection with timeout using simple package protocol.
+func (c *PoolConn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) (data []byte, err error) {
+ if err := c.SetReceiveDeadline(time.Now().Add(timeout)); err != nil {
+ return nil, err
+ }
+ defer c.SetReceiveDeadline(time.Time{})
+ data, err = c.RecvPkg(option...)
+ return
+}
+
+// SendPkgWithTimeout writes data to connection with timeout using simple package protocol.
+func (c *PoolConn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) (err error) {
+ if err := c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+ defer c.SetSendDeadline(time.Time{})
+ err = c.SendPkg(data, option...)
+ return
+}
+
+// SendRecvPkg writes data to connection and blocks reading response using simple package protocol.
+func (c *PoolConn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error) {
+ if err := c.SendPkg(data, option...); err == nil {
+ return c.RecvPkg(option...)
+ } else {
+ return nil, err
+ }
+}
+
+// SendRecvPkgWithTimeout reads data from connection with timeout using simple package protocol.
+func (c *PoolConn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error) {
+ if err := c.SendPkg(data, option...); err == nil {
+ return c.RecvPkgWithTimeout(timeout, option...)
+ } else {
+ return nil, err
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_server.go
new file mode 100644
index 000000000000..01f1920b3d9c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtcp/gtcp_server.go
@@ -0,0 +1,157 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtcp
+
+import (
+ "crypto/tls"
+ "net"
+ "sync"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ // defaultServer is the default TCP server name.
+ defaultServer = "default"
+)
+
+// Server is a TCP server.
+type Server struct {
+ mu sync.Mutex // Used for Server.listen concurrent safety.
+ listen net.Listener // Listener.
+ address string // Server listening address.
+ handler func(*Conn) // Connection handler.
+ tlsConfig *tls.Config // TLS configuration.
+}
+
+// Map for name to server, for singleton purpose.
+var serverMapping = gmap.NewStrAnyMap(true)
+
+// GetServer returns the TCP server with specified `name`,
+// or it returns a new normal TCP server named `name` if it does not exist.
+// The parameter `name` is used to specify the TCP server
+func GetServer(name ...interface{}) *Server {
+ serverName := defaultServer
+ if len(name) > 0 && name[0] != "" {
+ serverName = gconv.String(name[0])
+ }
+ return serverMapping.GetOrSetFuncLock(serverName, func() interface{} {
+ return NewServer("", nil)
+ }).(*Server)
+}
+
+// NewServer creates and returns a new normal TCP server.
+// The parameter `name` is optional, which is used to specify the instance name of the server.
+func NewServer(address string, handler func(*Conn), name ...string) *Server {
+ s := &Server{
+ address: address,
+ handler: handler,
+ }
+ if len(name) > 0 && name[0] != "" {
+ serverMapping.Set(name[0], s)
+ }
+ return s
+}
+
+// NewServerTLS creates and returns a new TCP server with TLS support.
+// The parameter `name` is optional, which is used to specify the instance name of the server.
+func NewServerTLS(address string, tlsConfig *tls.Config, handler func(*Conn), name ...string) *Server {
+ s := NewServer(address, handler, name...)
+ s.SetTLSConfig(tlsConfig)
+ return s
+}
+
+// NewServerKeyCrt creates and returns a new TCP server with TLS support.
+// The parameter `name` is optional, which is used to specify the instance name of the server.
+func NewServerKeyCrt(address, crtFile, keyFile string, handler func(*Conn), name ...string) (*Server, error) {
+ s := NewServer(address, handler, name...)
+ if err := s.SetTLSKeyCrt(crtFile, keyFile); err != nil {
+ return nil, err
+ }
+ return s, nil
+}
+
+// SetAddress sets the listening address for server.
+func (s *Server) SetAddress(address string) {
+ s.address = address
+}
+
+// SetHandler sets the connection handler for server.
+func (s *Server) SetHandler(handler func(*Conn)) {
+ s.handler = handler
+}
+
+// SetTLSKeyCrt sets the certificate and key file for TLS configuration of server.
+func (s *Server) SetTLSKeyCrt(crtFile, keyFile string) error {
+ tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
+ if err != nil {
+ return err
+ }
+ s.tlsConfig = tlsConfig
+ return nil
+}
+
+// SetTLSConfig sets the TLS configuration of server.
+func (s *Server) SetTLSConfig(tlsConfig *tls.Config) {
+ s.tlsConfig = tlsConfig
+}
+
+// Close closes the listener and shutdowns the server.
+func (s *Server) Close() error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.listen == nil {
+ return nil
+ }
+ return s.listen.Close()
+}
+
+// Run starts running the TCP Server.
+func (s *Server) Run() (err error) {
+ if s.handler == nil {
+ err = gerror.NewCode(gcode.CodeMissingConfiguration, "start running failed: socket handler not defined")
+ return
+ }
+ if s.tlsConfig != nil {
+ // TLS Server
+ s.mu.Lock()
+ s.listen, err = tls.Listen("tcp", s.address, s.tlsConfig)
+ s.mu.Unlock()
+ if err != nil {
+ err = gerror.Wrapf(err, `tls.Listen failed for address "%s"`, s.address)
+ return
+ }
+ } else {
+ // Normal Server
+ var tcpAddr *net.TCPAddr
+ if tcpAddr, err = net.ResolveTCPAddr("tcp", s.address); err != nil {
+ err = gerror.Wrapf(err, `net.ResolveTCPAddr failed for address "%s"`, s.address)
+ return err
+ }
+ s.mu.Lock()
+ s.listen, err = net.ListenTCP("tcp", tcpAddr)
+ s.mu.Unlock()
+ if err != nil {
+ err = gerror.Wrapf(err, `net.ListenTCP failed for address "%s"`, s.address)
+ return err
+ }
+ }
+ // Listening loop.
+ for {
+ var conn net.Conn
+ if conn, err = s.listen.Accept(); err != nil {
+ err = gerror.Wrapf(err, `Listener.Accept failed`)
+ return err
+ } else if conn != nil {
+ go s.handler(NewConnByNetConn(conn))
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace.go
new file mode 100644
index 000000000000..5c005b8b0dac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace.go
@@ -0,0 +1,166 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtrace provides convenience wrapping functionality for tracing feature using OpenTelemetry.
+package gtrace
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/propagation"
+ semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/net/gipv4"
+ "github.com/gogf/gf/v2/net/gtrace/internal/provider"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ tracingCommonKeyIpIntranet = `ip.intranet`
+ tracingCommonKeyIpHostname = `hostname`
+ commandEnvKeyForTraceEnabled = "gf.trace.enabled" // Main switch for tracing feature.
+ commandEnvKeyForMaxContentLogSize = "gf.gtrace.max.content.log.size" // To avoid too big tracing content.
+ commandEnvKeyForTracingInternal = "gf.gtrace.tracing.internal" // For detailed controlling for tracing content.
+)
+
+var (
+ intranetIps, _ = gipv4.GetIntranetIpArray()
+ intranetIpStr = strings.Join(intranetIps, ",")
+ hostname, _ = os.Hostname()
+ tracingInternal = true // tracingInternal enables tracing for internal type spans.
+ tracingMaxContentLogSize = 512 * 1024 // Max log size for request and response body, especially for HTTP/RPC request.
+ // defaultTextMapPropagator is the default propagator for context propagation between peers.
+ defaultTextMapPropagator = propagation.NewCompositeTextMapPropagator(
+ propagation.TraceContext{},
+ propagation.Baggage{},
+ )
+)
+
+func init() {
+ tracingInternal = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForTracingInternal, "true"))
+ if maxContentLogSize := gconv.Int(command.GetOptWithEnv(commandEnvKeyForMaxContentLogSize)); maxContentLogSize > 0 {
+ tracingMaxContentLogSize = maxContentLogSize
+ }
+ // Default trace provider.
+ otel.SetTracerProvider(provider.New())
+ CheckSetDefaultTextMapPropagator()
+}
+
+// IsUsingDefaultProvider checks and return if currently using default trace provider.
+func IsUsingDefaultProvider() bool {
+ _, ok := otel.GetTracerProvider().(*provider.TracerProvider)
+ return ok
+}
+
+// IsTracingInternal returns whether tracing spans of internal components.
+func IsTracingInternal() bool {
+ return tracingInternal
+}
+
+// MaxContentLogSize returns the max log size for request and response body, especially for HTTP/RPC request.
+func MaxContentLogSize() int {
+ return tracingMaxContentLogSize
+}
+
+// CommonLabels returns common used attribute labels:
+// ip.intranet, hostname.
+func CommonLabels() []attribute.KeyValue {
+ return []attribute.KeyValue{
+ attribute.String(tracingCommonKeyIpHostname, hostname),
+ attribute.String(tracingCommonKeyIpIntranet, intranetIpStr),
+ semconv.HostNameKey.String(hostname),
+ }
+}
+
+// CheckSetDefaultTextMapPropagator sets the default TextMapPropagator if it is not set previously.
+func CheckSetDefaultTextMapPropagator() {
+ p := otel.GetTextMapPropagator()
+ if len(p.Fields()) == 0 {
+ otel.SetTextMapPropagator(GetDefaultTextMapPropagator())
+ }
+}
+
+// GetDefaultTextMapPropagator returns the default propagator for context propagation between peers.
+func GetDefaultTextMapPropagator() propagation.TextMapPropagator {
+ return defaultTextMapPropagator
+}
+
+// GetTraceID retrieves and returns TraceId from context.
+// It returns an empty string is tracing feature is not activated.
+func GetTraceID(ctx context.Context) string {
+ if ctx == nil {
+ return ""
+ }
+ traceID := trace.SpanContextFromContext(ctx).TraceID()
+ if traceID.IsValid() {
+ return traceID.String()
+ }
+ return ""
+}
+
+// GetSpanID retrieves and returns SpanId from context.
+// It returns an empty string is tracing feature is not activated.
+func GetSpanID(ctx context.Context) string {
+ if ctx == nil {
+ return ""
+ }
+ spanID := trace.SpanContextFromContext(ctx).SpanID()
+ if spanID.IsValid() {
+ return spanID.String()
+ }
+ return ""
+}
+
+// SetBaggageValue is a convenient function for adding one key-value pair to baggage.
+// Note that it uses attribute.Any to set the key-value pair.
+func SetBaggageValue(ctx context.Context, key string, value interface{}) context.Context {
+ return NewBaggage(ctx).SetValue(key, value)
+}
+
+// SetBaggageMap is a convenient function for adding map key-value pairs to baggage.
+// Note that it uses attribute.Any to set the key-value pair.
+func SetBaggageMap(ctx context.Context, data map[string]interface{}) context.Context {
+ return NewBaggage(ctx).SetMap(data)
+}
+
+// GetBaggageMap retrieves and returns the baggage values as map.
+func GetBaggageMap(ctx context.Context) *gmap.StrAnyMap {
+ return NewBaggage(ctx).GetMap()
+}
+
+// GetBaggageVar retrieves value and returns a *gvar.Var for specified key from baggage.
+func GetBaggageVar(ctx context.Context, key string) *gvar.Var {
+ return NewBaggage(ctx).GetVar(key)
+}
+
+// WithTraceID injects custom trace id into context to propagate.
+func WithTraceID(ctx context.Context, traceID trace.TraceID) context.Context {
+ sc := trace.SpanContextFromContext(ctx)
+ if !sc.HasTraceID() {
+ var (
+ span trace.Span
+ )
+ ctx, span = NewSpan(ctx, "gtrace.WithTraceID")
+ defer span.End()
+ sc = trace.SpanContextFromContext(ctx)
+ }
+ ctx = trace.ContextWithRemoteSpanContext(ctx, trace.NewSpanContext(trace.SpanContextConfig{
+ TraceID: traceID,
+ SpanID: sc.SpanID(),
+ TraceFlags: sc.TraceFlags(),
+ TraceState: sc.TraceState(),
+ Remote: sc.IsRemote(),
+ }))
+ return ctx
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_baggage.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_baggage.go
new file mode 100644
index 000000000000..26a9eb86a115
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_baggage.go
@@ -0,0 +1,75 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtrace
+
+import (
+ "context"
+
+ "go.opentelemetry.io/otel/baggage"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Baggage holds the data through all tracing spans.
+type Baggage struct {
+ ctx context.Context
+}
+
+// NewBaggage creates and returns a new Baggage object from given tracing context.
+func NewBaggage(ctx context.Context) *Baggage {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ return &Baggage{
+ ctx: ctx,
+ }
+}
+
+// Ctx returns the context that Baggage holds.
+func (b *Baggage) Ctx() context.Context {
+ return b.ctx
+}
+
+// SetValue is a convenient function for adding one key-value pair to baggage.
+// Note that it uses attribute.Any to set the key-value pair.
+func (b *Baggage) SetValue(key string, value interface{}) context.Context {
+ member, _ := baggage.NewMember(key, gconv.String(value))
+ bag, _ := baggage.New(member)
+ b.ctx = baggage.ContextWithBaggage(b.ctx, bag)
+ return b.ctx
+}
+
+// SetMap is a convenient function for adding map key-value pairs to baggage.
+// Note that it uses attribute.Any to set the key-value pair.
+func (b *Baggage) SetMap(data map[string]interface{}) context.Context {
+ members := make([]baggage.Member, 0)
+ for k, v := range data {
+ member, _ := baggage.NewMember(k, gconv.String(v))
+ members = append(members, member)
+ }
+ bag, _ := baggage.New(members...)
+ b.ctx = baggage.ContextWithBaggage(b.ctx, bag)
+ return b.ctx
+}
+
+// GetMap retrieves and returns the baggage values as map.
+func (b *Baggage) GetMap() *gmap.StrAnyMap {
+ m := gmap.NewStrAnyMap()
+ members := baggage.FromContext(b.ctx).Members()
+ for i := range members {
+ m.Set(members[i].Key(), members[i].Value())
+ }
+ return m
+}
+
+// GetVar retrieves value and returns a *gvar.Var for specified key from baggage.
+func (b *Baggage) GetVar(key string) *gvar.Var {
+ value := baggage.FromContext(b.ctx).Member(key).Value()
+ return gvar.New(value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_carrier.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_carrier.go
new file mode 100644
index 000000000000..e29d7007bc99
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_carrier.go
@@ -0,0 +1,62 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtrace
+
+import (
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Carrier is the storage medium used by a TextMapPropagator.
+type Carrier map[string]interface{}
+
+// NewCarrier creates and returns a Carrier.
+func NewCarrier(data ...map[string]interface{}) Carrier {
+ if len(data) > 0 && data[0] != nil {
+ return data[0]
+ }
+ return make(map[string]interface{})
+}
+
+// Get returns the value associated with the passed key.
+func (c Carrier) Get(k string) string {
+ return gconv.String(c[k])
+}
+
+// Set stores the key-value pair.
+func (c Carrier) Set(k, v string) {
+ c[k] = v
+}
+
+// Keys lists the keys stored in this carrier.
+func (c Carrier) Keys() []string {
+ keys := make([]string, 0, len(c))
+ for k := range c {
+ keys = append(keys, k)
+ }
+ return keys
+}
+
+// MustMarshal .returns the JSON encoding of c
+func (c Carrier) MustMarshal() []byte {
+ b, err := json.Marshal(c)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+// String converts and returns current Carrier as string.
+func (c Carrier) String() string {
+ return string(c.MustMarshal())
+}
+
+// UnmarshalJSON implements interface UnmarshalJSON for package json.
+func (c Carrier) UnmarshalJSON(b []byte) error {
+ carrier := NewCarrier(nil)
+ return json.UnmarshalUseNumber(b, carrier)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_span.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_span.go
new file mode 100644
index 000000000000..0d7fb240b2cd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_span.go
@@ -0,0 +1,26 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtrace
+
+import (
+ "context"
+
+ "go.opentelemetry.io/otel/trace"
+)
+
+// Span warps trace.Span for compatibility and extension.
+type Span struct {
+ trace.Span
+}
+
+// NewSpan creates a span using default tracer.
+func NewSpan(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, *Span) {
+ ctx, span := NewTracer().Start(ctx, spanName, opts...)
+ return ctx, &Span{
+ Span: span,
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_tracer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_tracer.go
new file mode 100644
index 000000000000..47d2baa7225d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/gtrace_tracer.go
@@ -0,0 +1,28 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtrace
+
+import (
+ "go.opentelemetry.io/otel"
+ "go.opentelemetry.io/otel/trace"
+)
+
+// Tracer warps trace.Tracer for compatibility and extension.
+type Tracer struct {
+ trace.Tracer
+}
+
+// NewTracer Tracer is a short function for retrieving Tracer.
+func NewTracer(name ...string) *Tracer {
+ tracerName := ""
+ if len(name) > 0 {
+ tracerName = name[0]
+ }
+ return &Tracer{
+ Tracer: otel.Tracer(tracerName),
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/internal/provider/provider.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/internal/provider/provider.go
new file mode 100644
index 000000000000..66a6d80df2d7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/internal/provider/provider.go
@@ -0,0 +1,33 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package provider
+
+import (
+ sdkTrace "go.opentelemetry.io/otel/sdk/trace"
+)
+
+type TracerProvider struct {
+ *sdkTrace.TracerProvider
+}
+
+// New returns a new and configured TracerProvider, which has no SpanProcessor.
+//
+// In default the returned TracerProvider is configured with:
+// - a ParentBased(AlwaysSample) Sampler
+// - a unix nano timestamp and random umber based IDGenerator
+// - the resource.Default() Resource
+// - the default SpanLimits.
+//
+// The passed opts are used to override these default values and configure the
+// returned TracerProvider appropriately.
+func New() *TracerProvider {
+ return &TracerProvider{
+ TracerProvider: sdkTrace.NewTracerProvider(
+ sdkTrace.WithIDGenerator(NewIDGenerator()),
+ ),
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/internal/provider/provider_idgenerator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/internal/provider/provider_idgenerator.go
new file mode 100644
index 000000000000..83ffa845e215
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gtrace/internal/provider/provider_idgenerator.go
@@ -0,0 +1,30 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package provider
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/internal/tracing"
+ "go.opentelemetry.io/otel/trace"
+)
+
+type IDGenerator struct{}
+
+func NewIDGenerator() *IDGenerator {
+ return &IDGenerator{}
+}
+
+// NewIDs creates and returns a new trace and span ID.
+func (id *IDGenerator) NewIDs(ctx context.Context) (traceID trace.TraceID, spanID trace.SpanID) {
+ return tracing.NewIDs()
+}
+
+// NewSpanID returns an ID for a new span in the trace with traceID.
+func (id *IDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) (spanID trace.SpanID) {
+ return tracing.NewSpanID()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp.go
new file mode 100644
index 000000000000..1f0dc99d60dc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp.go
@@ -0,0 +1,8 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gudp provides UDP server and client implementations.
+package gudp
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_conn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_conn.go
new file mode 100644
index 000000000000..f9683b8dc5bb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_conn.go
@@ -0,0 +1,214 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gudp
+
+import (
+ "io"
+ "net"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Conn handles the UDP connection.
+type Conn struct {
+ *net.UDPConn // Underlying UDP connection.
+ remoteAddr *net.UDPAddr // Remote address.
+ receiveDeadline time.Time // Timeout point for reading data.
+ sendDeadline time.Time // Timeout point for writing data.
+ receiveBufferWait time.Duration // Interval duration for reading buffer.
+}
+
+const (
+ defaultRetryInterval = 100 * time.Millisecond // Retry interval.
+ defaultReadBufferSize = 1024 // (Byte)Buffer size.
+ receiveAllWaitTimeout = time.Millisecond // Default interval for reading buffer.
+)
+
+type Retry struct {
+ Count int // Max retry count.
+ Interval time.Duration // Retry interval.
+}
+
+// NewConn creates UDP connection to `remoteAddress`.
+// The optional parameter `localAddress` specifies the local address for connection.
+func NewConn(remoteAddress string, localAddress ...string) (*Conn, error) {
+ if conn, err := NewNetConn(remoteAddress, localAddress...); err == nil {
+ return NewConnByNetConn(conn), nil
+ } else {
+ return nil, err
+ }
+}
+
+// NewConnByNetConn creates a UDP connection object with given *net.UDPConn object.
+func NewConnByNetConn(udp *net.UDPConn) *Conn {
+ return &Conn{
+ UDPConn: udp,
+ receiveDeadline: time.Time{},
+ sendDeadline: time.Time{},
+ receiveBufferWait: receiveAllWaitTimeout,
+ }
+}
+
+// Send writes data to remote address.
+func (c *Conn) Send(data []byte, retry ...Retry) (err error) {
+ for {
+ if c.remoteAddr != nil {
+ _, err = c.WriteToUDP(data, c.remoteAddr)
+ } else {
+ _, err = c.Write(data)
+ }
+ if err != nil {
+ // Connection closed.
+ if err == io.EOF {
+ return err
+ }
+ // Still failed even after retrying.
+ if len(retry) == 0 || retry[0].Count == 0 {
+ err = gerror.Wrap(err, `Write data failed`)
+ return err
+ }
+ if len(retry) > 0 {
+ retry[0].Count--
+ if retry[0].Interval == 0 {
+ retry[0].Interval = defaultRetryInterval
+ }
+ time.Sleep(retry[0].Interval)
+ }
+ } else {
+ return nil
+ }
+ }
+}
+
+// Recv receives and returns data from remote address.
+// The parameter `buffer` is used for customizing the receiving buffer size. If `buffer` <= 0,
+// it uses the default buffer size, which is 1024 byte.
+//
+// There's package border in UDP protocol, we can receive a complete package if specified
+// buffer size is big enough. VERY NOTE that we should receive the complete package in once
+// or else the leftover package data would be dropped.
+func (c *Conn) Recv(buffer int, retry ...Retry) ([]byte, error) {
+ var (
+ err error // Reading error
+ size int // Reading size
+ data []byte // Buffer object
+ remoteAddr *net.UDPAddr // Current remote address for reading
+ )
+ if buffer > 0 {
+ data = make([]byte, buffer)
+ } else {
+ data = make([]byte, defaultReadBufferSize)
+ }
+ for {
+ size, remoteAddr, err = c.ReadFromUDP(data)
+ if err == nil {
+ c.remoteAddr = remoteAddr
+ }
+ if err != nil {
+ // Connection closed.
+ if err == io.EOF {
+ break
+ }
+ if len(retry) > 0 {
+ // It fails even it retried.
+ if retry[0].Count == 0 {
+ break
+ }
+ retry[0].Count--
+ if retry[0].Interval == 0 {
+ retry[0].Interval = defaultRetryInterval
+ }
+ time.Sleep(retry[0].Interval)
+ continue
+ }
+ err = gerror.Wrap(err, `ReadFromUDP failed`)
+ break
+ }
+ break
+ }
+ return data[:size], err
+}
+
+// SendRecv writes data to connection and blocks reading response.
+func (c *Conn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error) {
+ if err := c.Send(data, retry...); err == nil {
+ return c.Recv(receive, retry...)
+ } else {
+ return nil, err
+ }
+}
+
+// RecvWithTimeout reads data from remote address with timeout.
+func (c *Conn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error) {
+ if err = c.SetRecvDeadline(time.Now().Add(timeout)); err != nil {
+ return nil, err
+ }
+ defer c.SetRecvDeadline(time.Time{})
+ data, err = c.Recv(length, retry...)
+ return
+}
+
+// SendWithTimeout writes data to connection with timeout.
+func (c *Conn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) (err error) {
+ if err = c.SetSendDeadline(time.Now().Add(timeout)); err != nil {
+ return err
+ }
+ defer c.SetSendDeadline(time.Time{})
+ err = c.Send(data, retry...)
+ return
+}
+
+// SendRecvWithTimeout writes data to connection and reads response with timeout.
+func (c *Conn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
+ if err := c.Send(data, retry...); err == nil {
+ return c.RecvWithTimeout(receive, timeout, retry...)
+ } else {
+ return nil, err
+ }
+}
+
+func (c *Conn) SetDeadline(t time.Time) (err error) {
+ if err = c.UDPConn.SetDeadline(t); err == nil {
+ c.receiveDeadline = t
+ c.sendDeadline = t
+ } else {
+ err = gerror.Wrapf(err, `SetDeadline for connection failed with "%s"`, t)
+ }
+ return err
+}
+
+func (c *Conn) SetRecvDeadline(t time.Time) (err error) {
+ if err = c.SetReadDeadline(t); err == nil {
+ c.receiveDeadline = t
+ } else {
+ err = gerror.Wrapf(err, `SetReadDeadline for connection failed with "%s"`, t)
+ }
+ return err
+}
+
+func (c *Conn) SetSendDeadline(t time.Time) (err error) {
+ if err = c.SetWriteDeadline(t); err == nil {
+ c.sendDeadline = t
+ } else {
+ err = gerror.Wrapf(err, `SetWriteDeadline for connection failed with "%s"`, t)
+ }
+ return err
+}
+
+// SetRecvBufferWait sets the buffer waiting timeout when reading all data from connection.
+// The waiting duration cannot be too long which might delay receiving data from remote address.
+func (c *Conn) SetRecvBufferWait(d time.Duration) {
+ c.receiveBufferWait = d
+}
+
+// RemoteAddr returns the remote address of current UDP connection.
+// Note that it cannot use c.conn.RemoteAddr() as it is nil.
+func (c *Conn) RemoteAddr() net.Addr {
+ //return c.conn.RemoteAddr()
+ return c.remoteAddr
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_func.go
new file mode 100644
index 000000000000..07cd5c8fefd6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_func.go
@@ -0,0 +1,128 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gudp
+
+import (
+ "net"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// NewNetConn creates and returns a *net.UDPConn with given addresses.
+func NewNetConn(remoteAddress string, localAddress ...string) (*net.UDPConn, error) {
+ var (
+ err error
+ remoteAddr *net.UDPAddr
+ localAddr *net.UDPAddr
+ network = `udp`
+ )
+ remoteAddr, err = net.ResolveUDPAddr(network, remoteAddress)
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.ResolveUDPAddr failed for network "%s", address "%s"`,
+ network, remoteAddress,
+ )
+ }
+ if len(localAddress) > 0 {
+ localAddr, err = net.ResolveUDPAddr(network, localAddress[0])
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.ResolveUDPAddr failed for network "%s", address "%s"`,
+ network, localAddress[0],
+ )
+ }
+ }
+ conn, err := net.DialUDP(network, localAddr, remoteAddr)
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.DialUDP failed for network "%s", local "%s", remote "%s"`,
+ network, localAddr.String(), remoteAddr.String(),
+ )
+ }
+ return conn, nil
+}
+
+// Send writes data to `address` using UDP connection and then closes the connection.
+// Note that it is used for short connection usage.
+func Send(address string, data []byte, retry ...Retry) error {
+ conn, err := NewConn(address)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return conn.Send(data, retry...)
+}
+
+// SendRecv writes data to `address` using UDP connection, reads response and then closes the connection.
+// Note that it is used for short connection usage.
+func SendRecv(address string, data []byte, receive int, retry ...Retry) ([]byte, error) {
+ conn, err := NewConn(address)
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+ return conn.SendRecv(data, receive, retry...)
+}
+
+// GetFreePort retrieves and returns a port that is free.
+func GetFreePort() (port int, err error) {
+ var (
+ network = `udp`
+ address = `:0`
+ )
+ resolvedAddr, err := net.ResolveUDPAddr(network, address)
+ if err != nil {
+ return 0, gerror.Wrapf(
+ err,
+ `net.ResolveUDPAddr failed for network "%s", address "%s"`,
+ network, address,
+ )
+ }
+ l, err := net.ListenUDP(network, resolvedAddr)
+ if err != nil {
+ return 0, gerror.Wrapf(
+ err,
+ `net.ListenUDP failed for network "%s", address "%s"`,
+ network, resolvedAddr.String(),
+ )
+ }
+ port = l.LocalAddr().(*net.UDPAddr).Port
+ _ = l.Close()
+ return
+}
+
+// GetFreePorts retrieves and returns specified number of ports that are free.
+func GetFreePorts(count int) (ports []int, err error) {
+ var (
+ network = `udp`
+ address = `:0`
+ )
+ for i := 0; i < count; i++ {
+ resolvedAddr, err := net.ResolveUDPAddr(network, address)
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.ResolveUDPAddr failed for network "%s", address "%s"`,
+ network, address,
+ )
+ }
+ l, err := net.ListenUDP(network, resolvedAddr)
+ if err != nil {
+ return nil, gerror.Wrapf(
+ err,
+ `net.ListenUDP failed for network "%s", address "%s"`,
+ network, resolvedAddr.String(),
+ )
+ }
+ ports = append(ports, l.LocalAddr().(*net.UDPAddr).Port)
+ _ = l.Close()
+ }
+ return ports, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_server.go
new file mode 100644
index 000000000000..5bfd5ab5d009
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/net/gudp/gudp_server.go
@@ -0,0 +1,102 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gudp
+
+import (
+ "net"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ defaultServer = "default"
+)
+
+// Server is the UDP server.
+type Server struct {
+ conn *Conn // UDP server connection object.
+ address string // UDP server listening address.
+ handler func(*Conn) // Handler for UDP connection.
+}
+
+var (
+ // serverMapping is used for instance name to its UDP server mappings.
+ serverMapping = gmap.NewStrAnyMap(true)
+)
+
+// GetServer creates and returns a UDP server instance with given name.
+func GetServer(name ...interface{}) *Server {
+ serverName := defaultServer
+ if len(name) > 0 && name[0] != "" {
+ serverName = gconv.String(name[0])
+ }
+ if s := serverMapping.Get(serverName); s != nil {
+ return s.(*Server)
+ }
+ s := NewServer("", nil)
+ serverMapping.Set(serverName, s)
+ return s
+}
+
+// NewServer creates and returns a UDP server.
+// The optional parameter `name` is used to specify its name, which can be used for
+// GetServer function to retrieve its instance.
+func NewServer(address string, handler func(*Conn), name ...string) *Server {
+ s := &Server{
+ address: address,
+ handler: handler,
+ }
+ if len(name) > 0 && name[0] != "" {
+ serverMapping.Set(name[0], s)
+ }
+ return s
+}
+
+// SetAddress sets the server address for UDP server.
+func (s *Server) SetAddress(address string) {
+ s.address = address
+}
+
+// SetHandler sets the connection handler for UDP server.
+func (s *Server) SetHandler(handler func(*Conn)) {
+ s.handler = handler
+}
+
+// Close closes the connection.
+// It will make server shutdowns immediately.
+func (s *Server) Close() (err error) {
+ err = s.conn.Close()
+ if err != nil {
+ err = gerror.Wrap(err, "connection failed")
+ }
+ return
+}
+
+// Run starts listening UDP connection.
+func (s *Server) Run() error {
+ if s.handler == nil {
+ err := gerror.NewCode(gcode.CodeMissingConfiguration, "start running failed: socket handler not defined")
+ return err
+ }
+ addr, err := net.ResolveUDPAddr("udp", s.address)
+ if err != nil {
+ err = gerror.Wrapf(err, `net.ResolveUDPAddr failed for address "%s"`, s.address)
+ return err
+ }
+ conn, err := net.ListenUDP("udp", addr)
+ if err != nil {
+ err = gerror.Wrapf(err, `net.ListenUDP failed for address "%s"`, s.address)
+ return err
+ }
+ s.conn = NewConnByNetConn(conn)
+ s.handler(s.conn)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache.go
new file mode 100644
index 000000000000..75016fde5146
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache.go
@@ -0,0 +1,240 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcache provides kinds of cache management for process.
+//
+// It provides a concurrent-safe in-memory cache adapter for process in default.
+package gcache
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// Func is the cache function that calculates and returns the value.
+type Func func(ctx context.Context) (value interface{}, err error)
+
+// Default cache object.
+var defaultCache = New()
+
+// Set sets cache with `key`-`value` pair, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error {
+ return defaultCache.Set(ctx, key, value, duration)
+}
+
+// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func SetMap(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error {
+ return defaultCache.SetMap(ctx, data, duration)
+}
+
+// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`
+// if `key` does not exist in the cache. It returns true the `key` does not exist in the
+// cache, and it sets `value` successfully to the cache, or else it returns false.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+func SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) {
+ return defaultCache.SetIfNotExist(ctx, key, value, duration)
+}
+
+// SetIfNotExistFunc sets `key` with result of function `f` and returns true
+// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+//
+// The parameter `value` can be type of `func() interface{}`, but it does nothing if its
+// result is nil.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+func SetIfNotExistFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (bool, error) {
+ return defaultCache.SetIfNotExistFunc(ctx, key, f, duration)
+}
+
+// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true
+// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+//
+// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within
+// writing mutex lock for concurrent safety purpose.
+func SetIfNotExistFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (bool, error) {
+ return defaultCache.SetIfNotExistFuncLock(ctx, key, f, duration)
+}
+
+// Get retrieves and returns the associated value of given `key`.
+// It returns nil if it does not exist, or its value is nil, or it's expired.
+// If you would like to check if the `key` exists in the cache, it's better using function Contains.
+func Get(ctx context.Context, key interface{}) (*gvar.Var, error) {
+ return defaultCache.Get(ctx, key)
+}
+
+// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and
+// returns `value` if `key` does not exist in the cache. The key-value pair expires
+// after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+func GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (*gvar.Var, error) {
+ return defaultCache.GetOrSet(ctx, key, value, duration)
+}
+
+// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of
+// function `f` and returns its result if `key` does not exist in the cache. The key-value
+// pair expires after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+func GetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (*gvar.Var, error) {
+ return defaultCache.GetOrSetFunc(ctx, key, f, duration)
+}
+
+// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of
+// function `f` and returns its result if `key` does not exist in the cache. The key-value
+// pair expires after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+//
+// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within
+// writing mutex lock for concurrent safety purpose.
+func GetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (*gvar.Var, error) {
+ return defaultCache.GetOrSetFuncLock(ctx, key, f, duration)
+}
+
+// Contains checks and returns true if `key` exists in the cache, or else returns false.
+func Contains(ctx context.Context, key interface{}) (bool, error) {
+ return defaultCache.Contains(ctx, key)
+}
+
+// GetExpire retrieves and returns the expiration of `key` in the cache.
+//
+// Note that,
+// It returns 0 if the `key` does not expire.
+// It returns -1 if the `key` does not exist in the cache.
+func GetExpire(ctx context.Context, key interface{}) (time.Duration, error) {
+ return defaultCache.GetExpire(ctx, key)
+}
+
+// Remove deletes one or more keys from cache, and returns its value.
+// If multiple keys are given, it returns the value of the last deleted item.
+func Remove(ctx context.Context, keys ...interface{}) (value *gvar.Var, err error) {
+ return defaultCache.Remove(ctx, keys...)
+}
+
+// Removes deletes `keys` in the cache.
+func Removes(ctx context.Context, keys []interface{}) error {
+ return defaultCache.Removes(ctx, keys)
+}
+
+// Update updates the value of `key` without changing its expiration and returns the old value.
+// The returned value `exist` is false if the `key` does not exist in the cache.
+//
+// It deletes the `key` if given `value` is nil.
+// It does nothing if `key` does not exist in the cache.
+func Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) {
+ return defaultCache.Update(ctx, key, value)
+}
+
+// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.
+//
+// It returns -1 and does nothing if the `key` does not exist in the cache.
+// It deletes the `key` if `duration` < 0.
+func UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) {
+ return defaultCache.UpdateExpire(ctx, key, duration)
+}
+
+// Size returns the number of items in the cache.
+func Size(ctx context.Context) (int, error) {
+ return defaultCache.Size(ctx)
+}
+
+// Data returns a copy of all key-value pairs in the cache as map type.
+// Note that this function may lead lots of memory usage, you can implement this function
+// if necessary.
+func Data(ctx context.Context) (map[interface{}]interface{}, error) {
+ return defaultCache.Data(ctx)
+}
+
+// Keys returns all keys in the cache as slice.
+func Keys(ctx context.Context) ([]interface{}, error) {
+ return defaultCache.Keys(ctx)
+}
+
+// KeyStrings returns all keys in the cache as string slice.
+func KeyStrings(ctx context.Context) ([]string, error) {
+ return defaultCache.KeyStrings(ctx)
+}
+
+// Values returns all values in the cache as slice.
+func Values(ctx context.Context) ([]interface{}, error) {
+ return defaultCache.Values(ctx)
+}
+
+// MustGet acts like Get, but it panics if any error occurs.
+func MustGet(ctx context.Context, key interface{}) *gvar.Var {
+ return defaultCache.MustGet(ctx, key)
+}
+
+// MustGetOrSet acts like GetOrSet, but it panics if any error occurs.
+func MustGetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) *gvar.Var {
+ return defaultCache.MustGetOrSet(ctx, key, value, duration)
+}
+
+// MustGetOrSetFunc acts like GetOrSetFunc, but it panics if any error occurs.
+func MustGetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) *gvar.Var {
+ return defaultCache.MustGetOrSet(ctx, key, f, duration)
+}
+
+// MustGetOrSetFuncLock acts like GetOrSetFuncLock, but it panics if any error occurs.
+func MustGetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) *gvar.Var {
+ return defaultCache.MustGetOrSetFuncLock(ctx, key, f, duration)
+}
+
+// MustContains acts like Contains, but it panics if any error occurs.
+func MustContains(ctx context.Context, key interface{}) bool {
+ return defaultCache.MustContains(ctx, key)
+}
+
+// MustGetExpire acts like GetExpire, but it panics if any error occurs.
+func MustGetExpire(ctx context.Context, key interface{}) time.Duration {
+ return defaultCache.MustGetExpire(ctx, key)
+}
+
+// MustSize acts like Size, but it panics if any error occurs.
+func MustSize(ctx context.Context) int {
+ return defaultCache.MustSize(ctx)
+}
+
+// MustData acts like Data, but it panics if any error occurs.
+func MustData(ctx context.Context) map[interface{}]interface{} {
+ return defaultCache.MustData(ctx)
+}
+
+// MustKeys acts like Keys, but it panics if any error occurs.
+func MustKeys(ctx context.Context) []interface{} {
+ return defaultCache.MustKeys(ctx)
+}
+
+// MustKeyStrings acts like KeyStrings, but it panics if any error occurs.
+func MustKeyStrings(ctx context.Context) []string {
+ return defaultCache.MustKeyStrings(ctx)
+}
+
+// MustValues acts like Values, but it panics if any error occurs.
+func MustValues(ctx context.Context) []interface{} {
+ return defaultCache.MustValues(ctx)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter.go
new file mode 100644
index 000000000000..3c98011ba6fd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter.go
@@ -0,0 +1,142 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// Adapter is the core adapter for cache features implements.
+//
+// Note that the implementer itself should guarantee the concurrent safety of these functions.
+type Adapter interface {
+ // Set sets cache with `key`-`value` pair, which is expired after `duration`.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+ Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error
+
+ // SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+ SetMap(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error
+
+ // SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`
+ // if `key` does not exist in the cache. It returns true the `key` does not exist in the
+ // cache, and it sets `value` successfully to the cache, or else it returns false.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the `key` if `duration` < 0 or given `value` is nil.
+ SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (ok bool, err error)
+
+ // SetIfNotExistFunc sets `key` with result of function `f` and returns true
+ // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+ //
+ // The parameter `value` can be type of `func() interface{}`, but it does nothing if its
+ // result is nil.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the `key` if `duration` < 0 or given `value` is nil.
+ SetIfNotExistFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (ok bool, err error)
+
+ // SetIfNotExistFuncLock sets `key` with result of function `f` and returns true
+ // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the `key` if `duration` < 0 or given `value` is nil.
+ //
+ // Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within
+ // writing mutex lock for concurrent safety purpose.
+ SetIfNotExistFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (ok bool, err error)
+
+ // Get retrieves and returns the associated value of given `key`.
+ // It returns nil if it does not exist, or its value is nil, or it's expired.
+ // If you would like to check if the `key` exists in the cache, it's better using function Contains.
+ Get(ctx context.Context, key interface{}) (*gvar.Var, error)
+
+ // GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and
+ // returns `value` if `key` does not exist in the cache. The key-value pair expires
+ // after `duration`.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+ // if `value` is a function and the function result is nil.
+ GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error)
+
+ // GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of
+ // function `f` and returns its result if `key` does not exist in the cache. The key-value
+ // pair expires after `duration`.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+ // if `value` is a function and the function result is nil.
+ GetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (result *gvar.Var, err error)
+
+ // GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of
+ // function `f` and returns its result if `key` does not exist in the cache. The key-value
+ // pair expires after `duration`.
+ //
+ // It does not expire if `duration` == 0.
+ // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+ // if `value` is a function and the function result is nil.
+ //
+ // Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within
+ // writing mutex lock for concurrent safety purpose.
+ GetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (result *gvar.Var, err error)
+
+ // Contains checks and returns true if `key` exists in the cache, or else returns false.
+ Contains(ctx context.Context, key interface{}) (bool, error)
+
+ // Size returns the number of items in the cache.
+ Size(ctx context.Context) (size int, err error)
+
+ // Data returns a copy of all key-value pairs in the cache as map type.
+ // Note that this function may lead lots of memory usage, you can implement this function
+ // if necessary.
+ Data(ctx context.Context) (data map[interface{}]interface{}, err error)
+
+ // Keys returns all keys in the cache as slice.
+ Keys(ctx context.Context) (keys []interface{}, err error)
+
+ // Values returns all values in the cache as slice.
+ Values(ctx context.Context) (values []interface{}, err error)
+
+ // Update updates the value of `key` without changing its expiration and returns the old value.
+ // The returned value `exist` is false if the `key` does not exist in the cache.
+ //
+ // It deletes the `key` if given `value` is nil.
+ // It does nothing if `key` does not exist in the cache.
+ Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error)
+
+ // UpdateExpire updates the expiration of `key` and returns the old expiration duration value.
+ //
+ // It returns -1 and does nothing if the `key` does not exist in the cache.
+ // It deletes the `key` if `duration` < 0.
+ UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error)
+
+ // GetExpire retrieves and returns the expiration of `key` in the cache.
+ //
+ // Note that,
+ // It returns 0 if the `key` does not expire.
+ // It returns -1 if the `key` does not exist in the cache.
+ GetExpire(ctx context.Context, key interface{}) (time.Duration, error)
+
+ // Remove deletes one or more keys from cache, and returns its value.
+ // If multiple keys are given, it returns the value of the last deleted item.
+ Remove(ctx context.Context, keys ...interface{}) (lastValue *gvar.Var, err error)
+
+ // Clear clears all data of the cache.
+ // Note that this function is sensitive and should be carefully used.
+ Clear(ctx context.Context) error
+
+ // Close closes the cache if necessary.
+ Close(ctx context.Context) error
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory.go
new file mode 100644
index 000000000000..3bb001b4b710
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory.go
@@ -0,0 +1,477 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "math"
+ "time"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gtimer"
+)
+
+// AdapterMemory is an adapter implements using memory.
+type AdapterMemory struct {
+ // cap limits the size of the cache pool.
+ // If the size of the cache exceeds the cap,
+ // the cache expiration process performs according to the LRU algorithm.
+ // It is 0 in default which means no limits.
+ cap int
+ data *adapterMemoryData // data is the underlying cache data which is stored in a hash table.
+ expireTimes *adapterMemoryExpireTimes // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting.
+ expireSets *adapterMemoryExpireSets // expireSets is the expiring timestamp to its key set mapping, which is used for quick indexing and deleting.
+ lru *adapterMemoryLru // lru is the LRU manager, which is enabled when attribute cap > 0.
+ lruGetList *glist.List // lruGetList is the LRU history according to Get function.
+ eventList *glist.List // eventList is the asynchronous event list for internal data synchronization.
+ closed *gtype.Bool // closed controls the cache closed or not.
+}
+
+// Internal cache item.
+type adapterMemoryItem struct {
+ v interface{} // Value.
+ e int64 // Expire timestamp in milliseconds.
+}
+
+// Internal event item.
+type adapterMemoryEvent struct {
+ k interface{} // Key.
+ e int64 // Expire time in milliseconds.
+}
+
+const (
+ // defaultMaxExpire is the default expire time for no expiring items.
+ // It equals to math.MaxInt64/1000000.
+ defaultMaxExpire = 9223372036854
+)
+
+// NewAdapterMemory creates and returns a new memory cache object.
+func NewAdapterMemory(lruCap ...int) Adapter {
+ c := &AdapterMemory{
+ data: newAdapterMemoryData(),
+ lruGetList: glist.New(true),
+ expireTimes: newAdapterMemoryExpireTimes(),
+ expireSets: newAdapterMemoryExpireSets(),
+ eventList: glist.New(true),
+ closed: gtype.NewBool(),
+ }
+ if len(lruCap) > 0 {
+ c.cap = lruCap[0]
+ c.lru = newMemCacheLru(c)
+ }
+ return c
+}
+
+// Set sets cache with `key`-`value` pair, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func (c *AdapterMemory) Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error {
+ expireTime := c.getInternalExpire(duration)
+ c.data.Set(key, adapterMemoryItem{
+ v: value,
+ e: expireTime,
+ })
+ c.eventList.PushBack(&adapterMemoryEvent{
+ k: key,
+ e: expireTime,
+ })
+ return nil
+}
+
+// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func (c *AdapterMemory) SetMap(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error {
+ var (
+ expireTime = c.getInternalExpire(duration)
+ err = c.data.SetMap(data, expireTime)
+ )
+ if err != nil {
+ return err
+ }
+ for k := range data {
+ c.eventList.PushBack(&adapterMemoryEvent{
+ k: k,
+ e: expireTime,
+ })
+ }
+ return nil
+}
+
+// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`
+// if `key` does not exist in the cache. It returns true the `key` does not exist in the
+// cache, and it sets `value` successfully to the cache, or else it returns false.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+func (c *AdapterMemory) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) {
+ isContained, err := c.Contains(ctx, key)
+ if err != nil {
+ return false, err
+ }
+ if !isContained {
+ if _, err = c.doSetWithLockCheck(ctx, key, value, duration); err != nil {
+ return false, err
+ }
+ return true, nil
+ }
+ return false, nil
+}
+
+// SetIfNotExistFunc sets `key` with result of function `f` and returns true
+// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+//
+// The parameter `value` can be type of `func() interface{}`, but it does nothing if its
+// result is nil.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+func (c *AdapterMemory) SetIfNotExistFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (bool, error) {
+ isContained, err := c.Contains(ctx, key)
+ if err != nil {
+ return false, err
+ }
+ if !isContained {
+ value, err := f(ctx)
+ if err != nil {
+ return false, err
+ }
+ if _, err = c.doSetWithLockCheck(ctx, key, value, duration); err != nil {
+ return false, err
+ }
+ return true, nil
+ }
+ return false, nil
+}
+
+// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true
+// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+//
+// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within
+// writing mutex lock for concurrent safety purpose.
+func (c *AdapterMemory) SetIfNotExistFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (bool, error) {
+ isContained, err := c.Contains(ctx, key)
+ if err != nil {
+ return false, err
+ }
+ if !isContained {
+ if _, err = c.doSetWithLockCheck(ctx, key, f, duration); err != nil {
+ return false, err
+ }
+ return true, nil
+ }
+ return false, nil
+}
+
+// Get retrieves and returns the associated value of given `key`.
+// It returns nil if it does not exist, or its value is nil, or it's expired.
+// If you would like to check if the `key` exists in the cache, it's better using function Contains.
+func (c *AdapterMemory) Get(ctx context.Context, key interface{}) (*gvar.Var, error) {
+ item, ok := c.data.Get(key)
+ if ok && !item.IsExpired() {
+ // Adding to LRU history if LRU feature is enabled.
+ if c.cap > 0 {
+ c.lruGetList.PushBack(key)
+ }
+ return gvar.New(item.v), nil
+ }
+ return nil, nil
+}
+
+// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and
+// returns `value` if `key` does not exist in the cache. The key-value pair expires
+// after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+func (c *AdapterMemory) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (*gvar.Var, error) {
+ v, err := c.Get(ctx, key)
+ if err != nil {
+ return nil, err
+ }
+ if v == nil {
+ return c.doSetWithLockCheck(ctx, key, value, duration)
+ } else {
+ return v, nil
+ }
+}
+
+// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of
+// function `f` and returns its result if `key` does not exist in the cache. The key-value
+// pair expires after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+func (c *AdapterMemory) GetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (*gvar.Var, error) {
+ v, err := c.Get(ctx, key)
+ if err != nil {
+ return nil, err
+ }
+ if v == nil {
+ value, err := f(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if value == nil {
+ return nil, nil
+ }
+ return c.doSetWithLockCheck(ctx, key, value, duration)
+ } else {
+ return v, nil
+ }
+}
+
+// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of
+// function `f` and returns its result if `key` does not exist in the cache. The key-value
+// pair expires after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+//
+// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within
+// writing mutex lock for concurrent safety purpose.
+func (c *AdapterMemory) GetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (*gvar.Var, error) {
+ v, err := c.Get(ctx, key)
+ if err != nil {
+ return nil, err
+ }
+ if v == nil {
+ return c.doSetWithLockCheck(ctx, key, f, duration)
+ } else {
+ return v, nil
+ }
+}
+
+// Contains checks and returns true if `key` exists in the cache, or else returns false.
+func (c *AdapterMemory) Contains(ctx context.Context, key interface{}) (bool, error) {
+ v, err := c.Get(ctx, key)
+ if err != nil {
+ return false, err
+ }
+ return v != nil, nil
+}
+
+// GetExpire retrieves and returns the expiration of `key` in the cache.
+//
+// Note that,
+// It returns 0 if the `key` does not expire.
+// It returns -1 if the `key` does not exist in the cache.
+func (c *AdapterMemory) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) {
+ if item, ok := c.data.Get(key); ok {
+ return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil
+ }
+ return -1, nil
+}
+
+// Remove deletes one or more keys from cache, and returns its value.
+// If multiple keys are given, it returns the value of the last deleted item.
+func (c *AdapterMemory) Remove(ctx context.Context, keys ...interface{}) (*gvar.Var, error) {
+ var removedKeys []interface{}
+ removedKeys, value, err := c.data.Remove(keys...)
+ if err != nil {
+ return nil, err
+ }
+ for _, key := range removedKeys {
+ c.eventList.PushBack(&adapterMemoryEvent{
+ k: key,
+ e: gtime.TimestampMilli() - 1000000,
+ })
+ }
+ return gvar.New(value), nil
+}
+
+// Update updates the value of `key` without changing its expiration and returns the old value.
+// The returned value `exist` is false if the `key` does not exist in the cache.
+//
+// It deletes the `key` if given `value` is nil.
+// It does nothing if `key` does not exist in the cache.
+func (c *AdapterMemory) Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) {
+ v, exist, err := c.data.Update(key, value)
+ return gvar.New(v), exist, err
+}
+
+// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.
+//
+// It returns -1 and does nothing if the `key` does not exist in the cache.
+// It deletes the `key` if `duration` < 0.
+func (c *AdapterMemory) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) {
+ newExpireTime := c.getInternalExpire(duration)
+ oldDuration, err = c.data.UpdateExpire(key, newExpireTime)
+ if err != nil {
+ return
+ }
+ if oldDuration != -1 {
+ c.eventList.PushBack(&adapterMemoryEvent{
+ k: key,
+ e: newExpireTime,
+ })
+ }
+ return
+}
+
+// Size returns the size of the cache.
+func (c *AdapterMemory) Size(ctx context.Context) (size int, err error) {
+ return c.data.Size()
+}
+
+// Data returns a copy of all key-value pairs in the cache as map type.
+func (c *AdapterMemory) Data(ctx context.Context) (map[interface{}]interface{}, error) {
+ return c.data.Data()
+}
+
+// Keys returns all keys in the cache as slice.
+func (c *AdapterMemory) Keys(ctx context.Context) ([]interface{}, error) {
+ return c.data.Keys()
+}
+
+// Values returns all values in the cache as slice.
+func (c *AdapterMemory) Values(ctx context.Context) ([]interface{}, error) {
+ return c.data.Values()
+}
+
+// Clear clears all data of the cache.
+// Note that this function is sensitive and should be carefully used.
+func (c *AdapterMemory) Clear(ctx context.Context) error {
+ return c.data.Clear()
+}
+
+// Close closes the cache.
+func (c *AdapterMemory) Close(ctx context.Context) error {
+ if c.cap > 0 {
+ c.lru.Close()
+ }
+ c.closed.Set(true)
+ return nil
+}
+
+// doSetWithLockCheck sets cache with `key`-`value` pair if `key` does not exist in the
+// cache, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// The parameter `value` can be type of , but it does nothing if the
+// function result is nil.
+//
+// It doubly checks the `key` whether exists in the cache using mutex writing lock
+// before setting it to the cache.
+func (c *AdapterMemory) doSetWithLockCheck(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error) {
+ expireTimestamp := c.getInternalExpire(duration)
+ v, err := c.data.SetWithLock(ctx, key, value, expireTimestamp)
+ c.eventList.PushBack(&adapterMemoryEvent{k: key, e: expireTimestamp})
+ return gvar.New(v), err
+}
+
+// getInternalExpire converts and returns the expiration time with given expired duration in milliseconds.
+func (c *AdapterMemory) getInternalExpire(duration time.Duration) int64 {
+ if duration == 0 {
+ return defaultMaxExpire
+ } else {
+ return gtime.TimestampMilli() + duration.Nanoseconds()/1000000
+ }
+}
+
+// makeExpireKey groups the `expire` in milliseconds to its according seconds.
+func (c *AdapterMemory) makeExpireKey(expire int64) int64 {
+ return int64(math.Ceil(float64(expire/1000)+1) * 1000)
+}
+
+// syncEventAndClearExpired does the asynchronous task loop:
+// 1. Asynchronously process the data in the event list,
+// and synchronize the results to the `expireTimes` and `expireSets` properties.
+// 2. Clean up the expired key-value pair data.
+func (c *AdapterMemory) syncEventAndClearExpired(ctx context.Context) {
+ if c.closed.Val() {
+ gtimer.Exit()
+ return
+ }
+ var (
+ event *adapterMemoryEvent
+ oldExpireTime int64
+ newExpireTime int64
+ )
+ // ========================
+ // Data Synchronization.
+ // ========================
+ for {
+ v := c.eventList.PopFront()
+ if v == nil {
+ break
+ }
+ event = v.(*adapterMemoryEvent)
+ // Fetching the old expire set.
+ oldExpireTime = c.expireTimes.Get(event.k)
+ // Calculating the new expiration time set.
+ newExpireTime = c.makeExpireKey(event.e)
+ if newExpireTime != oldExpireTime {
+ c.expireSets.GetOrNew(newExpireTime).Add(event.k)
+ if oldExpireTime != 0 {
+ c.expireSets.GetOrNew(oldExpireTime).Remove(event.k)
+ }
+ // Updating the expired time for .
+ c.expireTimes.Set(event.k, newExpireTime)
+ }
+ // Adding the key the LRU history by writing operations.
+ if c.cap > 0 {
+ c.lru.Push(event.k)
+ }
+ }
+ // Processing expired keys from LRU.
+ if c.cap > 0 && c.lruGetList.Len() > 0 {
+ for {
+ if v := c.lruGetList.PopFront(); v != nil {
+ c.lru.Push(v)
+ } else {
+ break
+ }
+ }
+ }
+ // ========================
+ // Data Cleaning up.
+ // ========================
+ var (
+ expireSet *gset.Set
+ ek = c.makeExpireKey(gtime.TimestampMilli())
+ eks = []int64{ek - 1000, ek - 2000, ek - 3000, ek - 4000, ek - 5000}
+ )
+ for _, expireTime := range eks {
+ if expireSet = c.expireSets.Get(expireTime); expireSet != nil {
+ // Iterating the set to delete all keys in it.
+ expireSet.Iterator(func(key interface{}) bool {
+ c.clearByKey(key)
+ return true
+ })
+ // Deleting the set after all of its keys are deleted.
+ c.expireSets.Delete(expireTime)
+ }
+ }
+}
+
+// clearByKey deletes the key-value pair with given `key`.
+// The parameter `force` specifies whether doing this deleting forcibly.
+func (c *AdapterMemory) clearByKey(key interface{}, force ...bool) {
+ // Doubly check before really deleting it from cache.
+ c.data.DeleteWithDoubleCheck(key, force...)
+
+ // Deleting its expiration time from `expireTimes`.
+ c.expireTimes.Delete(key)
+
+ // Deleting it from LRU.
+ if c.cap > 0 {
+ c.lru.Remove(key)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_data.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_data.go
new file mode 100644
index 000000000000..941339d0f05c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_data.go
@@ -0,0 +1,206 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/gogf/gf/v2/os/gtime"
+)
+
+type adapterMemoryData struct {
+ mu sync.RWMutex // dataMu ensures the concurrent safety of underlying data map.
+ data map[interface{}]adapterMemoryItem // data is the underlying cache data which is stored in a hash table.
+}
+
+func newAdapterMemoryData() *adapterMemoryData {
+ return &adapterMemoryData{
+ data: make(map[interface{}]adapterMemoryItem),
+ }
+}
+
+// Update updates the value of `key` without changing its expiration and returns the old value.
+// The returned value `exist` is false if the `key` does not exist in the cache.
+//
+// It deletes the `key` if given `value` is nil.
+// It does nothing if `key` does not exist in the cache.
+func (d *adapterMemoryData) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if item, ok := d.data[key]; ok {
+ d.data[key] = adapterMemoryItem{
+ v: value,
+ e: item.e,
+ }
+ return item.v, true, nil
+ }
+ return nil, false, nil
+}
+
+// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.
+//
+// It returns -1 and does nothing if the `key` does not exist in the cache.
+// It deletes the `key` if `duration` < 0.
+func (d *adapterMemoryData) UpdateExpire(key interface{}, expireTime int64) (oldDuration time.Duration, err error) {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if item, ok := d.data[key]; ok {
+ d.data[key] = adapterMemoryItem{
+ v: item.v,
+ e: expireTime,
+ }
+ return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil
+ }
+ return -1, nil
+}
+
+// Remove deletes the one or more keys from cache, and returns its value.
+// If multiple keys are given, it returns the value of the deleted last item.
+func (d *adapterMemoryData) Remove(keys ...interface{}) (removedKeys []interface{}, value interface{}, err error) {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ removedKeys = make([]interface{}, 0)
+ for _, key := range keys {
+ item, ok := d.data[key]
+ if ok {
+ value = item.v
+ delete(d.data, key)
+ removedKeys = append(removedKeys, key)
+ }
+ }
+ return removedKeys, value, nil
+}
+
+// Data returns a copy of all key-value pairs in the cache as map type.
+func (d *adapterMemoryData) Data() (map[interface{}]interface{}, error) {
+ d.mu.RLock()
+ m := make(map[interface{}]interface{}, len(d.data))
+ for k, v := range d.data {
+ if !v.IsExpired() {
+ m[k] = v.v
+ }
+ }
+ d.mu.RUnlock()
+ return m, nil
+}
+
+// Keys returns all keys in the cache as slice.
+func (d *adapterMemoryData) Keys() ([]interface{}, error) {
+ d.mu.RLock()
+ var (
+ index = 0
+ keys = make([]interface{}, len(d.data))
+ )
+ for k, v := range d.data {
+ if !v.IsExpired() {
+ keys[index] = k
+ index++
+ }
+ }
+ d.mu.RUnlock()
+ return keys, nil
+}
+
+// Values returns all values in the cache as slice.
+func (d *adapterMemoryData) Values() ([]interface{}, error) {
+ d.mu.RLock()
+ var (
+ index = 0
+ values = make([]interface{}, len(d.data))
+ )
+ for _, v := range d.data {
+ if !v.IsExpired() {
+ values[index] = v.v
+ index++
+ }
+ }
+ d.mu.RUnlock()
+ return values, nil
+}
+
+// Size returns the size of the cache.
+func (d *adapterMemoryData) Size() (size int, err error) {
+ d.mu.RLock()
+ size = len(d.data)
+ d.mu.RUnlock()
+ return size, nil
+}
+
+// Clear clears all data of the cache.
+// Note that this function is sensitive and should be carefully used.
+func (d *adapterMemoryData) Clear() error {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ d.data = make(map[interface{}]adapterMemoryItem)
+ return nil
+}
+
+func (d *adapterMemoryData) Get(key interface{}) (item adapterMemoryItem, ok bool) {
+ d.mu.RLock()
+ item, ok = d.data[key]
+ d.mu.RUnlock()
+ return
+}
+
+func (d *adapterMemoryData) Set(key interface{}, value adapterMemoryItem) {
+ d.mu.Lock()
+ d.data[key] = value
+ d.mu.Unlock()
+}
+
+// SetMap batch sets cache with key-value pairs by `data`, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func (d *adapterMemoryData) SetMap(data map[interface{}]interface{}, expireTime int64) error {
+ d.mu.Lock()
+ for k, v := range data {
+ d.data[k] = adapterMemoryItem{
+ v: v,
+ e: expireTime,
+ }
+ }
+ d.mu.Unlock()
+ return nil
+}
+
+func (d *adapterMemoryData) SetWithLock(ctx context.Context, key interface{}, value interface{}, expireTimestamp int64) (interface{}, error) {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ var (
+ err error
+ )
+ if v, ok := d.data[key]; ok && !v.IsExpired() {
+ return v.v, nil
+ }
+ f, ok := value.(Func)
+ if !ok {
+ // Compatible with raw function value.
+ f, ok = value.(func(ctx context.Context) (value interface{}, err error))
+ }
+ if ok {
+ if value, err = f(ctx); err != nil {
+ return nil, err
+ }
+ if value == nil {
+ return nil, nil
+ }
+ }
+ d.data[key] = adapterMemoryItem{v: value, e: expireTimestamp}
+ return value, nil
+}
+
+func (d *adapterMemoryData) DeleteWithDoubleCheck(key interface{}, force ...bool) {
+ d.mu.Lock()
+ // Doubly check before really deleting it from cache.
+ if item, ok := d.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) {
+ delete(d.data, key)
+ }
+ d.mu.Unlock()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_expire_sets.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_expire_sets.go
new file mode 100644
index 000000000000..b49678c7c222
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_expire_sets.go
@@ -0,0 +1,52 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "sync"
+
+ "github.com/gogf/gf/v2/container/gset"
+)
+
+type adapterMemoryExpireSets struct {
+ mu sync.RWMutex // expireSetMu ensures the concurrent safety of expireSets map.
+ expireSets map[int64]*gset.Set // expireSets is the expiring timestamp to its key set mapping, which is used for quick indexing and deleting.
+}
+
+func newAdapterMemoryExpireSets() *adapterMemoryExpireSets {
+ return &adapterMemoryExpireSets{
+ expireSets: make(map[int64]*gset.Set),
+ }
+}
+
+func (d *adapterMemoryExpireSets) Get(key int64) (result *gset.Set) {
+ d.mu.RLock()
+ result = d.expireSets[key]
+ d.mu.RUnlock()
+ return
+}
+
+func (d *adapterMemoryExpireSets) GetOrNew(key int64) (result *gset.Set) {
+ if result = d.Get(key); result != nil {
+ return
+ }
+ d.mu.Lock()
+ if es, ok := d.expireSets[key]; ok {
+ result = es
+ } else {
+ result = gset.New(true)
+ d.expireSets[key] = result
+ }
+ d.mu.Unlock()
+ return
+}
+
+func (d *adapterMemoryExpireSets) Delete(key int64) {
+ d.mu.Lock()
+ delete(d.expireSets, key)
+ d.mu.Unlock()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_expire_times.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_expire_times.go
new file mode 100644
index 000000000000..af3d4b41933f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_expire_times.go
@@ -0,0 +1,41 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "sync"
+)
+
+type adapterMemoryExpireTimes struct {
+ mu sync.RWMutex // expireTimeMu ensures the concurrent safety of expireTimes map.
+ expireTimes map[interface{}]int64 // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting.
+}
+
+func newAdapterMemoryExpireTimes() *adapterMemoryExpireTimes {
+ return &adapterMemoryExpireTimes{
+ expireTimes: make(map[interface{}]int64),
+ }
+}
+
+func (d *adapterMemoryExpireTimes) Get(key interface{}) (value int64) {
+ d.mu.RLock()
+ value = d.expireTimes[key]
+ d.mu.RUnlock()
+ return
+}
+
+func (d *adapterMemoryExpireTimes) Set(key interface{}, value int64) {
+ d.mu.Lock()
+ d.expireTimes[key] = value
+ d.mu.Unlock()
+}
+
+func (d *adapterMemoryExpireTimes) Delete(key interface{}) {
+ d.mu.Lock()
+ delete(d.expireTimes, key)
+ d.mu.Unlock()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_item.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_item.go
new file mode 100644
index 000000000000..5a7862cae7e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_item.go
@@ -0,0 +1,19 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "github.com/gogf/gf/v2/os/gtime"
+)
+
+// IsExpired checks whether `item` is expired.
+func (item *adapterMemoryItem) IsExpired() bool {
+ // Note that it should use greater than or equal judgement here
+ // imagining that the cache time is only 1 millisecond.
+
+ return item.e < gtime.TimestampMilli()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_lru.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_lru.go
new file mode 100644
index 000000000000..cf478996c9c9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_memory_lru.go
@@ -0,0 +1,112 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/os/gtimer"
+)
+
+// LRU cache object.
+// It uses list.List from stdlib for its underlying doubly linked list.
+type adapterMemoryLru struct {
+ cache *AdapterMemory // Parent cache object.
+ data *gmap.Map // Key mapping to the item of the list.
+ list *glist.List // Key list.
+ rawList *glist.List // History for key adding.
+ closed *gtype.Bool // Closed or not.
+}
+
+// newMemCacheLru creates and returns a new LRU object.
+func newMemCacheLru(cache *AdapterMemory) *adapterMemoryLru {
+ lru := &adapterMemoryLru{
+ cache: cache,
+ data: gmap.New(true),
+ list: glist.New(true),
+ rawList: glist.New(true),
+ closed: gtype.NewBool(),
+ }
+ gtimer.AddSingleton(context.Background(), time.Second, lru.SyncAndClear)
+ return lru
+}
+
+// Close closes the LRU object.
+func (lru *adapterMemoryLru) Close() {
+ lru.closed.Set(true)
+}
+
+// Remove deletes the `key` FROM `lru`.
+func (lru *adapterMemoryLru) Remove(key interface{}) {
+ if v := lru.data.Get(key); v != nil {
+ lru.data.Remove(key)
+ lru.list.Remove(v.(*glist.Element))
+ }
+}
+
+// Size returns the size of `lru`.
+func (lru *adapterMemoryLru) Size() int {
+ return lru.data.Size()
+}
+
+// Push pushes `key` to the tail of `lru`.
+func (lru *adapterMemoryLru) Push(key interface{}) {
+ lru.rawList.PushBack(key)
+}
+
+// Pop deletes and returns the key from tail of `lru`.
+func (lru *adapterMemoryLru) Pop() interface{} {
+ if v := lru.list.PopBack(); v != nil {
+ lru.data.Remove(v)
+ return v
+ }
+ return nil
+}
+
+// Print is used for test only.
+// func (lru *adapterMemoryLru) Print() {
+// for _, v := range lru.list.FrontAll() {
+// fmt.Printf("%v ", v)
+// }
+// fmt.Println()
+// }
+
+// SyncAndClear synchronizes the keys from `rawList` to `list` and `data`
+// using Least Recently Used algorithm.
+func (lru *adapterMemoryLru) SyncAndClear(ctx context.Context) {
+ if lru.closed.Val() {
+ gtimer.Exit()
+ return
+ }
+ // Data synchronization.
+ var (
+ alreadyExistItem interface{}
+ )
+ for {
+ if rawListItem := lru.rawList.PopFront(); rawListItem != nil {
+ // Deleting the key from list.
+ if alreadyExistItem = lru.data.Get(rawListItem); alreadyExistItem != nil {
+ lru.list.Remove(alreadyExistItem.(*glist.Element))
+ }
+ // Pushing key to the head of the list
+ // and setting its list item to hash table for quick indexing.
+ lru.data.Set(rawListItem, lru.list.PushFront(rawListItem))
+ } else {
+ break
+ }
+ }
+ // Data cleaning up.
+ for i := lru.Size() - lru.cache.cap; i > 0; i-- {
+ if s := lru.Pop(); s != nil {
+ lru.cache.clearByKey(s, true)
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_redis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_redis.go
new file mode 100644
index 000000000000..2ee71388a91f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_adapter_redis.go
@@ -0,0 +1,437 @@
+// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/database/gredis"
+)
+
+// AdapterRedis is the gcache adapter implements using Redis server.
+type AdapterRedis struct {
+ redis *gredis.Redis
+}
+
+// NewAdapterRedis creates and returns a new memory cache object.
+func NewAdapterRedis(redis *gredis.Redis) Adapter {
+ return &AdapterRedis{
+ redis: redis,
+ }
+}
+
+// Set sets cache with `key`-`value` pair, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func (c *AdapterRedis) Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (err error) {
+ if value == nil || duration < 0 {
+ _, err = c.redis.Do(ctx, "DEL", key)
+ } else {
+ if duration == 0 {
+ _, err = c.redis.Do(ctx, "SET", key, value)
+ } else {
+ _, err = c.redis.Do(ctx, "SETEX", key, uint64(duration.Seconds()), value)
+ }
+ }
+ return err
+}
+
+// SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the keys of `data` if `duration` < 0 or given `value` is nil.
+func (c *AdapterRedis) SetMap(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error {
+ if len(data) == 0 {
+ return nil
+ }
+ // DEL.
+ if duration < 0 {
+ var (
+ index = 0
+ keys = make([]interface{}, len(data))
+ )
+ for k, _ := range data {
+ keys[index] = k
+ index += 1
+ }
+ _, err := c.redis.Do(ctx, "DEL", keys...)
+ if err != nil {
+ return err
+ }
+ }
+ if duration == 0 {
+ var (
+ index = 0
+ keyValues = make([]interface{}, len(data)*2)
+ )
+ for k, v := range data {
+ keyValues[index] = k
+ keyValues[index+1] = v
+ index += 2
+ }
+ _, err := c.redis.Do(ctx, "MSET", keyValues...)
+ if err != nil {
+ return err
+ }
+ }
+ if duration > 0 {
+ var err error
+ for k, v := range data {
+ if err = c.Set(ctx, k, v, duration); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration`
+// if `key` does not exist in the cache. It returns true the `key` does not exist in the
+// cache, and it sets `value` successfully to the cache, or else it returns false.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+func (c *AdapterRedis) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) {
+ var (
+ v *gvar.Var
+ err error
+ )
+ // Execute the function and retrieve the result.
+ f, ok := value.(Func)
+ if !ok {
+ // Compatible with raw function value.
+ f, ok = value.(func(ctx context.Context) (value interface{}, err error))
+ }
+ if ok {
+ if value, err = f(ctx); err != nil {
+ return false, err
+ }
+ }
+ // DEL.
+ if duration < 0 || value == nil {
+ if v, err = c.redis.Do(ctx, "DEL", key, value); err != nil {
+ return false, err
+ }
+ if v.Int() == 1 {
+ return true, err
+ } else {
+ return false, err
+ }
+ }
+ if v, err = c.redis.Do(ctx, "SETNX", key, value); err != nil {
+ return false, err
+ }
+ if v.Int() > 0 && duration > 0 {
+ // Set the expiration.
+ _, err = c.redis.Do(ctx, "EXPIRE", key, uint64(duration.Seconds()))
+ if err != nil {
+ return false, err
+ }
+ return true, err
+ }
+ return false, err
+}
+
+// SetIfNotExistFunc sets `key` with result of function `f` and returns true
+// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+//
+// The parameter `value` can be type of `func() interface{}`, but it does nothing if its
+// result is nil.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+func (c *AdapterRedis) SetIfNotExistFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (ok bool, err error) {
+ value, err := f(ctx)
+ if err != nil {
+ return false, err
+ }
+ return c.SetIfNotExist(ctx, key, value, duration)
+}
+
+// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true
+// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil.
+//
+// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within
+// writing mutex lock for concurrent safety purpose.
+func (c *AdapterRedis) SetIfNotExistFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (ok bool, err error) {
+ value, err := f(ctx)
+ if err != nil {
+ return false, err
+ }
+ return c.SetIfNotExist(ctx, key, value, duration)
+}
+
+// Get retrieves and returns the associated value of given .
+// It returns nil if it does not exist or its value is nil.
+func (c *AdapterRedis) Get(ctx context.Context, key interface{}) (*gvar.Var, error) {
+ return c.redis.Do(ctx, "GET", key)
+}
+
+// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and
+// returns `value` if `key` does not exist in the cache. The key-value pair expires
+// after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+func (c *AdapterRedis) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error) {
+ result, err = c.Get(ctx, key)
+ if err != nil {
+ return nil, err
+ }
+ if result == nil {
+ return gvar.New(value), c.Set(ctx, key, value, duration)
+ }
+ return
+}
+
+// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of
+// function `f` and returns its result if `key` does not exist in the cache. The key-value
+// pair expires after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+func (c *AdapterRedis) GetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (result *gvar.Var, err error) {
+ v, err := c.Get(ctx, key)
+ if err != nil {
+ return nil, err
+ }
+ if v == nil {
+ value, err := f(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if value == nil {
+ return nil, nil
+ }
+ return gvar.New(value), c.Set(ctx, key, value, duration)
+ } else {
+ return v, nil
+ }
+}
+
+// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of
+// function `f` and returns its result if `key` does not exist in the cache. The key-value
+// pair expires after `duration`.
+//
+// It does not expire if `duration` == 0.
+// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing
+// if `value` is a function and the function result is nil.
+//
+// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within
+// writing mutex lock for concurrent safety purpose.
+func (c *AdapterRedis) GetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (result *gvar.Var, err error) {
+ return c.GetOrSetFunc(ctx, key, f, duration)
+}
+
+// Contains checks and returns true if `key` exists in the cache, or else returns false.
+func (c *AdapterRedis) Contains(ctx context.Context, key interface{}) (bool, error) {
+ v, err := c.redis.Do(ctx, "EXISTS", key)
+ if err != nil {
+ return false, err
+ }
+ return v.Bool(), nil
+}
+
+// Size returns the number of items in the cache.
+func (c *AdapterRedis) Size(ctx context.Context) (size int, err error) {
+ v, err := c.redis.Do(ctx, "DBSIZE")
+ if err != nil {
+ return 0, err
+ }
+ return v.Int(), nil
+}
+
+// Data returns a copy of all key-value pairs in the cache as map type.
+// Note that this function may lead lots of memory usage, you can implement this function
+// if necessary.
+func (c *AdapterRedis) Data(ctx context.Context) (map[interface{}]interface{}, error) {
+ // Keys.
+ v, err := c.redis.Do(ctx, "KEYS", "*")
+ if err != nil {
+ return nil, err
+ }
+ keys := v.Slice()
+ // Values.
+ v, err = c.redis.Do(ctx, "MGET", keys...)
+ if err != nil {
+ return nil, err
+ }
+ values := v.Slice()
+ // Compose keys and values.
+ data := make(map[interface{}]interface{})
+ for i := 0; i < len(keys); i++ {
+ data[keys[i]] = values[i]
+ }
+ return data, nil
+}
+
+// Keys returns all keys in the cache as slice.
+func (c *AdapterRedis) Keys(ctx context.Context) ([]interface{}, error) {
+ v, err := c.redis.Do(ctx, "KEYS", "*")
+ if err != nil {
+ return nil, err
+ }
+ return v.Slice(), nil
+}
+
+// Values returns all values in the cache as slice.
+func (c *AdapterRedis) Values(ctx context.Context) ([]interface{}, error) {
+ // Keys.
+ v, err := c.redis.Do(ctx, "KEYS", "*")
+ if err != nil {
+ return nil, err
+ }
+ keys := v.Slice()
+ // Values.
+ v, err = c.redis.Do(ctx, "MGET", keys...)
+ if err != nil {
+ return nil, err
+ }
+ return v.Slice(), nil
+}
+
+// Update updates the value of `key` without changing its expiration and returns the old value.
+// The returned value `exist` is false if the `key` does not exist in the cache.
+//
+// It deletes the `key` if given `value` is nil.
+// It does nothing if `key` does not exist in the cache.
+func (c *AdapterRedis) Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) {
+ var (
+ v *gvar.Var
+ oldDuration time.Duration
+ )
+ // TTL.
+ v, err = c.redis.Do(ctx, "TTL", key)
+ if err != nil {
+ return
+ }
+ oldDuration = v.Duration()
+ if oldDuration == -2 {
+ // It does not exist.
+ return
+ }
+ // Check existence.
+ v, err = c.redis.Do(ctx, "GET", key)
+ if err != nil {
+ return
+ }
+ oldValue = v
+ // DEL.
+ if value == nil {
+ _, err = c.redis.Do(ctx, "DEL", key)
+ if err != nil {
+ return
+ }
+ return
+ }
+ // Update the value.
+ if oldDuration == -1 {
+ _, err = c.redis.Do(ctx, "SET", key, value)
+ } else {
+ oldDuration *= time.Second
+ _, err = c.redis.Do(ctx, "SETEX", key, uint64(oldDuration.Seconds()), value)
+ }
+ return oldValue, true, err
+}
+
+// UpdateExpire updates the expiration of `key` and returns the old expiration duration value.
+//
+// It returns -1 and does nothing if the `key` does not exist in the cache.
+// It deletes the `key` if `duration` < 0.
+func (c *AdapterRedis) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) {
+ var (
+ v *gvar.Var
+ )
+ // TTL.
+ v, err = c.redis.Do(ctx, "TTL", key)
+ if err != nil {
+ return
+ }
+ oldDuration = v.Duration()
+ if oldDuration == -2 {
+ // It does not exist.
+ oldDuration = -1
+ return
+ }
+ oldDuration *= time.Second
+ // DEL.
+ if duration < 0 {
+ _, err = c.redis.Do(ctx, "DEL", key)
+ return
+ }
+ // Update the expire.
+ if duration > 0 {
+ _, err = c.redis.Do(ctx, "EXPIRE", key, uint64(duration.Seconds()))
+ }
+ // No expire.
+ if duration == 0 {
+ v, err = c.redis.Do(ctx, "GET", key)
+ if err != nil {
+ return
+ }
+ _, err = c.redis.Do(ctx, "SET", key, v.Val())
+ }
+ return
+}
+
+// GetExpire retrieves and returns the expiration of `key` in the cache.
+//
+// Note that,
+// It returns 0 if the `key` does not expire.
+// It returns -1 if the `key` does not exist in the cache.
+func (c *AdapterRedis) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) {
+ v, err := c.redis.Do(ctx, "TTL", key)
+ if err != nil {
+ return 0, err
+ }
+ switch v.Int() {
+ case -1:
+ return 0, nil
+ case -2:
+ return -1, nil
+ default:
+ return v.Duration() * time.Second, nil
+ }
+}
+
+// Remove deletes the one or more keys from cache, and returns its value.
+// If multiple keys are given, it returns the value of the deleted last item.
+func (c *AdapterRedis) Remove(ctx context.Context, keys ...interface{}) (lastValue *gvar.Var, err error) {
+ if len(keys) == 0 {
+ return nil, nil
+ }
+ // Retrieves the last key value.
+ if lastValue, err = c.redis.Do(ctx, "GET", keys[len(keys)-1]); err != nil {
+ return nil, err
+ }
+ // Deletes all given keys.
+ _, err = c.redis.Do(ctx, "DEL", keys...)
+ return
+}
+
+// Clear clears all data of the cache.
+// Note that this function is sensitive and should be carefully used.
+// It uses `FLUSHDB` command in redis server, which might be disabled in server.
+func (c *AdapterRedis) Clear(ctx context.Context) (err error) {
+ // The "FLUSHDB" may not be available.
+ _, err = c.redis.Do(ctx, "FLUSHDB")
+ return
+}
+
+// Close closes the cache.
+func (c *AdapterRedis) Close(ctx context.Context) error {
+ // It does nothing.
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_cache.go
new file mode 100644
index 000000000000..9a039457c66d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_cache.go
@@ -0,0 +1,70 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/os/gtimer"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Cache struct.
+type Cache struct {
+ localAdapter
+}
+
+// localAdapter is alias of Adapter, for embedded attribute purpose only.
+type localAdapter = Adapter
+
+// New creates and returns a new cache object using default memory adapter.
+// Note that the LRU feature is only available using memory adapter.
+func New(lruCap ...int) *Cache {
+ memAdapter := NewAdapterMemory(lruCap...)
+ c := &Cache{
+ localAdapter: memAdapter,
+ }
+ // Here may be a "timer leak" if adapter is manually changed from memory adapter.
+ // Do not worry about this, as adapter is less changed, and it does nothing if it's not used.
+ gtimer.AddSingleton(context.Background(), time.Second, memAdapter.(*AdapterMemory).syncEventAndClearExpired)
+ return c
+}
+
+// NewWithAdapter creates and returns a Cache object with given Adapter implements.
+func NewWithAdapter(adapter Adapter) *Cache {
+ return &Cache{
+ localAdapter: adapter,
+ }
+}
+
+// SetAdapter changes the adapter for this cache.
+// Be very note that, this setting function is not concurrent-safe, which means you should not call
+// this setting function concurrently in multiple goroutines.
+func (c *Cache) SetAdapter(adapter Adapter) {
+ c.localAdapter = adapter
+}
+
+// GetAdapter returns the adapter that is set in current Cache.
+func (c *Cache) GetAdapter() Adapter {
+ return c.localAdapter
+}
+
+// Removes deletes `keys` in the cache.
+func (c *Cache) Removes(ctx context.Context, keys []interface{}) error {
+ _, err := c.Remove(ctx, keys...)
+ return err
+}
+
+// KeyStrings returns all keys in the cache as string slice.
+func (c *Cache) KeyStrings(ctx context.Context) ([]string, error) {
+ keys, err := c.Keys(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return gconv.Strings(keys), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_cache_must.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_cache_must.go
new file mode 100644
index 000000000000..65961a0018c9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcache/gcache_cache_must.go
@@ -0,0 +1,113 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcache
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gvar"
+)
+
+// MustGet acts like Get, but it panics if any error occurs.
+func (c *Cache) MustGet(ctx context.Context, key interface{}) *gvar.Var {
+ v, err := c.Get(ctx, key)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustGetOrSet acts like GetOrSet, but it panics if any error occurs.
+func (c *Cache) MustGetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) *gvar.Var {
+ v, err := c.GetOrSet(ctx, key, value, duration)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustGetOrSetFunc acts like GetOrSetFunc, but it panics if any error occurs.
+func (c *Cache) MustGetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) *gvar.Var {
+ v, err := c.GetOrSetFunc(ctx, key, f, duration)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustGetOrSetFuncLock acts like GetOrSetFuncLock, but it panics if any error occurs.
+func (c *Cache) MustGetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) *gvar.Var {
+ v, err := c.GetOrSetFuncLock(ctx, key, f, duration)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustContains acts like Contains, but it panics if any error occurs.
+func (c *Cache) MustContains(ctx context.Context, key interface{}) bool {
+ v, err := c.Contains(ctx, key)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustGetExpire acts like GetExpire, but it panics if any error occurs.
+func (c *Cache) MustGetExpire(ctx context.Context, key interface{}) time.Duration {
+ v, err := c.GetExpire(ctx, key)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustSize acts like Size, but it panics if any error occurs.
+func (c *Cache) MustSize(ctx context.Context) int {
+ v, err := c.Size(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustData acts like Data, but it panics if any error occurs.
+func (c *Cache) MustData(ctx context.Context) map[interface{}]interface{} {
+ v, err := c.Data(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustKeys acts like Keys, but it panics if any error occurs.
+func (c *Cache) MustKeys(ctx context.Context) []interface{} {
+ v, err := c.Keys(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustKeyStrings acts like KeyStrings, but it panics if any error occurs.
+func (c *Cache) MustKeyStrings(ctx context.Context) []string {
+ v, err := c.KeyStrings(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustValues acts like Values, but it panics if any error occurs.
+func (c *Cache) MustValues(ctx context.Context) []interface{} {
+ v, err := c.Values(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg.go
new file mode 100644
index 000000000000..74cad55d00b9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg.go
@@ -0,0 +1,211 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gcfg provides reading, caching and managing for configuration.
+package gcfg
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/genv"
+)
+
+// Config is the configuration management object.
+type Config struct {
+ adapter Adapter
+}
+
+const (
+ DefaultName = "config" // DefaultName is the default group name for instance usage.
+)
+
+// New creates and returns a Config object with default adapter of AdapterFile.
+func New() (*Config, error) {
+ adapterFile, err := NewAdapterFile()
+ if err != nil {
+ return nil, err
+ }
+ return &Config{
+ adapter: adapterFile,
+ }, nil
+}
+
+// NewWithAdapter creates and returns a Config object with given adapter.
+func NewWithAdapter(adapter Adapter) *Config {
+ return &Config{
+ adapter: adapter,
+ }
+}
+
+// Instance returns an instance of Config with default settings.
+// The parameter `name` is the name for the instance. But very note that, if the file "name.toml"
+// exists in the configuration directory, it then sets it as the default configuration file. The
+// toml file type is the default configuration file type.
+func Instance(name ...string) *Config {
+ var (
+ ctx = context.TODO()
+ key = DefaultName
+ )
+ if len(name) > 0 && name[0] != "" {
+ key = name[0]
+ }
+ return localInstances.GetOrSetFuncLock(key, func() interface{} {
+ adapter, err := NewAdapterFile()
+ if err != nil {
+ intlog.Errorf(context.Background(), `%+v`, err)
+ return nil
+ }
+ // If it's not using default configuration or its configuration file is not available,
+ // it searches the possible configuration file according to the name and all supported
+ // file types.
+ if key != DefaultName || !adapter.Available(ctx) {
+ for _, fileType := range supportedFileTypes {
+ if file := fmt.Sprintf(`%s.%s`, key, fileType); adapter.Available(ctx, file) {
+ adapter.SetFileName(file)
+ break
+ }
+ }
+ }
+ return NewWithAdapter(adapter)
+ }).(*Config)
+}
+
+// SetAdapter sets the adapter of current Config object.
+func (c *Config) SetAdapter(adapter Adapter) {
+ c.adapter = adapter
+}
+
+// GetAdapter returns the adapter of current Config object.
+func (c *Config) GetAdapter() Adapter {
+ return c.adapter
+}
+
+// Available checks and returns the configuration service is available.
+// The optional parameter `pattern` specifies certain configuration resource.
+//
+// It returns true if configuration file is present in default AdapterFile, or else false.
+// Note that this function does not return error as it just does simply check for backend configuration service.
+func (c *Config) Available(ctx context.Context, resource ...string) (ok bool) {
+ return c.adapter.Available(ctx, resource...)
+}
+
+// Get retrieves and returns value by specified `pattern`.
+// It returns all values of current Json object if `pattern` is given empty or string ".".
+// It returns nil if no value found by `pattern`.
+//
+// It returns a default value specified by `def` if value for `pattern` is not found.
+func (c *Config) Get(ctx context.Context, pattern string, def ...interface{}) (*gvar.Var, error) {
+ var (
+ err error
+ value interface{}
+ )
+ value, err = c.adapter.Get(ctx, pattern)
+ if err != nil {
+ return nil, err
+ }
+ if value == nil {
+ if len(def) > 0 {
+ return gvar.New(def[0]), nil
+ }
+ return nil, nil
+ }
+ return gvar.New(value), nil
+}
+
+// GetWithEnv returns the configuration value specified by pattern `pattern`.
+// If the configuration value does not exist, then it retrieves and returns the environment value specified by `key`.
+// It returns the default value `def` if none of them exists.
+//
+// Fetching Rules: Environment arguments are in uppercase format, eg: GF_PACKAGE_VARIABLE.
+func (c *Config) GetWithEnv(ctx context.Context, pattern string, def ...interface{}) (*gvar.Var, error) {
+ value, err := c.Get(ctx, pattern)
+ if err != nil && gerror.Code(err) != gcode.CodeNotFound {
+ return nil, err
+ }
+ if value == nil {
+ if v := genv.Get(utils.FormatEnvKey(pattern)); v != nil {
+ return v, nil
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0]), nil
+ }
+ return nil, nil
+ }
+ return value, nil
+}
+
+// GetWithCmd returns the configuration value specified by pattern `pattern`.
+// If the configuration value does not exist, then it retrieves and returns the command line option specified by `key`.
+// It returns the default value `def` if none of them exists.
+//
+// Fetching Rules: Command line arguments are in lowercase format, eg: gf.package.variable.
+func (c *Config) GetWithCmd(ctx context.Context, pattern string, def ...interface{}) (*gvar.Var, error) {
+ value, err := c.Get(ctx, pattern)
+ if err != nil && gerror.Code(err) != gcode.CodeNotFound {
+ return nil, err
+ }
+ if value == nil {
+ if v := command.GetOpt(utils.FormatCmdKey(pattern)); v != "" {
+ return gvar.New(v), nil
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0]), nil
+ }
+ return nil, nil
+ }
+ return value, nil
+}
+
+// Data retrieves and returns all configuration data as map type.
+func (c *Config) Data(ctx context.Context) (data map[string]interface{}, err error) {
+ return c.adapter.Data(ctx)
+}
+
+// MustGet acts as function Get, but it panics if error occurs.
+func (c *Config) MustGet(ctx context.Context, pattern string, def ...interface{}) *gvar.Var {
+ v, err := c.Get(ctx, pattern, def...)
+ if err != nil {
+ panic(err)
+ }
+ if v == nil {
+ return nil
+ }
+ return v
+}
+
+// MustGetWithEnv acts as function GetWithEnv, but it panics if error occurs.
+func (c *Config) MustGetWithEnv(ctx context.Context, pattern string, def ...interface{}) *gvar.Var {
+ v, err := c.GetWithEnv(ctx, pattern, def...)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustGetWithCmd acts as function GetWithCmd, but it panics if error occurs.
+func (c *Config) MustGetWithCmd(ctx context.Context, pattern string, def ...interface{}) *gvar.Var {
+ v, err := c.GetWithCmd(ctx, pattern, def...)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustData acts as function Data, but it panics if error occurs.
+func (c *Config) MustData(ctx context.Context) map[string]interface{} {
+ v, err := c.Data(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adaper.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adaper.go
new file mode 100644
index 000000000000..e45c5cd5c3af
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adaper.go
@@ -0,0 +1,27 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcfg
+
+import "context"
+
+// Adapter is the interface for configuration retrieving.
+type Adapter interface {
+ // Available checks and returns the configuration service is available.
+ // The optional parameter `resource` specifies certain configuration resource.
+ //
+ // It returns true if configuration file is present in default AdapterFile, or else false.
+ // Note that this function does not return error as it just does simply check for backend configuration service.
+ Available(ctx context.Context, resource ...string) (ok bool)
+
+ // Get retrieves and returns value by specified `pattern`.
+ Get(ctx context.Context, pattern string) (value interface{}, err error)
+
+ // Data retrieves and returns all configuration data as map type.
+ // Note that this function may lead lots of memory usage if configuration data is too large,
+ // you can implement this function if necessary.
+ Data(ctx context.Context) (data map[string]interface{}, err error)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file.go
new file mode 100644
index 000000000000..80ea4c4c799a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file.go
@@ -0,0 +1,281 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcfg
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gfsnotify"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/util/gmode"
+)
+
+type AdapterFile struct {
+ defaultName string // Default configuration file name.
+ searchPaths *garray.StrArray // Searching path array.
+ jsonMap *gmap.StrAnyMap // The pared JSON objects for configuration files.
+ violenceCheck bool // Whether it does violence check in value index searching. It affects the performance when set true(false in default).
+}
+
+const (
+ DefaultConfigFile = "config.toml" // DefaultConfigFile is the default configuration file name.
+ commandEnvKeyForFile = "gf.gcfg.file" // commandEnvKeyForFile is the configuration key for command argument or environment configuring file name.
+ commandEnvKeyForPath = "gf.gcfg.path" // commandEnvKeyForPath is the configuration key for command argument or environment configuring directory path.
+)
+
+var (
+ supportedFileTypes = []string{"toml", "yaml", "yml", "json", "ini", "xml"} // All supported file types suffixes.
+ localInstances = gmap.NewStrAnyMap(true) // Instances map containing configuration instances.
+ customConfigContentMap = gmap.NewStrStrMap(true) // Customized configuration content.
+
+ // Prefix array for trying searching in resource manager.
+ resourceTryFolders = []string{
+ "", "/", "config/", "config", "/config", "/config/",
+ "manifest/config/", "manifest/config", "/manifest/config", "/manifest/config/",
+ }
+
+ // Prefix array for trying searching in local system.
+ localSystemTryFolders = []string{"", "config/", "manifest/config"}
+)
+
+// NewAdapterFile returns a new configuration management object.
+// The parameter `file` specifies the default configuration file name for reading.
+func NewAdapterFile(file ...string) (*AdapterFile, error) {
+ var (
+ err error
+ name = DefaultConfigFile
+ )
+ if len(file) > 0 {
+ name = file[0]
+ } else {
+ // Custom default configuration file name from command line or environment.
+ if customFile := command.GetOptWithEnv(commandEnvKeyForFile); customFile != "" {
+ name = customFile
+ }
+ }
+ config := &AdapterFile{
+ defaultName: name,
+ searchPaths: garray.NewStrArray(true),
+ jsonMap: gmap.NewStrAnyMap(true),
+ }
+ // Customized dir path from env/cmd.
+ if customPath := command.GetOptWithEnv(commandEnvKeyForPath); customPath != "" {
+ if gfile.Exists(customPath) {
+ if err = config.SetPath(customPath); err != nil {
+ return nil, err
+ }
+ } else {
+ return nil, gerror.Newf(`configuration directory path "%s" does not exist`, customPath)
+ }
+ } else {
+ // ================================================================================
+ // Automatic searching directories.
+ // It does not affect adapter object cresting if these directories do not exist.
+ // ================================================================================
+
+ // Dir path of working dir.
+ if err = config.AddPath(gfile.Pwd()); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+
+ // Dir path of main package.
+ if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) {
+ if err = config.AddPath(mainPath); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+
+ // Dir path of binary.
+ if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) {
+ if err = config.AddPath(selfPath); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ }
+ return config, nil
+}
+
+// SetViolenceCheck sets whether to perform hierarchical conflict checking.
+// This feature needs to be enabled when there is a level symbol in the key name.
+// It is off in default.
+//
+// Note that, turning on this feature is quite expensive, and it is not recommended
+// allowing separators in the key names. It is best to avoid this on the application side.
+func (c *AdapterFile) SetViolenceCheck(check bool) {
+ c.violenceCheck = check
+ c.Clear()
+}
+
+// SetFileName sets the default configuration file name.
+func (c *AdapterFile) SetFileName(name string) {
+ c.defaultName = name
+}
+
+// GetFileName returns the default configuration file name.
+func (c *AdapterFile) GetFileName() string {
+ return c.defaultName
+}
+
+// Get retrieves and returns value by specified `pattern`.
+// It returns all values of current Json object if `pattern` is given empty or string ".".
+// It returns nil if no value found by `pattern`.
+//
+// We can also access slice item by its index number in `pattern` like:
+// "list.10", "array.0.name", "array.0.1.id".
+//
+// It returns a default value specified by `def` if value for `pattern` is not found.
+func (c *AdapterFile) Get(ctx context.Context, pattern string) (value interface{}, err error) {
+ j, err := c.getJson()
+ if err != nil {
+ return nil, err
+ }
+ if j != nil {
+ return j.Get(pattern).Val(), nil
+ }
+ return nil, nil
+}
+
+// Data retrieves and returns all configuration data as map type.
+func (c *AdapterFile) Data(ctx context.Context) (data map[string]interface{}, err error) {
+ j, err := c.getJson()
+ if err != nil {
+ return nil, err
+ }
+ if j != nil {
+ return j.Var().Map(), nil
+ }
+ return nil, nil
+}
+
+// MustGet acts as function Get, but it panics if error occurs.
+func (c *AdapterFile) MustGet(ctx context.Context, pattern string) *gvar.Var {
+ v, err := c.Get(ctx, pattern)
+ if err != nil {
+ panic(err)
+ }
+ return gvar.New(v)
+}
+
+// Clear removes all parsed configuration files content cache,
+// which will force reload configuration content from file.
+func (c *AdapterFile) Clear() {
+ c.jsonMap.Clear()
+}
+
+// Dump prints current Json object with more manually readable.
+func (c *AdapterFile) Dump() {
+ if j, _ := c.getJson(); j != nil {
+ j.Dump()
+ }
+}
+
+// Available checks and returns whether configuration of given `file` is available.
+func (c *AdapterFile) Available(ctx context.Context, fileName ...string) bool {
+ var (
+ usedFileName string
+ )
+ if len(fileName) > 0 && fileName[0] != "" {
+ usedFileName = fileName[0]
+ } else {
+ usedFileName = c.defaultName
+ }
+ if path, _ := c.GetFilePath(usedFileName); path != "" {
+ return true
+ }
+ if c.GetContent(usedFileName) != "" {
+ return true
+ }
+ return false
+}
+
+// autoCheckAndAddMainPkgPathToSearchPaths automatically checks and adds directory path of package main
+// to the searching path list if it's currently in development environment.
+func (c *AdapterFile) autoCheckAndAddMainPkgPathToSearchPaths() {
+ if gmode.IsDevelop() {
+ mainPkgPath := gfile.MainPkgPath()
+ if mainPkgPath != "" {
+ if !c.searchPaths.Contains(mainPkgPath) {
+ c.searchPaths.Append(mainPkgPath)
+ }
+ }
+ }
+}
+
+// getJson returns a *gjson.Json object for the specified `file` content.
+// It would print error if file reading fails. It returns nil if any error occurs.
+func (c *AdapterFile) getJson(fileName ...string) (configJson *gjson.Json, err error) {
+ var (
+ usedFileName = c.defaultName
+ )
+ if len(fileName) > 0 && fileName[0] != "" {
+ usedFileName = fileName[0]
+ } else {
+ usedFileName = c.defaultName
+ }
+ result := c.jsonMap.GetOrSetFuncLock(usedFileName, func() interface{} {
+ var (
+ content string
+ filePath string
+ )
+ // The configured content can be any kind of data type different from its file type.
+ isFromConfigContent := true
+ if content = c.GetContent(usedFileName); content == "" {
+ isFromConfigContent = false
+ filePath, err = c.GetFilePath(usedFileName)
+ if err != nil {
+ return nil
+ }
+ if filePath == "" {
+ return nil
+ }
+ if file := gres.Get(filePath); file != nil {
+ content = string(file.Content())
+ } else {
+ content = gfile.GetContents(filePath)
+ }
+ }
+ // Note that the underlying configuration json object operations are concurrent safe.
+ dataType := gfile.ExtName(usedFileName)
+ if gjson.IsValidDataType(dataType) && !isFromConfigContent {
+ configJson, err = gjson.LoadContentType(dataType, content, true)
+ } else {
+ configJson, err = gjson.LoadContent(content, true)
+ }
+ if err != nil {
+ if filePath != "" {
+ err = gerror.Wrapf(err, `load config file "%s" failed`, filePath)
+ } else {
+ err = gerror.Wrap(err, `load configuration failed`)
+ }
+ return nil
+ }
+ configJson.SetViolenceCheck(c.violenceCheck)
+ // Add monitor for this configuration file,
+ // any changes of this file will refresh its cache in Config object.
+ if filePath != "" && !gres.Contains(filePath) {
+ _, err = gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
+ c.jsonMap.Remove(usedFileName)
+ })
+ if err != nil {
+ return nil
+ }
+ }
+ return configJson
+ })
+ if result != nil {
+ return result.(*gjson.Json), err
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file_content.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file_content.go
new file mode 100644
index 000000000000..f72f7ff097af
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file_content.go
@@ -0,0 +1,85 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcfg
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// SetContent sets customized configuration content for specified `file`.
+// The `file` is unnecessary param, default is DefaultConfigFile.
+func (c *AdapterFile) SetContent(content string, file ...string) {
+ name := DefaultConfigFile
+ if len(file) > 0 {
+ name = file[0]
+ }
+ // Clear file cache for instances which cached `name`.
+ localInstances.LockFunc(func(m map[string]interface{}) {
+ if customConfigContentMap.Contains(name) {
+ for _, v := range m {
+ if configInstance, ok := v.(*Config); ok {
+ if fileConfig, ok := configInstance.GetAdapter().(*AdapterFile); ok {
+ fileConfig.jsonMap.Remove(name)
+ }
+ }
+ }
+ }
+ customConfigContentMap.Set(name, content)
+ })
+}
+
+// GetContent returns customized configuration content for specified `file`.
+// The `file` is unnecessary param, default is DefaultConfigFile.
+func (c *AdapterFile) GetContent(file ...string) string {
+ name := DefaultConfigFile
+ if len(file) > 0 {
+ name = file[0]
+ }
+ return customConfigContentMap.Get(name)
+}
+
+// RemoveContent removes the global configuration with specified `file`.
+// If `name` is not passed, it removes configuration of the default group name.
+func (c *AdapterFile) RemoveContent(file ...string) {
+ name := DefaultConfigFile
+ if len(file) > 0 {
+ name = file[0]
+ }
+ // Clear file cache for instances which cached `name`.
+ localInstances.LockFunc(func(m map[string]interface{}) {
+ if customConfigContentMap.Contains(name) {
+ for _, v := range m {
+ if configInstance, ok := v.(*Config); ok {
+ if fileConfig, ok := configInstance.GetAdapter().(*AdapterFile); ok {
+ fileConfig.jsonMap.Remove(name)
+ }
+ }
+ }
+ customConfigContentMap.Remove(name)
+ }
+ })
+
+ intlog.Printf(context.TODO(), `RemoveContent: %s`, name)
+}
+
+// ClearContent removes all global configuration contents.
+func (c *AdapterFile) ClearContent() {
+ customConfigContentMap.Clear()
+ // Clear cache for all instances.
+ localInstances.LockFunc(func(m map[string]interface{}) {
+ for _, v := range m {
+ if configInstance, ok := v.(*Config); ok {
+ if fileConfig, ok := configInstance.GetAdapter().(*AdapterFile); ok {
+ fileConfig.jsonMap.Clear()
+ }
+ }
+ }
+ })
+ intlog.Print(context.TODO(), `RemoveConfig`)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file_path.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file_path.go
new file mode 100644
index 000000000000..b23c682fcead
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcfg/gcfg_adapter_file_path.go
@@ -0,0 +1,225 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gcfg
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gspath"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// SetPath sets the configuration directory path for file search.
+// The parameter `path` can be absolute or relative path,
+// but absolute path is strongly recommended.
+func (c *AdapterFile) SetPath(path string) (err error) {
+ var (
+ isDir = false
+ realPath = ""
+ )
+ if file := gres.Get(path); file != nil {
+ realPath = path
+ isDir = file.FileInfo().IsDir()
+ } else {
+ // Absolute path.
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ // Relative path.
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, v := range array {
+ if searchedPath, _ := gspath.Search(v, path); searchedPath != "" {
+ realPath = searchedPath
+ break
+ }
+ }
+ })
+ }
+ if realPath != "" {
+ isDir = gfile.IsDir(realPath)
+ }
+ }
+ // Path not exist.
+ if realPath == "" {
+ buffer := bytes.NewBuffer(nil)
+ if c.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf(`SetPath failed: cannot find directory "%s" in following paths:`, path))
+ c.searchPaths.RLockFunc(func(array []string) {
+ for k, v := range array {
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf(`SetPath failed: path "%s" does not exist`, path))
+ }
+ return gerror.New(buffer.String())
+ }
+ // Should be a directory.
+ if !isDir {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `SetPath failed: path "%s" should be directory type`,
+ path,
+ )
+ }
+ // Repeated path check.
+ if c.searchPaths.Search(realPath) != -1 {
+ return nil
+ }
+ c.jsonMap.Clear()
+ c.searchPaths.Clear()
+ c.searchPaths.Append(realPath)
+ intlog.Print(context.TODO(), "SetPath:", realPath)
+ return nil
+}
+
+// AddPath adds an absolute or relative path to the search paths.
+func (c *AdapterFile) AddPath(path string) (err error) {
+ var (
+ isDir = false
+ realPath = ""
+ )
+ // It firstly checks the resource manager,
+ // and then checks the filesystem for the path.
+ if file := gres.Get(path); file != nil {
+ realPath = path
+ isDir = file.FileInfo().IsDir()
+ } else {
+ // Absolute path.
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ // Relative path.
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, v := range array {
+ if searchedPath, _ := gspath.Search(v, path); searchedPath != "" {
+ realPath = searchedPath
+ break
+ }
+ }
+ })
+ }
+ if realPath != "" {
+ isDir = gfile.IsDir(realPath)
+ }
+ }
+ if realPath == "" {
+ buffer := bytes.NewBuffer(nil)
+ if c.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf(`AddPath failed: cannot find directory "%s" in following paths:`, path))
+ c.searchPaths.RLockFunc(func(array []string) {
+ for k, v := range array {
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf(`AddPath failed: path "%s" does not exist`, path))
+ }
+ return gerror.New(buffer.String())
+ }
+ if !isDir {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `AddPath failed: path "%s" should be directory type`, path)
+ }
+ // Repeated path check.
+ if c.searchPaths.Search(realPath) != -1 {
+ return nil
+ }
+ c.searchPaths.Append(realPath)
+ intlog.Print(context.TODO(), "AddPath:", realPath)
+ return nil
+}
+
+// GetFilePath returns the absolute configuration file path for the given filename by `file`.
+// If `file` is not passed, it returns the configuration file path of the default name.
+// It returns an empty `path` string and an error if the given `file` does not exist.
+func (c *AdapterFile) GetFilePath(fileName ...string) (path string, err error) {
+ var (
+ tempPath string
+ usedFileName = c.defaultName
+ )
+ if len(fileName) > 0 {
+ usedFileName = fileName[0]
+ }
+ // Searching resource manager.
+ if !gres.IsEmpty() {
+ for _, tryFolder := range resourceTryFolders {
+ tempPath = tryFolder + usedFileName
+ if file := gres.Get(tempPath); file != nil {
+ path = file.Name()
+ return
+ }
+ }
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, searchPath := range array {
+ for _, tryFolder := range resourceTryFolders {
+ tempPath = searchPath + tryFolder + usedFileName
+ if file := gres.Get(tempPath); file != nil {
+ path = file.Name()
+ return
+ }
+ }
+ }
+ })
+ }
+
+ c.autoCheckAndAddMainPkgPathToSearchPaths()
+
+ // Searching local file system.
+ if path == "" {
+ // Absolute path.
+ if path = gfile.RealPath(usedFileName); path != "" {
+ return
+ }
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, searchPath := range array {
+ searchPath = gstr.TrimRight(searchPath, `\/`)
+ for _, tryFolder := range localSystemTryFolders {
+ relativePath := gstr.TrimRight(
+ gfile.Join(tryFolder, usedFileName),
+ `\/`,
+ )
+ if path, _ = gspath.Search(searchPath, relativePath); path != "" {
+ return
+ }
+ }
+ }
+ })
+ }
+
+ // If it cannot find the path of `file`, it formats and returns a detailed error.
+ if path == "" {
+ var buffer = bytes.NewBuffer(nil)
+ if c.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf(
+ `config file "%s" not found in resource manager or the following system searching paths:`,
+ usedFileName,
+ ))
+ c.searchPaths.RLockFunc(func(array []string) {
+ index := 1
+ for _, searchPath := range array {
+ searchPath = gstr.TrimRight(searchPath, `\/`)
+ for _, tryFolder := range localSystemTryFolders {
+ buffer.WriteString(fmt.Sprintf(
+ "\n%d. %s",
+ index, gfile.Join(searchPath, tryFolder),
+ ))
+ index++
+ }
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf(`cannot find config file "%s" with no path configured`, usedFileName))
+ }
+ err = gerror.NewCode(gcode.CodeNotFound, buffer.String())
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd.go
new file mode 100644
index 000000000000..d8a3a97e9645
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd.go
@@ -0,0 +1,107 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+// Package gcmd provides console operations, like options/arguments reading and command running.
+package gcmd
+
+import (
+ "os"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gctx"
+)
+
+const (
+ CtxKeyParser gctx.StrKey = `CtxKeyParser`
+ CtxKeyCommand gctx.StrKey = `CtxKeyCommand`
+ CtxKeyArguments gctx.StrKey = `CtxKeyArguments`
+)
+
+const (
+ helpOptionName = "help"
+ helpOptionNameShort = "h"
+ maxLineChars = 120
+)
+
+// Init does custom initialization.
+func Init(args ...string) {
+ command.Init(args...)
+}
+
+// GetOpt returns the option value named `name` as gvar.Var.
+func GetOpt(name string, def ...string) *gvar.Var {
+ if v := command.GetOpt(name, def...); v != "" {
+ return gvar.New(v)
+ }
+ if command.ContainsOpt(name) {
+ return gvar.New("")
+ }
+ return nil
+}
+
+// GetOptAll returns all parsed options.
+func GetOptAll() map[string]string {
+ return command.GetOptAll()
+}
+
+// GetArg returns the argument at `index` as gvar.Var.
+func GetArg(index int, def ...string) *gvar.Var {
+ if v := command.GetArg(index, def...); v != "" {
+ return gvar.New(v)
+ }
+ return nil
+}
+
+// GetArgAll returns all parsed arguments.
+func GetArgAll() []string {
+ return command.GetArgAll()
+}
+
+// GetOptWithEnv returns the command line argument of the specified `key`.
+// If the argument does not exist, then it returns the environment variable with specified `key`.
+// It returns the default value `def` if none of them exists.
+//
+// Fetching Rules:
+// 1. Command line arguments are in lowercase format, eg: gf.`package name`.;
+// 2. Environment arguments are in uppercase format, eg: GF_`package name`_;
+func GetOptWithEnv(key string, def ...interface{}) *gvar.Var {
+ cmdKey := utils.FormatCmdKey(key)
+ if command.ContainsOpt(cmdKey) {
+ return gvar.New(GetOpt(cmdKey))
+ } else {
+ envKey := utils.FormatEnvKey(key)
+ if r, ok := os.LookupEnv(envKey); ok {
+ return gvar.New(r)
+ } else {
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ }
+ }
+ return nil
+}
+
+// BuildOptions builds the options as string.
+func BuildOptions(m map[string]string, prefix ...string) string {
+ options := ""
+ leadStr := "-"
+ if len(prefix) > 0 {
+ leadStr = prefix[0]
+ }
+ for k, v := range m {
+ if len(options) > 0 {
+ options += " "
+ }
+ options += leadStr + k
+ if v != "" {
+ options += "=" + v
+ }
+ }
+ return options
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command.go
new file mode 100644
index 000000000000..a7d0187865ce
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command.go
@@ -0,0 +1,116 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gcmd
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Command holds the info about an argument that can handle custom logic.
+type Command struct {
+ Name string // Command name(case-sensitive).
+ Usage string // A brief line description about its usage, eg: gf build main.go [OPTION]
+ Brief string // A brief info that describes what this command will do.
+ Description string // A detailed description.
+ Arguments []Argument // Argument array, configuring how this command act.
+ Func Function // Custom function.
+ FuncWithValue FuncWithValue // Custom function with output parameters that can interact with command caller.
+ HelpFunc Function // Custom help function
+ Examples string // Usage examples.
+ Additional string // Additional info about this command, which will be appended to the end of help info.
+ Strict bool // Strict parsing options, which means it returns error if invalid option given.
+ Config string // Config node name, which also retrieves the values from config component along with command line.
+ parent *Command // Parent command for internal usage.
+ commands []*Command // Sub commands of this command.
+}
+
+// Function is a custom command callback function that is bound to a certain argument.
+type Function func(ctx context.Context, parser *Parser) (err error)
+
+// FuncWithValue is similar like Func but with output parameters that can interact with command caller.
+type FuncWithValue func(ctx context.Context, parser *Parser) (out interface{}, err error)
+
+// Argument is the command value that are used by certain command.
+type Argument struct {
+ Name string // Option name.
+ Short string // Option short.
+ Brief string // Brief info about this Option, which is used in help info.
+ IsArg bool // IsArg marks this argument taking value from command line argument instead of option.
+ Orphan bool // Whether this Option having or having no value bound to it.
+}
+
+var (
+ // defaultHelpOption is the default help option that will be automatically added to each command.
+ defaultHelpOption = Argument{
+ Name: `help`,
+ Short: `h`,
+ Brief: `more information about this command`,
+ Orphan: true,
+ }
+)
+
+// CommandFromCtx retrieves and returns Command from context.
+func CommandFromCtx(ctx context.Context) *Command {
+ if v := ctx.Value(CtxKeyCommand); v != nil {
+ if p, ok := v.(*Command); ok {
+ return p
+ }
+ }
+ return nil
+}
+
+// AddCommand adds one or more sub-commands to current command.
+func (c *Command) AddCommand(commands ...*Command) error {
+ for _, cmd := range commands {
+ if err := c.doAddCommand(cmd); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// doAddCommand adds one sub-command to current command.
+func (c *Command) doAddCommand(command *Command) error {
+ command.Name = gstr.Trim(command.Name)
+ if command.Name == "" {
+ return gerror.New("command name should not be empty")
+ }
+ // Repeated check.
+ var (
+ commandNameSet = gset.NewStrSet()
+ )
+ for _, cmd := range c.commands {
+ commandNameSet.Add(cmd.Name)
+ }
+ if commandNameSet.Contains(command.Name) {
+ return gerror.Newf(`command "%s" is already added to command "%s"`, command.Name, c.Name)
+ }
+ // Add the given command to its sub-commands array.
+ command.parent = c
+ c.commands = append(c.commands, command)
+ return nil
+}
+
+// AddObject adds one or more sub-commands to current command using struct object.
+func (c *Command) AddObject(objects ...interface{}) error {
+ var (
+ commands []*Command
+ )
+ for _, object := range objects {
+ rootCommand, err := NewFromObject(object)
+ if err != nil {
+ return err
+ }
+ commands = append(commands, rootCommand)
+ }
+ return c.AddCommand(commands...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_help.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_help.go
new file mode 100644
index 000000000000..7f9ff472ae0b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_help.go
@@ -0,0 +1,234 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gcmd
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Print prints help info to stdout for current command.
+func (c *Command) Print() {
+ var (
+ prefix = gstr.Repeat(" ", 4)
+ buffer = bytes.NewBuffer(nil)
+ arguments = make([]Argument, len(c.Arguments))
+ )
+ // Copy options for printing.
+ copy(arguments, c.Arguments)
+ // Add built-in help option, just for info only.
+ arguments = append(arguments, defaultHelpOption)
+
+ // Usage.
+ if c.Usage != "" || c.Name != "" {
+ buffer.WriteString("USAGE\n")
+ buffer.WriteString(prefix)
+ if c.Usage != "" {
+ buffer.WriteString(c.Usage)
+ } else {
+ var (
+ p = c
+ name = c.Name
+ )
+ for p.parent != nil {
+ name = p.parent.Name + " " + name
+ p = p.parent
+ }
+ buffer.WriteString(name)
+ if len(c.commands) > 0 {
+ buffer.WriteString(` COMMAND`)
+ }
+ if c.hasArgumentFromIndex() {
+ buffer.WriteString(` ARGUMENT`)
+ }
+ buffer.WriteString(` [OPTION]`)
+ }
+ buffer.WriteString("\n\n")
+ }
+ // Command.
+ if len(c.commands) > 0 {
+ buffer.WriteString("COMMAND\n")
+ var (
+ maxSpaceLength = 0
+ )
+ for _, cmd := range c.commands {
+ if len(cmd.Name) > maxSpaceLength {
+ maxSpaceLength = len(cmd.Name)
+ }
+ }
+ for _, cmd := range c.commands {
+ var (
+ spaceLength = maxSpaceLength - len(cmd.Name)
+ wordwrapPrefix = gstr.Repeat(" ", len(prefix+cmd.Name)+spaceLength+4)
+ )
+ c.printLineBrief(printLineBriefInput{
+ Buffer: buffer,
+ Name: cmd.Name,
+ Prefix: prefix,
+ Brief: gstr.Trim(cmd.Brief),
+ WordwrapPrefix: wordwrapPrefix,
+ SpaceLength: spaceLength,
+ })
+ }
+ buffer.WriteString("\n")
+ }
+
+ // Argument.
+ if c.hasArgumentFromIndex() {
+ buffer.WriteString("ARGUMENT\n")
+ var (
+ maxSpaceLength = 0
+ )
+ for _, arg := range arguments {
+ if !arg.IsArg {
+ continue
+ }
+ if len(arg.Name) > maxSpaceLength {
+ maxSpaceLength = len(arg.Name)
+ }
+ }
+ for _, arg := range arguments {
+ if !arg.IsArg {
+ continue
+ }
+ var (
+ spaceLength = maxSpaceLength - len(arg.Name)
+ wordwrapPrefix = gstr.Repeat(" ", len(prefix+arg.Name)+spaceLength+4)
+ )
+ c.printLineBrief(printLineBriefInput{
+ Buffer: buffer,
+ Name: arg.Name,
+ Prefix: prefix,
+ Brief: gstr.Trim(arg.Brief),
+ WordwrapPrefix: wordwrapPrefix,
+ SpaceLength: spaceLength,
+ })
+ }
+ buffer.WriteString("\n")
+ }
+
+ // Option.
+ if c.hasArgumentFromOption() {
+ buffer.WriteString("OPTION\n")
+ var (
+ nameStr string
+ maxSpaceLength = 0
+ )
+ for _, arg := range arguments {
+ if arg.IsArg {
+ continue
+ }
+ if arg.Short != "" {
+ nameStr = fmt.Sprintf("-%s,--%s", arg.Short, arg.Name)
+ } else {
+ nameStr = fmt.Sprintf("-/--%s", arg.Name)
+ }
+ if len(nameStr) > maxSpaceLength {
+ maxSpaceLength = len(nameStr)
+ }
+ }
+ for _, arg := range arguments {
+ if arg.IsArg {
+ continue
+ }
+ if arg.Short != "" {
+ nameStr = fmt.Sprintf("-%s, --%s", arg.Short, arg.Name)
+ } else {
+ nameStr = fmt.Sprintf("-/--%s", arg.Name)
+ }
+ var (
+ brief = gstr.Trim(arg.Brief)
+ spaceLength = maxSpaceLength - len(nameStr)
+ wordwrapPrefix = gstr.Repeat(" ", len(prefix+nameStr)+spaceLength+4)
+ )
+ c.printLineBrief(printLineBriefInput{
+ Buffer: buffer,
+ Name: nameStr,
+ Prefix: prefix,
+ Brief: brief,
+ WordwrapPrefix: wordwrapPrefix,
+ SpaceLength: spaceLength,
+ })
+ }
+ buffer.WriteString("\n")
+ }
+
+ // Example.
+ if c.Examples != "" {
+ buffer.WriteString("EXAMPLE\n")
+ for _, line := range gstr.SplitAndTrim(gstr.Trim(c.Examples), "\n") {
+ buffer.WriteString(prefix)
+ buffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, "\n"+prefix))
+ buffer.WriteString("\n")
+ }
+ buffer.WriteString("\n")
+ }
+
+ // Description.
+ if c.Description != "" {
+ buffer.WriteString("DESCRIPTION\n")
+ for _, line := range gstr.SplitAndTrim(gstr.Trim(c.Description), "\n") {
+ buffer.WriteString(prefix)
+ buffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, "\n"+prefix))
+ buffer.WriteString("\n")
+ }
+ buffer.WriteString("\n")
+ }
+
+ // Additional.
+ if c.Additional != "" {
+ lineStr := gstr.WordWrap(gstr.Trim(c.Additional), maxLineChars, "\n")
+ buffer.WriteString(lineStr)
+ buffer.WriteString("\n")
+ }
+ content := buffer.String()
+ content = gstr.Replace(content, "\t", " ")
+ fmt.Println(content)
+}
+
+type printLineBriefInput struct {
+ Buffer *bytes.Buffer
+ Name string
+ Prefix string
+ Brief string
+ WordwrapPrefix string
+ SpaceLength int
+}
+
+func (c *Command) printLineBrief(in printLineBriefInput) {
+ briefArray := gstr.SplitAndTrim(in.Brief, "\n")
+ if len(briefArray) == 0 {
+ // If command brief is empty, it just prints its command name.
+ briefArray = []string{""}
+ }
+ for i, line := range briefArray {
+ var lineStr string
+ if i == 0 {
+ lineStr = fmt.Sprintf(
+ "%s%s%s%s\n",
+ in.Prefix, in.Name, gstr.Repeat(" ", in.SpaceLength+4), line,
+ )
+ } else {
+ lineStr = fmt.Sprintf(
+ "%s%s%s%s\n",
+ in.Prefix, gstr.Repeat(" ", len(in.Name)), gstr.Repeat(" ", in.SpaceLength+4), line,
+ )
+ }
+ lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+in.WordwrapPrefix)
+ in.Buffer.WriteString(lineStr)
+ }
+}
+
+func (c *Command) defaultHelpFunc(ctx context.Context, parser *Parser) error {
+ // Print command help info to stdout.
+ c.Print()
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_object.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_object.go
new file mode 100644
index 000000000000..9924f743e50d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_object.go
@@ -0,0 +1,391 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gcmd
+
+import (
+ "context"
+ "reflect"
+
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gmeta"
+ "github.com/gogf/gf/v2/util/gutil"
+ "github.com/gogf/gf/v2/util/gvalid"
+)
+
+const (
+ tagNameDc = `dc`
+ tagNameAd = `ad`
+ tagNameEg = `eg`
+ tagNameArg = `arg`
+ tagNameRoot = `root`
+)
+
+var (
+ // defaultValueTags is the struct tag names for default value storing.
+ defaultValueTags = []string{"d", "default"}
+)
+
+// NewFromObject creates and returns a root command object using given object.
+func NewFromObject(object interface{}) (rootCmd *Command, err error) {
+ originValueAndKind := utils.OriginValueAndKind(object)
+ if originValueAndKind.OriginKind != reflect.Struct {
+ err = gerror.Newf(
+ `input object should be type of struct, but got "%s"`,
+ originValueAndKind.InputValue.Type().String(),
+ )
+ return
+ }
+ var reflectValue = originValueAndKind.InputValue
+ // If given `object` is not pointer, it then creates a temporary one,
+ // of which the value is `reflectValue`.
+ // It then can retrieve all the methods both of struct/*struct.
+ if reflectValue.Kind() == reflect.Struct {
+ newValue := reflect.New(reflectValue.Type())
+ newValue.Elem().Set(reflectValue)
+ reflectValue = newValue
+ }
+
+ // Root command creating.
+ rootCmd, err = newCommandFromObjectMeta(object)
+ if err != nil {
+ return
+ }
+ // Sub command creating.
+ var (
+ nameSet = gset.NewStrSet()
+ rootCommandName = gmeta.Get(object, tagNameRoot).String()
+ subCommands []*Command
+ )
+ if rootCommandName == "" {
+ rootCommandName = rootCmd.Name
+ }
+ for i := 0; i < reflectValue.NumMethod(); i++ {
+ var (
+ method = reflectValue.Method(i)
+ methodCmd *Command
+ )
+ methodCmd, err = newCommandFromMethod(object, method)
+ if err != nil {
+ return
+ }
+ if nameSet.Contains(methodCmd.Name) {
+ err = gerror.Newf(
+ `command name should be unique, found duplicated command name in method "%s"`,
+ method.Type().String(),
+ )
+ return
+ }
+ if rootCommandName == methodCmd.Name {
+ methodToRootCmdWhenNameEqual(rootCmd, methodCmd)
+ } else {
+ subCommands = append(subCommands, methodCmd)
+ }
+ }
+ if len(subCommands) > 0 {
+ err = rootCmd.AddCommand(subCommands...)
+ }
+ return
+}
+
+func methodToRootCmdWhenNameEqual(rootCmd *Command, methodCmd *Command) {
+ if rootCmd.Usage == "" {
+ rootCmd.Usage = methodCmd.Usage
+ }
+ if rootCmd.Brief == "" {
+ rootCmd.Brief = methodCmd.Brief
+ }
+ if rootCmd.Description == "" {
+ rootCmd.Description = methodCmd.Description
+ }
+ if rootCmd.Examples == "" {
+ rootCmd.Examples = methodCmd.Examples
+ }
+ if rootCmd.Func == nil {
+ rootCmd.Func = methodCmd.Func
+ }
+ if rootCmd.FuncWithValue == nil {
+ rootCmd.FuncWithValue = methodCmd.FuncWithValue
+ }
+ if rootCmd.HelpFunc == nil {
+ rootCmd.HelpFunc = methodCmd.HelpFunc
+ }
+ if len(rootCmd.Arguments) == 0 {
+ rootCmd.Arguments = methodCmd.Arguments
+ }
+ if !rootCmd.Strict {
+ rootCmd.Strict = methodCmd.Strict
+ }
+ if rootCmd.Config == "" {
+ rootCmd.Config = methodCmd.Config
+ }
+}
+
+func newCommandFromObjectMeta(object interface{}) (command *Command, err error) {
+ var (
+ metaData = gmeta.Data(object)
+ )
+ if len(metaData) == 0 {
+ err = gerror.Newf(
+ `no meta data found in struct "%s"`,
+ reflect.TypeOf(object).String(),
+ )
+ return
+ }
+ if err = gconv.Scan(metaData, &command); err != nil {
+ return
+ }
+ // Name filed is necessary.
+ if command.Name == "" {
+ err = gerror.Newf(
+ `command name cannot be empty, "name" tag not found in meta of struct "%s"`,
+ reflect.TypeOf(object).String(),
+ )
+ return
+ }
+ if command.Description == "" {
+ command.Description = metaData[tagNameDc]
+ }
+ if command.Examples == "" {
+ command.Examples = metaData[tagNameEg]
+ }
+ if command.Additional == "" {
+ command.Additional = metaData[tagNameAd]
+ }
+ return
+}
+
+func newCommandFromMethod(object interface{}, method reflect.Value) (command *Command, err error) {
+ var (
+ reflectType = method.Type()
+ )
+ // Necessary validation for input/output parameters and naming.
+ if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
+ if reflectType.PkgPath() != "" {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid command: %s.%s.%s defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
+ reflectType.PkgPath(), reflect.TypeOf(object).Name(), reflectType.Name(), reflectType.String(),
+ )
+ } else {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid command: defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
+ reflectType.String(),
+ )
+ }
+ return
+ }
+ if reflectType.In(0).String() != "context.Context" {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid command: defined as "%s", but the first input parameter should be type of "context.Context"`,
+ reflectType.String(),
+ )
+ return
+ }
+ if reflectType.Out(1).String() != "error" {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid command: defined as "%s", but the last output parameter should be type of "error"`,
+ reflectType.String(),
+ )
+ return
+ }
+ // The input struct should be named as `xxxInput`.
+ if !gstr.HasSuffix(reflectType.In(1).String(), `Input`) {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid struct naming for input: defined as "%s", but it should be named with "Input" suffix like "xxxInput"`,
+ reflectType.In(1).String(),
+ )
+ return
+ }
+ // The output struct should be named as `xxxOutput`.
+ if !gstr.HasSuffix(reflectType.Out(0).String(), `Output`) {
+ err = gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid struct naming for output: defined as "%s", but it should be named with "Output" suffix like "xxxOutput"`,
+ reflectType.Out(0).String(),
+ )
+ return
+ }
+
+ var (
+ inputObject reflect.Value
+ )
+ if method.Type().In(1).Kind() == reflect.Ptr {
+ inputObject = reflect.New(method.Type().In(1).Elem()).Elem()
+ } else {
+ inputObject = reflect.New(method.Type().In(1)).Elem()
+ }
+
+ // Command creating.
+ if command, err = newCommandFromObjectMeta(inputObject.Interface()); err != nil {
+ return
+ }
+
+ // Options creating.
+ if command.Arguments, err = newArgumentsFromInput(inputObject.Interface()); err != nil {
+ return
+ }
+
+ // =============================================================================================
+ // Create function that has value return.
+ // =============================================================================================
+ command.FuncWithValue = func(ctx context.Context, parser *Parser) (out interface{}, err error) {
+ ctx = context.WithValue(ctx, CtxKeyParser, parser)
+ var (
+ data = gconv.Map(parser.GetOptAll())
+ argIndex = 0
+ arguments = gconv.Strings(ctx.Value(CtxKeyArguments))
+ inputValues = []reflect.Value{reflect.ValueOf(ctx)}
+ )
+ if data == nil {
+ data = map[string]interface{}{}
+ }
+ // Handle orphan options.
+ for _, arg := range command.Arguments {
+ if arg.IsArg {
+ // Read argument from command line index.
+ if argIndex < len(arguments) {
+ data[arg.Name] = arguments[argIndex]
+ argIndex++
+ }
+ } else {
+ // Read argument from command line option name.
+ if arg.Orphan && parser.GetOpt(arg.Name) != nil {
+ data[arg.Name] = "true"
+ }
+ }
+ }
+ // Default values from struct tag.
+ if err = mergeDefaultStructValue(data, inputObject.Interface()); err != nil {
+ return nil, err
+ }
+ // Construct input parameters.
+ if len(data) > 0 {
+ if inputObject.Kind() == reflect.Ptr {
+ err = gconv.Scan(data, inputObject.Interface())
+ } else {
+ err = gconv.Struct(data, inputObject.Addr().Interface())
+ }
+ if err != nil {
+ return
+ }
+ }
+
+ // Parameters validation.
+ if err = gvalid.New().Bail().Data(inputObject.Interface()).Assoc(data).Run(ctx); err != nil {
+ err = gerror.Wrapf(gerror.Current(err), `arguments validation failed for command "%s"`, command.Name)
+ return
+ }
+ inputValues = append(inputValues, inputObject)
+
+ // Call handler with dynamic created parameter values.
+ results := method.Call(inputValues)
+ out = results[0].Interface()
+ if !results[1].IsNil() {
+ if v, ok := results[1].Interface().(error); ok {
+ err = v
+ }
+ }
+ return
+ }
+ return
+}
+
+func newArgumentsFromInput(object interface{}) (args []Argument, err error) {
+ var (
+ fields []gstructs.Field
+ nameSet = gset.NewStrSet()
+ shortSet = gset.NewStrSet()
+ )
+ fields, err = gstructs.Fields(gstructs.FieldsInput{
+ Pointer: object,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ for _, field := range fields {
+ var (
+ arg = Argument{}
+ metaData = field.TagMap()
+ )
+ if err = gconv.Scan(metaData, &arg); err != nil {
+ return nil, err
+ }
+ if arg.Name == "" {
+ arg.Name = field.Name()
+ }
+ if arg.Name == helpOptionName {
+ return nil, gerror.Newf(
+ `argument name "%s" defined in "%s.%s" is already token by built-in arguments`,
+ arg.Name, reflect.TypeOf(object).String(), field.Name(),
+ )
+ }
+ if arg.Short == helpOptionNameShort {
+ return nil, gerror.Newf(
+ `short argument name "%s" defined in "%s.%s" is already token by built-in arguments`,
+ arg.Short, reflect.TypeOf(object).String(), field.Name(),
+ )
+ }
+ if v, ok := metaData[tagNameArg]; ok {
+ arg.IsArg = gconv.Bool(v)
+ }
+ if nameSet.Contains(arg.Name) {
+ return nil, gerror.Newf(
+ `argument name "%s" defined in "%s.%s" is already token by other argument`,
+ arg.Name, reflect.TypeOf(object).String(), field.Name(),
+ )
+ }
+ nameSet.Add(arg.Name)
+
+ if arg.Short != "" {
+ if shortSet.Contains(arg.Short) {
+ return nil, gerror.Newf(
+ `short argument name "%s" defined in "%s.%s" is already token by other argument`,
+ arg.Short, reflect.TypeOf(object).String(), field.Name(),
+ )
+ }
+ shortSet.Add(arg.Short)
+ }
+
+ args = append(args, arg)
+ }
+
+ return
+}
+
+// mergeDefaultStructValue merges the request parameters with default values from struct tag definition.
+func mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error {
+ tagFields, err := gstructs.TagFields(pointer, defaultValueTags)
+ if err != nil {
+ return err
+ }
+ if len(tagFields) > 0 {
+ var (
+ foundKey string
+ foundValue interface{}
+ )
+ for _, field := range tagFields {
+ foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
+ if foundKey == "" {
+ data[field.Name()] = field.TagValue
+ } else {
+ if utils.IsEmpty(foundValue) {
+ data[foundKey] = field.TagValue
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go
new file mode 100644
index 000000000000..845900fa88d2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go
@@ -0,0 +1,216 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gcmd
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gcfg"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// Run calls custom function that bound to this command.
+// It exits this process with exit code 1 if any error occurs.
+func (c *Command) Run(ctx context.Context) {
+ _ = c.RunWithValue(ctx)
+}
+
+// RunWithValue calls custom function that bound to this command with value output.
+// It exits this process with exit code 1 if any error occurs.
+func (c *Command) RunWithValue(ctx context.Context) (value interface{}) {
+ value, err := c.RunWithValueError(ctx)
+ if err != nil {
+ var (
+ code = gerror.Code(err)
+ detail = code.Detail()
+ )
+ if code.Code() == gcode.CodeNotFound.Code() {
+ fmt.Printf("ERROR: %s\n", gstr.Trim(err.Error()))
+ if lastCmd, ok := detail.(*Command); ok {
+ lastCmd.Print()
+ } else {
+ c.Print()
+ }
+ } else {
+ fmt.Printf("%+v\n", err)
+ }
+ os.Exit(1)
+ }
+ return value
+}
+
+// RunWithError calls custom function that bound to this command with error output.
+func (c *Command) RunWithError(ctx context.Context) (err error) {
+ _, err = c.RunWithValueError(ctx)
+ return
+}
+
+// RunWithValueError calls custom function that bound to this command with value and error output.
+func (c *Command) RunWithValueError(ctx context.Context) (value interface{}, err error) {
+ // Parse command arguments and options using default algorithm.
+ parser, err := Parse(nil)
+ if err != nil {
+ return nil, err
+ }
+ args := parser.GetArgAll()
+ if len(args) == 1 {
+ return c.doRun(ctx, parser)
+ }
+
+ // Exclude the root binary name.
+ args = args[1:]
+
+ // Find the matched command and run it.
+ lastCmd, foundCmd, newCtx := c.searchCommand(ctx, args)
+ if foundCmd != nil {
+ return foundCmd.doRun(newCtx, parser)
+ }
+
+ // Print error and help command if no command found.
+ err = gerror.NewCodef(
+ gcode.WithCode(gcode.CodeNotFound, lastCmd),
+ `command "%s" not found for command "%s", command line: %s`,
+ gstr.Join(args, " "),
+ c.Name,
+ gstr.Join(os.Args, " "),
+ )
+ return
+}
+
+func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{}, err error) {
+ defer func() {
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.Newf(`exception recovered: %+v`, exception)
+ }
+ }
+ }()
+
+ ctx = context.WithValue(ctx, CtxKeyCommand, c)
+ // Check built-in help command.
+ if parser.GetOpt(helpOptionName) != nil || parser.GetOpt(helpOptionNameShort) != nil {
+ if c.HelpFunc != nil {
+ return nil, c.HelpFunc(ctx, parser)
+ }
+ return nil, c.defaultHelpFunc(ctx, parser)
+ }
+ // Reparse the arguments for current command configuration.
+ parser, err = c.reParse(ctx, parser)
+ if err != nil {
+ return nil, err
+ }
+ // Registered command function calling.
+ if c.Func != nil {
+ return nil, c.Func(ctx, parser)
+ }
+ if c.FuncWithValue != nil {
+ return c.FuncWithValue(ctx, parser)
+ }
+ // If no function defined in current command, it then prints help.
+ if c.HelpFunc != nil {
+ return nil, c.HelpFunc(ctx, parser)
+ }
+ return nil, c.defaultHelpFunc(ctx, parser)
+}
+
+// reParse re-parses the arguments using option configuration of current command.
+func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error) {
+ if len(c.Arguments) == 0 {
+ return parser, nil
+ }
+ var (
+ optionKey string
+ supportedOptions = make(map[string]bool)
+ )
+ for _, arg := range c.Arguments {
+ if arg.IsArg {
+ continue
+ }
+ if arg.Short != "" {
+ optionKey = fmt.Sprintf(`%s,%s`, arg.Name, arg.Short)
+ } else {
+ optionKey = arg.Name
+ }
+ supportedOptions[optionKey] = !arg.Orphan
+ }
+ parser, err := Parse(supportedOptions, c.Strict)
+ if err != nil {
+ return nil, err
+ }
+ // Retrieve option values from config component if it has "config" tag.
+ if c.Config != "" && gcfg.Instance().Available(ctx) {
+ value, err := gcfg.Instance().Get(ctx, c.Config)
+ if err != nil {
+ return nil, err
+ }
+ configMap := value.Map()
+ for optionName, _ := range parser.supportedOptions {
+ // The command line has the high priority.
+ if parser.GetOpt(optionName) != nil {
+ continue
+ }
+ // Merge the config value into parser.
+ foundKey, foundValue := gutil.MapPossibleItemByKey(configMap, optionName)
+ if foundKey != "" {
+ parser.parsedOptions[optionName] = gconv.String(foundValue)
+ }
+ }
+ }
+ return parser, nil
+}
+
+// searchCommand recursively searches the command according given arguments.
+func (c *Command) searchCommand(ctx context.Context, args []string) (lastCmd, foundCmd *Command, newCtx context.Context) {
+ if len(args) == 0 {
+ return c, nil, ctx
+ }
+ for _, cmd := range c.commands {
+ // Recursively searching the command.
+ if cmd.Name == args[0] {
+ leftArgs := args[1:]
+ // If this command needs argument,
+ // it then gives all its left arguments to it.
+ if cmd.hasArgumentFromIndex() {
+ ctx = context.WithValue(ctx, CtxKeyArguments, leftArgs)
+ return c, cmd, ctx
+ }
+ // Recursively searching.
+ if len(leftArgs) == 0 {
+ return c, cmd, ctx
+ }
+ return cmd.searchCommand(ctx, leftArgs)
+ }
+ }
+ return c, nil, ctx
+}
+
+func (c *Command) hasArgumentFromIndex() bool {
+ for _, arg := range c.Arguments {
+ if arg.IsArg {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *Command) hasArgumentFromOption() bool {
+ for _, arg := range c.Arguments {
+ if !arg.IsArg {
+ return true
+ }
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_parser.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_parser.go
new file mode 100644
index 000000000000..35aa4ae8246c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_parser.go
@@ -0,0 +1,225 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gcmd
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Parser for arguments.
+type Parser struct {
+ strict bool // Whether stops parsing and returns error if invalid option passed.
+ parsedArgs []string // As name described.
+ parsedOptions map[string]string // As name described.
+ passedOptions map[string]bool // User passed supported options, like: map[string]bool{"name,n":true}
+ supportedOptions map[string]bool // Option [OptionName:WhetherNeedArgument], like: map[string]bool{"name":true, "n":true}
+ commandFuncMap map[string]func() // Command function map for function handler.
+}
+
+// ParserFromCtx retrieves and returns Parser from context.
+func ParserFromCtx(ctx context.Context) *Parser {
+ if v := ctx.Value(CtxKeyParser); v != nil {
+ if p, ok := v.(*Parser); ok {
+ return p
+ }
+ }
+ return nil
+}
+
+// Parse creates and returns a new Parser with os.Args and supported options.
+//
+// Note that the parameter `supportedOptions` is as [option name: need argument], which means
+// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.
+//
+// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.
+func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
+ if supportedOptions == nil {
+ command.Init(os.Args...)
+ return &Parser{
+ parsedArgs: GetArgAll(),
+ parsedOptions: GetOptAll(),
+ }, nil
+ }
+ return ParseArgs(os.Args, supportedOptions, strict...)
+}
+
+// ParseArgs creates and returns a new Parser with given arguments and supported options.
+//
+// Note that the parameter `supportedOptions` is as [option name: need argument], which means
+// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.
+//
+// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.
+func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
+ if supportedOptions == nil {
+ command.Init(args...)
+ return &Parser{
+ parsedArgs: GetArgAll(),
+ parsedOptions: GetOptAll(),
+ }, nil
+ }
+ strictParsing := false
+ if len(strict) > 0 {
+ strictParsing = strict[0]
+ }
+ parser := &Parser{
+ strict: strictParsing,
+ parsedArgs: make([]string, 0),
+ parsedOptions: make(map[string]string),
+ passedOptions: supportedOptions,
+ supportedOptions: make(map[string]bool),
+ commandFuncMap: make(map[string]func()),
+ }
+ for name, needArgument := range supportedOptions {
+ for _, v := range strings.Split(name, ",") {
+ parser.supportedOptions[strings.TrimSpace(v)] = needArgument
+ }
+ }
+
+ for i := 0; i < len(args); {
+ if option := parser.parseOption(args[i]); option != "" {
+ array, _ := gregex.MatchString(`^(.+?)=(.+)$`, option)
+ if len(array) == 3 {
+ if parser.isOptionValid(array[1]) {
+ parser.setOptionValue(array[1], array[2])
+ }
+ } else {
+ if parser.isOptionValid(option) {
+ if parser.isOptionNeedArgument(option) {
+ if i < len(args)-1 {
+ parser.setOptionValue(option, args[i+1])
+ i += 2
+ continue
+ }
+ } else {
+ parser.setOptionValue(option, "")
+ i++
+ continue
+ }
+ } else {
+ // Multiple options?
+ if array = parser.parseMultiOption(option); len(array) > 0 {
+ for _, v := range array {
+ parser.setOptionValue(v, "")
+ }
+ i++
+ continue
+ } else if parser.strict {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid option '%s'`, args[i])
+ }
+ }
+ }
+ } else {
+ parser.parsedArgs = append(parser.parsedArgs, args[i])
+ }
+ i++
+ }
+ return parser, nil
+}
+
+// parseMultiOption parses option to multiple valid options like: --dav.
+// It returns nil if given option is not multi-option.
+func (p *Parser) parseMultiOption(option string) []string {
+ for i := 1; i <= len(option); i++ {
+ s := option[:i]
+ if p.isOptionValid(s) && !p.isOptionNeedArgument(s) {
+ if i == len(option) {
+ return []string{s}
+ }
+ array := p.parseMultiOption(option[i:])
+ if len(array) == 0 {
+ return nil
+ }
+ return append(array, s)
+ }
+ }
+ return nil
+}
+
+func (p *Parser) parseOption(argument string) string {
+ array, _ := gregex.MatchString(`^\-{1,2}(.+)$`, argument)
+ if len(array) == 2 {
+ return array[1]
+ }
+ return ""
+}
+
+func (p *Parser) isOptionValid(name string) bool {
+ _, ok := p.supportedOptions[name]
+ return ok
+}
+
+func (p *Parser) isOptionNeedArgument(name string) bool {
+ return p.supportedOptions[name]
+}
+
+// setOptionValue sets the option value for name and according alias.
+func (p *Parser) setOptionValue(name, value string) {
+ for optionName, _ := range p.passedOptions {
+ array := gstr.SplitAndTrim(optionName, ",")
+ for _, v := range array {
+ if strings.EqualFold(v, name) {
+ for _, v := range array {
+ p.parsedOptions[v] = value
+ }
+ return
+ }
+ }
+ }
+}
+
+// GetOpt returns the option value named `name` as gvar.Var.
+func (p *Parser) GetOpt(name string, def ...interface{}) *gvar.Var {
+ if v, ok := p.parsedOptions[name]; ok {
+ return gvar.New(v)
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// GetOptAll returns all parsed options.
+func (p *Parser) GetOptAll() map[string]string {
+ return p.parsedOptions
+}
+
+// GetArg returns the argument at `index` as gvar.Var.
+func (p *Parser) GetArg(index int, def ...string) *gvar.Var {
+ if index < len(p.parsedArgs) {
+ return gvar.New(p.parsedArgs[index])
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// GetArgAll returns all parsed arguments.
+func (p *Parser) GetArgAll() []string {
+ return p.parsedArgs
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (p Parser) MarshalJSON() ([]byte, error) {
+ return json.Marshal(map[string]interface{}{
+ "parsedArgs": p.parsedArgs,
+ "parsedOptions": p.parsedOptions,
+ "passedOptions": p.passedOptions,
+ "supportedOptions": p.supportedOptions,
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_scan.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_scan.go
new file mode 100644
index 000000000000..d29296b18c52
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gcmd/gcmd_scan.go
@@ -0,0 +1,36 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+
+package gcmd
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Scan prints `info` to stdout, reads and returns user input, which stops by '\n'.
+func Scan(info ...interface{}) string {
+ fmt.Print(info...)
+ return readline()
+}
+
+// Scanf prints `info` to stdout with `format`, reads and returns user input, which stops by '\n'.
+func Scanf(format string, info ...interface{}) string {
+ fmt.Printf(format, info...)
+ return readline()
+}
+
+func readline() string {
+ var s string
+ reader := bufio.NewReader(os.Stdin)
+ s, _ = reader.ReadString('\n')
+ s = gstr.Trim(s)
+ return s
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gctx/gctx.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gctx/gctx.go
new file mode 100644
index 000000000000..a81138379c90
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gctx/gctx.go
@@ -0,0 +1,39 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gctx wraps context.Context and provides extra context features.
+package gctx
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/net/gtrace"
+)
+
+type (
+ Ctx = context.Context // Ctx is short name alias for context.Context.
+ StrKey string // StrKey is a type for warps basic type string as context key.
+)
+
+// New creates and returns a context which contains context id.
+func New() context.Context {
+ return WithCtx(context.Background())
+}
+
+// WithCtx creates and returns a context containing context id upon given parent context `ctx`.
+func WithCtx(ctx context.Context) context.Context {
+ if gtrace.IsUsingDefaultProvider() {
+ var span *gtrace.Span
+ ctx, span = gtrace.NewSpan(ctx, "gctx.WithCtx")
+ defer span.End()
+ }
+ return ctx
+}
+
+// CtxId retrieves and returns the context id from context.
+func CtxId(ctx context.Context) string {
+ return gtrace.GetTraceID(ctx)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/genv/genv.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/genv/genv.go
new file mode 100644
index 000000000000..f687f32202e2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/genv/genv.go
@@ -0,0 +1,119 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package genv provides operations for environment variables of system.
+package genv
+
+import (
+ "os"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// All returns a copy of strings representing the environment,
+// in the form "key=value".
+func All() []string {
+ return os.Environ()
+}
+
+// Map returns a copy of strings representing the environment as a map.
+func Map() map[string]string {
+ m := make(map[string]string)
+ i := 0
+ for _, s := range os.Environ() {
+ i = strings.IndexByte(s, '=')
+ m[s[0:i]] = s[i+1:]
+ }
+ return m
+}
+
+// Get creates and returns a Var with the value of the environment variable
+// named by the `key`. It uses the given `def` if the variable does not exist
+// in the environment.
+func Get(key string, def ...interface{}) *gvar.Var {
+ v, ok := os.LookupEnv(key)
+ if !ok {
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+ }
+ return gvar.New(v)
+}
+
+// Set sets the value of the environment variable named by the `key`.
+// It returns an error, if any.
+func Set(key, value string) (err error) {
+ err = os.Setenv(key, value)
+ if err != nil {
+ err = gerror.Wrapf(err, `set environment key-value failed with key "%s", value "%s"`, key, value)
+ }
+ return
+}
+
+// SetMap sets the environment variables using map.
+func SetMap(m map[string]string) (err error) {
+ for k, v := range m {
+ if err = Set(k, v); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Contains checks whether the environment variable named `key` exists.
+func Contains(key string) bool {
+ _, ok := os.LookupEnv(key)
+ return ok
+}
+
+// Remove deletes one or more environment variables.
+func Remove(key ...string) (err error) {
+ for _, v := range key {
+ if err = os.Unsetenv(v); err != nil {
+ err = gerror.Wrapf(err, `delete environment key failed with key "%s"`, v)
+ return err
+ }
+ }
+ return nil
+}
+
+// GetWithCmd returns the environment value specified `key`.
+// If the environment value does not exist, then it retrieves and returns the value from command line options.
+// It returns the default value `def` if none of them exists.
+//
+// Fetching Rules:
+// 1. Environment arguments are in uppercase format, eg: GF__;
+// 2. Command line arguments are in lowercase format, eg: gf..;
+func GetWithCmd(key string, def ...interface{}) *gvar.Var {
+ envKey := utils.FormatEnvKey(key)
+ if v := os.Getenv(envKey); v != "" {
+ return gvar.New(v)
+ }
+ cmdKey := utils.FormatCmdKey(key)
+ if v := command.GetOpt(cmdKey); v != "" {
+ return gvar.New(v)
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0])
+ }
+ return nil
+}
+
+// Build builds a map to an environment variable slice.
+func Build(m map[string]string) []string {
+ array := make([]string, len(m))
+ index := 0
+ for k, v := range m {
+ array[index] = k + "=" + v
+ index++
+ }
+ return array
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/genv/genv_must.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/genv/genv_must.go
new file mode 100644
index 000000000000..3ee5539f248b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/genv/genv_must.go
@@ -0,0 +1,21 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package genv
+
+// MustSet performs as Set, but it panics if any error occurs.
+func MustSet(key, value string) {
+ if err := Set(key, value); err != nil {
+ panic(err)
+ }
+}
+
+// MustRemove performs as Remove, but it panics if any error occurs.
+func MustRemove(key ...string) {
+ if err := Remove(key...); err != nil {
+ panic(err)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile.go
new file mode 100644
index 000000000000..590112bf7af3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile.go
@@ -0,0 +1,447 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gfile provides easy-to-use operations for file system.
+package gfile
+
+import (
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ // Separator for file system.
+ // It here defines the separator as variable
+ // to allow it modified by developer if necessary.
+ Separator = string(filepath.Separator)
+
+ // DefaultPermOpen is the default perm for file opening.
+ DefaultPermOpen = os.FileMode(0666)
+
+ // DefaultPermCopy is the default perm for file/folder copy.
+ DefaultPermCopy = os.FileMode(0777)
+)
+
+var (
+ // The absolute file path for main package.
+ // It can be only checked and set once.
+ mainPkgPath = gtype.NewString()
+
+ // selfPath is the current running binary path.
+ // As it is most commonly used, it is so defined as an internal package variable.
+ selfPath = ""
+
+ // Temporary directory of system.
+ tempDir = "/tmp"
+)
+
+func init() {
+ // Initialize internal package variable: tempDir.
+ if Separator != "/" || !Exists(tempDir) {
+ tempDir = os.TempDir()
+ }
+ // Initialize internal package variable: selfPath.
+ selfPath, _ = exec.LookPath(os.Args[0])
+ if selfPath != "" {
+ selfPath, _ = filepath.Abs(selfPath)
+ }
+ if selfPath == "" {
+ selfPath, _ = filepath.Abs(os.Args[0])
+ }
+}
+
+// Mkdir creates directories recursively with given `path`.
+// The parameter `path` is suggested to be an absolute path instead of relative one.
+func Mkdir(path string) (err error) {
+ if err = os.MkdirAll(path, os.ModePerm); err != nil {
+ err = gerror.Wrapf(err, `os.MkdirAll failed for path "%s" with perm "%d"`, path, os.ModePerm)
+ return err
+ }
+ return nil
+}
+
+// Create creates file with given `path` recursively.
+// The parameter `path` is suggested to be absolute path.
+func Create(path string) (*os.File, error) {
+ dir := Dir(path)
+ if !Exists(dir) {
+ if err := Mkdir(dir); err != nil {
+ return nil, err
+ }
+ }
+ file, err := os.Create(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Create failed for name "%s"`, path)
+ }
+ return file, err
+}
+
+// Open opens file/directory READONLY.
+func Open(path string) (*os.File, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Open failed for name "%s"`, path)
+ }
+ return file, err
+}
+
+// OpenFile opens file/directory with custom `flag` and `perm`.
+// The parameter `flag` is like: O_RDONLY, O_RDWR, O_RDWR|O_CREATE|O_TRUNC, etc.
+func OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {
+ file, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.OpenFile failed with name "%s", flag "%d", perm "%d"`, path, flag, perm)
+ }
+ return file, err
+}
+
+// OpenWithFlag opens file/directory with default perm and custom `flag`.
+// The default `perm` is 0666.
+// The parameter `flag` is like: O_RDONLY, O_RDWR, O_RDWR|O_CREATE|O_TRUNC, etc.
+func OpenWithFlag(path string, flag int) (*os.File, error) {
+ file, err := OpenFile(path, flag, DefaultPermOpen)
+ if err != nil {
+ return nil, err
+ }
+ return file, nil
+}
+
+// OpenWithFlagPerm opens file/directory with custom `flag` and `perm`.
+// The parameter `flag` is like: O_RDONLY, O_RDWR, O_RDWR|O_CREATE|O_TRUNC, etc.
+// The parameter `perm` is like: 0600, 0666, 0777, etc.
+func OpenWithFlagPerm(path string, flag int, perm os.FileMode) (*os.File, error) {
+ file, err := OpenFile(path, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ return file, nil
+}
+
+// Join joins string array paths with file separator of current system.
+func Join(paths ...string) string {
+ var s string
+ for _, path := range paths {
+ if s != "" {
+ s += Separator
+ }
+ s += gstr.TrimRight(path, Separator)
+ }
+ return s
+}
+
+// Exists checks whether given `path` exist.
+func Exists(path string) bool {
+ if stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {
+ return true
+ }
+ return false
+}
+
+// IsDir checks whether given `path` a directory.
+// Note that it returns false if the `path` does not exist.
+func IsDir(path string) bool {
+ s, err := os.Stat(path)
+ if err != nil {
+ return false
+ }
+ return s.IsDir()
+}
+
+// Pwd returns absolute path of current working directory.
+// Note that it returns an empty string if retrieving current
+// working directory failed.
+func Pwd() string {
+ path, err := os.Getwd()
+ if err != nil {
+ return ""
+ }
+ return path
+}
+
+// Chdir changes the current working directory to the named directory.
+// If there is an error, it will be of type *PathError.
+func Chdir(dir string) (err error) {
+ err = os.Chdir(dir)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Chdir failed with dir "%s"`, dir)
+ }
+ return
+}
+
+// IsFile checks whether given `path` a file, which means it's not a directory.
+// Note that it returns false if the `path` does not exist.
+func IsFile(path string) bool {
+ s, err := Stat(path)
+ if err != nil {
+ return false
+ }
+ return !s.IsDir()
+}
+
+// Stat returns a FileInfo describing the named file.
+// If there is an error, it will be of type *PathError.
+func Stat(path string) (os.FileInfo, error) {
+ info, err := os.Stat(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Stat failed for file "%s"`, path)
+ }
+ return info, err
+}
+
+// Move renames (moves) `src` to `dst` path.
+// If `dst` already exists and is not a directory, it'll be replaced.
+func Move(src string, dst string) (err error) {
+ err = os.Rename(src, dst)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Rename failed from "%s" to "%s"`, src, dst)
+ }
+ return
+}
+
+// Rename is alias of Move.
+// See Move.
+func Rename(src string, dst string) error {
+ return Move(src, dst)
+}
+
+// DirNames returns sub-file names of given directory `path`.
+// Note that the returned names are NOT absolute paths.
+func DirNames(path string) ([]string, error) {
+ f, err := Open(path)
+ if err != nil {
+ return nil, err
+ }
+ list, err := f.Readdirnames(-1)
+ _ = f.Close()
+ if err != nil {
+ err = gerror.Wrapf(err, `Read dir files failed from path "%s"`, path)
+ return nil, err
+ }
+ return list, nil
+}
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of patterns is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed (assuming the Separator is '/').
+//
+// Glob ignores file system errors such as I/O errors reading directories.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
+func Glob(pattern string, onlyNames ...bool) ([]string, error) {
+ list, err := filepath.Glob(pattern)
+ if err != nil {
+ err = gerror.Wrapf(err, `filepath.Glob failed for pattern "%s"`, pattern)
+ return nil, err
+ }
+ if len(onlyNames) > 0 && onlyNames[0] && len(list) > 0 {
+ array := make([]string, len(list))
+ for k, v := range list {
+ array[k] = Basename(v)
+ }
+ return array, nil
+ }
+ return list, nil
+}
+
+// Remove deletes all file/directory with `path` parameter.
+// If parameter `path` is directory, it deletes it recursively.
+func Remove(path string) (err error) {
+ err = os.RemoveAll(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.RemoveAll failed for path "%s"`, path)
+ }
+ return
+}
+
+// IsReadable checks whether given `path` is readable.
+func IsReadable(path string) bool {
+ result := true
+ file, err := os.OpenFile(path, os.O_RDONLY, DefaultPermOpen)
+ if err != nil {
+ result = false
+ }
+ file.Close()
+ return result
+}
+
+// IsWritable checks whether given `path` is writable.
+//
+// TODO improve performance; use golang.org/x/sys to cross-plat-form
+func IsWritable(path string) bool {
+ result := true
+ if IsDir(path) {
+ // If it's a directory, create a temporary file to test whether it's writable.
+ tmpFile := strings.TrimRight(path, Separator) + Separator + gconv.String(time.Now().UnixNano())
+ if f, err := Create(tmpFile); err != nil || !Exists(tmpFile) {
+ result = false
+ } else {
+ _ = f.Close()
+ _ = Remove(tmpFile)
+ }
+ } else {
+ // If it's a file, check if it can open it.
+ file, err := os.OpenFile(path, os.O_WRONLY, DefaultPermOpen)
+ if err != nil {
+ result = false
+ }
+ _ = file.Close()
+ }
+ return result
+}
+
+// Chmod is alias of os.Chmod.
+// See os.Chmod.
+func Chmod(path string, mode os.FileMode) (err error) {
+ err = os.Chmod(path, mode)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Chmod failed with path "%s" and mode "%s"`, path, mode)
+ }
+ return
+}
+
+// Abs returns an absolute representation of path.
+// If the path is not absolute it will be joined with the current
+// working directory to turn it into an absolute path. The absolute
+// path name for a given file is not guaranteed to be unique.
+// Abs calls Clean on the result.
+func Abs(path string) string {
+ p, _ := filepath.Abs(path)
+ return p
+}
+
+// RealPath converts the given `path` to its absolute path
+// and checks if the file path exists.
+// If the file does not exist, return an empty string.
+func RealPath(path string) string {
+ p, err := filepath.Abs(path)
+ if err != nil {
+ return ""
+ }
+ if !Exists(p) {
+ return ""
+ }
+ return p
+}
+
+// SelfPath returns absolute file path of current running process(binary).
+func SelfPath() string {
+ return selfPath
+}
+
+// SelfName returns file name of current running process(binary).
+func SelfName() string {
+ return Basename(SelfPath())
+}
+
+// SelfDir returns absolute directory path of current running process(binary).
+func SelfDir() string {
+ return filepath.Dir(SelfPath())
+}
+
+// Basename returns the last element of path, which contains file extension.
+// Trailing path separators are removed before extracting the last element.
+// If the path is empty, Base returns ".".
+// If the path consists entirely of separators, Basename returns a single separator.
+// Example:
+// /var/www/file.js -> file.js
+// file.js -> file.js
+func Basename(path string) string {
+ return filepath.Base(path)
+}
+
+// Name returns the last element of path without file extension.
+// Example:
+// /var/www/file.js -> file
+// file.js -> file
+func Name(path string) string {
+ base := filepath.Base(path)
+ if i := strings.LastIndexByte(base, '.'); i != -1 {
+ return base[:i]
+ }
+ return base
+}
+
+// Dir returns all but the last element of path, typically the path's directory.
+// After dropping the final element, Dir calls Clean on the path and trailing
+// slashes are removed.
+// If the `path` is empty, Dir returns ".".
+// If the `path` is ".", Dir treats the path as current working directory.
+// If the `path` consists entirely of separators, Dir returns a single separator.
+// The returned path does not end in a separator unless it is the root directory.
+func Dir(path string) string {
+ if path == "." {
+ return filepath.Dir(RealPath(path))
+ }
+ return filepath.Dir(path)
+}
+
+// IsEmpty checks whether the given `path` is empty.
+// If `path` is a folder, it checks if there's any file under it.
+// If `path` is a file, it checks if the file size is zero.
+//
+// Note that it returns true if `path` does not exist.
+func IsEmpty(path string) bool {
+ stat, err := Stat(path)
+ if err != nil {
+ return true
+ }
+ if stat.IsDir() {
+ file, err := os.Open(path)
+ if err != nil {
+ return true
+ }
+ defer file.Close()
+ names, err := file.Readdirnames(-1)
+ if err != nil {
+ return true
+ }
+ return len(names) == 0
+ } else {
+ return stat.Size() == 0
+ }
+}
+
+// Ext returns the file name extension used by path.
+// The extension is the suffix beginning at the final dot
+// in the final element of path; it is empty if there is
+// no dot.
+//
+// Note: the result contains symbol '.'.
+func Ext(path string) string {
+ ext := filepath.Ext(path)
+ if p := strings.IndexByte(ext, '?'); p != -1 {
+ ext = ext[0:p]
+ }
+ return ext
+}
+
+// ExtName is like function Ext, which returns the file name extension used by path,
+// but the result does not contain symbol '.'.
+func ExtName(path string) string {
+ return strings.TrimLeft(Ext(path), ".")
+}
+
+// Temp retrieves and returns the temporary directory of current system.
+// It returns "/tmp" is current in *nix system, or else it returns os.TempDir().
+//
+// The optional parameter `names` specifies the sub-folders/sub-files,
+// which will be joined with current system separator and returned with the path.
+func Temp(names ...string) string {
+ path := tempDir
+ for _, name := range names {
+ path += Separator + name
+ }
+ return path
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_cache.go
new file mode 100644
index 000000000000..526bec196f77
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_cache.go
@@ -0,0 +1,79 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcache"
+ "github.com/gogf/gf/v2/os/gfsnotify"
+)
+
+const (
+ defaultCacheExpire = "1m" // defaultCacheExpire is the expire time for file content caching in seconds.
+ commandEnvKeyForCache = "gf.gfile.cache" // commandEnvKeyForCache is the configuration key for command argument or environment configuring cache expire duration.
+)
+
+var (
+ // Default expire time for file content caching.
+ cacheExpire = getCacheExpire()
+
+ // internalCache is the memory cache for internal usage.
+ internalCache = gcache.New()
+)
+
+func getCacheExpire() time.Duration {
+ d, err := time.ParseDuration(command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheExpire))
+ if err != nil {
+ panic(err)
+ }
+ return d
+}
+
+// GetContentsWithCache returns string content of given file by `path` from cache.
+// If there's no content in the cache, it will read it from disk file specified by `path`.
+// The parameter `expire` specifies the caching time for this file content in seconds.
+func GetContentsWithCache(path string, duration ...time.Duration) string {
+ return string(GetBytesWithCache(path, duration...))
+}
+
+// GetBytesWithCache returns []byte content of given file by `path` from cache.
+// If there's no content in the cache, it will read it from disk file specified by `path`.
+// The parameter `expire` specifies the caching time for this file content in seconds.
+func GetBytesWithCache(path string, duration ...time.Duration) []byte {
+ var (
+ ctx = context.Background()
+ expire = cacheExpire
+ cacheKey = commandEnvKeyForCache + path
+ )
+
+ if len(duration) > 0 {
+ expire = duration[0]
+ }
+ r, _ := internalCache.GetOrSetFuncLock(ctx, cacheKey, func(ctx context.Context) (interface{}, error) {
+ b := GetBytes(path)
+ if b != nil {
+ // Adding this `path` to gfsnotify,
+ // it will clear its cache if there's any changes of the file.
+ _, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
+ _, err := internalCache.Remove(ctx, cacheKey)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ gfsnotify.Exit()
+ })
+ }
+ return b, nil
+ }, expire)
+ if r != nil {
+ return r.Bytes()
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_contents.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_contents.go
new file mode 100644
index 000000000000..5db609e5de6c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_contents.go
@@ -0,0 +1,214 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "bufio"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+var (
+ // DefaultReadBuffer is the buffer size for reading file content.
+ DefaultReadBuffer = 1024
+)
+
+// GetContents returns the file content of `path` as string.
+// It returns en empty string if it fails reading.
+func GetContents(path string) string {
+ return string(GetBytes(path))
+}
+
+// GetBytes returns the file content of `path` as []byte.
+// It returns nil if it fails reading.
+func GetBytes(path string) []byte {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil
+ }
+ return data
+}
+
+// putContents puts binary content to file of `path`.
+func putContents(path string, data []byte, flag int, perm os.FileMode) error {
+ // It supports creating file of `path` recursively.
+ dir := Dir(path)
+ if !Exists(dir) {
+ if err := Mkdir(dir); err != nil {
+ return err
+ }
+ }
+ // Opening file with given `flag` and `perm`.
+ f, err := OpenWithFlagPerm(path, flag, perm)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ // Write data.
+ var n int
+ if n, err = f.Write(data); err != nil {
+ err = gerror.Wrapf(err, `Write data to file "%s" failed`, path)
+ return err
+ } else if n < len(data) {
+ return io.ErrShortWrite
+ }
+ return nil
+}
+
+// Truncate truncates file of `path` to given size by `size`.
+func Truncate(path string, size int) (err error) {
+ err = os.Truncate(path, int64(size))
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Truncate failed for file "%s", size "%d"`, path, size)
+ }
+ return
+}
+
+// PutContents puts string `content` to file of `path`.
+// It creates file of `path` recursively if it does not exist.
+func PutContents(path string, content string) error {
+ return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen)
+}
+
+// PutContentsAppend appends string `content` to file of `path`.
+// It creates file of `path` recursively if it does not exist.
+func PutContentsAppend(path string, content string) error {
+ return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen)
+}
+
+// PutBytes puts binary `content` to file of `path`.
+// It creates file of `path` recursively if it does not exist.
+func PutBytes(path string, content []byte) error {
+ return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen)
+}
+
+// PutBytesAppend appends binary `content` to file of `path`.
+// It creates file of `path` recursively if it does not exist.
+func PutBytesAppend(path string, content []byte) error {
+ return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen)
+}
+
+// GetNextCharOffset returns the file offset for given `char` starting from `start`.
+func GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 {
+ buffer := make([]byte, DefaultReadBuffer)
+ offset := start
+ for {
+ if n, err := reader.ReadAt(buffer, offset); n > 0 {
+ for i := 0; i < n; i++ {
+ if buffer[i] == char {
+ return int64(i) + offset
+ }
+ }
+ offset += int64(n)
+ } else if err != nil {
+ break
+ }
+ }
+ return -1
+}
+
+// GetNextCharOffsetByPath returns the file offset for given `char` starting from `start`.
+// It opens file of `path` for reading with os.O_RDONLY flag and default perm.
+func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
+ if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {
+ defer f.Close()
+ return GetNextCharOffset(f, char, start)
+ }
+ return -1
+}
+
+// GetBytesTilChar returns the contents of the file as []byte
+// until the next specified byte `char` position.
+//
+// Note: Returned value contains the character of the last position.
+func GetBytesTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
+ if offset := GetNextCharOffset(reader, char, start); offset != -1 {
+ return GetBytesByTwoOffsets(reader, start, offset+1), offset
+ }
+ return nil, -1
+}
+
+// GetBytesTilCharByPath returns the contents of the file given by `path` as []byte
+// until the next specified byte `char` position.
+// It opens file of `path` for reading with os.O_RDONLY flag and default perm.
+//
+// Note: Returned value contains the character of the last position.
+func GetBytesTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
+ if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {
+ defer f.Close()
+ return GetBytesTilChar(f, char, start)
+ }
+ return nil, -1
+}
+
+// GetBytesByTwoOffsets returns the binary content as []byte from `start` to `end`.
+// Note: Returned value does not contain the character of the last position, which means
+// it returns content range as [start, end).
+func GetBytesByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
+ buffer := make([]byte, end-start)
+ if _, err := reader.ReadAt(buffer, start); err != nil {
+ return nil
+ }
+ return buffer
+}
+
+// GetBytesByTwoOffsetsByPath returns the binary content as []byte from `start` to `end`.
+// Note: Returned value does not contain the character of the last position, which means
+// it returns content range as [start, end).
+// It opens file of `path` for reading with os.O_RDONLY flag and default perm.
+func GetBytesByTwoOffsetsByPath(path string, start int64, end int64) []byte {
+ if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {
+ defer f.Close()
+ return GetBytesByTwoOffsets(f, start, end)
+ }
+ return nil
+}
+
+// ReadLines reads file content line by line, which is passed to the callback function `callback` as string.
+// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker.
+//
+// Note that the parameter passed to callback function might be an empty value, and the last non-empty line
+// will be passed to callback function `callback` even if it has no newline marker.
+func ReadLines(file string, callback func(text string) error) error {
+ f, err := Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ if err = callback(scanner.Text()); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ReadLinesBytes reads file content line by line, which is passed to the callback function `callback` as []byte.
+// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker.
+//
+// Note that the parameter passed to callback function might be an empty value, and the last non-empty line
+// will be passed to callback function `callback` even if it has no newline marker.
+func ReadLinesBytes(file string, callback func(bytes []byte) error) error {
+ f, err := Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ if err = callback(scanner.Bytes()); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_copy.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_copy.go
new file mode 100644
index 000000000000..77198cc9e83e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_copy.go
@@ -0,0 +1,138 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Copy file/directory from `src` to `dst`.
+//
+// If `src` is file, it calls CopyFile to implements copy feature,
+// or else it calls CopyDir.
+func Copy(src string, dst string) error {
+ if src == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "source path cannot be empty")
+ }
+ if dst == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "destination path cannot be empty")
+ }
+ if IsFile(src) {
+ return CopyFile(src, dst)
+ }
+ return CopyDir(src, dst)
+}
+
+// CopyFile copies the contents of the file named `src` to the file named
+// by `dst`. The file will be created if it does not exist. If the
+// destination file exists, all it's contents will be replaced by the contents
+// of the source file. The file mode will be copied from the source and
+// the copied data is synced/flushed to stable storage.
+// Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
+func CopyFile(src, dst string) (err error) {
+ if src == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "source file cannot be empty")
+ }
+ if dst == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "destination file cannot be empty")
+ }
+ // If src and dst are the same path, it does nothing.
+ if src == dst {
+ return nil
+ }
+ in, err := Open(src)
+ if err != nil {
+ return
+ }
+ defer func() {
+ if e := in.Close(); e != nil {
+ err = gerror.Wrapf(e, `file close failed for "%s"`, src)
+ }
+ }()
+ out, err := Create(dst)
+ if err != nil {
+ return
+ }
+ defer func() {
+ if e := out.Close(); e != nil {
+ err = gerror.Wrapf(e, `file close failed for "%s"`, dst)
+ }
+ }()
+ if _, err = io.Copy(out, in); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed from "%s" to "%s"`, src, dst)
+ return
+ }
+ if err = out.Sync(); err != nil {
+ err = gerror.Wrapf(err, `file sync failed for file "%s"`, dst)
+ return
+ }
+ err = Chmod(dst, DefaultPermCopy)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// CopyDir recursively copies a directory tree, attempting to preserve permissions.
+//
+// Note that, the Source directory must exist and symlinks are ignored and skipped.
+func CopyDir(src string, dst string) (err error) {
+ if src == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "source directory cannot be empty")
+ }
+ if dst == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "destination directory cannot be empty")
+ }
+ // If src and dst are the same path, it does nothing.
+ if src == dst {
+ return nil
+ }
+ src = filepath.Clean(src)
+ dst = filepath.Clean(dst)
+ si, err := Stat(src)
+ if err != nil {
+ return err
+ }
+ if !si.IsDir() {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "source is not a directory")
+ }
+ if !Exists(dst) {
+ if err = os.MkdirAll(dst, DefaultPermCopy); err != nil {
+ err = gerror.Wrapf(err, `create directory failed for path "%s", perm "%s"`, dst, DefaultPermCopy)
+ return
+ }
+ }
+ entries, err := ioutil.ReadDir(src)
+ if err != nil {
+ err = gerror.Wrapf(err, `read directory failed for path "%s"`, src)
+ return
+ }
+ for _, entry := range entries {
+ srcPath := filepath.Join(src, entry.Name())
+ dstPath := filepath.Join(dst, entry.Name())
+ if entry.IsDir() {
+ if err = CopyDir(srcPath, dstPath); err != nil {
+ return
+ }
+ } else {
+ // Skip symlinks.
+ if entry.Mode()&os.ModeSymlink != 0 {
+ continue
+ }
+ if err = CopyFile(srcPath, dstPath); err != nil {
+ return
+ }
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_home.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_home.go
new file mode 100644
index 000000000000..817e74bf7a6e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_home.go
@@ -0,0 +1,82 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "bytes"
+ "os"
+ "os/exec"
+ "os/user"
+ "runtime"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Home returns absolute path of current user's home directory.
+// The optional parameter `names` specifies the sub-folders/sub-files,
+// which will be joined with current system separator and returned with the path.
+func Home(names ...string) (string, error) {
+ path, err := getHomePath()
+ if err != nil {
+ return "", err
+ }
+ for _, name := range names {
+ path += Separator + name
+ }
+ return path, nil
+}
+
+// getHomePath returns absolute path of current user's home directory.
+func getHomePath() (string, error) {
+ u, err := user.Current()
+ if nil == err {
+ return u.HomeDir, nil
+ }
+ if runtime.GOOS == "windows" {
+ return homeWindows()
+ }
+ return homeUnix()
+}
+
+// homeUnix retrieves and returns the home on unix system.
+func homeUnix() (string, error) {
+ if home := os.Getenv("HOME"); home != "" {
+ return home, nil
+ }
+ var stdout bytes.Buffer
+ cmd := exec.Command("sh", "-c", "eval echo ~$USER")
+ cmd.Stdout = &stdout
+ if err := cmd.Run(); err != nil {
+ err = gerror.Wrapf(err, `retrieve home directory failed`)
+ return "", err
+ }
+
+ result := strings.TrimSpace(stdout.String())
+ if result == "" {
+ return "", gerror.New("blank output when reading home directory")
+ }
+
+ return result, nil
+}
+
+// homeWindows retrieves and returns the home on windows system.
+func homeWindows() (string, error) {
+ var (
+ drive = os.Getenv("HOMEDRIVE")
+ path = os.Getenv("HOMEPATH")
+ home = drive + path
+ )
+ if drive == "" || path == "" {
+ home = os.Getenv("USERPROFILE")
+ }
+ if home == "" {
+ return "", gerror.New("environment keys HOMEDRIVE, HOMEPATH and USERPROFILE are empty")
+ }
+
+ return home, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_replace.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_replace.go
new file mode 100644
index 000000000000..3cb7b689fac2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_replace.go
@@ -0,0 +1,58 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// ReplaceFile replaces content for file `path`.
+func ReplaceFile(search, replace, path string) error {
+ return PutContents(path, gstr.Replace(GetContents(path), search, replace))
+}
+
+// ReplaceFileFunc replaces content for file `path` with callback function `f`.
+func ReplaceFileFunc(f func(path, content string) string, path string) error {
+ data := GetContents(path)
+ result := f(path, data)
+ if len(data) != len(result) && data != result {
+ return PutContents(path, result)
+ }
+ return nil
+}
+
+// ReplaceDir replaces content for files under `path`.
+// The parameter `pattern` specifies the file pattern which matches to be replaced.
+// It does replacement recursively if given parameter `recursive` is true.
+func ReplaceDir(search, replace, path, pattern string, recursive ...bool) error {
+ files, err := ScanDirFile(path, pattern, recursive...)
+ if err != nil {
+ return err
+ }
+ for _, file := range files {
+ if err = ReplaceFile(search, replace, file); err != nil {
+ return err
+ }
+ }
+ return err
+}
+
+// ReplaceDirFunc replaces content for files under `path` with callback function `f`.
+// The parameter `pattern` specifies the file pattern which matches to be replaced.
+// It does replacement recursively if given parameter `recursive` is true.
+func ReplaceDirFunc(f func(path, content string) string, path, pattern string, recursive ...bool) error {
+ files, err := ScanDirFile(path, pattern, recursive...)
+ if err != nil {
+ return err
+ }
+ for _, file := range files {
+ if err = ReplaceFileFunc(f, file); err != nil {
+ return err
+ }
+ }
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_scan.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_scan.go
new file mode 100644
index 000000000000..9e73e0a82a24
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_scan.go
@@ -0,0 +1,184 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "path/filepath"
+ "sort"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+const (
+ // Max recursive depth for directory scanning.
+ maxScanDepth = 100000
+)
+
+// ScanDir returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// The pattern parameter `pattern` supports multiple file name patterns,
+// using the ',' symbol to separate multiple patterns.
+func ScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
+ isRecursive := false
+ if len(recursive) > 0 {
+ isRecursive = recursive[0]
+ }
+ list, err := doScanDir(0, path, pattern, isRecursive, nil)
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ sort.Strings(list)
+ }
+ return list, nil
+}
+
+// ScanDirFunc returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// The pattern parameter `pattern` supports multiple file name patterns, using the ','
+// symbol to separate multiple patterns.
+//
+// The parameter `recursive` specifies whether scanning the `path` recursively, which
+// means it scans its sub-files and appends the files path to result array if the sub-file
+// is also a folder. It is false in default.
+//
+// The parameter `handler` specifies the callback function handling each sub-file path of
+// the `path` and its sub-folders. It ignores the sub-file path if `handler` returns an empty
+// string, or else it appends the sub-file path to result slice.
+func ScanDirFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
+ list, err := doScanDir(0, path, pattern, recursive, handler)
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ sort.Strings(list)
+ }
+ return list, nil
+}
+
+// ScanDirFile returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// The pattern parameter `pattern` supports multiple file name patterns,
+// using the ',' symbol to separate multiple patterns.
+//
+// Note that it returns only files, exclusive of directories.
+func ScanDirFile(path string, pattern string, recursive ...bool) ([]string, error) {
+ isRecursive := false
+ if len(recursive) > 0 {
+ isRecursive = recursive[0]
+ }
+ list, err := doScanDir(0, path, pattern, isRecursive, func(path string) string {
+ if IsDir(path) {
+ return ""
+ }
+ return path
+ })
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ sort.Strings(list)
+ }
+ return list, nil
+}
+
+// ScanDirFileFunc returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// The pattern parameter `pattern` supports multiple file name patterns, using the ','
+// symbol to separate multiple patterns.
+//
+// The parameter `recursive` specifies whether scanning the `path` recursively, which
+// means it scans its sub-files and appends the files path to result array if the sub-file
+// is also a folder. It is false in default.
+//
+// The parameter `handler` specifies the callback function handling each sub-file path of
+// the `path` and its sub-folders. It ignores the sub-file path if `handler` returns an empty
+// string, or else it appends the sub-file path to result slice.
+//
+// Note that the parameter `path` for `handler` is not a directory but a file.
+// It returns only files, exclusive of directories.
+func ScanDirFileFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
+ list, err := doScanDir(0, path, pattern, recursive, func(path string) string {
+ if IsDir(path) {
+ return ""
+ }
+ return handler(path)
+ })
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ sort.Strings(list)
+ }
+ return list, nil
+}
+
+// doScanDir is an internal method which scans directory and returns the absolute path
+// list of files that are not sorted.
+//
+// The pattern parameter `pattern` supports multiple file name patterns, using the ','
+// symbol to separate multiple patterns.
+//
+// The parameter `recursive` specifies whether scanning the `path` recursively, which
+// means it scans its sub-files and appends the files path to result array if the sub-file
+// is also a folder. It is false in default.
+//
+// The parameter `handler` specifies the callback function handling each sub-file path of
+// the `path` and its sub-folders. It ignores the sub-file path if `handler` returns an empty
+// string, or else it appends the sub-file path to result slice.
+func doScanDir(depth int, path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
+ if depth >= maxScanDepth {
+ return nil, gerror.Newf("directory scanning exceeds max recursive depth: %d", maxScanDepth)
+ }
+ var (
+ list []string
+ file, err = Open(path)
+ )
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+ names, err := file.Readdirnames(-1)
+ if err != nil {
+ err = gerror.Wrapf(err, `read directory files failed from path "%s"`, path)
+ return nil, err
+ }
+ var (
+ filePath = ""
+ patterns = gstr.SplitAndTrim(pattern, ",")
+ )
+ for _, name := range names {
+ filePath = path + Separator + name
+ if IsDir(filePath) && recursive {
+ array, _ := doScanDir(depth+1, filePath, pattern, true, handler)
+ if len(array) > 0 {
+ list = append(list, array...)
+ }
+ }
+ // Handler filtering.
+ if handler != nil {
+ filePath = handler(filePath)
+ if filePath == "" {
+ continue
+ }
+ }
+ // If it meets pattern, then add it to the result list.
+ for _, p := range patterns {
+ if match, _ := filepath.Match(p, name); match {
+ if filePath = Abs(filePath); filePath != "" {
+ list = append(list, filePath)
+ }
+ }
+ }
+ }
+ return list, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_search.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_search.go
new file mode 100644
index 000000000000..a0d06999de27
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_search.go
@@ -0,0 +1,58 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Search searches file by name `name` in following paths with priority:
+// prioritySearchPaths, Pwd()、SelfDir()、MainPkgPath().
+// It returns the absolute file path of `name` if found, or en empty string if not found.
+func Search(name string, prioritySearchPaths ...string) (realPath string, err error) {
+ // Check if it's an absolute path.
+ realPath = RealPath(name)
+ if realPath != "" {
+ return
+ }
+ // Search paths array.
+ array := garray.NewStrArray()
+ array.Append(prioritySearchPaths...)
+ array.Append(Pwd(), SelfDir())
+ if path := MainPkgPath(); path != "" {
+ array.Append(path)
+ }
+ // Remove repeated items.
+ array.Unique()
+ // Do the searching.
+ array.RLockFunc(func(array []string) {
+ path := ""
+ for _, v := range array {
+ path = RealPath(v + Separator + name)
+ if path != "" {
+ realPath = path
+ break
+ }
+ }
+ })
+ // If it fails searching, it returns formatted error.
+ if realPath == "" {
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteString(fmt.Sprintf(`cannot find "%s" in following paths:`, name))
+ array.RLockFunc(func(array []string) {
+ for k, v := range array {
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
+ }
+ })
+ err = gerror.New(buffer.String())
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_size.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_size.go
new file mode 100644
index 000000000000..fb8fca764b52
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_size.go
@@ -0,0 +1,131 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Size returns the size of file specified by `path` in byte.
+func Size(path string) int64 {
+ s, e := os.Stat(path)
+ if e != nil {
+ return 0
+ }
+ return s.Size()
+}
+
+// SizeFormat returns the size of file specified by `path` in format string.
+func SizeFormat(path string) string {
+ return FormatSize(Size(path))
+}
+
+// ReadableSize formats size of file given by `path`, for more human readable.
+func ReadableSize(path string) string {
+ return FormatSize(Size(path))
+}
+
+// StrToSize converts formatted size string to its size in bytes.
+func StrToSize(sizeStr string) int64 {
+ i := 0
+ for ; i < len(sizeStr); i++ {
+ if sizeStr[i] == '.' || (sizeStr[i] >= '0' && sizeStr[i] <= '9') {
+ continue
+ } else {
+ break
+ }
+ }
+ var (
+ unit = sizeStr[i:]
+ number, _ = strconv.ParseFloat(sizeStr[:i], 64)
+ )
+ if unit == "" {
+ return int64(number)
+ }
+ switch strings.ToLower(unit) {
+ case "b", "bytes":
+ return int64(number)
+ case "k", "kb", "ki", "kib", "kilobyte":
+ return int64(number * 1024)
+ case "m", "mb", "mi", "mib", "mebibyte":
+ return int64(number * 1024 * 1024)
+ case "g", "gb", "gi", "gib", "gigabyte":
+ return int64(number * 1024 * 1024 * 1024)
+ case "t", "tb", "ti", "tib", "terabyte":
+ return int64(number * 1024 * 1024 * 1024 * 1024)
+ case "p", "pb", "pi", "pib", "petabyte":
+ return int64(number * 1024 * 1024 * 1024 * 1024 * 1024)
+ case "e", "eb", "ei", "eib", "exabyte":
+ return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
+ case "z", "zb", "zi", "zib", "zettabyte":
+ return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
+ case "y", "yb", "yi", "yib", "yottabyte":
+ return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
+ case "bb", "brontobyte":
+ return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
+ }
+ return -1
+}
+
+// FormatSize formats size `raw` for more manually readable.
+func FormatSize(raw int64) string {
+ var r float64 = float64(raw)
+ var t float64 = 1024
+ var d float64 = 1
+ if r < t {
+ return fmt.Sprintf("%.2fB", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fK", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fM", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fG", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fT", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fP", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fE", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fZ", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fY", r/d)
+ }
+ d *= 1024
+ t *= 1024
+ if r < t {
+ return fmt.Sprintf("%.2fBB", r/d)
+ }
+ return "TooLarge"
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_sort.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_sort.go
new file mode 100644
index 000000000000..3772cb07dc92
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_sort.go
@@ -0,0 +1,40 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/container/garray"
+)
+
+// fileSortFunc is the comparison function for files.
+// It sorts the array in order of: directory -> file.
+// If `path1` and `path2` are the same type, it then sorts them as strings.
+func fileSortFunc(path1, path2 string) int {
+ isDirPath1 := IsDir(path1)
+ isDirPath2 := IsDir(path2)
+ if isDirPath1 && !isDirPath2 {
+ return -1
+ }
+ if !isDirPath1 && isDirPath2 {
+ return 1
+ }
+ if n := strings.Compare(path1, path2); n != 0 {
+ return n
+ } else {
+ return -1
+ }
+}
+
+// SortFiles sorts the `files` in order of: directory -> file.
+// Note that the item of `files` should be absolute path.
+func SortFiles(files []string) []string {
+ array := garray.NewSortedStrArrayComparator(fileSortFunc)
+ array.Add(files...)
+ return array.Slice()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_source.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_source.go
new file mode 100644
index 000000000000..4f97266337f3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_source.go
@@ -0,0 +1,91 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "os"
+ "runtime"
+ "strings"
+
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+var (
+ // goRootForFilter is used for stack filtering purpose.
+ goRootForFilter = runtime.GOROOT()
+)
+
+func init() {
+ if goRootForFilter != "" {
+ goRootForFilter = strings.Replace(goRootForFilter, "\\", "/", -1)
+ }
+}
+
+// MainPkgPath returns absolute file path of package main,
+// which contains the entrance function main.
+//
+// It's only available in develop environment.
+//
+// Note1: Only valid for source development environments,
+// IE only valid for systems that generate this executable.
+//
+// Note2: When the method is called for the first time, if it is in an asynchronous goroutine,
+// the method may not get the main package path.
+func MainPkgPath() string {
+ // It is only for source development environments.
+ if goRootForFilter == "" {
+ return ""
+ }
+ path := mainPkgPath.Val()
+ if path != "" {
+ return path
+ }
+ var lastFile string
+ for i := 1; i < 10000; i++ {
+ if pc, file, _, ok := runtime.Caller(i); ok {
+ if goRootForFilter != "" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter {
+ continue
+ }
+ if Ext(file) != ".go" {
+ continue
+ }
+ lastFile = file
+ // Check if it is called in package initialization function,
+ // in which it here cannot retrieve main package path,
+ // it so just returns that can make next check.
+ if fn := runtime.FuncForPC(pc); fn != nil {
+ array := gstr.Split(fn.Name(), ".")
+ if array[0] != "main" {
+ continue
+ }
+ }
+ if gregex.IsMatchString(`package\s+main\s+`, GetContents(file)) {
+ mainPkgPath.Set(Dir(file))
+ return Dir(file)
+ }
+ } else {
+ break
+ }
+ }
+ // If it still cannot find the path of the package main,
+ // it recursively searches the directory and its parents directory of the last go file.
+ // It's usually necessary for uint testing cases of business project.
+ if lastFile != "" {
+ for path = Dir(lastFile); len(path) > 1 && Exists(path) && path[len(path)-1] != os.PathSeparator; {
+ files, _ := ScanDir(path, "*.go")
+ for _, v := range files {
+ if gregex.IsMatchString(`package\s+main\s+`, GetContents(v)) {
+ mainPkgPath.Set(path)
+ return path
+ }
+ }
+ path = Dir(path)
+ }
+ }
+ return ""
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_time.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_time.go
new file mode 100644
index 000000000000..21053b7355ee
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfile/gfile_time.go
@@ -0,0 +1,39 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfile
+
+import (
+ "os"
+ "time"
+)
+
+// MTime returns the modification time of file given by `path` in second.
+func MTime(path string) time.Time {
+ s, e := os.Stat(path)
+ if e != nil {
+ return time.Time{}
+ }
+ return s.ModTime()
+}
+
+// MTimestamp returns the modification time of file given by `path` in second.
+func MTimestamp(path string) int64 {
+ mtime := MTime(path)
+ if mtime.IsZero() {
+ return -1
+ }
+ return mtime.Unix()
+}
+
+// MTimestampMilli returns the modification time of file given by `path` in millisecond.
+func MTimestampMilli(path string) int64 {
+ mtime := MTime(path)
+ if mtime.IsZero() {
+ return -1
+ }
+ return mtime.UnixNano() / 1000000
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool.go
new file mode 100644
index 000000000000..5eec01b27ef1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool.go
@@ -0,0 +1,41 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gfpool provides io-reusable pool for file pointer.
+package gfpool
+
+import (
+ "os"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gpool"
+ "github.com/gogf/gf/v2/container/gtype"
+)
+
+// Pool pointer pool.
+type Pool struct {
+ id *gtype.Int // Pool id, which is used to mark this pool whether recreated.
+ pool *gpool.Pool // Underlying pool.
+ init *gtype.Bool // Whether initialized, used for marking this file added to fsnotify, and it can only be added just once.
+ ttl time.Duration // Time to live for file pointer items.
+}
+
+// File is an item in the pool.
+type File struct {
+ *os.File // Underlying file pointer.
+ stat os.FileInfo // State of current file pointer.
+ pid int // Belonging pool id, which is set when file pointer created. It's used to check whether the pool is recreated.
+ pool *Pool // Belonging ool.
+ flag int // Flash for opening file.
+ perm os.FileMode // Permission for opening file.
+ path string // Absolute path of the file.
+}
+
+var (
+ // Global file pointer pool.
+ pools = gmap.NewStrAnyMap(true)
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool_file.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool_file.go
new file mode 100644
index 000000000000..2a774ad2f850
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool_file.go
@@ -0,0 +1,56 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfpool
+
+import (
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Open creates and returns a file item with given file path, flag and opening permission.
+// It automatically creates an associated file pointer pool internally when it's called first time.
+// It retrieves a file item from the file pointer pool after then.
+func Open(path string, flag int, perm os.FileMode, ttl ...time.Duration) (file *File, err error) {
+ var fpTTL time.Duration
+ if len(ttl) > 0 {
+ fpTTL = ttl[0]
+ }
+ // DO NOT search the path here wasting performance!
+ // Leave following codes just for warning you.
+ //
+ // path, err = gfile.Search(path)
+ // if err != nil {
+ // return nil, err
+ // }
+ pool := pools.GetOrSetFuncLock(
+ fmt.Sprintf("%s&%d&%d&%d", path, flag, fpTTL, perm),
+ func() interface{} {
+ return New(path, flag, perm, fpTTL)
+ },
+ ).(*Pool)
+
+ return pool.File()
+}
+
+// Stat returns the FileInfo structure describing file.
+func (f *File) Stat() (os.FileInfo, error) {
+ if f.stat == nil {
+ return nil, gerror.New("file stat is empty")
+ }
+ return f.stat, nil
+}
+
+// Close puts the file pointer back to the file pointer pool.
+func (f *File) Close() error {
+ if f.pid == f.pool.id.Val() {
+ return f.pool.pool.Put(f)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool_pool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool_pool.go
new file mode 100644
index 000000000000..5db0fcea3122
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfpool/gfpool_pool.go
@@ -0,0 +1,122 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfpool
+
+import (
+ "os"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gpool"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gfsnotify"
+)
+
+// New creates and returns a file pointer pool with given file path, flag and opening permission.
+//
+// Note the expiration logic:
+// ttl = 0 : not expired;
+// ttl < 0 : immediate expired after use;
+// ttl > 0 : timeout expired;
+// It is not expired in default.
+func New(path string, flag int, perm os.FileMode, ttl ...time.Duration) *Pool {
+ var fpTTL time.Duration
+ if len(ttl) > 0 {
+ fpTTL = ttl[0]
+ }
+ p := &Pool{
+ id: gtype.NewInt(),
+ ttl: fpTTL,
+ init: gtype.NewBool(),
+ }
+ p.pool = newFilePool(p, path, flag, perm, fpTTL)
+ return p
+}
+
+// newFilePool creates and returns a file pointer pool with given file path, flag and opening permission.
+func newFilePool(p *Pool, path string, flag int, perm os.FileMode, ttl time.Duration) *gpool.Pool {
+ pool := gpool.New(ttl, func() (interface{}, error) {
+ file, err := os.OpenFile(path, flag, perm)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.OpenFile failed for file "%s", flag "%d", perm "%s"`, path, flag, perm)
+ return nil, err
+ }
+ return &File{
+ File: file,
+ pid: p.id.Val(),
+ pool: p,
+ flag: flag,
+ perm: perm,
+ path: path,
+ }, nil
+ }, func(i interface{}) {
+ _ = i.(*File).File.Close()
+ })
+ return pool
+}
+
+// File retrieves file item from the file pointer pool and returns it. It creates one if
+// the file pointer pool is empty.
+// Note that it should be closed when it will never be used. When it's closed, it is not
+// really closed the underlying file pointer but put back to the file pinter pool.
+func (p *Pool) File() (*File, error) {
+ if v, err := p.pool.Get(); err != nil {
+ return nil, err
+ } else {
+ f := v.(*File)
+ f.stat, err = os.Stat(f.path)
+ if f.flag&os.O_CREATE > 0 {
+ if os.IsNotExist(err) {
+ if f.File, err = os.OpenFile(f.path, f.flag, f.perm); err != nil {
+ return nil, err
+ } else {
+ // Retrieve the state of the new created file.
+ if f.stat, err = f.File.Stat(); err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ if f.flag&os.O_TRUNC > 0 {
+ if f.stat.Size() > 0 {
+ if err = f.Truncate(0); err != nil {
+ return nil, err
+ }
+ }
+ }
+ if f.flag&os.O_APPEND > 0 {
+ if _, err = f.Seek(0, 2); err != nil {
+ return nil, err
+ }
+ } else {
+ if _, err = f.Seek(0, 0); err != nil {
+ return nil, err
+ }
+ }
+ // It firstly checks using !p.init.Val() for performance purpose.
+ if !p.init.Val() && p.init.Cas(false, true) {
+ _, _ = gfsnotify.Add(f.path, func(event *gfsnotify.Event) {
+ // If teh file is removed or renamed, recreates the pool by increasing the pool id.
+ if event.IsRemove() || event.IsRename() {
+ // It drops the old pool.
+ p.id.Add(1)
+ // Clears the pool items staying in the pool.
+ p.pool.Clear()
+ // It uses another adding to drop the file items between the two adding.
+ // Whenever the pool id changes, the pool will be recreated.
+ p.id.Add(1)
+ }
+ }, false)
+ }
+ return f, nil
+ }
+}
+
+// Close closes current file pointer pool.
+func (p *Pool) Close() {
+ p.pool.Close()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify.go
new file mode 100644
index 000000000000..b6de60e0e13c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify.go
@@ -0,0 +1,167 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gfsnotify provides a platform-independent interface for file system notifications.
+package gfsnotify
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/fsnotify/fsnotify"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gqueue"
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcache"
+)
+
+// Watcher is the monitor for file changes.
+type Watcher struct {
+ watcher *fsnotify.Watcher // Underlying fsnotify object.
+ events *gqueue.Queue // Used for internal event management.
+ cache *gcache.Cache // Used for repeated event filter.
+ nameSet *gset.StrSet // Used for AddOnce feature.
+ callbacks *gmap.StrAnyMap // Path(file/folder) to callbacks mapping.
+ closeChan chan struct{} // Used for watcher closing notification.
+}
+
+// Callback is the callback function for Watcher.
+type Callback struct {
+ Id int // Unique id for callback object.
+ Func func(event *Event) // Callback function.
+ Path string // Bound file path (absolute).
+ name string // Registered name for AddOnce.
+ elem *glist.Element // Element in the callbacks of watcher.
+ recursive bool // Is bound to path recursively or not.
+}
+
+// Event is the event produced by underlying fsnotify.
+type Event struct {
+ event fsnotify.Event // Underlying event.
+ Path string // Absolute file path.
+ Op Op // File operation.
+ Watcher *Watcher // Parent watcher.
+}
+
+// Op is the bits union for file operations.
+type Op uint32
+
+const (
+ CREATE Op = 1 << iota
+ WRITE
+ REMOVE
+ RENAME
+ CHMOD
+)
+
+const (
+ repeatEventFilterDuration = time.Millisecond // Duration for repeated event filter.
+ callbackExitEventPanicStr = "exit" // Custom exit event for internal usage.
+)
+
+var (
+ mu sync.Mutex // Mutex for concurrent safety of defaultWatcher.
+ defaultWatcher *Watcher // Default watcher.
+ callbackIdMap = gmap.NewIntAnyMap(true) // Id to callback mapping.
+ callbackIdGenerator = gtype.NewInt() // Atomic id generator for callback.
+)
+
+// New creates and returns a new watcher.
+// Note that the watcher number is limited by the file handle setting of the system.
+// Eg: fs.inotify.max_user_instances system variable in linux systems.
+func New() (*Watcher, error) {
+ w := &Watcher{
+ cache: gcache.New(),
+ events: gqueue.New(),
+ nameSet: gset.NewStrSet(true),
+ closeChan: make(chan struct{}),
+ callbacks: gmap.NewStrAnyMap(true),
+ }
+ if watcher, err := fsnotify.NewWatcher(); err == nil {
+ w.watcher = watcher
+ } else {
+ intlog.Printf(context.TODO(), "New watcher failed: %v", err)
+ return nil, err
+ }
+ w.watchLoop()
+ w.eventLoop()
+ return w, nil
+}
+
+// Add monitors `path` using default watcher with callback function `callbackFunc`.
+// The optional parameter `recursive` specifies whether monitoring the `path` recursively, which is true in default.
+func Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
+ w, err := getDefaultWatcher()
+ if err != nil {
+ return nil, err
+ }
+ return w.Add(path, callbackFunc, recursive...)
+}
+
+// AddOnce monitors `path` using default watcher with callback function `callbackFunc` only once using unique name `name`.
+// If AddOnce is called multiple times with the same `name` parameter, `path` is only added to monitor once. It returns error
+// if it's called twice with the same `name`.
+//
+// The optional parameter `recursive` specifies whether monitoring the `path` recursively, which is true in default.
+func AddOnce(name, path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
+ w, err := getDefaultWatcher()
+ if err != nil {
+ return nil, err
+ }
+ return w.AddOnce(name, path, callbackFunc, recursive...)
+}
+
+// Remove removes all monitoring callbacks of given `path` from watcher recursively.
+func Remove(path string) error {
+ w, err := getDefaultWatcher()
+ if err != nil {
+ return err
+ }
+ return w.Remove(path)
+}
+
+// RemoveCallback removes specified callback with given id from watcher.
+func RemoveCallback(callbackId int) error {
+ w, err := getDefaultWatcher()
+ if err != nil {
+ return err
+ }
+ callback := (*Callback)(nil)
+ if r := callbackIdMap.Get(callbackId); r != nil {
+ callback = r.(*Callback)
+ }
+ if callback == nil {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `callback for id %d not found`, callbackId)
+ }
+ w.RemoveCallback(callbackId)
+ return nil
+}
+
+// Exit is only used in the callback function, which can be used to remove current callback
+// of itself from the watcher.
+func Exit() {
+ panic(callbackExitEventPanicStr)
+}
+
+// getDefaultWatcher creates and returns the default watcher.
+// This is used for lazy initialization purpose.
+func getDefaultWatcher() (*Watcher, error) {
+ mu.Lock()
+ defer mu.Unlock()
+ if defaultWatcher != nil {
+ return defaultWatcher, nil
+ }
+ var err error
+ defaultWatcher, err = New()
+ return defaultWatcher, err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_event.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_event.go
new file mode 100644
index 000000000000..f91638ca5228
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_event.go
@@ -0,0 +1,37 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// ThIs Source Code Form Is subject to the terms of the MIT License.
+// If a copy of the MIT was not dIstributed with thIs file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfsnotify
+
+// String returns current event as string.
+func (e *Event) String() string {
+ return e.event.String()
+}
+
+// IsCreate checks whether current event contains file/folder create event.
+func (e *Event) IsCreate() bool {
+ return e.Op == 1 || e.Op&CREATE == CREATE
+}
+
+// IsWrite checks whether current event contains file/folder write event.
+func (e *Event) IsWrite() bool {
+ return e.Op&WRITE == WRITE
+}
+
+// IsRemove checks whether current event contains file/folder remove event.
+func (e *Event) IsRemove() bool {
+ return e.Op&REMOVE == REMOVE
+}
+
+// IsRename checks whether current event contains file/folder rename event.
+func (e *Event) IsRename() bool {
+ return e.Op&RENAME == RENAME
+}
+
+// IsChmod checks whether current event contains file/folder chmod event.
+func (e *Event) IsChmod() bool {
+ return e.Op&CHMOD == CHMOD
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_filefunc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_filefunc.go
new file mode 100644
index 000000000000..c8f4c7b0c3c1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_filefunc.go
@@ -0,0 +1,134 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// ThIs Source Code Form Is subject to the terms of the MIT License.
+// If a copy of the MIT was not dIstributed with thIs file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfsnotify
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// fileDir returns all but the last element of path, typically the path's directory.
+// After dropping the final element, Dir calls Clean on the path and trailing
+// slashes are removed.
+// If the path is empty, Dir returns ".".
+// If the path consists entirely of separators, Dir returns a single separator.
+// The returned path does not end in a separator unless it is the root directory.
+func fileDir(path string) string {
+ return filepath.Dir(path)
+}
+
+// fileRealPath converts the given `path` to its absolute path
+// and checks if the file path exists.
+// If the file does not exist, return an empty string.
+func fileRealPath(path string) string {
+ p, err := filepath.Abs(path)
+ if err != nil {
+ return ""
+ }
+ if !fileExists(p) {
+ return ""
+ }
+ return p
+}
+
+// fileExists checks whether given `path` exist.
+func fileExists(path string) bool {
+ if stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {
+ return true
+ }
+ return false
+}
+
+// fileIsDir checks whether given `path` a directory.
+func fileIsDir(path string) bool {
+ s, err := os.Stat(path)
+ if err != nil {
+ return false
+ }
+ return s.IsDir()
+}
+
+// fileAllDirs returns all sub-folders including itself of given `path` recursively.
+func fileAllDirs(path string) (list []string) {
+ list = []string{path}
+ file, err := os.Open(path)
+ if err != nil {
+ return list
+ }
+ defer file.Close()
+ names, err := file.Readdirnames(-1)
+ if err != nil {
+ return list
+ }
+ for _, name := range names {
+ tempPath := fmt.Sprintf("%s%s%s", path, string(filepath.Separator), name)
+ if fileIsDir(tempPath) {
+ if array := fileAllDirs(tempPath); len(array) > 0 {
+ list = append(list, array...)
+ }
+ }
+ }
+ return
+}
+
+// fileScanDir returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+func fileScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
+ list, err := doFileScanDir(path, pattern, recursive...)
+ if err != nil {
+ return nil, err
+ }
+ if len(list) > 0 {
+ sort.Strings(list)
+ }
+ return list, nil
+}
+
+// doFileScanDir is an internal method which scans directory
+// and returns the absolute path list of files that are not sorted.
+//
+// The pattern parameter `pattern` supports multiple file name patterns,
+// using the ',' symbol to separate multiple patterns.
+//
+// It scans directory recursively if given parameter `recursive` is true.
+func doFileScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
+ var (
+ list []string
+ file, err = os.Open(path)
+ )
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Open failed for path "%s"`, path)
+ return nil, err
+ }
+ defer file.Close()
+ names, err := file.Readdirnames(-1)
+ if err != nil {
+ err = gerror.Wrapf(err, `read directory files failed for path "%s"`, path)
+ return nil, err
+ }
+ filePath := ""
+ for _, name := range names {
+ filePath = fmt.Sprintf("%s%s%s", path, string(filepath.Separator), name)
+ if fileIsDir(filePath) && len(recursive) > 0 && recursive[0] {
+ array, _ := doFileScanDir(filePath, pattern, true)
+ if len(array) > 0 {
+ list = append(list, array...)
+ }
+ }
+ for _, p := range strings.Split(pattern, ",") {
+ if match, _ := filepath.Match(strings.TrimSpace(p), name); match {
+ list = append(list, filePath)
+ }
+ }
+ }
+ return list, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_watcher.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_watcher.go
new file mode 100644
index 000000000000..80da7638dccd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_watcher.go
@@ -0,0 +1,198 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfsnotify
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// Add monitors `path` with callback function `callbackFunc` to the watcher.
+// The optional parameter `recursive` specifies whether monitoring the `path` recursively,
+// which is true in default.
+func (w *Watcher) Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
+ return w.AddOnce("", path, callbackFunc, recursive...)
+}
+
+// AddOnce monitors `path` with callback function `callbackFunc` only once using unique name
+// `name` to the watcher. If AddOnce is called multiple times with the same `name` parameter,
+// `path` is only added to monitor once.
+//
+// It returns error if it's called twice with the same `name`.
+//
+// The optional parameter `recursive` specifies whether monitoring the `path` recursively,
+// which is true in default.
+func (w *Watcher) AddOnce(name, path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
+ w.nameSet.AddIfNotExistFuncLock(name, func() bool {
+ // Firstly add the path to watcher.
+ callback, err = w.addWithCallbackFunc(name, path, callbackFunc, recursive...)
+ if err != nil {
+ return false
+ }
+ // If it's recursive adding, it then adds all sub-folders to the monitor.
+ // NOTE:
+ // 1. It only recursively adds **folders** to the monitor, NOT files,
+ // because if the folders are monitored and their sub-files are also monitored.
+ // 2. It bounds no callbacks to the folders, because it will search the callbacks
+ // from its parent recursively if any event produced.
+ if fileIsDir(path) && (len(recursive) == 0 || recursive[0]) {
+ for _, subPath := range fileAllDirs(path) {
+ if fileIsDir(subPath) {
+ if err = w.watcher.Add(subPath); err != nil {
+ err = gerror.Wrapf(err, `add watch failed for path "%s"`, subPath)
+ } else {
+ intlog.Printf(context.TODO(), "watcher adds monitor for: %s", subPath)
+ }
+ }
+ }
+ }
+ if name == "" {
+ return false
+ }
+ return true
+ })
+ return
+}
+
+// addWithCallbackFunc adds the path to underlying monitor, creates and returns a callback object.
+// Very note that if it calls multiple times with the same `path`, the latest one will overwrite the previous one.
+func (w *Watcher) addWithCallbackFunc(name, path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
+ // Check and convert the given path to absolute path.
+ if t := fileRealPath(path); t == "" {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" does not exist`, path)
+ } else {
+ path = t
+ }
+ // Create callback object.
+ callback = &Callback{
+ Id: callbackIdGenerator.Add(1),
+ Func: callbackFunc,
+ Path: path,
+ name: name,
+ recursive: true,
+ }
+ if len(recursive) > 0 {
+ callback.recursive = recursive[0]
+ }
+ // Register the callback to watcher.
+ w.callbacks.LockFunc(func(m map[string]interface{}) {
+ list := (*glist.List)(nil)
+ if v, ok := m[path]; !ok {
+ list = glist.New(true)
+ m[path] = list
+ } else {
+ list = v.(*glist.List)
+ }
+ callback.elem = list.PushBack(callback)
+ })
+ // Add the path to underlying monitor.
+ if err = w.watcher.Add(path); err != nil {
+ err = gerror.Wrapf(err, `add watch failed for path "%s"`, path)
+ } else {
+ intlog.Printf(context.TODO(), "watcher adds monitor for: %s", path)
+ }
+ // Add the callback to global callback map.
+ callbackIdMap.Set(callback.Id, callback)
+ return
+}
+
+// Close closes the watcher.
+func (w *Watcher) Close() {
+ w.events.Close()
+ if err := w.watcher.Close(); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ close(w.closeChan)
+}
+
+// Remove removes monitor and all callbacks associated with the `path` recursively.
+func (w *Watcher) Remove(path string) error {
+ // Firstly remove the callbacks of the path.
+ if value := w.callbacks.Remove(path); value != nil {
+ list := value.(*glist.List)
+ for {
+ if item := list.PopFront(); item != nil {
+ callbackIdMap.Remove(item.(*Callback).Id)
+ } else {
+ break
+ }
+ }
+ }
+ // Secondly remove monitor of all sub-files which have no callbacks.
+ if subPaths, err := fileScanDir(path, "*", true); err == nil && len(subPaths) > 0 {
+ for _, subPath := range subPaths {
+ if w.checkPathCanBeRemoved(subPath) {
+ if internalErr := w.watcher.Remove(subPath); internalErr != nil {
+ intlog.Errorf(context.TODO(), `%+v`, internalErr)
+ }
+ }
+ }
+ }
+ // Lastly remove the monitor of the path from underlying monitor.
+ err := w.watcher.Remove(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `remove watch failed for path "%s"`, path)
+ }
+ return err
+}
+
+// checkPathCanBeRemoved checks whether the given path have no callbacks bound.
+func (w *Watcher) checkPathCanBeRemoved(path string) bool {
+ // Firstly check the callbacks in the watcher directly.
+ if v := w.callbacks.Get(path); v != nil {
+ return false
+ }
+ // Secondly check its parent whether has callbacks.
+ dirPath := fileDir(path)
+ if v := w.callbacks.Get(dirPath); v != nil {
+ for _, c := range v.(*glist.List).FrontAll() {
+ if c.(*Callback).recursive {
+ return false
+ }
+ }
+ return false
+ }
+ // Recursively check its parent.
+ parentDirPath := ""
+ for {
+ parentDirPath = fileDir(dirPath)
+ if parentDirPath == dirPath {
+ break
+ }
+ if v := w.callbacks.Get(parentDirPath); v != nil {
+ for _, c := range v.(*glist.List).FrontAll() {
+ if c.(*Callback).recursive {
+ return false
+ }
+ }
+ return false
+ }
+ dirPath = parentDirPath
+ }
+ return true
+}
+
+// RemoveCallback removes callback with given callback id from watcher.
+func (w *Watcher) RemoveCallback(callbackId int) {
+ callback := (*Callback)(nil)
+ if r := callbackIdMap.Get(callbackId); r != nil {
+ callback = r.(*Callback)
+ }
+ if callback != nil {
+ if r := w.callbacks.Get(callback.Path); r != nil {
+ r.(*glist.List).Remove(callback.elem)
+ }
+ callbackIdMap.Remove(callbackId)
+ if callback.name != "" {
+ w.nameSet.Remove(callback.name)
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_watcher_loop.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_watcher_loop.go
new file mode 100644
index 000000000000..7621ffb5ecfb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gfsnotify/gfsnotify_watcher_loop.go
@@ -0,0 +1,182 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gfsnotify
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// watchLoop starts the loop for event listening from underlying inotify monitor.
+func (w *Watcher) watchLoop() {
+ go func() {
+ for {
+ select {
+ // Close event.
+ case <-w.closeChan:
+ return
+
+ // Event listening.
+ case ev := <-w.watcher.Events:
+ // Filter the repeated event in custom duration.
+ _, err := w.cache.SetIfNotExist(
+ context.Background(),
+ ev.String(),
+ func(ctx context.Context) (value interface{}, err error) {
+ w.events.Push(&Event{
+ event: ev,
+ Path: ev.Name,
+ Op: Op(ev.Op),
+ Watcher: w,
+ })
+ return struct{}{}, nil
+ }, repeatEventFilterDuration,
+ )
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+
+ case err := <-w.watcher.Errors:
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ }()
+}
+
+// eventLoop is the core event handler.
+func (w *Watcher) eventLoop() {
+ go func() {
+ for {
+ if v := w.events.Pop(); v != nil {
+ event := v.(*Event)
+ // If there's no any callback of this path, it removes it from monitor.
+ callbacks := w.getCallbacks(event.Path)
+ if len(callbacks) == 0 {
+ w.watcher.Remove(event.Path)
+ continue
+ }
+ switch {
+ case event.IsRemove():
+ // It should check again the existence of the path.
+ // It adds it back to the monitor if it still exists.
+ if fileExists(event.Path) {
+ // It adds the path back to monitor.
+ // We need no worry about the repeat adding.
+ if err := w.watcher.Add(event.Path); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ } else {
+ intlog.Printf(context.TODO(), "fake remove event, watcher re-adds monitor for: %s", event.Path)
+ }
+ // Change the event to RENAME, which means it renames itself to its origin name.
+ event.Op = RENAME
+ }
+
+ case event.IsRename():
+ // It should check again the existence of the path.
+ // It adds it back to the monitor if it still exists.
+ // Especially Some editors might do RENAME and then CHMOD when it's editing file.
+ if fileExists(event.Path) {
+ // It might lost the monitoring for the path, so we add the path back to monitor.
+ // We need no worry about the repeat adding.
+ if err := w.watcher.Add(event.Path); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ } else {
+ intlog.Printf(context.TODO(), "fake rename event, watcher re-adds monitor for: %s", event.Path)
+ }
+ // Change the event to CHMOD.
+ event.Op = CHMOD
+ }
+
+ case event.IsCreate():
+ // =========================================
+ // Note that it here just adds the path to monitor without any callback registering,
+ // because its parent already has the callbacks.
+ // =========================================
+ if fileIsDir(event.Path) {
+ // If it's a folder, it then does adding recursively to monitor.
+ for _, subPath := range fileAllDirs(event.Path) {
+ if fileIsDir(subPath) {
+ if err := w.watcher.Add(subPath); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ } else {
+ intlog.Printf(context.TODO(), "folder creation event, watcher adds monitor for: %s", subPath)
+ }
+ }
+ }
+ } else {
+ // If it's a file, it directly adds it to monitor.
+ if err := w.watcher.Add(event.Path); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ } else {
+ intlog.Printf(context.TODO(), "file creation event, watcher adds monitor for: %s", event.Path)
+ }
+ }
+
+ }
+ // Calling the callbacks in order.
+ for _, v := range callbacks {
+ go func(callback *Callback) {
+ defer func() {
+ if err := recover(); err != nil {
+ switch err {
+ case callbackExitEventPanicStr:
+ w.RemoveCallback(callback.Id)
+ default:
+ panic(err)
+ }
+ }
+ }()
+ callback.Func(event)
+ }(v)
+ }
+ } else {
+ break
+ }
+ }
+ }()
+}
+
+// getCallbacks searches and returns all callbacks with given `path`.
+// It also searches its parents for callbacks if they're recursive.
+func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) {
+ // Firstly add the callbacks of itself.
+ if v := w.callbacks.Get(path); v != nil {
+ for _, v := range v.(*glist.List).FrontAll() {
+ callback := v.(*Callback)
+ callbacks = append(callbacks, callback)
+ }
+ }
+ // Secondly searches its direct parent for callbacks.
+ // It is special handling here, which is the different between `recursive` and `not recursive` logic
+ // for direct parent folder of `path` that events are from.
+ dirPath := fileDir(path)
+ if v := w.callbacks.Get(dirPath); v != nil {
+ for _, v := range v.(*glist.List).FrontAll() {
+ callback := v.(*Callback)
+ callbacks = append(callbacks, callback)
+ }
+ }
+ // Lastly searches all the parents of directory of `path` recursively for callbacks.
+ for {
+ parentDirPath := fileDir(dirPath)
+ if parentDirPath == dirPath {
+ break
+ }
+ if v := w.callbacks.Get(parentDirPath); v != nil {
+ for _, v := range v.(*glist.List).FrontAll() {
+ callback := v.(*Callback)
+ if callback.recursive {
+ callbacks = append(callbacks, callback)
+ }
+ }
+ }
+ dirPath = parentDirPath
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog.go
new file mode 100644
index 000000000000..fae74aff6ff1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog.go
@@ -0,0 +1,47 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package glog implements powerful and easy-to-use levelled logging functionality.
+package glog
+
+import (
+ "github.com/gogf/gf/v2/os/gcmd"
+ "github.com/gogf/gf/v2/os/grpool"
+)
+
+const (
+ commandEnvKeyForDebug = "gf.glog.debug"
+)
+
+var (
+ // Default logger object, for package method usage.
+ defaultLogger = New()
+
+ // Goroutine pool for async logging output.
+ // It uses only one asynchronous worker to ensure log sequence.
+ asyncPool = grpool.New(1)
+
+ // defaultDebug enables debug level or not in default,
+ // which can be configured using command option or system environment.
+ defaultDebug = true
+)
+
+func init() {
+ defaultDebug = gcmd.GetOptWithEnv(commandEnvKeyForDebug, true).Bool()
+ SetDebug(defaultDebug)
+}
+
+// DefaultLogger returns the default logger.
+func DefaultLogger() *Logger {
+ return defaultLogger
+}
+
+// SetDefaultLogger sets the default logger for package glog.
+// Note that there might be concurrent safety issue if calls this function
+// in different goroutines.
+func SetDefaultLogger(l *Logger) {
+ defaultLogger = l
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_api.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_api.go
new file mode 100644
index 000000000000..3529973e8e63
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_api.go
@@ -0,0 +1,109 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import "context"
+
+// Print prints `v` with newline using fmt.Sprintln.
+// The parameter `v` can be multiple variables.
+func Print(ctx context.Context, v ...interface{}) {
+ defaultLogger.Print(ctx, v...)
+}
+
+// Printf prints `v` with format `format` using fmt.Sprintf.
+// The parameter `v` can be multiple variables.
+func Printf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Printf(ctx, format, v...)
+}
+
+// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
+func Fatal(ctx context.Context, v ...interface{}) {
+ defaultLogger.Fatal(ctx, v...)
+}
+
+// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
+func Fatalf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Fatalf(ctx, format, v...)
+}
+
+// Panic prints the logging content with [PANI] header and newline, then panics.
+func Panic(ctx context.Context, v ...interface{}) {
+ defaultLogger.Panic(ctx, v...)
+}
+
+// Panicf prints the logging content with [PANI] header, custom format and newline, then panics.
+func Panicf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Panicf(ctx, format, v...)
+}
+
+// Info prints the logging content with [INFO] header and newline.
+func Info(ctx context.Context, v ...interface{}) {
+ defaultLogger.Info(ctx, v...)
+}
+
+// Infof prints the logging content with [INFO] header, custom format and newline.
+func Infof(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Infof(ctx, format, v...)
+}
+
+// Debug prints the logging content with [DEBU] header and newline.
+func Debug(ctx context.Context, v ...interface{}) {
+ defaultLogger.Debug(ctx, v...)
+}
+
+// Debugf prints the logging content with [DEBU] header, custom format and newline.
+func Debugf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Debugf(ctx, format, v...)
+}
+
+// Notice prints the logging content with [NOTI] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Notice(ctx context.Context, v ...interface{}) {
+ defaultLogger.Notice(ctx, v...)
+}
+
+// Noticef prints the logging content with [NOTI] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Noticef(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Noticef(ctx, format, v...)
+}
+
+// Warning prints the logging content with [WARN] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Warning(ctx context.Context, v ...interface{}) {
+ defaultLogger.Warning(ctx, v...)
+}
+
+// Warningf prints the logging content with [WARN] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Warningf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Warningf(ctx, format, v...)
+}
+
+// Error prints the logging content with [ERRO] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Error(ctx context.Context, v ...interface{}) {
+ defaultLogger.Error(ctx, v...)
+}
+
+// Errorf prints the logging content with [ERRO] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Errorf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Errorf(ctx, format, v...)
+}
+
+// Critical prints the logging content with [CRIT] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Critical(ctx context.Context, v ...interface{}) {
+ defaultLogger.Critical(ctx, v...)
+}
+
+// Criticalf prints the logging content with [CRIT] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func Criticalf(ctx context.Context, format string, v ...interface{}) {
+ defaultLogger.Criticalf(ctx, format, v...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_chaining.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_chaining.go
new file mode 100644
index 000000000000..391def3e5518
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_chaining.go
@@ -0,0 +1,98 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "io"
+)
+
+// Expose returns the default logger of package glog.
+func Expose() *Logger {
+ return defaultLogger
+}
+
+// To is a chaining function,
+// which redirects current logging content output to the sepecified `writer`.
+func To(writer io.Writer) *Logger {
+ return defaultLogger.To(writer)
+}
+
+// Path is a chaining function,
+// which sets the directory path to `path` for current logging content output.
+func Path(path string) *Logger {
+ return defaultLogger.Path(path)
+}
+
+// Cat is a chaining function,
+// which sets the category to `category` for current logging content output.
+func Cat(category string) *Logger {
+ return defaultLogger.Cat(category)
+}
+
+// File is a chaining function,
+// which sets file name `pattern` for the current logging content output.
+func File(pattern string) *Logger {
+ return defaultLogger.File(pattern)
+}
+
+// Level is a chaining function,
+// which sets logging level for the current logging content output.
+func Level(level int) *Logger {
+ return defaultLogger.Level(level)
+}
+
+// LevelStr is a chaining function,
+// which sets logging level for the current logging content output using level string.
+func LevelStr(levelStr string) *Logger {
+ return defaultLogger.LevelStr(levelStr)
+}
+
+// Skip is a chaining function,
+// which sets stack skip for the current logging content output.
+// It also affects the caller file path checks when line number printing enabled.
+func Skip(skip int) *Logger {
+ return defaultLogger.Skip(skip)
+}
+
+// Stack is a chaining function,
+// which sets stack options for the current logging content output .
+func Stack(enabled bool, skip ...int) *Logger {
+ return defaultLogger.Stack(enabled, skip...)
+}
+
+// StackWithFilter is a chaining function,
+// which sets stack filter for the current logging content output .
+func StackWithFilter(filter string) *Logger {
+ return defaultLogger.StackWithFilter(filter)
+}
+
+// Stdout is a chaining function,
+// which enables/disables stdout for the current logging content output.
+// It's enabled in default.
+func Stdout(enabled ...bool) *Logger {
+ return defaultLogger.Stdout(enabled...)
+}
+
+// Header is a chaining function,
+// which enables/disables log header for the current logging content output.
+// It's enabled in default.
+func Header(enabled ...bool) *Logger {
+ return defaultLogger.Header(enabled...)
+}
+
+// Line is a chaining function,
+// which enables/disables printing its caller file along with its line number.
+// The parameter `long` specified whether print the long absolute file path, eg: /a/b/c/d.go:23.
+func Line(long ...bool) *Logger {
+ return defaultLogger.Line(long...)
+}
+
+// Async is a chaining function,
+// which enables/disables async logging output feature.
+func Async(enabled ...bool) *Logger {
+ return defaultLogger.Async(enabled...)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_config.go
new file mode 100644
index 000000000000..7eace27fceb3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_config.go
@@ -0,0 +1,161 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "context"
+ "io"
+)
+
+// SetConfig set configurations for the defaultLogger.
+func SetConfig(config Config) error {
+ return defaultLogger.SetConfig(config)
+}
+
+// SetConfigWithMap set configurations with map for the defaultLogger.
+func SetConfigWithMap(m map[string]interface{}) error {
+ return defaultLogger.SetConfigWithMap(m)
+}
+
+// SetPath sets the directory path for file logging.
+func SetPath(path string) error {
+ return defaultLogger.SetPath(path)
+}
+
+// GetPath returns the logging directory path for file logging.
+// It returns empty string if no directory path set.
+func GetPath() string {
+ return defaultLogger.GetPath()
+}
+
+// SetFile sets the file name `pattern` for file logging.
+// Datetime pattern can be used in `pattern`, eg: access-{Ymd}.log.
+// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
+func SetFile(pattern string) {
+ defaultLogger.SetFile(pattern)
+}
+
+// SetLevel sets the default logging level.
+func SetLevel(level int) {
+ defaultLogger.SetLevel(level)
+}
+
+// GetLevel returns the default logging level value.
+func GetLevel() int {
+ return defaultLogger.GetLevel()
+}
+
+// SetWriter sets the customized logging `writer` for logging.
+// The `writer` object should implements the io.Writer interface.
+// Developer can use customized logging `writer` to redirect logging output to another service,
+// eg: kafka, mysql, mongodb, etc.
+func SetWriter(writer io.Writer) {
+ defaultLogger.SetWriter(writer)
+}
+
+// GetWriter returns the customized writer object, which implements the io.Writer interface.
+// It returns nil if no customized writer set.
+func GetWriter() io.Writer {
+ return defaultLogger.GetWriter()
+}
+
+// SetDebug enables/disables the debug level for default defaultLogger.
+// The debug level is enabled in default.
+func SetDebug(debug bool) {
+ defaultLogger.SetDebug(debug)
+}
+
+// SetAsync enables/disables async logging output feature for default defaultLogger.
+func SetAsync(enabled bool) {
+ defaultLogger.SetAsync(enabled)
+}
+
+// SetStdoutPrint sets whether ouptput the logging contents to stdout, which is true in default.
+func SetStdoutPrint(enabled bool) {
+ defaultLogger.SetStdoutPrint(enabled)
+}
+
+// SetHeaderPrint sets whether output header of the logging contents, which is true in default.
+func SetHeaderPrint(enabled bool) {
+ defaultLogger.SetHeaderPrint(enabled)
+}
+
+// SetPrefix sets prefix string for every logging content.
+// Prefix is part of header, which means if header output is shut, no prefix will be output.
+func SetPrefix(prefix string) {
+ defaultLogger.SetPrefix(prefix)
+}
+
+// SetFlags sets extra flags for logging output features.
+func SetFlags(flags int) {
+ defaultLogger.SetFlags(flags)
+}
+
+// GetFlags returns the flags of defaultLogger.
+func GetFlags() int {
+ return defaultLogger.GetFlags()
+}
+
+// SetCtxKeys sets the context keys for defaultLogger. The keys is used for retrieving values
+// from context and printing them to logging content.
+//
+// Note that multiple calls of this function will overwrite the previous set context keys.
+func SetCtxKeys(keys ...interface{}) {
+ defaultLogger.SetCtxKeys(keys...)
+}
+
+// GetCtxKeys retrieves and returns the context keys for logging.
+func GetCtxKeys() []interface{} {
+ return defaultLogger.GetCtxKeys()
+}
+
+// PrintStack prints the caller stack,
+// the optional parameter `skip` specify the skipped stack offset from the end point.
+func PrintStack(ctx context.Context, skip ...int) {
+ defaultLogger.PrintStack(ctx, skip...)
+}
+
+// GetStack returns the caller stack content,
+// the optional parameter `skip` specify the skipped stack offset from the end point.
+func GetStack(skip ...int) string {
+ return defaultLogger.GetStack(skip...)
+}
+
+// SetStack enables/disables the stack feature in failure logging outputs.
+func SetStack(enabled bool) {
+ defaultLogger.SetStack(enabled)
+}
+
+// SetLevelStr sets the logging level by level string.
+func SetLevelStr(levelStr string) error {
+ return defaultLogger.SetLevelStr(levelStr)
+}
+
+// SetLevelPrefix sets the prefix string for specified level.
+func SetLevelPrefix(level int, prefix string) {
+ defaultLogger.SetLevelPrefix(level, prefix)
+}
+
+// SetLevelPrefixes sets the level to prefix string mapping for the defaultLogger.
+func SetLevelPrefixes(prefixes map[int]string) {
+ defaultLogger.SetLevelPrefixes(prefixes)
+}
+
+// GetLevelPrefix returns the prefix string for specified level.
+func GetLevelPrefix(level int) string {
+ return defaultLogger.GetLevelPrefix(level)
+}
+
+// SetHandlers sets the logging handlers for default defaultLogger.
+func SetHandlers(handlers ...Handler) {
+ defaultLogger.SetHandlers(handlers...)
+}
+
+//SetWriterColorEnable sets the file logging with color
+func SetWriterColorEnable(enabled bool) {
+ defaultLogger.SetWriterColorEnable(enabled)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_instance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_instance.go
new file mode 100644
index 000000000000..3b732606ded4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_instance.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import "github.com/gogf/gf/v2/container/gmap"
+
+const (
+ // DefaultName is the default group name for instance usage.
+ DefaultName = "default"
+)
+
+var (
+ // Instances map.
+ instances = gmap.NewStrAnyMap(true)
+)
+
+// Instance returns an instance of Logger with default settings.
+// The parameter `name` is the name for the instance.
+func Instance(name ...string) *Logger {
+ key := DefaultName
+ if len(name) > 0 && name[0] != "" {
+ key = name[0]
+ }
+ return instances.GetOrSetFuncLock(key, func() interface{} {
+ return New()
+ }).(*Logger)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger.go
new file mode 100644
index 000000000000..8dd985759e92
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger.go
@@ -0,0 +1,386 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/fatih/color"
+ "github.com/gogf/gf/v2/internal/utils"
+ "go.opentelemetry.io/otel/trace"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/debug/gdebug"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gctx"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gfpool"
+ "github.com/gogf/gf/v2/os/gmlock"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gtimer"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Logger is the struct for logging management.
+type Logger struct {
+ init *gtype.Bool // Initialized.
+ parent *Logger // Parent logger, if it is not empty, it means the logger is used in chaining function.
+ config Config // Logger configuration.
+}
+
+const (
+ defaultFileFormat = `{Y-m-d}.log`
+ defaultFileFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND
+ defaultFilePerm = os.FileMode(0666)
+ defaultFileExpire = time.Minute
+ pathFilterKey = "/os/glog/glog"
+ memoryLockPrefixForPrintingToFile = "glog.printToFile:"
+)
+
+const (
+ F_ASYNC = 1 << iota // Print logging content asynchronously。
+ F_FILE_LONG // Print full file name and line number: /a/b/c/d.go:23.
+ F_FILE_SHORT // Print final file name element and line number: d.go:23. overrides F_FILE_LONG.
+ F_TIME_DATE // Print the date in the local time zone: 2009-01-23.
+ F_TIME_TIME // Print the time in the local time zone: 01:23:23.
+ F_TIME_MILLI // Print the time with milliseconds in the local time zone: 01:23:23.675.
+ F_CALLER_FN // Print Caller function name and package: main.main
+ F_TIME_STD = F_TIME_DATE | F_TIME_MILLI
+)
+
+// New creates and returns a custom logger.
+func New() *Logger {
+ logger := &Logger{
+ init: gtype.NewBool(),
+ config: DefaultConfig(),
+ }
+ return logger
+}
+
+// NewWithWriter creates and returns a custom logger with io.Writer.
+func NewWithWriter(writer io.Writer) *Logger {
+ l := New()
+ l.SetWriter(writer)
+ return l
+}
+
+// Clone returns a new logger, which is the clone the current logger.
+// It's commonly used for chaining operations.
+func (l *Logger) Clone() *Logger {
+ newLogger := New()
+ newLogger.config = l.config
+ newLogger.parent = l
+ return newLogger
+}
+
+// getFilePath returns the logging file path.
+// The logging file name must have extension name of "log".
+func (l *Logger) getFilePath(now time.Time) string {
+ // Content containing "{}" in the file name is formatted using gtime.
+ file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.config.File, func(s string) string {
+ return gtime.New(now).Format(strings.Trim(s, "{}"))
+ })
+ file = gfile.Join(l.config.Path, file)
+ return file
+}
+
+// print prints `s` to defined writer, logging file or passed `std`.
+func (l *Logger) print(ctx context.Context, level int, values ...interface{}) {
+ // Lazy initialize for rotation feature.
+ // It uses atomic reading operation to enhance the performance checking.
+ // It here uses CAP for performance and concurrent safety.
+ p := l
+ if p.parent != nil {
+ p = p.parent
+ }
+ // It just initializes once for each logger.
+ if p.config.RotateSize > 0 || p.config.RotateExpire > 0 {
+ if !p.init.Val() && p.init.Cas(false, true) {
+ gtimer.AddOnce(context.Background(), p.config.RotateCheckInterval, p.rotateChecksTimely)
+ intlog.Printf(ctx, "logger rotation initialized: every %s", p.config.RotateCheckInterval.String())
+ }
+ }
+
+ var (
+ now = time.Now()
+ input = &HandlerInput{
+ Logger: l,
+ Buffer: bytes.NewBuffer(nil),
+ Ctx: ctx,
+ Time: now,
+ Color: defaultLevelColor[level],
+ Level: level,
+ handlerIndex: -1,
+ }
+ )
+ if l.config.HeaderPrint {
+ // Time.
+ timeFormat := ""
+ if l.config.Flags&F_TIME_DATE > 0 {
+ timeFormat += "2006-01-02"
+ }
+ if l.config.Flags&F_TIME_TIME > 0 {
+ if timeFormat != "" {
+ timeFormat += " "
+ }
+ timeFormat += "15:04:05"
+ }
+ if l.config.Flags&F_TIME_MILLI > 0 {
+ if timeFormat != "" {
+ timeFormat += " "
+ }
+ timeFormat += "15:04:05.000"
+ }
+ if len(timeFormat) > 0 {
+ input.TimeFormat = now.Format(timeFormat)
+ }
+
+ // Level string.
+ input.LevelFormat = l.getLevelPrefixWithBrackets(level)
+
+ // Caller path and Fn name.
+ if l.config.Flags&(F_FILE_LONG|F_FILE_SHORT|F_CALLER_FN) > 0 {
+ callerFnName, path, line := gdebug.CallerWithFilter(
+ []string{utils.StackFilterKeyForGoFrame},
+ l.config.StSkip,
+ )
+ if l.config.Flags&F_CALLER_FN > 0 {
+ if len(callerFnName) > 2 {
+ input.CallerFunc = fmt.Sprintf(`[%s]`, callerFnName)
+ }
+ }
+ if line >= 0 && len(path) > 1 {
+ if l.config.Flags&F_FILE_LONG > 0 {
+ input.CallerPath = fmt.Sprintf(`%s:%d:`, path, line)
+ }
+ if l.config.Flags&F_FILE_SHORT > 0 {
+ input.CallerPath = fmt.Sprintf(`%s:%d:`, gfile.Basename(path), line)
+ }
+ }
+ }
+ // Prefix.
+ if len(l.config.Prefix) > 0 {
+ input.Prefix = l.config.Prefix
+ }
+ }
+ // Convert value to string.
+ if ctx != nil {
+ // Tracing values.
+ spanCtx := trace.SpanContextFromContext(ctx)
+ if traceId := spanCtx.TraceID(); traceId.IsValid() {
+ input.CtxStr = traceId.String()
+ }
+ // Context values.
+ if len(l.config.CtxKeys) > 0 {
+ for _, ctxKey := range l.config.CtxKeys {
+ var ctxValue interface{}
+ if ctxValue = ctx.Value(ctxKey); ctxValue == nil {
+ ctxValue = ctx.Value(gctx.StrKey(gconv.String(ctxKey)))
+ }
+ if ctxValue != nil {
+ if input.CtxStr != "" {
+ input.CtxStr += ", "
+ }
+ input.CtxStr += gconv.String(ctxValue)
+ }
+ }
+ }
+ if input.CtxStr != "" {
+ input.CtxStr = "{" + input.CtxStr + "}"
+ }
+ }
+ var tempStr string
+ for _, v := range values {
+ tempStr = gconv.String(v)
+ if len(input.Content) > 0 {
+ if input.Content[len(input.Content)-1] == '\n' {
+ // Remove one blank line(\n\n).
+ if len(tempStr) > 0 && tempStr[0] == '\n' {
+ input.Content += tempStr[1:]
+ } else {
+ input.Content += tempStr
+ }
+ } else {
+ input.Content += " " + tempStr
+ }
+ } else {
+ input.Content = tempStr
+ }
+ }
+ if l.config.Flags&F_ASYNC > 0 {
+ input.IsAsync = true
+ err := asyncPool.Add(ctx, func(ctx context.Context) {
+ input.Next()
+ })
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ } else {
+ input.Next()
+ }
+}
+
+// doDefaultPrint outputs the logging content according configuration.
+func (l *Logger) doDefaultPrint(ctx context.Context, input *HandlerInput) *bytes.Buffer {
+ var buffer *bytes.Buffer
+ if l.config.Writer == nil {
+ // Allow output to stdout?
+ if l.config.StdoutPrint {
+ if buf := l.printToStdout(ctx, input); buf != nil {
+ buffer = buf
+ }
+ }
+
+ // Output content to disk file.
+ if l.config.Path != "" {
+ if buf := l.printToFile(ctx, input.Time, input); buf != nil {
+ buffer = buf
+ }
+ }
+ } else {
+ // Output to custom writer.
+ if buf := l.printToWriter(ctx, input); buf != nil {
+ buffer = buf
+ }
+ }
+ return buffer
+}
+
+// printToWriter writes buffer to writer.
+func (l *Logger) printToWriter(ctx context.Context, input *HandlerInput) *bytes.Buffer {
+ if l.config.Writer != nil {
+ var (
+ buffer = input.getRealBuffer(l.config.WriterColorEnable)
+ )
+ if _, err := l.config.Writer.Write(buffer.Bytes()); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ return buffer
+ }
+ return nil
+}
+
+// printToStdout outputs logging content to stdout.
+func (l *Logger) printToStdout(ctx context.Context, input *HandlerInput) *bytes.Buffer {
+ if l.config.StdoutPrint {
+ var (
+ err error
+ buffer = input.getRealBuffer(!l.config.StdoutColorDisabled)
+ )
+ // This will lose color in Windows os system.
+ // if _, err := os.Stdout.Write(input.getRealBuffer(true).Bytes()); err != nil {
+
+ // This will print color in Windows os system.
+ if _, err = fmt.Fprint(color.Output, buffer.String()); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ return buffer
+ }
+ return nil
+}
+
+// printToFile outputs logging content to disk file.
+func (l *Logger) printToFile(ctx context.Context, t time.Time, in *HandlerInput) *bytes.Buffer {
+ var (
+ buffer = in.getRealBuffer(l.config.WriterColorEnable)
+ logFilePath = l.getFilePath(t)
+ memoryLockKey = memoryLockPrefixForPrintingToFile + logFilePath
+ )
+ gmlock.Lock(memoryLockKey)
+ defer gmlock.Unlock(memoryLockKey)
+
+ // Rotation file size checks.
+ if l.config.RotateSize > 0 {
+ if gfile.Size(logFilePath) > l.config.RotateSize {
+ l.rotateFileBySize(ctx, t)
+ }
+ }
+ // Logging content outputting to disk file.
+ if file := l.getFilePointer(ctx, logFilePath); file == nil {
+ intlog.Errorf(ctx, `got nil file pointer for: %s`, logFilePath)
+ } else {
+ if _, err := file.Write(buffer.Bytes()); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ if err := file.Close(); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ return buffer
+}
+
+// getFilePointer retrieves and returns a file pointer from file pool.
+func (l *Logger) getFilePointer(ctx context.Context, path string) *gfpool.File {
+ file, err := gfpool.Open(
+ path,
+ defaultFileFlags,
+ defaultFilePerm,
+ defaultFileExpire,
+ )
+ if err != nil {
+ // panic(err)
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ return file
+}
+
+// printStd prints content `s` without stack.
+func (l *Logger) printStd(ctx context.Context, level int, value ...interface{}) {
+ l.print(ctx, level, value...)
+}
+
+// printStd prints content `s` with stack check.
+func (l *Logger) printErr(ctx context.Context, level int, value ...interface{}) {
+ if l.config.StStatus == 1 {
+ if s := l.GetStack(); s != "" {
+ value = append(value, "\nStack:\n"+s)
+ }
+ }
+ // In matter of sequence, do not use stderr here, but use the same stdout.
+ l.print(ctx, level, value...)
+}
+
+// format formats `values` using fmt.Sprintf.
+func (l *Logger) format(format string, value ...interface{}) string {
+ return fmt.Sprintf(format, value...)
+}
+
+// PrintStack prints the caller stack,
+// the optional parameter `skip` specify the skipped stack offset from the end point.
+func (l *Logger) PrintStack(ctx context.Context, skip ...int) {
+ if s := l.GetStack(skip...); s != "" {
+ l.Print(ctx, "Stack:\n"+s)
+ } else {
+ l.Print(ctx)
+ }
+}
+
+// GetStack returns the caller stack content,
+// the optional parameter `skip` specify the skipped stack offset from the end point.
+func (l *Logger) GetStack(skip ...int) string {
+ stackSkip := l.config.StSkip
+ if len(skip) > 0 {
+ stackSkip += skip[0]
+ }
+ filters := []string{pathFilterKey}
+ if l.config.StFilter != "" {
+ filters = append(filters, l.config.StFilter)
+ }
+ return gdebug.StackWithFilters(filters, stackSkip)
+}
+
+// GetConfig returns the configuration of current Logger.
+func (l *Logger) GetConfig() Config {
+ return l.config
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_api.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_api.go
new file mode 100644
index 000000000000..d485d6fc2e11
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_api.go
@@ -0,0 +1,146 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "context"
+ "fmt"
+ "os"
+)
+
+// Print prints `v` with newline using fmt.Sprintln.
+// The parameter `v` can be multiple variables.
+func (l *Logger) Print(ctx context.Context, v ...interface{}) {
+ l.printStd(ctx, LEVEL_NONE, v...)
+}
+
+// Printf prints `v` with format `format` using fmt.Sprintf.
+// The parameter `v` can be multiple variables.
+func (l *Logger) Printf(ctx context.Context, format string, v ...interface{}) {
+ l.printStd(ctx, LEVEL_NONE, l.format(format, v...))
+}
+
+// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
+func (l *Logger) Fatal(ctx context.Context, v ...interface{}) {
+ l.printErr(ctx, LEVEL_FATA, v...)
+ os.Exit(1)
+}
+
+// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
+func (l *Logger) Fatalf(ctx context.Context, format string, v ...interface{}) {
+ l.printErr(ctx, LEVEL_FATA, l.format(format, v...))
+ os.Exit(1)
+}
+
+// Panic prints the logging content with [PANI] header and newline, then panics.
+func (l *Logger) Panic(ctx context.Context, v ...interface{}) {
+ l.printErr(ctx, LEVEL_PANI, v...)
+ panic(fmt.Sprint(v...))
+}
+
+// Panicf prints the logging content with [PANI] header, custom format and newline, then panics.
+func (l *Logger) Panicf(ctx context.Context, format string, v ...interface{}) {
+ l.printErr(ctx, LEVEL_PANI, l.format(format, v...))
+ panic(l.format(format, v...))
+}
+
+// Info prints the logging content with [INFO] header and newline.
+func (l *Logger) Info(ctx context.Context, v ...interface{}) {
+ if l.checkLevel(LEVEL_INFO) {
+ l.printStd(ctx, LEVEL_INFO, v...)
+ }
+}
+
+// Infof prints the logging content with [INFO] header, custom format and newline.
+func (l *Logger) Infof(ctx context.Context, format string, v ...interface{}) {
+ if l.checkLevel(LEVEL_INFO) {
+ l.printStd(ctx, LEVEL_INFO, l.format(format, v...))
+ }
+}
+
+// Debug prints the logging content with [DEBU] header and newline.
+func (l *Logger) Debug(ctx context.Context, v ...interface{}) {
+ if l.checkLevel(LEVEL_DEBU) {
+ l.printStd(ctx, LEVEL_DEBU, v...)
+ }
+}
+
+// Debugf prints the logging content with [DEBU] header, custom format and newline.
+func (l *Logger) Debugf(ctx context.Context, format string, v ...interface{}) {
+ if l.checkLevel(LEVEL_DEBU) {
+ l.printStd(ctx, LEVEL_DEBU, l.format(format, v...))
+ }
+}
+
+// Notice prints the logging content with [NOTI] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Notice(ctx context.Context, v ...interface{}) {
+ if l.checkLevel(LEVEL_NOTI) {
+ l.printStd(ctx, LEVEL_NOTI, v...)
+ }
+}
+
+// Noticef prints the logging content with [NOTI] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Noticef(ctx context.Context, format string, v ...interface{}) {
+ if l.checkLevel(LEVEL_NOTI) {
+ l.printStd(ctx, LEVEL_NOTI, l.format(format, v...))
+ }
+}
+
+// Warning prints the logging content with [WARN] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Warning(ctx context.Context, v ...interface{}) {
+ if l.checkLevel(LEVEL_WARN) {
+ l.printStd(ctx, LEVEL_WARN, v...)
+ }
+}
+
+// Warningf prints the logging content with [WARN] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Warningf(ctx context.Context, format string, v ...interface{}) {
+ if l.checkLevel(LEVEL_WARN) {
+ l.printStd(ctx, LEVEL_WARN, l.format(format, v...))
+ }
+}
+
+// Error prints the logging content with [ERRO] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Error(ctx context.Context, v ...interface{}) {
+ if l.checkLevel(LEVEL_ERRO) {
+ l.printErr(ctx, LEVEL_ERRO, v...)
+ }
+}
+
+// Errorf prints the logging content with [ERRO] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Errorf(ctx context.Context, format string, v ...interface{}) {
+ if l.checkLevel(LEVEL_ERRO) {
+ l.printErr(ctx, LEVEL_ERRO, l.format(format, v...))
+ }
+}
+
+// Critical prints the logging content with [CRIT] header and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Critical(ctx context.Context, v ...interface{}) {
+ if l.checkLevel(LEVEL_CRIT) {
+ l.printErr(ctx, LEVEL_CRIT, v...)
+ }
+}
+
+// Criticalf prints the logging content with [CRIT] header, custom format and newline.
+// It also prints caller stack info if stack feature is enabled.
+func (l *Logger) Criticalf(ctx context.Context, format string, v ...interface{}) {
+ if l.checkLevel(LEVEL_CRIT) {
+ l.printErr(ctx, LEVEL_CRIT, l.format(format, v...))
+ }
+}
+
+// checkLevel checks whether the given `level` could be output.
+func (l *Logger) checkLevel(level int) bool {
+ return l.config.Level&level > 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_chaining.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_chaining.go
new file mode 100644
index 000000000000..29ebade2f0d7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_chaining.go
@@ -0,0 +1,223 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "io"
+
+ "github.com/gogf/gf/v2/os/gfile"
+)
+
+// To is a chaining function,
+// which redirects current logging content output to the specified `writer`.
+func (l *Logger) To(writer io.Writer) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ logger.SetWriter(writer)
+ return logger
+}
+
+// Path is a chaining function,
+// which sets the directory path to `path` for current logging content output.
+//
+// Note that the parameter `path` is a directory path, not a file path.
+func (l *Logger) Path(path string) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ if path != "" {
+ if err := logger.SetPath(path); err != nil {
+ panic(err)
+ }
+ }
+ return logger
+}
+
+// Cat is a chaining function,
+// which sets the category to `category` for current logging content output.
+// Param `category` can be hierarchical, eg: module/user.
+func (l *Logger) Cat(category string) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ if logger.config.Path != "" {
+ if err := logger.SetPath(gfile.Join(logger.config.Path, category)); err != nil {
+ panic(err)
+ }
+ }
+ return logger
+}
+
+// File is a chaining function,
+// which sets file name `pattern` for the current logging content output.
+func (l *Logger) File(file string) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ logger.SetFile(file)
+ return logger
+}
+
+// Level is a chaining function,
+// which sets logging level for the current logging content output.
+func (l *Logger) Level(level int) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ logger.SetLevel(level)
+ return logger
+}
+
+// LevelStr is a chaining function,
+// which sets logging level for the current logging content output using level string.
+func (l *Logger) LevelStr(levelStr string) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ if err := logger.SetLevelStr(levelStr); err != nil {
+ panic(err)
+ }
+ return logger
+}
+
+// Skip is a chaining function,
+// which sets stack skip for the current logging content output.
+// It also affects the caller file path checks when line number printing enabled.
+func (l *Logger) Skip(skip int) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ logger.SetStackSkip(skip)
+ return logger
+}
+
+// Stack is a chaining function,
+// which sets stack options for the current logging content output .
+func (l *Logger) Stack(enabled bool, skip ...int) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ logger.SetStack(enabled)
+ if len(skip) > 0 {
+ logger.SetStackSkip(skip[0])
+ }
+ return logger
+}
+
+// StackWithFilter is a chaining function,
+// which sets stack filter for the current logging content output .
+func (l *Logger) StackWithFilter(filter string) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ logger.SetStack(true)
+ logger.SetStackFilter(filter)
+ return logger
+}
+
+// Stdout is a chaining function,
+// which enables/disables stdout for the current logging content output.
+// It's enabled in default.
+func (l *Logger) Stdout(enabled ...bool) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ // stdout printing is enabled if `enabled` is not passed.
+ if len(enabled) > 0 && !enabled[0] {
+ logger.config.StdoutPrint = false
+ } else {
+ logger.config.StdoutPrint = true
+ }
+ return logger
+}
+
+// Header is a chaining function,
+// which enables/disables log header for the current logging content output.
+// It's enabled in default.
+func (l *Logger) Header(enabled ...bool) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ // header is enabled if `enabled` is not passed.
+ if len(enabled) > 0 && !enabled[0] {
+ logger.SetHeaderPrint(false)
+ } else {
+ logger.SetHeaderPrint(true)
+ }
+ return logger
+}
+
+// Line is a chaining function,
+// which enables/disables printing its caller file path along with its line number.
+// The parameter `long` specified whether print the long absolute file path, eg: /a/b/c/d.go:23,
+// or else short one: d.go:23.
+func (l *Logger) Line(long ...bool) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ if len(long) > 0 && long[0] {
+ logger.config.Flags |= F_FILE_LONG
+ } else {
+ logger.config.Flags |= F_FILE_SHORT
+ }
+ return logger
+}
+
+// Async is a chaining function,
+// which enables/disables async logging output feature.
+func (l *Logger) Async(enabled ...bool) *Logger {
+ logger := (*Logger)(nil)
+ if l.parent == nil {
+ logger = l.Clone()
+ } else {
+ logger = l
+ }
+ // async feature is enabled if `enabled` is not passed.
+ if len(enabled) > 0 && !enabled[0] {
+ logger.SetAsync(false)
+ } else {
+ logger.SetAsync(true)
+ }
+ return logger
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_color.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_color.go
new file mode 100644
index 000000000000..98bf966c5f86
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_color.go
@@ -0,0 +1,53 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import "github.com/fatih/color"
+
+const (
+ COLOR_BLACK = 30 + iota
+ COLOR_RED
+ COLOR_GREEN
+ COLOR_YELLOW
+ COLOR_BLUE
+ COLOR_MAGENTA
+ COLOR_CYAN
+ COLOR_WHITE
+)
+
+// Foreground Hi-Intensity text colors
+const (
+ COLOR_HI_BLACK = 90 + iota
+ COLOR_HI_RED
+ COLOR_HI_GREEN
+ COLOR_HI_YELLOW
+ COLOR_HI_BLUE
+ COLOR_HI_MAGENTA
+ COLOR_HI_CYAN
+ COLOR_HI_WHITE
+)
+
+// defaultLevelColor defines the default level and its mapping prefix string.
+var defaultLevelColor = map[int]int{
+ LEVEL_DEBU: COLOR_YELLOW,
+ LEVEL_INFO: COLOR_GREEN,
+ LEVEL_NOTI: COLOR_CYAN,
+ LEVEL_WARN: COLOR_MAGENTA,
+ LEVEL_ERRO: COLOR_RED,
+ LEVEL_CRIT: COLOR_HI_RED,
+ LEVEL_PANI: COLOR_HI_RED,
+ LEVEL_FATA: COLOR_HI_RED,
+}
+
+// getColoredStr returns a string that is colored by given color.
+func (l *Logger) getColoredStr(c int, s string) string {
+ return color.New(color.Attribute(c)).Sprint(s)
+}
+
+func (l *Logger) getColorByLevel(level int) int {
+ return defaultLevelColor[level]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_config.go
new file mode 100644
index 000000000000..9dcd1ee513e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_config.go
@@ -0,0 +1,265 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "context"
+ "io"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// Config is the configuration object for logger.
+type Config struct {
+ Handlers []Handler `json:"-"` // Logger handlers which implement feature similar as middleware.
+ Writer io.Writer `json:"-"` // Customized io.Writer.
+ Flags int `json:"flags"` // Extra flags for logging output features.
+ Path string `json:"path"` // Logging directory path.
+ File string `json:"file"` // Format pattern for logging file.
+ Level int `json:"level"` // Output level.
+ Prefix string `json:"prefix"` // Prefix string for every logging content.
+ StSkip int `json:"stSkip"` // Skipping count for stack.
+ StStatus int `json:"stStatus"` // Stack status(1: enabled - default; 0: disabled)
+ StFilter string `json:"stFilter"` // Stack string filter.
+ CtxKeys []interface{} `json:"ctxKeys"` // Context keys for logging, which is used for value retrieving from context.
+ HeaderPrint bool `json:"header"` // Print header or not(true in default).
+ StdoutPrint bool `json:"stdout"` // Output to stdout or not(true in default).
+ LevelPrefixes map[int]string `json:"levelPrefixes"` // Logging level to its prefix string mapping.
+ RotateSize int64 `json:"rotateSize"` // Rotate the logging file if its size > 0 in bytes.
+ RotateExpire time.Duration `json:"rotateExpire"` // Rotate the logging file if its mtime exceeds this duration.
+ RotateBackupLimit int `json:"rotateBackupLimit"` // Max backup for rotated files, default is 0, means no backups.
+ RotateBackupExpire time.Duration `json:"rotateBackupExpire"` // Max expires for rotated files, which is 0 in default, means no expiration.
+ RotateBackupCompress int `json:"rotateBackupCompress"` // Compress level for rotated files using gzip algorithm. It's 0 in default, means no compression.
+ RotateCheckInterval time.Duration `json:"rotateCheckInterval"` // Asynchronously checks the backups and expiration at intervals. It's 1 hour in default.
+ StdoutColorDisabled bool `json:"stdoutColorDisabled"` // Logging level prefix with color to writer or not (false in default).
+ WriterColorEnable bool `json:"writerColorEnable"` // Logging level prefix with color to writer or not (false in default).
+}
+
+// DefaultConfig returns the default configuration for logger.
+func DefaultConfig() Config {
+ c := Config{
+ File: defaultFileFormat,
+ Flags: F_TIME_STD,
+ Level: LEVEL_ALL,
+ CtxKeys: []interface{}{},
+ StStatus: 1,
+ HeaderPrint: true,
+ StdoutPrint: true,
+ LevelPrefixes: make(map[int]string, len(defaultLevelPrefixes)),
+ RotateCheckInterval: time.Hour,
+ }
+ for k, v := range defaultLevelPrefixes {
+ c.LevelPrefixes[k] = v
+ }
+ if !defaultDebug {
+ c.Level = c.Level & ^LEVEL_DEBU
+ }
+ return c
+}
+
+// SetConfig set configurations for the logger.
+func (l *Logger) SetConfig(config Config) error {
+ l.config = config
+ // Necessary validation.
+ if config.Path != "" {
+ if err := l.SetPath(config.Path); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ return err
+ }
+ }
+ intlog.Printf(context.TODO(), "SetConfig: %+v", l.config)
+ return nil
+}
+
+// SetConfigWithMap set configurations with map for the logger.
+func (l *Logger) SetConfigWithMap(m map[string]interface{}) error {
+ if m == nil || len(m) == 0 {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "configuration cannot be empty")
+ }
+ // The m now is a shallow copy of m.
+ // A little tricky, isn't it?
+ m = gutil.MapCopy(m)
+ // Change string configuration to int value for level.
+ levelKey, levelValue := gutil.MapPossibleItemByKey(m, "Level")
+ if levelValue != nil {
+ if level, ok := levelStringMap[strings.ToUpper(gconv.String(levelValue))]; ok {
+ m[levelKey] = level
+ } else {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid level string: %v`, levelValue)
+ }
+ }
+ // Change string configuration to int value for file rotation size.
+ rotateSizeKey, rotateSizeValue := gutil.MapPossibleItemByKey(m, "RotateSize")
+ if rotateSizeValue != nil {
+ m[rotateSizeKey] = gfile.StrToSize(gconv.String(rotateSizeValue))
+ if m[rotateSizeKey] == -1 {
+ return gerror.NewCodef(gcode.CodeInvalidConfiguration, `invalid rotate size: %v`, rotateSizeValue)
+ }
+ }
+ if err := gconv.Struct(m, &l.config); err != nil {
+ return err
+ }
+ return l.SetConfig(l.config)
+}
+
+// SetDebug enables/disables the debug level for logger.
+// The debug level is enabled in default.
+func (l *Logger) SetDebug(debug bool) {
+ if debug {
+ l.config.Level = l.config.Level | LEVEL_DEBU
+ } else {
+ l.config.Level = l.config.Level & ^LEVEL_DEBU
+ }
+}
+
+// SetAsync enables/disables async logging output feature.
+func (l *Logger) SetAsync(enabled bool) {
+ if enabled {
+ l.config.Flags = l.config.Flags | F_ASYNC
+ } else {
+ l.config.Flags = l.config.Flags & ^F_ASYNC
+ }
+}
+
+// SetFlags sets extra flags for logging output features.
+func (l *Logger) SetFlags(flags int) {
+ l.config.Flags = flags
+}
+
+// GetFlags returns the flags of logger.
+func (l *Logger) GetFlags() int {
+ return l.config.Flags
+}
+
+// SetStack enables/disables the stack feature in failure logging outputs.
+func (l *Logger) SetStack(enabled bool) {
+ if enabled {
+ l.config.StStatus = 1
+ } else {
+ l.config.StStatus = 0
+ }
+}
+
+// SetStackSkip sets the stack offset from the end point.
+func (l *Logger) SetStackSkip(skip int) {
+ l.config.StSkip = skip
+}
+
+// SetStackFilter sets the stack filter from the end point.
+func (l *Logger) SetStackFilter(filter string) {
+ l.config.StFilter = filter
+}
+
+// SetCtxKeys sets the context keys for logger. The keys is used for retrieving values
+// from context and printing them to logging content.
+//
+// Note that multiple calls of this function will overwrite the previous set context keys.
+func (l *Logger) SetCtxKeys(keys ...interface{}) {
+ l.config.CtxKeys = keys
+}
+
+// AppendCtxKeys appends extra keys to logger.
+// It ignores the key if it is already appended to the logger previously.
+func (l *Logger) AppendCtxKeys(keys ...interface{}) {
+ var isExist bool
+ for _, key := range keys {
+ isExist = false
+ for _, ctxKey := range l.config.CtxKeys {
+ if ctxKey == key {
+ isExist = true
+ break
+ }
+ }
+ if !isExist {
+ l.config.CtxKeys = append(l.config.CtxKeys, key)
+ }
+ }
+}
+
+// GetCtxKeys retrieves and returns the context keys for logging.
+func (l *Logger) GetCtxKeys() []interface{} {
+ return l.config.CtxKeys
+}
+
+// SetWriter sets the customized logging `writer` for logging.
+// The `writer` object should implement the io.Writer interface.
+// Developer can use customized logging `writer` to redirect logging output to another service,
+// eg: kafka, mysql, mongodb, etc.
+func (l *Logger) SetWriter(writer io.Writer) {
+ l.config.Writer = writer
+}
+
+// GetWriter returns the customized writer object, which implements the io.Writer interface.
+// It returns nil if no writer previously set.
+func (l *Logger) GetWriter() io.Writer {
+ return l.config.Writer
+}
+
+// SetPath sets the directory path for file logging.
+func (l *Logger) SetPath(path string) error {
+ if path == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "logging path is empty")
+ }
+ if !gfile.Exists(path) {
+ if err := gfile.Mkdir(path); err != nil {
+ return gerror.Wrapf(err, `Mkdir "%s" failed in PWD "%s"`, path, gfile.Pwd())
+ }
+ }
+ l.config.Path = strings.TrimRight(path, gfile.Separator)
+ return nil
+}
+
+// GetPath returns the logging directory path for file logging.
+// It returns empty string if no directory path set.
+func (l *Logger) GetPath() string {
+ return l.config.Path
+}
+
+// SetFile sets the file name `pattern` for file logging.
+// Datetime pattern can be used in `pattern`, eg: access-{Ymd}.log.
+// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
+func (l *Logger) SetFile(pattern string) {
+ l.config.File = pattern
+}
+
+// SetStdoutPrint sets whether output the logging contents to stdout, which is true in default.
+func (l *Logger) SetStdoutPrint(enabled bool) {
+ l.config.StdoutPrint = enabled
+}
+
+// SetHeaderPrint sets whether output header of the logging contents, which is true in default.
+func (l *Logger) SetHeaderPrint(enabled bool) {
+ l.config.HeaderPrint = enabled
+}
+
+// SetPrefix sets prefix string for every logging content.
+// Prefix is part of header, which means if header output is shut, no prefix will be output.
+func (l *Logger) SetPrefix(prefix string) {
+ l.config.Prefix = prefix
+}
+
+// SetHandlers sets the logging handlers for current logger.
+func (l *Logger) SetHandlers(handlers ...Handler) {
+ l.config.Handlers = handlers
+}
+
+// SetWriterColorEnable enables file/writer logging with color.
+func (l *Logger) SetWriterColorEnable(enabled bool) {
+ l.config.WriterColorEnable = enabled
+}
+
+// SetStdoutColorDisabled disables stdout logging with color.
+func (l *Logger) SetStdoutColorDisabled(disabled bool) {
+ l.config.StdoutColorDisabled = disabled
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_handler.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_handler.go
new file mode 100644
index 000000000000..bdeb4cdfc3f3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_handler.go
@@ -0,0 +1,111 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "bytes"
+ "context"
+ "time"
+)
+
+// Handler is function handler for custom logging content outputs.
+type Handler func(ctx context.Context, in *HandlerInput)
+
+// HandlerInput is the input parameter struct for logging Handler.
+type HandlerInput struct {
+ Logger *Logger // Logger.
+ Ctx context.Context // Context.
+ Buffer *bytes.Buffer // Buffer for logging content outputs.
+ Time time.Time // Logging time, which is the time that logging triggers.
+ TimeFormat string // Formatted time string, like "2016-01-09 12:00:00".
+ Color int // Using color, like COLOR_RED, COLOR_BLUE, etc.
+ Level int // Using level, like LEVEL_INFO, LEVEL_ERRO, etc.
+ LevelFormat string // Formatted level string, like "DEBU", "ERRO", etc.
+ CallerFunc string // The source function name that calls logging.
+ CallerPath string // The source file path and its line number that calls logging.
+ CtxStr string // The retrieved context value string from context.
+ Prefix string // Custom prefix string for logging content.
+ Content string // Content is the main logging content that passed by you.
+ IsAsync bool // IsAsync marks it is in asynchronous logging.
+ handlerIndex int // Middleware handling index for internal usage.
+}
+
+// Next calls the next logging handler in middleware way.
+func (i *HandlerInput) Next() {
+ if len(i.Logger.config.Handlers)-1 > i.handlerIndex {
+ i.handlerIndex++
+ i.Logger.config.Handlers[i.handlerIndex](i.Ctx, i)
+ } else {
+ defaultHandler(i.Ctx, i)
+ }
+}
+
+// String returns the logging content formatted by default logging handler.
+func (i *HandlerInput) String(withColor ...bool) string {
+ formatWithColor := false
+ if len(withColor) > 0 {
+ formatWithColor = withColor[0]
+ }
+ return i.getDefaultBuffer(formatWithColor).String()
+}
+
+func (i *HandlerInput) getDefaultBuffer(withColor bool) *bytes.Buffer {
+ buffer := bytes.NewBuffer(nil)
+ if i.TimeFormat != "" {
+ buffer.WriteString(i.TimeFormat)
+ }
+ if i.LevelFormat != "" {
+ if withColor {
+ i.addStringToBuffer(buffer, i.Logger.getColoredStr(
+ i.Logger.getColorByLevel(i.Level), i.LevelFormat,
+ ))
+ } else {
+ i.addStringToBuffer(buffer, i.LevelFormat)
+ }
+ }
+ if i.Prefix != "" {
+ i.addStringToBuffer(buffer, i.Prefix)
+ }
+ if i.CtxStr != "" {
+ i.addStringToBuffer(buffer, i.CtxStr)
+ }
+ if i.CallerFunc != "" {
+ i.addStringToBuffer(buffer, i.CallerFunc)
+ }
+ if i.CallerPath != "" {
+ i.addStringToBuffer(buffer, i.CallerPath)
+ }
+ if i.Content != "" {
+ i.addStringToBuffer(buffer, i.Content)
+ }
+ i.addStringToBuffer(buffer, "\n")
+ return buffer
+}
+
+func (i *HandlerInput) getRealBuffer(withColor bool) *bytes.Buffer {
+ if i.Buffer.Len() > 0 {
+ return i.Buffer
+ }
+ return i.getDefaultBuffer(withColor)
+}
+
+// defaultHandler is the default handler for logger.
+func defaultHandler(ctx context.Context, in *HandlerInput) {
+ buffer := in.Logger.doDefaultPrint(ctx, in)
+ if in.Buffer.Len() == 0 {
+ in.Buffer = buffer
+ }
+}
+
+func (i *HandlerInput) addStringToBuffer(buffer *bytes.Buffer, strings ...string) {
+ for _, s := range strings {
+ if buffer.Len() > 0 {
+ buffer.WriteByte(' ')
+ }
+ buffer.WriteString(s)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_level.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_level.go
new file mode 100644
index 000000000000..e1fe6b6a3f44
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_level.go
@@ -0,0 +1,111 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Note that the LEVEL_PANI and LEVEL_FATA levels are not used for logging output,
+// but for prefix configurations.
+const (
+ LEVEL_ALL = LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT
+ LEVEL_DEV = LEVEL_ALL
+ LEVEL_PROD = LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT
+ LEVEL_NONE = 0
+ LEVEL_DEBU = 1 << iota // 8
+ LEVEL_INFO // 16
+ LEVEL_NOTI // 32
+ LEVEL_WARN // 64
+ LEVEL_ERRO // 128
+ LEVEL_CRIT // 256
+ LEVEL_PANI // 512
+ LEVEL_FATA // 1024
+)
+
+// defaultLevelPrefixes defines the default level and its mapping prefix string.
+var defaultLevelPrefixes = map[int]string{
+ LEVEL_DEBU: "DEBU",
+ LEVEL_INFO: "INFO",
+ LEVEL_NOTI: "NOTI",
+ LEVEL_WARN: "WARN",
+ LEVEL_ERRO: "ERRO",
+ LEVEL_CRIT: "CRIT",
+ LEVEL_PANI: "PANI",
+ LEVEL_FATA: "FATA",
+}
+
+// levelStringMap defines level string name to its level mapping.
+var levelStringMap = map[string]int{
+ "ALL": LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "DEV": LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "DEVELOP": LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "PROD": LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "PRODUCT": LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "DEBU": LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "DEBUG": LEVEL_DEBU | LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "INFO": LEVEL_INFO | LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "NOTI": LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "NOTICE": LEVEL_NOTI | LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "WARN": LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "WARNING": LEVEL_WARN | LEVEL_ERRO | LEVEL_CRIT,
+ "ERRO": LEVEL_ERRO | LEVEL_CRIT,
+ "ERROR": LEVEL_ERRO | LEVEL_CRIT,
+ "CRIT": LEVEL_CRIT,
+ "CRITICAL": LEVEL_CRIT,
+}
+
+// SetLevel sets the logging level.
+// Note that levels ` LEVEL_CRIT | LEVEL_PANI | LEVEL_FATA ` cannot be removed for logging content,
+// which are automatically added to levels.
+func (l *Logger) SetLevel(level int) {
+ l.config.Level = level | LEVEL_CRIT | LEVEL_PANI | LEVEL_FATA
+}
+
+// GetLevel returns the logging level value.
+func (l *Logger) GetLevel() int {
+ return l.config.Level
+}
+
+// SetLevelStr sets the logging level by level string.
+func (l *Logger) SetLevelStr(levelStr string) error {
+ if level, ok := levelStringMap[strings.ToUpper(levelStr)]; ok {
+ l.config.Level = level
+ } else {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid level string: %s`, levelStr)
+ }
+ return nil
+}
+
+// SetLevelPrefix sets the prefix string for specified level.
+func (l *Logger) SetLevelPrefix(level int, prefix string) {
+ l.config.LevelPrefixes[level] = prefix
+}
+
+// SetLevelPrefixes sets the level to prefix string mapping for the logger.
+func (l *Logger) SetLevelPrefixes(prefixes map[int]string) {
+ for k, v := range prefixes {
+ l.config.LevelPrefixes[k] = v
+ }
+}
+
+// GetLevelPrefix returns the prefix string for specified level.
+func (l *Logger) GetLevelPrefix(level int) string {
+ return l.config.LevelPrefixes[level]
+}
+
+// getLevelPrefixWithBrackets returns the prefix string with brackets for specified level.
+func (l *Logger) getLevelPrefixWithBrackets(level int) string {
+ levelStr := ""
+ if s, ok := l.config.LevelPrefixes[level]; ok {
+ levelStr = "[" + s + "]"
+ }
+ return levelStr
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_rotate.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_rotate.go
new file mode 100644
index 000000000000..6d18fb808fe1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_rotate.go
@@ -0,0 +1,281 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/encoding/gcompress"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gmlock"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gtimer"
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+const (
+ memoryLockPrefixForRotating = "glog.rotateChecksTimely:"
+)
+
+// rotateFileBySize rotates the current logging file according to the
+// configured rotation size.
+func (l *Logger) rotateFileBySize(ctx context.Context, now time.Time) {
+ if l.config.RotateSize <= 0 {
+ return
+ }
+ if err := l.doRotateFile(ctx, l.getFilePath(now)); err != nil {
+ // panic(err)
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+}
+
+// doRotateFile rotates the given logging file.
+func (l *Logger) doRotateFile(ctx context.Context, filePath string) error {
+ memoryLockKey := "glog.doRotateFile:" + filePath
+ if !gmlock.TryLock(memoryLockKey) {
+ return nil
+ }
+ defer gmlock.Unlock(memoryLockKey)
+
+ intlog.PrintFunc(ctx, func() string {
+ return fmt.Sprintf(`start rotating file by size: %s, file: %s`, gfile.SizeFormat(filePath), filePath)
+ })
+ defer intlog.PrintFunc(ctx, func() string {
+ return fmt.Sprintf(`done rotating file by size: %s, size: %s`, gfile.SizeFormat(filePath), filePath)
+ })
+
+ // No backups, it then just removes the current logging file.
+ if l.config.RotateBackupLimit == 0 {
+ if err := gfile.Remove(filePath); err != nil {
+ return err
+ }
+ intlog.Printf(
+ ctx,
+ `%d size exceeds, no backups set, remove original logging file: %s`,
+ l.config.RotateSize, filePath,
+ )
+ return nil
+ }
+ // Else it creates new backup files.
+ var (
+ dirPath = gfile.Dir(filePath)
+ fileName = gfile.Name(filePath)
+ fileExtName = gfile.ExtName(filePath)
+ newFilePath = ""
+ )
+ // Rename the logging file by adding extra datetime information to microseconds, like:
+ // access.log -> access.20200326101301899002.log
+ // access.20200326.log -> access.20200326.20200326101301899002.log
+ for {
+ var (
+ now = gtime.Now()
+ micro = now.Microsecond() % 1000
+ )
+ if micro == 0 {
+ micro = 101
+ } else {
+ for micro < 100 {
+ micro *= 10
+ }
+ }
+ newFilePath = gfile.Join(
+ dirPath,
+ fmt.Sprintf(
+ `%s.%s%d.%s`,
+ fileName, now.Format("YmdHisu"), micro, fileExtName,
+ ),
+ )
+ if !gfile.Exists(newFilePath) {
+ break
+ } else {
+ intlog.Printf(ctx, `rotation file exists, continue: %s`, newFilePath)
+ }
+ }
+ intlog.Printf(ctx, "rotating file by size from %s to %s", filePath, newFilePath)
+ if err := gfile.Rename(filePath, newFilePath); err != nil {
+ return err
+ }
+ return nil
+}
+
+// rotateChecksTimely timely checks the backups expiration and the compression.
+func (l *Logger) rotateChecksTimely(ctx context.Context) {
+ defer gtimer.AddOnce(ctx, l.config.RotateCheckInterval, l.rotateChecksTimely)
+
+ // Checks whether file rotation not enabled.
+ if l.config.RotateSize <= 0 && l.config.RotateExpire == 0 {
+ intlog.Printf(
+ ctx,
+ "logging rotation ignore checks: RotateSize: %d, RotateExpire: %s",
+ l.config.RotateSize, l.config.RotateExpire.String(),
+ )
+ return
+ }
+
+ // It here uses memory lock to guarantee the concurrent safety.
+ memoryLockKey := memoryLockPrefixForRotating + l.config.Path
+ if !gmlock.TryLock(memoryLockKey) {
+ return
+ }
+ defer gmlock.Unlock(memoryLockKey)
+
+ var (
+ now = time.Now()
+ pattern = "*.log, *.gz"
+ files, err = gfile.ScanDirFile(l.config.Path, pattern, true)
+ )
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ intlog.Printf(ctx, "logging rotation start checks: %+v", files)
+ // =============================================================
+ // Rotation of expired file checks.
+ // =============================================================
+ if l.config.RotateExpire > 0 {
+ var (
+ mtime time.Time
+ subDuration time.Duration
+ expireRotated bool
+ )
+ for _, file := range files {
+ if gfile.ExtName(file) == "gz" {
+ continue
+ }
+ mtime = gfile.MTime(file)
+ subDuration = now.Sub(mtime)
+ if subDuration > l.config.RotateExpire {
+ expireRotated = true
+ intlog.Printf(
+ ctx,
+ `%v - %v = %v > %v, rotation expire logging file: %s`,
+ now, mtime, subDuration, l.config.RotateExpire, file,
+ )
+ if err := l.doRotateFile(ctx, file); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ }
+ if expireRotated {
+ // Update the files array.
+ files, err = gfile.ScanDirFile(l.config.Path, pattern, true)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ }
+
+ // =============================================================
+ // Rotated file compression.
+ // =============================================================
+ needCompressFileArray := garray.NewStrArray()
+ if l.config.RotateBackupCompress > 0 {
+ for _, file := range files {
+ // Eg: access.20200326101301899002.log.gz
+ if gfile.ExtName(file) == "gz" {
+ continue
+ }
+ // Eg:
+ // access.20200326101301899002.log
+ if gregex.IsMatchString(`.+\.\d{20}\.log`, gfile.Basename(file)) {
+ needCompressFileArray.Append(file)
+ }
+ }
+ if needCompressFileArray.Len() > 0 {
+ needCompressFileArray.Iterator(func(_ int, path string) bool {
+ err := gcompress.GzipFile(path, path+".gz")
+ if err == nil {
+ intlog.Printf(ctx, `compressed done, remove original logging file: %s`, path)
+ if err = gfile.Remove(path); err != nil {
+ intlog.Print(ctx, err)
+ }
+ } else {
+ intlog.Print(ctx, err)
+ }
+ return true
+ })
+ // Update the files array.
+ files, err = gfile.ScanDirFile(l.config.Path, pattern, true)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ }
+
+ // =============================================================
+ // Backups count limitation and expiration checks.
+ // =============================================================
+ var (
+ backupFilesMap = make(map[string]*garray.SortedArray)
+ originalLoggingFilePath = ""
+ )
+ if l.config.RotateBackupLimit > 0 || l.config.RotateBackupExpire > 0 {
+ for _, file := range files {
+ originalLoggingFilePath, _ = gregex.ReplaceString(`\.\d{20}`, "", file)
+ if backupFilesMap[originalLoggingFilePath] == nil {
+ backupFilesMap[originalLoggingFilePath] = garray.NewSortedArray(func(a, b interface{}) int {
+ // Sorted by rotated/backup file mtime.
+ // The older rotated/backup file is put in the head of array.
+ var (
+ file1 = a.(string)
+ file2 = b.(string)
+ result = gfile.MTimestampMilli(file1) - gfile.MTimestampMilli(file2)
+ )
+ if result <= 0 {
+ return -1
+ }
+ return 1
+ })
+ }
+ // Check if this file a rotated/backup file.
+ if gregex.IsMatchString(`.+\.\d{20}\.log`, gfile.Basename(file)) {
+ backupFilesMap[originalLoggingFilePath].Add(file)
+ }
+ }
+ intlog.Printf(ctx, `calculated backup files map: %+v`, backupFilesMap)
+ for _, array := range backupFilesMap {
+ diff := array.Len() - l.config.RotateBackupLimit
+ for i := 0; i < diff; i++ {
+ path, _ := array.PopLeft()
+ intlog.Printf(ctx, `remove exceeded backup limit file: %s`, path)
+ if err := gfile.Remove(path.(string)); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ }
+ // Backups expiration checking.
+ if l.config.RotateBackupExpire > 0 {
+ var (
+ mtime time.Time
+ subDuration time.Duration
+ )
+ for _, array := range backupFilesMap {
+ array.Iterator(func(_ int, v interface{}) bool {
+ path := v.(string)
+ mtime = gfile.MTime(path)
+ subDuration = now.Sub(mtime)
+ if subDuration > l.config.RotateBackupExpire {
+ intlog.Printf(
+ ctx,
+ `%v - %v = %v > %v, remove expired backup file: %s`,
+ now, mtime, subDuration, l.config.RotateBackupExpire, path,
+ )
+ if err := gfile.Remove(path); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ return true
+ } else {
+ return false
+ }
+ })
+ }
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_writer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_writer.go
new file mode 100644
index 000000000000..610e5e5317cb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/glog/glog_logger_writer.go
@@ -0,0 +1,19 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package glog
+
+import (
+ "bytes"
+ "context"
+)
+
+// Write implements the io.Writer interface.
+// It just prints the content using Print.
+func (l *Logger) Write(p []byte) (n int, err error) {
+ l.Header(false).Print(context.TODO(), string(bytes.TrimRight(p, "\r\n")))
+ return len(p), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmlock/gmlock.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmlock/gmlock.go
new file mode 100644
index 000000000000..92be26f444e5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmlock/gmlock.go
@@ -0,0 +1,89 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gmlock implements a concurrent-safe memory-based locker.
+package gmlock
+
+var (
+ // Default locker.
+ locker = New()
+)
+
+// Lock locks the `key` with writing lock.
+// If there's a write/reading lock the `key`,
+// it will blocks until the lock is released.
+func Lock(key string) {
+ locker.Lock(key)
+}
+
+// TryLock tries locking the `key` with writing lock,
+// it returns true if success, or if there's a write/reading lock the `key`,
+// it returns false.
+func TryLock(key string) bool {
+ return locker.TryLock(key)
+}
+
+// Unlock unlocks the writing lock of the `key`.
+func Unlock(key string) {
+ locker.Unlock(key)
+}
+
+// RLock locks the `key` with reading lock.
+// If there's a writing lock on `key`,
+// it will blocks until the writing lock is released.
+func RLock(key string) {
+ locker.RLock(key)
+}
+
+// TryRLock tries locking the `key` with reading lock.
+// It returns true if success, or if there's a writing lock on `key`, it returns false.
+func TryRLock(key string) bool {
+ return locker.TryRLock(key)
+}
+
+// RUnlock unlocks the reading lock of the `key`.
+func RUnlock(key string) {
+ locker.RUnlock(key)
+}
+
+// LockFunc locks the `key` with writing lock and callback function `f`.
+// If there's a write/reading lock the `key`,
+// it will blocks until the lock is released.
+//
+// It releases the lock after `f` is executed.
+func LockFunc(key string, f func()) {
+ locker.LockFunc(key, f)
+}
+
+// RLockFunc locks the `key` with reading lock and callback function `f`.
+// If there's a writing lock the `key`,
+// it will blocks until the lock is released.
+//
+// It releases the lock after `f` is executed.
+func RLockFunc(key string, f func()) {
+ locker.RLockFunc(key, f)
+}
+
+// TryLockFunc locks the `key` with writing lock and callback function `f`.
+// It returns true if success, or else if there's a write/reading lock the `key`, it return false.
+//
+// It releases the lock after `f` is executed.
+func TryLockFunc(key string, f func()) bool {
+ return locker.TryLockFunc(key, f)
+}
+
+// TryRLockFunc locks the `key` with reading lock and callback function `f`.
+// It returns true if success, or else if there's a writing lock the `key`, it returns false.
+//
+// It releases the lock after `f` is executed.
+func TryRLockFunc(key string, f func()) bool {
+ return locker.TryRLockFunc(key, f)
+}
+
+// Remove removes mutex with given `key`.
+func Remove(key string) {
+ locker.Remove(key)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmlock/gmlock_locker.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmlock/gmlock_locker.go
new file mode 100644
index 000000000000..5336f92db63a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmlock/gmlock_locker.go
@@ -0,0 +1,133 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gmlock
+
+import (
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/os/gmutex"
+)
+
+// Locker is a memory based locker.
+// Note that there's no cache expire mechanism for mutex in locker.
+// You need remove certain mutex manually when you do not want use it anymore.
+type Locker struct {
+ m *gmap.StrAnyMap
+}
+
+// New creates and returns a new memory locker.
+// A memory locker can lock/unlock with dynamic string key.
+func New() *Locker {
+ return &Locker{
+ m: gmap.NewStrAnyMap(true),
+ }
+}
+
+// Lock locks the `key` with writing lock.
+// If there's a write/reading lock the `key`,
+// it will block until the lock is released.
+func (l *Locker) Lock(key string) {
+ l.getOrNewMutex(key).Lock()
+}
+
+// TryLock tries locking the `key` with writing lock,
+// it returns true if success, or it returns false if there's a writing/reading lock the `key`.
+func (l *Locker) TryLock(key string) bool {
+ return l.getOrNewMutex(key).TryLock()
+}
+
+// Unlock unlocks the writing lock of the `key`.
+func (l *Locker) Unlock(key string) {
+ if v := l.m.Get(key); v != nil {
+ v.(*gmutex.Mutex).Unlock()
+ }
+}
+
+// RLock locks the `key` with reading lock.
+// If there's a writing lock on `key`,
+// it will blocks until the writing lock is released.
+func (l *Locker) RLock(key string) {
+ l.getOrNewMutex(key).RLock()
+}
+
+// TryRLock tries locking the `key` with reading lock.
+// It returns true if success, or if there's a writing lock on `key`, it returns false.
+func (l *Locker) TryRLock(key string) bool {
+ return l.getOrNewMutex(key).TryRLock()
+}
+
+// RUnlock unlocks the reading lock of the `key`.
+func (l *Locker) RUnlock(key string) {
+ if v := l.m.Get(key); v != nil {
+ v.(*gmutex.Mutex).RUnlock()
+ }
+}
+
+// LockFunc locks the `key` with writing lock and callback function `f`.
+// If there's a write/reading lock the `key`,
+// it will block until the lock is released.
+//
+// It releases the lock after `f` is executed.
+func (l *Locker) LockFunc(key string, f func()) {
+ l.Lock(key)
+ defer l.Unlock(key)
+ f()
+}
+
+// RLockFunc locks the `key` with reading lock and callback function `f`.
+// If there's a writing lock the `key`,
+// it will block until the lock is released.
+//
+// It releases the lock after `f` is executed.
+func (l *Locker) RLockFunc(key string, f func()) {
+ l.RLock(key)
+ defer l.RUnlock(key)
+ f()
+}
+
+// TryLockFunc locks the `key` with writing lock and callback function `f`.
+// It returns true if success, or else if there's a write/reading lock the `key`, it return false.
+//
+// It releases the lock after `f` is executed.
+func (l *Locker) TryLockFunc(key string, f func()) bool {
+ if l.TryLock(key) {
+ defer l.Unlock(key)
+ f()
+ return true
+ }
+ return false
+}
+
+// TryRLockFunc locks the `key` with reading lock and callback function `f`.
+// It returns true if success, or else if there's a writing lock the `key`, it returns false.
+//
+// It releases the lock after `f` is executed.
+func (l *Locker) TryRLockFunc(key string, f func()) bool {
+ if l.TryRLock(key) {
+ defer l.RUnlock(key)
+ f()
+ return true
+ }
+ return false
+}
+
+// Remove removes mutex with given `key` from locker.
+func (l *Locker) Remove(key string) {
+ l.m.Remove(key)
+}
+
+// Clear removes all mutexes from locker.
+func (l *Locker) Clear() {
+ l.m.Clear()
+}
+
+// getOrNewMutex returns the mutex of given `key` if it exists,
+// or else creates and returns a new one.
+func (l *Locker) getOrNewMutex(key string) *gmutex.Mutex {
+ return l.m.GetOrSetFuncLock(key, func() interface{} {
+ return gmutex.New()
+ }).(*gmutex.Mutex)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmutex/gmutex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmutex/gmutex.go
new file mode 100644
index 000000000000..a0464b6c5352
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gmutex/gmutex.go
@@ -0,0 +1,227 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gmutex implements graceful concurrent-safe mutex with more rich features.
+package gmutex
+
+import (
+ "math"
+ "runtime"
+
+ "github.com/gogf/gf/v2/container/gtype"
+)
+
+// Mutex is a high level Mutex, which implements more rich features for mutex.
+type Mutex struct {
+ state *gtype.Int32 // Indicates the state of mutex. -1: writing locked; > 1 reading locked.
+ writer *gtype.Int32 // Pending writer count.
+ reader *gtype.Int32 // Pending reader count.
+ writing chan struct{} // Channel for writer blocking.
+ reading chan struct{} // Channel for reader blocking.
+}
+
+// New creates and returns a new mutex.
+func New() *Mutex {
+ return &Mutex{
+ state: gtype.NewInt32(),
+ writer: gtype.NewInt32(),
+ reader: gtype.NewInt32(),
+ writing: make(chan struct{}, 1),
+ reading: make(chan struct{}, math.MaxInt32),
+ }
+}
+
+// Lock locks the mutex for writing purpose.
+// If the mutex is already locked by another goroutine for reading or writing,
+// it blocks until the lock is available.
+func (m *Mutex) Lock() {
+ for {
+ // Using CAS operation to get the writing lock atomically.
+ if m.state.Cas(0, -1) {
+ return
+ }
+ // It or else blocks to wait for the next chance.
+ m.writer.Add(1)
+ <-m.writing
+ }
+}
+
+// Unlock unlocks writing lock on the mutex.
+// It is safe to be called multiple times even there's no locks.
+func (m *Mutex) Unlock() {
+ if m.state.Cas(-1, 0) {
+ // Note that there might be more than one goroutines can enter this block.
+ var n int32
+ // Writing lock unlocks, then first check the blocked readers.
+ // If there are readers blocked, it unlocks them with preemption.
+ for {
+ if n = m.reader.Val(); n > 0 {
+ if m.reader.Cas(n, 0) {
+ for ; n > 0; n-- {
+ m.reading <- struct{}{}
+ }
+ break
+ } else {
+ runtime.Gosched()
+ }
+ } else {
+ break
+ }
+ }
+
+ // It then also kindly feeds the pending writers with one chance.
+ if n = m.writer.Val(); n > 0 {
+ if m.writer.Cas(n, n-1) {
+ m.writing <- struct{}{}
+ }
+ }
+ }
+}
+
+// TryLock tries locking the mutex for writing purpose.
+// It returns true immediately if success, or if there's a write/reading lock on the mutex,
+// it returns false immediately.
+func (m *Mutex) TryLock() bool {
+ if m.state.Cas(0, -1) {
+ return true
+ }
+ return false
+}
+
+// RLock locks mutex for reading purpose.
+// If the mutex is already locked for writing,
+// it blocks until the lock is available.
+func (m *Mutex) RLock() {
+ var n int32
+ for {
+ if n = m.state.Val(); n >= 0 {
+ // If there's no writing lock currently, then do the reading lock checks.
+ if m.state.Cas(n, n+1) {
+ return
+ } else {
+ runtime.Gosched()
+ }
+ } else {
+ // It or else pends the reader.
+ m.reader.Add(1)
+ <-m.reading
+ }
+ }
+}
+
+// RUnlock unlocks the reading lock on the mutex.
+// It is safe to be called multiple times even there's no locks.
+func (m *Mutex) RUnlock() {
+ var n int32
+ for {
+ if n = m.state.Val(); n >= 1 {
+ if m.state.Cas(n, n-1) {
+ break
+ } else {
+ runtime.Gosched()
+ }
+ } else {
+ break
+ }
+ }
+ // Reading lock unlocks, it then only check the blocked writers.
+ // Note that it is not necessary to check the pending readers here.
+ // `n == 1` means the state of mutex comes down to zero.
+ if n == 1 {
+ if n = m.writer.Val(); n > 0 {
+ if m.writer.Cas(n, n-1) {
+ m.writing <- struct{}{}
+ }
+ }
+ }
+}
+
+// TryRLock tries locking the mutex for reading purpose.
+// It returns true immediately if success, or if there's a writing lock on the mutex,
+// it returns false immediately.
+func (m *Mutex) TryRLock() bool {
+ var n int32
+ for {
+ if n = m.state.Val(); n >= 0 {
+ if m.state.Cas(n, n+1) {
+ return true
+ } else {
+ runtime.Gosched()
+ }
+ } else {
+ return false
+ }
+ }
+}
+
+// IsLocked checks whether the mutex is locked with writing or reading lock.
+// Note that the result might be changed after it's called,
+// so it cannot be the criterion for atomic operations.
+func (m *Mutex) IsLocked() bool {
+ return m.state.Val() != 0
+}
+
+// IsWLocked checks whether the mutex is locked by writing lock.
+// Note that the result might be changed after it's called,
+// so it cannot be the criterion for atomic operations.
+func (m *Mutex) IsWLocked() bool {
+ return m.state.Val() < 0
+}
+
+// IsRLocked checks whether the mutex is locked by reading lock.
+// Note that the result might be changed after it's called,
+// so it cannot be the criterion for atomic operations.
+func (m *Mutex) IsRLocked() bool {
+ return m.state.Val() > 0
+}
+
+// LockFunc locks the mutex for writing with given callback function `f`.
+// If there's a write/reading lock the mutex, it will blocks until the lock is released.
+//
+// It releases the lock after `f` is executed.
+func (m *Mutex) LockFunc(f func()) {
+ m.Lock()
+ defer m.Unlock()
+ f()
+}
+
+// RLockFunc locks the mutex for reading with given callback function `f`.
+// If there's a writing lock the mutex, it will blocks until the lock is released.
+//
+// It releases the lock after `f` is executed.
+func (m *Mutex) RLockFunc(f func()) {
+ m.RLock()
+ defer m.RUnlock()
+ f()
+}
+
+// TryLockFunc tries locking the mutex for writing with given callback function `f`.
+// it returns true immediately if success, or if there's a write/reading lock on the mutex,
+// it returns false immediately.
+//
+// It releases the lock after `f` is executed.
+func (m *Mutex) TryLockFunc(f func()) (result bool) {
+ if m.TryLock() {
+ result = true
+ defer m.Unlock()
+ f()
+ }
+ return
+}
+
+// TryRLockFunc tries locking the mutex for reading with given callback function `f`.
+// It returns true immediately if success, or if there's a writing lock on the mutex,
+// it returns false immediately.
+//
+// It releases the lock after `f` is executed.
+func (m *Mutex) TryRLockFunc(f func()) (result bool) {
+ if m.TryRLock() {
+ result = true
+ defer m.RUnlock()
+ f()
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc.go
new file mode 100644
index 000000000000..3c96073838a9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc.go
@@ -0,0 +1,234 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gproc implements management and communication for processes.
+package gproc
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "runtime"
+ "time"
+
+ "github.com/gogf/gf/v2/os/genv"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ envKeyPPid = "GPROC_PPID"
+)
+
+var (
+ processPid = os.Getpid() // processPid is the pid of current process.
+ processStartTime = time.Now() // processStartTime is the start time of current process.
+)
+
+// Pid returns the pid of current process.
+func Pid() int {
+ return processPid
+}
+
+// PPid returns the custom parent pid if exists, or else it returns the system parent pid.
+func PPid() int {
+ if !IsChild() {
+ return Pid()
+ }
+ ppidValue := os.Getenv(envKeyPPid)
+ if ppidValue != "" && ppidValue != "0" {
+ return gconv.Int(ppidValue)
+ }
+ return PPidOS()
+}
+
+// PPidOS returns the system parent pid of current process.
+// Note that the difference between PPidOS and PPid function is that the PPidOS returns
+// the system ppid, but the PPid functions may return the custom pid by gproc if the custom
+// ppid exists.
+func PPidOS() int {
+ return os.Getppid()
+}
+
+// IsChild checks and returns whether current process is a child process.
+// A child process is forked by another gproc process.
+func IsChild() bool {
+ ppidValue := os.Getenv(envKeyPPid)
+ return ppidValue != "" && ppidValue != "0"
+}
+
+// SetPPid sets custom parent pid for current process.
+func SetPPid(ppid int) error {
+ if ppid > 0 {
+ return os.Setenv(envKeyPPid, gconv.String(ppid))
+ } else {
+ return os.Unsetenv(envKeyPPid)
+ }
+}
+
+// StartTime returns the start time of current process.
+func StartTime() time.Time {
+ return processStartTime
+}
+
+// Uptime returns the duration which current process has been running
+func Uptime() time.Duration {
+ return time.Now().Sub(processStartTime)
+}
+
+// Shell executes command `cmd` synchronously with given input pipe `in` and output pipe `out`.
+// The command `cmd` reads the input parameters from input pipe `in`, and writes its output automatically
+// to output pipe `out`.
+func Shell(cmd string, out io.Writer, in io.Reader) error {
+ p := NewProcess(
+ getShell(),
+ append([]string{getShellOption()}, parseCommand(cmd)...),
+ )
+ p.Stdin = in
+ p.Stdout = out
+ return p.Run()
+}
+
+// ShellRun executes given command `cmd` synchronously and outputs the command result to the stdout.
+func ShellRun(cmd string) error {
+ p := NewProcess(
+ getShell(),
+ append([]string{getShellOption()}, parseCommand(cmd)...),
+ )
+ return p.Run()
+}
+
+// ShellExec executes given command `cmd` synchronously and returns the command result.
+func ShellExec(cmd string, environment ...[]string) (result string, err error) {
+ var (
+ buf = bytes.NewBuffer(nil)
+ p = NewProcess(
+ getShell(),
+ append([]string{getShellOption()}, parseCommand(cmd)...),
+ environment...,
+ )
+ )
+ p.Stdout = buf
+ p.Stderr = buf
+ err = p.Run()
+ result = buf.String()
+ return
+}
+
+// parseCommand parses command `cmd` into slice arguments.
+//
+// Note that it just parses the `cmd` for "cmd.exe" binary in windows, but it is not necessary
+// parsing the `cmd` for other systems using "bash"/"sh" binary.
+func parseCommand(cmd string) (args []string) {
+ if runtime.GOOS != "windows" {
+ return []string{cmd}
+ }
+ // Just for "cmd.exe" in windows.
+ var argStr string
+ var firstChar, prevChar, lastChar1, lastChar2 byte
+ array := gstr.SplitAndTrim(cmd, " ")
+ for _, v := range array {
+ if len(argStr) > 0 {
+ argStr += " "
+ }
+ firstChar = v[0]
+ lastChar1 = v[len(v)-1]
+ lastChar2 = 0
+ if len(v) > 1 {
+ lastChar2 = v[len(v)-2]
+ }
+ if prevChar == 0 && (firstChar == '"' || firstChar == '\'') {
+ // It should remove the first quote char.
+ argStr += v[1:]
+ prevChar = firstChar
+ } else if prevChar != 0 && lastChar2 != '\\' && lastChar1 == prevChar {
+ // It should remove the last quote char.
+ argStr += v[:len(v)-1]
+ args = append(args, argStr)
+ argStr = ""
+ prevChar = 0
+ } else if len(argStr) > 0 {
+ argStr += v
+ } else {
+ args = append(args, v)
+ }
+ }
+ return
+}
+
+// getShell returns the shell command depending on current working operating system.
+// It returns "cmd.exe" for windows, and "bash" or "sh" for others.
+func getShell() string {
+ switch runtime.GOOS {
+ case "windows":
+ return SearchBinary("cmd.exe")
+ default:
+ // Check the default binary storage path.
+ if gfile.Exists("/bin/bash") {
+ return "/bin/bash"
+ }
+ if gfile.Exists("/bin/sh") {
+ return "/bin/sh"
+ }
+ // Else search the env PATH.
+ path := SearchBinary("bash")
+ if path == "" {
+ path = SearchBinary("sh")
+ }
+ return path
+ }
+}
+
+// getShellOption returns the shell option depending on current working operating system.
+// It returns "/c" for windows, and "-c" for others.
+func getShellOption() string {
+ switch runtime.GOOS {
+ case "windows":
+ return "/c"
+ default:
+ return "-c"
+ }
+}
+
+// SearchBinary searches the binary `file` in current working folder and PATH environment.
+func SearchBinary(file string) string {
+ // Check if it is absolute path of exists at current working directory.
+ if gfile.Exists(file) {
+ return file
+ }
+ return SearchBinaryPath(file)
+}
+
+// SearchBinaryPath searches the binary `file` in PATH environment.
+func SearchBinaryPath(file string) string {
+ array := ([]string)(nil)
+ switch runtime.GOOS {
+ case "windows":
+ envPath := genv.Get("PATH", genv.Get("Path")).String()
+ if gstr.Contains(envPath, ";") {
+ array = gstr.SplitAndTrim(envPath, ";")
+ } else if gstr.Contains(envPath, ":") {
+ array = gstr.SplitAndTrim(envPath, ":")
+ }
+ if gfile.Ext(file) != ".exe" {
+ file += ".exe"
+ }
+
+ default:
+ array = gstr.SplitAndTrim(genv.Get("PATH").String(), ":")
+ }
+ if len(array) > 0 {
+ path := ""
+ for _, v := range array {
+ path = v + gfile.Separator + file
+ if gfile.Exists(path) && gfile.IsFile(path) {
+ return path
+ }
+ }
+ }
+ return ""
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm.go
new file mode 100644
index 000000000000..546142a1610e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm.go
@@ -0,0 +1,117 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/net/gtcp"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// MsgRequest is the request structure for process communication.
+type MsgRequest struct {
+ SenderPid int // Sender PID.
+ ReceiverPid int // Receiver PID.
+ Group string // Message group name.
+ Data []byte // Request data.
+}
+
+// MsgResponse is the response structure for process communication.
+type MsgResponse struct {
+ Code int // 1: OK; Other: Error.
+ Message string // Response message.
+ Data []byte // Response data.
+}
+
+const (
+ defaultFolderNameForProcComm = "gf_pid_port_mapping" // Default folder name for storing pid to port mapping files.
+ defaultGroupNameForProcComm = "" // Default group name.
+ defaultTcpPortForProcComm = 10000 // Starting port number for receiver listening.
+ maxLengthForProcMsgQueue = 10000 // Max size for each message queue of the group.
+)
+
+var (
+ // commReceiveQueues is the group name to queue map for storing received data.
+ // The value of the map is type of *gqueue.Queue.
+ commReceiveQueues = gmap.NewStrAnyMap(true)
+
+ // commPidFolderPath specifies the folder path storing pid to port mapping files.
+ commPidFolderPath string
+
+ // commPidFolderPathOnce is used for lazy calculation for `commPidFolderPath` is necessary.
+ commPidFolderPathOnce sync.Once
+)
+
+// getConnByPid creates and returns a TCP connection for specified pid.
+func getConnByPid(pid int) (*gtcp.PoolConn, error) {
+ port := getPortByPid(pid)
+ if port > 0 {
+ if conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", port)); err == nil {
+ return conn, nil
+ } else {
+ return nil, err
+ }
+ }
+ return nil, gerror.Newf(`could not find port for pid "%d"`, pid)
+}
+
+// getPortByPid returns the listening port for specified pid.
+// It returns 0 if no port found for the specified pid.
+func getPortByPid(pid int) int {
+ path := getCommFilePath(pid)
+ if path == "" {
+ return 0
+ }
+ return gconv.Int(gfile.GetContentsWithCache(path))
+}
+
+// getCommFilePath returns the pid to port mapping file path for given pid.
+func getCommFilePath(pid int) string {
+ path, err := getCommPidFolderPath()
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ return ""
+ }
+ return gfile.Join(path, gconv.String(pid))
+}
+
+// getCommPidFolderPath retrieves and returns the available directory for storing pid mapping files.
+func getCommPidFolderPath() (folderPath string, err error) {
+ commPidFolderPathOnce.Do(func() {
+ availablePaths := []string{
+ "/var/tmp",
+ "/var/run",
+ }
+ if path, _ := gfile.Home(".config"); path != "" {
+ availablePaths = append(availablePaths, path)
+ }
+ availablePaths = append(availablePaths, gfile.Temp())
+ for _, availablePath := range availablePaths {
+ checkPath := gfile.Join(availablePath, defaultFolderNameForProcComm)
+ if !gfile.Exists(checkPath) && gfile.Mkdir(checkPath) != nil {
+ continue
+ }
+ if gfile.IsWritable(checkPath) {
+ commPidFolderPath = checkPath
+ break
+ }
+ }
+ err = gerror.Newf(
+ `cannot find available folder for storing pid to port mapping files in paths: %+v`,
+ availablePaths,
+ )
+ })
+ folderPath = commPidFolderPath
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm_receive.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm_receive.go
new file mode 100644
index 000000000000..942c04e69f9e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm_receive.go
@@ -0,0 +1,135 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "context"
+ "fmt"
+ "net"
+
+ "github.com/gogf/gf/v2/container/gqueue"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/net/gtcp"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+var (
+ // tcpListened marks whether the receiving listening service started.
+ tcpListened = gtype.NewBool()
+)
+
+// Receive blocks and receives message from other process using local TCP listening.
+// Note that, it only enables the TCP listening service when this function called.
+func Receive(group ...string) *MsgRequest {
+ // Use atomic operations to guarantee only one receiver goroutine listening.
+ if tcpListened.Cas(false, true) {
+ go receiveTcpListening()
+ }
+ var groupName string
+ if len(group) > 0 {
+ groupName = group[0]
+ } else {
+ groupName = defaultGroupNameForProcComm
+ }
+ queue := commReceiveQueues.GetOrSetFuncLock(groupName, func() interface{} {
+ return gqueue.New(maxLengthForProcMsgQueue)
+ }).(*gqueue.Queue)
+
+ // Blocking receiving.
+ if v := queue.Pop(); v != nil {
+ return v.(*MsgRequest)
+ }
+ return nil
+}
+
+// receiveTcpListening scans local for available port and starts listening.
+func receiveTcpListening() {
+ var (
+ listen *net.TCPListener
+ conn net.Conn
+ port = gtcp.MustGetFreePort()
+ address = fmt.Sprintf("127.0.0.1:%d", port)
+ )
+ tcpAddress, err := net.ResolveTCPAddr("tcp", address)
+ if err != nil {
+ panic(gerror.Wrap(err, `net.ResolveTCPAddr failed`))
+ }
+ listen, err = net.ListenTCP("tcp", tcpAddress)
+ if err != nil {
+ panic(gerror.Wrapf(err, `net.ListenTCP failed for address "%s"`, address))
+ }
+ // Save the port to the pid file.
+ if err = gfile.PutContents(getCommFilePath(Pid()), gconv.String(port)); err != nil {
+ panic(err)
+ }
+ // Start listening.
+ for {
+ if conn, err = listen.Accept(); err != nil {
+ glog.Error(context.TODO(), err)
+ } else if conn != nil {
+ go receiveTcpHandler(gtcp.NewConnByNetConn(conn))
+ }
+ }
+}
+
+// receiveTcpHandler is the connection handler for receiving data.
+func receiveTcpHandler(conn *gtcp.Conn) {
+ var (
+ ctx = context.TODO()
+ result []byte
+ response MsgResponse
+ )
+ for {
+ response.Code = 0
+ response.Message = ""
+ response.Data = nil
+ buffer, err := conn.RecvPkg()
+ if len(buffer) > 0 {
+ // Package decoding.
+ msg := new(MsgRequest)
+ if err = json.UnmarshalUseNumber(buffer, msg); err != nil {
+ continue
+ }
+ if msg.ReceiverPid != Pid() {
+ // Not mine package.
+ response.Message = fmt.Sprintf(
+ "receiver pid not match, target: %d, current: %d",
+ msg.ReceiverPid, Pid(),
+ )
+ } else if v := commReceiveQueues.Get(msg.Group); v == nil {
+ // Group check.
+ response.Message = fmt.Sprintf("group [%s] does not exist", msg.Group)
+ } else {
+ // Push to buffer queue.
+ response.Code = 1
+ v.(*gqueue.Queue).Push(msg)
+ }
+ } else {
+ // Empty package.
+ response.Message = "empty package"
+ }
+ if err == nil {
+ result, err = json.Marshal(response)
+ if err != nil {
+ glog.Error(ctx, err)
+ }
+ if err = conn.SendPkg(result); err != nil {
+ glog.Error(ctx, err)
+ }
+ } else {
+ // Just close the connection if any error occurs.
+ if err = conn.Close(); err != nil {
+ glog.Error(ctx, err)
+ }
+ break
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm_send.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm_send.go
new file mode 100644
index 000000000000..a42ec47e376a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_comm_send.go
@@ -0,0 +1,58 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "io"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/net/gtcp"
+)
+
+// Send sends data to specified process of given pid.
+func Send(pid int, data []byte, group ...string) error {
+ msg := MsgRequest{
+ SenderPid: Pid(),
+ ReceiverPid: pid,
+ Group: defaultGroupNameForProcComm,
+ Data: data,
+ }
+ if len(group) > 0 {
+ msg.Group = group[0]
+ }
+ msgBytes, err := json.Marshal(msg)
+ if err != nil {
+ return err
+ }
+ var conn *gtcp.PoolConn
+ conn, err = getConnByPid(pid)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ // Do the sending.
+ var result []byte
+ result, err = conn.SendRecvPkg(msgBytes, gtcp.PkgOption{
+ Retry: gtcp.Retry{
+ Count: 3,
+ },
+ })
+ if len(result) > 0 {
+ response := new(MsgResponse)
+ if err = json.UnmarshalUseNumber(result, response); err == nil {
+ if response.Code != 1 {
+ err = gerror.New(response.Message)
+ }
+ }
+ }
+ // EOF is not really an error.
+ if err == io.EOF {
+ err = nil
+ }
+ return err
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_manager.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_manager.go
new file mode 100644
index 000000000000..f3b525a2f26d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_manager.go
@@ -0,0 +1,128 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "os"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Manager is a process manager maintaining multiple processes.
+type Manager struct {
+ processes *gmap.IntAnyMap // Process id to Process object mapping.
+}
+
+// NewManager creates and returns a new process manager.
+func NewManager() *Manager {
+ return &Manager{
+ processes: gmap.NewIntAnyMap(true),
+ }
+}
+
+// NewProcess creates and returns a Process object.
+func (m *Manager) NewProcess(path string, args []string, environment []string) *Process {
+ p := NewProcess(path, args, environment)
+ p.Manager = m
+ return p
+}
+
+// GetProcess retrieves and returns a Process object.
+// It returns nil if it does not find the process with given `pid`.
+func (m *Manager) GetProcess(pid int) *Process {
+ if v := m.processes.Get(pid); v != nil {
+ return v.(*Process)
+ }
+ return nil
+}
+
+// AddProcess adds a process to current manager.
+// It does nothing if the process with given `pid` does not exist.
+func (m *Manager) AddProcess(pid int) {
+ if m.processes.Get(pid) == nil {
+ if process, err := os.FindProcess(pid); err == nil {
+ p := m.NewProcess("", nil, nil)
+ p.Process = process
+ m.processes.Set(pid, p)
+ }
+ }
+}
+
+// RemoveProcess removes a process from current manager.
+func (m *Manager) RemoveProcess(pid int) {
+ m.processes.Remove(pid)
+}
+
+// Processes retrieves and returns all processes in current manager.
+func (m *Manager) Processes() []*Process {
+ processes := make([]*Process, 0)
+ m.processes.RLockFunc(func(m map[int]interface{}) {
+ for _, v := range m {
+ processes = append(processes, v.(*Process))
+ }
+ })
+ return processes
+}
+
+// Pids retrieves and returns all process id array in current manager.
+func (m *Manager) Pids() []int {
+ return m.processes.Keys()
+}
+
+// WaitAll waits until all process exit.
+func (m *Manager) WaitAll() {
+ processes := m.Processes()
+ if len(processes) > 0 {
+ for _, p := range processes {
+ p.Wait()
+ }
+ }
+}
+
+// KillAll kills all processes in current manager.
+func (m *Manager) KillAll() error {
+ for _, p := range m.Processes() {
+ if err := p.Kill(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SignalAll sends a signal `sig` to all processes in current manager.
+func (m *Manager) SignalAll(sig os.Signal) error {
+ for _, p := range m.Processes() {
+ if err := p.Signal(sig); err != nil {
+ err = gerror.Wrapf(err, `send signal to process failed for pid "%d" with signal "%s"`, p.Process.Pid, sig)
+ return err
+ }
+ }
+ return nil
+}
+
+// Send sends data bytes to all processes in current manager.
+func (m *Manager) Send(data []byte) {
+ for _, p := range m.Processes() {
+ _ = p.Send(data)
+ }
+}
+
+// SendTo sneds data bytes to specified processe in current manager.
+func (m *Manager) SendTo(pid int, data []byte) error {
+ return Send(pid, data)
+}
+
+// Clear removes all processes in current manager.
+func (m *Manager) Clear() {
+ m.processes.Clear()
+}
+
+// Size returns the size of processes in current manager.
+func (m *Manager) Size() int {
+ return m.processes.Size()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_must.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_must.go
new file mode 100644
index 000000000000..5e7584f016fc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_must.go
@@ -0,0 +1,34 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "io"
+)
+
+// MustShell performs as Shell, but it panics if any error occurs.
+func MustShell(cmd string, out io.Writer, in io.Reader) {
+ if err := Shell(cmd, out, in); err != nil {
+ panic(err)
+ }
+}
+
+// MustShellRun performs as ShellRun, but it panics if any error occurs.
+func MustShellRun(cmd string) {
+ if err := ShellRun(cmd); err != nil {
+ panic(err)
+ }
+}
+
+// MustShellExec performs as ShellExec, but it panics if any error occurs.
+func MustShellExec(cmd string, environment ...[]string) string {
+ result, err := ShellExec(cmd, environment...)
+ if err != nil {
+ panic(err)
+ }
+ return result
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_process.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_process.go
new file mode 100644
index 000000000000..b1a589428216
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_process.go
@@ -0,0 +1,139 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "os/exec"
+ "runtime"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// Process is the struct for a single process.
+type Process struct {
+ exec.Cmd
+ Manager *Manager
+ PPid int
+}
+
+// NewProcess creates and returns a new Process.
+func NewProcess(path string, args []string, environment ...[]string) *Process {
+ env := os.Environ()
+ if len(environment) > 0 {
+ env = append(env, environment[0]...)
+ }
+ process := &Process{
+ Manager: nil,
+ PPid: os.Getpid(),
+ Cmd: exec.Cmd{
+ Args: []string{path},
+ Path: path,
+ Stdin: os.Stdin,
+ Stdout: os.Stdout,
+ Stderr: os.Stderr,
+ Env: env,
+ ExtraFiles: make([]*os.File, 0),
+ },
+ }
+ process.Dir, _ = os.Getwd()
+ if len(args) > 0 {
+ // Exclude of current binary path.
+ start := 0
+ if strings.EqualFold(path, args[0]) {
+ start = 1
+ }
+ process.Args = append(process.Args, args[start:]...)
+ }
+ return process
+}
+
+// NewProcessCmd creates and returns a process with given command and optional environment variable array.
+func NewProcessCmd(cmd string, environment ...[]string) *Process {
+ return NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), environment...)
+}
+
+// Start starts executing the process in non-blocking way.
+// It returns the pid if success, or else it returns an error.
+func (p *Process) Start() (int, error) {
+ if p.Process != nil {
+ return p.Pid(), nil
+ }
+ p.Env = append(p.Env, fmt.Sprintf("%s=%d", envKeyPPid, p.PPid))
+ if err := p.Cmd.Start(); err == nil {
+ if p.Manager != nil {
+ p.Manager.processes.Set(p.Process.Pid, p)
+ }
+ return p.Process.Pid, nil
+ } else {
+ return 0, err
+ }
+}
+
+// Run executes the process in blocking way.
+func (p *Process) Run() error {
+ if _, err := p.Start(); err == nil {
+ return p.Wait()
+ } else {
+ return err
+ }
+}
+
+// Pid retrieves and returns the PID for the process.
+func (p *Process) Pid() int {
+ if p.Process != nil {
+ return p.Process.Pid
+ }
+ return 0
+}
+
+// Send sends custom data to the process.
+func (p *Process) Send(data []byte) error {
+ if p.Process != nil {
+ return Send(p.Process.Pid, data)
+ }
+ return gerror.NewCode(gcode.CodeInvalidParameter, "invalid process")
+}
+
+// Release releases any resources associated with the Process p,
+// rendering it unusable in the future.
+// Release only needs to be called if Wait is not.
+func (p *Process) Release() error {
+ return p.Process.Release()
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() (err error) {
+ err = p.Process.Kill()
+ if err != nil {
+ err = gerror.Wrapf(err, `kill process failed for pid "%d"`, p.Process.Pid)
+ return err
+ }
+ if p.Manager != nil {
+ p.Manager.processes.Remove(p.Pid())
+ }
+ if runtime.GOOS != "windows" {
+ if err = p.Process.Release(); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ // It ignores this error, just log it.
+ _, err = p.Process.Wait()
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ return nil
+}
+
+// Signal sends a signal to the Process.
+// Sending Interrupt on Windows is not implemented.
+func (p *Process) Signal(sig os.Signal) error {
+ return p.Process.Signal(sig)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_signal.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_signal.go
new file mode 100644
index 000000000000..4454d8745916
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gproc/gproc_signal.go
@@ -0,0 +1,89 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gproc
+
+import (
+ "context"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// SigHandler defines a function type for signal handling.
+type SigHandler func(sig os.Signal)
+
+var (
+ signalHandlerMap = make(map[os.Signal][]SigHandler)
+ shutdownSignalMap = map[os.Signal]struct{}{
+ syscall.SIGINT: {},
+ syscall.SIGQUIT: {},
+ syscall.SIGKILL: {},
+ syscall.SIGTERM: {},
+ syscall.SIGABRT: {},
+ }
+)
+
+func init() {
+ for sig, _ := range shutdownSignalMap {
+ signalHandlerMap[sig] = make([]SigHandler, 0)
+ }
+}
+
+// AddSigHandler adds custom signal handler for custom one or more signals.
+func AddSigHandler(handler SigHandler, signals ...os.Signal) {
+ for _, sig := range signals {
+ signalHandlerMap[sig] = append(signalHandlerMap[sig], handler)
+ }
+}
+
+// AddSigHandlerShutdown adds custom signal handler for shutdown signals:
+// syscall.SIGINT,
+// syscall.SIGQUIT,
+// syscall.SIGKILL,
+// syscall.SIGTERM,
+// syscall.SIGABRT.
+func AddSigHandlerShutdown(handler ...SigHandler) {
+ for _, h := range handler {
+ for sig, _ := range shutdownSignalMap {
+ signalHandlerMap[sig] = append(signalHandlerMap[sig], h)
+ }
+ }
+}
+
+// Listen blocks and does signal listening and handling.
+func Listen() {
+ signals := make([]os.Signal, 0)
+ for sig, _ := range signalHandlerMap {
+ signals = append(signals, sig)
+ }
+ sigChan := make(chan os.Signal, 1)
+ signal.Notify(sigChan, signals...)
+ var sig os.Signal
+ for {
+ wg := sync.WaitGroup{}
+ sig = <-sigChan
+ intlog.Printf(context.TODO(), `signal received: %s`, sig.String())
+ if handlers, ok := signalHandlerMap[sig]; ok {
+ for _, handler := range handlers {
+ wg.Add(1)
+ go func(handler SigHandler, sig os.Signal) {
+ defer wg.Done()
+ handler(sig)
+ }(handler, sig)
+ }
+ }
+ // If it is shutdown signal, it exits this signal listening.
+ if _, ok := shutdownSignalMap[sig]; ok {
+ // Wait until signal handlers done.
+ wg.Wait()
+ return
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres.go
new file mode 100644
index 000000000000..7bb9e815dd59
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres.go
@@ -0,0 +1,88 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gres provides resource management and packing/unpacking feature between files and bytes.
+package gres
+
+const (
+ // Separator for directories.
+ Separator = "/"
+)
+
+var (
+ // Default resource object.
+ defaultResource = Instance()
+)
+
+// Add unpacks and adds the `content` into the default resource object.
+// The unnecessary parameter `prefix` indicates the prefix
+// for each file storing into current resource object.
+func Add(content string, prefix ...string) error {
+ return defaultResource.Add(content, prefix...)
+}
+
+// Load loads, unpacks and adds the data from `path` into the default resource object.
+// The unnecessary parameter `prefix` indicates the prefix
+// for each file storing into current resource object.
+func Load(path string, prefix ...string) error {
+ return defaultResource.Load(path, prefix...)
+}
+
+// Get returns the file with given path.
+func Get(path string) *File {
+ return defaultResource.Get(path)
+}
+
+// GetWithIndex searches file with `path`, if the file is directory
+// it then does index files searching under this directory.
+//
+// GetWithIndex is usually used for http static file service.
+func GetWithIndex(path string, indexFiles []string) *File {
+ return defaultResource.GetWithIndex(path, indexFiles)
+}
+
+// GetContent directly returns the content of `path` in default resource object.
+func GetContent(path string) []byte {
+ return defaultResource.GetContent(path)
+}
+
+// Contains checks whether the `path` exists in the default resource object.
+func Contains(path string) bool {
+ return defaultResource.Contains(path)
+}
+
+// IsEmpty checks and returns whether the resource manager is empty.
+func IsEmpty() bool {
+ return defaultResource.tree.IsEmpty()
+}
+
+// ScanDir returns the files under the given path, the parameter `path` should be a folder type.
+//
+// The pattern parameter `pattern` supports multiple file name patterns,
+// using the ',' symbol to separate multiple patterns.
+//
+// It scans directory recursively if given parameter `recursive` is true.
+func ScanDir(path string, pattern string, recursive ...bool) []*File {
+ return defaultResource.ScanDir(path, pattern, recursive...)
+}
+
+// ScanDirFile returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// Note that it returns only files, exclusive of directories.
+func ScanDirFile(path string, pattern string, recursive ...bool) []*File {
+ return defaultResource.ScanDirFile(path, pattern, recursive...)
+}
+
+// Export exports and saves specified path `src` and all its sub files to specified system path `dst` recursively.
+func Export(src, dst string, option ...ExportOption) error {
+ return defaultResource.Export(src, dst, option...)
+}
+
+// Dump prints the files of the default resource object.
+func Dump() {
+ defaultResource.Dump()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_file.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_file.go
new file mode 100644
index 000000000000..3a826a8cc0b9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_file.go
@@ -0,0 +1,66 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gres
+
+import (
+ "archive/zip"
+ "bytes"
+ "io"
+ "os"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+type File struct {
+ file *zip.File
+ reader *bytes.Reader
+ resource *Resource
+}
+
+// Name returns the name of the file.
+func (f *File) Name() string {
+ return f.file.Name
+}
+
+// Open returns a ReadCloser that provides access to the File's contents.
+// Multiple files may be read concurrently.
+func (f *File) Open() (io.ReadCloser, error) {
+ return f.file.Open()
+}
+
+// Content returns the content of the file.
+func (f *File) Content() []byte {
+ reader, err := f.Open()
+ if err != nil {
+ err = gerror.Wrapf(err, `open file failed for name "%s"`, f.Name())
+ return nil
+ }
+ defer reader.Close()
+ buffer := bytes.NewBuffer(nil)
+ if _, err = io.Copy(buffer, reader); err != nil {
+ err = gerror.Wrapf(err, `read file content failed for name "%s"`, f.Name())
+ return nil
+ }
+ return buffer.Bytes()
+}
+
+// FileInfo returns an os.FileInfo for the FileHeader.
+func (f *File) FileInfo() os.FileInfo {
+ return f.file.FileInfo()
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+func (f File) MarshalJSON() ([]byte, error) {
+ info := f.FileInfo()
+ return json.Marshal(map[string]interface{}{
+ "name": f.Name(),
+ "size": info.Size(),
+ "time": info.ModTime(),
+ "file": !info.IsDir(),
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_func.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_func.go
new file mode 100644
index 000000000000..9e302a734e57
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_func.go
@@ -0,0 +1,176 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gres
+
+import (
+ "archive/zip"
+ "bytes"
+ "encoding/hex"
+ "fmt"
+
+ "github.com/gogf/gf/v2/encoding/gbase64"
+ "github.com/gogf/gf/v2/encoding/gcompress"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+const (
+ packedGoSourceTemplate = `
+package %s
+
+import "github.com/gogf/gf/v2/os/gres"
+
+func init() {
+ if err := gres.Add("%s"); err != nil {
+ panic("add binary content to resource manager failed: " + err.Error())
+ }
+}
+`
+)
+
+// Pack packs the path specified by `srcPaths` into bytes.
+// The unnecessary parameter `keyPrefix` indicates the prefix for each file
+// packed into the result bytes.
+//
+// Note that parameter `srcPaths` supports multiple paths join with ','.
+func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
+ var (
+ buffer = bytes.NewBuffer(nil)
+ headerPrefix = ""
+ )
+ if len(keyPrefix) > 0 && keyPrefix[0] != "" {
+ headerPrefix = keyPrefix[0]
+ }
+ err := zipPathWriter(srcPaths, buffer, headerPrefix)
+ if err != nil {
+ return nil, err
+ }
+ // Gzip the data bytes to reduce the size.
+ return gcompress.Gzip(buffer.Bytes(), 9)
+}
+
+// PackToFile packs the path specified by `srcPaths` to target file `dstPath`.
+// The unnecessary parameter `keyPrefix` indicates the prefix for each file
+// packed into the result bytes.
+//
+// Note that parameter `srcPaths` supports multiple paths join with ','.
+func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
+ data, err := Pack(srcPaths, keyPrefix...)
+ if err != nil {
+ return err
+ }
+ return gfile.PutBytes(dstPath, data)
+}
+
+// PackToGoFile packs the path specified by `srcPaths` to target go file `goFilePath`
+// with given package name `pkgName`.
+//
+// The unnecessary parameter `keyPrefix` indicates the prefix for each file
+// packed into the result bytes.
+//
+// Note that parameter `srcPaths` supports multiple paths join with ','.
+func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
+ data, err := Pack(srcPath, keyPrefix...)
+ if err != nil {
+ return err
+ }
+ return gfile.PutContents(
+ goFilePath,
+ fmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),
+ )
+}
+
+// Unpack unpacks the content specified by `path` to []*File.
+func Unpack(path string) ([]*File, error) {
+ realPath, err := gfile.Search(path)
+ if err != nil {
+ return nil, err
+ }
+ return UnpackContent(gfile.GetContents(realPath))
+}
+
+// UnpackContent unpacks the content to []*File.
+func UnpackContent(content string) ([]*File, error) {
+ var (
+ err error
+ data []byte
+ )
+ if isHexStr(content) {
+ // It here keeps compatible with old version packing string using hex string.
+ // TODO remove this support in the future.
+ data, err = gcompress.UnGzip(hexStrToBytes(content))
+ if err != nil {
+ return nil, err
+ }
+ } else if isBase64(content) {
+ // New version packing string using base64.
+ b, err := gbase64.DecodeString(content)
+ if err != nil {
+ return nil, err
+ }
+ data, err = gcompress.UnGzip(b)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ data, err = gcompress.UnGzip([]byte(content))
+ if err != nil {
+ return nil, err
+ }
+ }
+ reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
+ if err != nil {
+ err = gerror.Wrapf(err, `create zip reader failed`)
+ return nil, err
+ }
+ array := make([]*File, len(reader.File))
+ for i, file := range reader.File {
+ array[i] = &File{file: file}
+ }
+ return array, nil
+}
+
+// isBase64 checks and returns whether given content `s` is base64 string.
+// It returns true if `s` is base64 string, or false if not.
+func isBase64(s string) bool {
+ var r bool
+ for i := 0; i < len(s); i++ {
+ r = (s[i] >= '0' && s[i] <= '9') ||
+ (s[i] >= 'a' && s[i] <= 'z') ||
+ (s[i] >= 'A' && s[i] <= 'Z') ||
+ (s[i] == '+' || s[i] == '-') ||
+ (s[i] == '_' || s[i] == '/') || s[i] == '='
+ if !r {
+ return false
+ }
+ }
+ return true
+}
+
+// isHexStr checks and returns whether given content `s` is hex string.
+// It returns true if `s` is hex string, or false if not.
+func isHexStr(s string) bool {
+ var r bool
+ for i := 0; i < len(s); i++ {
+ r = (s[i] >= '0' && s[i] <= '9') ||
+ (s[i] >= 'a' && s[i] <= 'f') ||
+ (s[i] >= 'A' && s[i] <= 'F')
+ if !r {
+ return false
+ }
+ }
+ return true
+}
+
+// hexStrToBytes converts hex string content to []byte.
+func hexStrToBytes(s string) []byte {
+ src := []byte(s)
+ dst := make([]byte, hex.DecodedLen(len(src)))
+ _, _ = hex.Decode(dst, src)
+ return dst
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_func_zip.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_func_zip.go
new file mode 100644
index 000000000000..108852076bd5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_func_zip.go
@@ -0,0 +1,162 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gres
+
+import (
+ "archive/zip"
+ "context"
+ "io"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/fileinfo"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+// ZipPathWriter compresses `paths` to `writer` using zip compressing algorithm.
+// The unnecessary parameter `prefix` indicates the path prefix for zip file.
+//
+// Note that the parameter `paths` can be either a directory or a file, which
+// supports multiple paths join with ','.
+func zipPathWriter(paths string, writer io.Writer, prefix ...string) error {
+ zipWriter := zip.NewWriter(writer)
+ defer zipWriter.Close()
+ for _, path := range strings.Split(paths, ",") {
+ path = strings.TrimSpace(path)
+ if err := doZipPathWriter(path, "", zipWriter, prefix...); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// doZipPathWriter compresses the file of given `path` and writes the content to `zipWriter`.
+// The parameter `exclude` specifies the exclusive file path that is not compressed to `zipWriter`,
+// commonly the destination zip file path.
+// The unnecessary parameter `prefix` indicates the path prefix for zip file.
+func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix ...string) error {
+ var (
+ err error
+ files []string
+ )
+ path, err = gfile.Search(path)
+ if err != nil {
+ return err
+ }
+ if gfile.IsDir(path) {
+ files, err = gfile.ScanDir(path, "*", true)
+ if err != nil {
+ return err
+ }
+ } else {
+ files = []string{path}
+ }
+ headerPrefix := ""
+ if len(prefix) > 0 && prefix[0] != "" {
+ headerPrefix = prefix[0]
+ }
+ headerPrefix = strings.TrimRight(headerPrefix, `\/`)
+ if len(headerPrefix) > 0 && gfile.IsDir(path) {
+ headerPrefix += "/"
+ }
+ if headerPrefix == "" {
+ headerPrefix = gfile.Basename(path)
+ }
+ headerPrefix = strings.Replace(headerPrefix, `//`, `/`, -1)
+ for _, file := range files {
+ if exclude == file {
+ intlog.Printf(context.TODO(), `exclude file path: %s`, file)
+ continue
+ }
+ if err = zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter); err != nil {
+ return err
+ }
+ }
+ // Add all directories to zip archive.
+ if headerPrefix != "" {
+ var name string
+ path = headerPrefix
+ for {
+ name = strings.Replace(gfile.Basename(path), `\`, `/`, -1)
+ if err = zipFileVirtual(fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), path, zipWriter); err != nil {
+ return err
+ }
+ if path == `/` || !strings.Contains(path, `/`) {
+ break
+ }
+ path = gfile.Dir(path)
+ }
+ }
+ return nil
+}
+
+// zipFile compresses the file of given `path` and writes the content to `zw`.
+// The parameter `prefix` indicates the path prefix for zip file.
+func zipFile(path string, prefix string, zw *zip.Writer) error {
+ prefix = strings.Replace(prefix, `//`, `/`, -1)
+ file, err := os.Open(path)
+ if err != nil {
+ err = gerror.Wrapf(err, `os.Open failed for file "%s"`, path)
+ return nil
+ }
+ defer file.Close()
+ info, err := file.Stat()
+ if err != nil {
+ err = gerror.Wrapf(err, `read file stat failed for file "%s"`, path)
+ return err
+ }
+ header, err := createFileHeader(info, prefix)
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ header.Method = zip.Deflate
+ }
+ writer, err := zw.CreateHeader(header)
+ if err != nil {
+ err = gerror.Wrapf(err, `create zip header failed for %#v`, header)
+ return err
+ }
+ if !info.IsDir() {
+ if _, err = io.Copy(writer, file); err != nil {
+ err = gerror.Wrapf(err, `io.Copy failed for file "%s"`, path)
+ return err
+ }
+ }
+ return nil
+}
+
+func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error {
+ header, err := createFileHeader(info, "")
+ if err != nil {
+ return err
+ }
+ header.Name = path
+ if _, err = zw.CreateHeader(header); err != nil {
+ err = gerror.Wrapf(err, `create zip header failed for %#v`, header)
+ return err
+ }
+ return nil
+}
+
+func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {
+ header, err := zip.FileInfoHeader(info)
+ if err != nil {
+ err = gerror.Wrapf(err, `create file header failed for name "%s"`, info.Name())
+ return nil, err
+ }
+ if len(prefix) > 0 {
+ header.Name = prefix + `/` + header.Name
+ header.Name = strings.Replace(header.Name, `\`, `/`, -1)
+ header.Name, _ = gregex.ReplaceString(`/{2,}`, `/`, header.Name)
+ }
+ return header, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_http_file.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_http_file.go
new file mode 100644
index 000000000000..e6d10124c7c7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_http_file.go
@@ -0,0 +1,71 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gres
+
+import (
+ "bytes"
+ "os"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Close implements interface of http.File.
+func (f *File) Close() error {
+ return nil
+}
+
+// Readdir implements Readdir interface of http.File.
+func (f *File) Readdir(count int) ([]os.FileInfo, error) {
+ files := f.resource.ScanDir(f.Name(), "*", false)
+ if len(files) > 0 {
+ if count <= 0 || count > len(files) {
+ count = len(files)
+ }
+ infos := make([]os.FileInfo, count)
+ for k, v := range files {
+ infos[k] = v.FileInfo()
+ }
+ return infos, nil
+ }
+ return nil, nil
+}
+
+// Stat implements Stat interface of http.File.
+func (f *File) Stat() (os.FileInfo, error) {
+ return f.FileInfo(), nil
+}
+
+// Read implements the io.Reader interface.
+func (f *File) Read(b []byte) (n int, err error) {
+ reader, err := f.getReader()
+ if err != nil {
+ return 0, err
+ }
+ if n, err = reader.Read(b); err != nil {
+ err = gerror.Wrapf(err, `read content failed`)
+ }
+ return
+}
+
+// Seek implements the io.Seeker interface.
+func (f *File) Seek(offset int64, whence int) (n int64, err error) {
+ reader, err := f.getReader()
+ if err != nil {
+ return 0, err
+ }
+ if n, err = reader.Seek(offset, whence); err != nil {
+ err = gerror.Wrapf(err, `seek failed for offset %d, whence %d`, offset, whence)
+ }
+ return
+}
+
+func (f *File) getReader() (*bytes.Reader, error) {
+ if f.reader == nil {
+ f.reader = bytes.NewReader(f.Content())
+ }
+ return f.reader, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_instance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_instance.go
new file mode 100644
index 000000000000..e04dc4311922
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_instance.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gres
+
+import "github.com/gogf/gf/v2/container/gmap"
+
+const (
+ // DefaultName default group name for instance usage.
+ DefaultName = "default"
+)
+
+var (
+ // Instances map.
+ instances = gmap.NewStrAnyMap(true)
+)
+
+// Instance returns an instance of Resource.
+// The parameter `name` is the name for the instance.
+func Instance(name ...string) *Resource {
+ key := DefaultName
+ if len(name) > 0 && name[0] != "" {
+ key = name[0]
+ }
+ return instances.GetOrSetFuncLock(key, func() interface{} {
+ return New()
+ }).(*Resource)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_resource.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_resource.go
new file mode 100644
index 000000000000..1a925d444659
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gres/gres_resource.go
@@ -0,0 +1,281 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gres
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/gtree"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+type Resource struct {
+ tree *gtree.BTree
+}
+
+const (
+ defaultTreeM = 100
+)
+
+// New creates and returns a new resource object.
+func New() *Resource {
+ return &Resource{
+ tree: gtree.NewBTree(defaultTreeM, func(v1, v2 interface{}) int {
+ return strings.Compare(v1.(string), v2.(string))
+ }),
+ }
+}
+
+// Add unpacks and adds the `content` into current resource object.
+// The unnecessary parameter `prefix` indicates the prefix
+// for each file storing into current resource object.
+func (r *Resource) Add(content string, prefix ...string) error {
+ files, err := UnpackContent(content)
+ if err != nil {
+ intlog.Printf(context.TODO(), "Add resource files failed: %v", err)
+ return err
+ }
+ namePrefix := ""
+ if len(prefix) > 0 {
+ namePrefix = prefix[0]
+ }
+ for i := 0; i < len(files); i++ {
+ files[i].resource = r
+ r.tree.Set(namePrefix+files[i].file.Name, files[i])
+ }
+ intlog.Printf(context.TODO(), "Add %d files to resource manager", r.tree.Size())
+ return nil
+}
+
+// Load loads, unpacks and adds the data from `path` into current resource object.
+// The unnecessary parameter `prefix` indicates the prefix
+// for each file storing into current resource object.
+func (r *Resource) Load(path string, prefix ...string) error {
+ realPath, err := gfile.Search(path)
+ if err != nil {
+ return err
+ }
+ return r.Add(gfile.GetContents(realPath), prefix...)
+}
+
+// Get returns the file with given path.
+func (r *Resource) Get(path string) *File {
+ if path == "" {
+ return nil
+ }
+ path = strings.Replace(path, "\\", "/", -1)
+ path = strings.Replace(path, "//", "/", -1)
+ if path != "/" {
+ for path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+ }
+ result := r.tree.Get(path)
+ if result != nil {
+ return result.(*File)
+ }
+ return nil
+}
+
+// GetWithIndex searches file with `path`, if the file is directory
+// it then does index files searching under this directory.
+//
+// GetWithIndex is usually used for http static file service.
+func (r *Resource) GetWithIndex(path string, indexFiles []string) *File {
+ // Necessary for double char '/' replacement in prefix.
+ path = strings.Replace(path, "\\", "/", -1)
+ path = strings.Replace(path, "//", "/", -1)
+ if path != "/" {
+ for path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+ }
+ if file := r.Get(path); file != nil {
+ if len(indexFiles) > 0 && file.FileInfo().IsDir() {
+ var f *File
+ for _, name := range indexFiles {
+ if f = r.Get(path + "/" + name); f != nil {
+ return f
+ }
+ }
+ }
+ return file
+ }
+ return nil
+}
+
+// GetContent directly returns the content of `path`.
+func (r *Resource) GetContent(path string) []byte {
+ file := r.Get(path)
+ if file != nil {
+ return file.Content()
+ }
+ return nil
+}
+
+// Contains checks whether the `path` exists in current resource object.
+func (r *Resource) Contains(path string) bool {
+ return r.Get(path) != nil
+}
+
+// IsEmpty checks and returns whether the resource manager is empty.
+func (r *Resource) IsEmpty() bool {
+ return r.tree.IsEmpty()
+}
+
+// ScanDir returns the files under the given path, the parameter `path` should be a folder type.
+//
+// The pattern parameter `pattern` supports multiple file name patterns,
+// using the ',' symbol to separate multiple patterns.
+//
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// Note that the returned files does not contain given parameter `path`.
+func (r *Resource) ScanDir(path string, pattern string, recursive ...bool) []*File {
+ isRecursive := false
+ if len(recursive) > 0 {
+ isRecursive = recursive[0]
+ }
+ return r.doScanDir(path, pattern, isRecursive, false)
+}
+
+// ScanDirFile returns all sub-files with absolute paths of given `path`,
+// It scans directory recursively if given parameter `recursive` is true.
+//
+// Note that it returns only files, exclusive of directories.
+func (r *Resource) ScanDirFile(path string, pattern string, recursive ...bool) []*File {
+ isRecursive := false
+ if len(recursive) > 0 {
+ isRecursive = recursive[0]
+ }
+ return r.doScanDir(path, pattern, isRecursive, true)
+}
+
+// doScanDir is an internal method which scans directory
+// and returns the absolute path list of files that are not sorted.
+//
+// The pattern parameter `pattern` supports multiple file name patterns,
+// using the ',' symbol to separate multiple patterns.
+//
+// It scans directory recursively if given parameter `recursive` is true.
+func (r *Resource) doScanDir(path string, pattern string, recursive bool, onlyFile bool) []*File {
+ path = strings.Replace(path, "\\", "/", -1)
+ path = strings.Replace(path, "//", "/", -1)
+ if path != "/" {
+ for path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+ }
+ var (
+ name = ""
+ files = make([]*File, 0)
+ length = len(path)
+ patterns = strings.Split(pattern, ",")
+ )
+ for i := 0; i < len(patterns); i++ {
+ patterns[i] = strings.TrimSpace(patterns[i])
+ }
+ // Used for type checking for first entry.
+ first := true
+ r.tree.IteratorFrom(path, true, func(key, value interface{}) bool {
+ if first {
+ if !value.(*File).FileInfo().IsDir() {
+ return false
+ }
+ first = false
+ }
+ if onlyFile && value.(*File).FileInfo().IsDir() {
+ return true
+ }
+ name = key.(string)
+ if len(name) <= length {
+ return true
+ }
+ if path != name[:length] {
+ return false
+ }
+ // To avoid of, eg: /i18n and /i18n-dir
+ if !first && name[length] != '/' {
+ return true
+ }
+ if !recursive {
+ if strings.IndexByte(name[length+1:], '/') != -1 {
+ return true
+ }
+ }
+ for _, p := range patterns {
+ if match, err := filepath.Match(p, gfile.Basename(name)); err == nil && match {
+ files = append(files, value.(*File))
+ return true
+ }
+ }
+ return true
+ })
+ return files
+}
+
+// ExportOption is the option for function Export.
+type ExportOption struct {
+ RemovePrefix string // Remove the prefix of file name from resource.
+}
+
+// Export exports and saves specified path `srcPath` and all its sub files to specified system path `dstPath` recursively.
+func (r *Resource) Export(src, dst string, option ...ExportOption) error {
+ var (
+ err error
+ name string
+ path string
+ exportOption ExportOption
+ files = r.doScanDir(src, "*", true, false)
+ )
+ if len(option) > 0 {
+ exportOption = option[0]
+ }
+ for _, file := range files {
+ name = file.Name()
+ if exportOption.RemovePrefix != "" {
+ name = gstr.TrimLeftStr(name, exportOption.RemovePrefix)
+ }
+ name = gstr.Trim(name, `\/`)
+ if name == "" {
+ continue
+ }
+ path = gfile.Join(dst, name)
+ if file.FileInfo().IsDir() {
+ err = gfile.Mkdir(path)
+ } else {
+ err = gfile.PutBytes(path, file.Content())
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Dump prints the files of current resource object.
+func (r *Resource) Dump() {
+ var info os.FileInfo
+ r.tree.Iterator(func(key, value interface{}) bool {
+ info = value.(*File).FileInfo()
+ fmt.Printf(
+ "%v %7s %s\n",
+ gtime.New(info.ModTime()).ISO8601(),
+ gfile.FormatSize(info.Size()),
+ key,
+ )
+ return true
+ })
+ fmt.Printf("TOTAL FILES: %d\n", r.tree.Size())
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/grpool/grpool.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/grpool/grpool.go
new file mode 100644
index 000000000000..ba9c6e46d86e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/grpool/grpool.go
@@ -0,0 +1,175 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package grpool implements a goroutine reusable pool.
+package grpool
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/glist"
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Func is the pool function which contains context parameter.
+type Func func(ctx context.Context)
+
+// Pool manages the goroutines using pool.
+type Pool struct {
+ limit int // Max goroutine count limit.
+ count *gtype.Int // Current running goroutine count.
+ list *glist.List // Job list for asynchronous job adding purpose.
+ closed *gtype.Bool // Is pool closed or not.
+}
+
+type internalPoolItem struct {
+ Ctx context.Context
+ Func Func
+}
+
+// Default goroutine pool.
+var (
+ pool = New()
+)
+
+// New creates and returns a new goroutine pool object.
+// The parameter `limit` is used to limit the max goroutine count,
+// which is not limited in default.
+func New(limit ...int) *Pool {
+ p := &Pool{
+ limit: -1,
+ count: gtype.NewInt(),
+ list: glist.New(true),
+ closed: gtype.NewBool(),
+ }
+ if len(limit) > 0 && limit[0] > 0 {
+ p.limit = limit[0]
+ }
+ return p
+}
+
+// Add pushes a new job to the pool using default goroutine pool.
+// The job will be executed asynchronously.
+func Add(ctx context.Context, f Func) error {
+ return pool.Add(ctx, f)
+}
+
+// AddWithRecover pushes a new job to the pool with specified recover function.
+// The optional `recoverFunc` is called when any panic during executing of `userFunc`.
+// If `recoverFunc` is not passed or given nil, it ignores the panic from `userFunc`.
+// The job will be executed asynchronously.
+func AddWithRecover(ctx context.Context, userFunc Func, recoverFunc ...func(err error)) error {
+ return pool.AddWithRecover(ctx, userFunc, recoverFunc...)
+}
+
+// Size returns current goroutine count of default goroutine pool.
+func Size() int {
+ return pool.Size()
+}
+
+// Jobs returns current job count of default goroutine pool.
+func Jobs() int {
+ return pool.Jobs()
+}
+
+// Add pushes a new job to the pool.
+// The job will be executed asynchronously.
+func (p *Pool) Add(ctx context.Context, f Func) error {
+ for p.closed.Val() {
+ return gerror.NewCode(gcode.CodeInvalidOperation, "pool closed")
+ }
+ p.list.PushFront(&internalPoolItem{
+ Ctx: ctx,
+ Func: f,
+ })
+ // Check whether fork new goroutine or not.
+ var n int
+ for {
+ n = p.count.Val()
+ if p.limit != -1 && n >= p.limit {
+ // No need fork new goroutine.
+ return nil
+ }
+ if p.count.Cas(n, n+1) {
+ // Use CAS to guarantee atomicity.
+ break
+ }
+ }
+ p.fork()
+ return nil
+}
+
+// AddWithRecover pushes a new job to the pool with specified recover function.
+// The optional `recoverFunc` is called when any panic during executing of `userFunc`.
+// If `recoverFunc` is not passed or given nil, it ignores the panic from `userFunc`.
+// The job will be executed asynchronously.
+func (p *Pool) AddWithRecover(ctx context.Context, userFunc Func, recoverFunc ...func(err error)) error {
+ return p.Add(ctx, func(ctx context.Context) {
+ defer func() {
+ if exception := recover(); exception != nil {
+ if len(recoverFunc) > 0 && recoverFunc[0] != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ recoverFunc[0](v)
+ } else {
+ recoverFunc[0](gerror.Newf(`%+v`, exception))
+ }
+ }
+ }
+ }()
+ userFunc(ctx)
+ })
+}
+
+// Cap returns the capacity of the pool.
+// This capacity is defined when pool is created.
+// It returns -1 if there's no limit.
+func (p *Pool) Cap() int {
+ return p.limit
+}
+
+// Size returns current goroutine count of the pool.
+func (p *Pool) Size() int {
+ return p.count.Val()
+}
+
+// Jobs returns current job count of the pool.
+// Note that, it does not return worker/goroutine count but the job/task count.
+func (p *Pool) Jobs() int {
+ return p.list.Size()
+}
+
+// fork creates a new goroutine worker.
+// Note that the worker dies if the job function panics.
+func (p *Pool) fork() {
+ go func() {
+ defer p.count.Add(-1)
+
+ var (
+ listItem interface{}
+ poolItem *internalPoolItem
+ )
+ for !p.closed.Val() {
+ if listItem = p.list.PopBack(); listItem != nil {
+ poolItem = listItem.(*internalPoolItem)
+ poolItem.Func(poolItem.Ctx)
+ } else {
+ return
+ }
+ }
+ }()
+}
+
+// IsClosed returns if pool is closed.
+func (p *Pool) IsClosed() bool {
+ return p.closed.Val()
+}
+
+// Close closes the goroutine pool, which makes all goroutines exit.
+func (p *Pool) Close() {
+ p.closed.Set(true)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession.go
new file mode 100644
index 000000000000..f057ec63e707
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession.go
@@ -0,0 +1,28 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gsession implements manager and storage features for sessions.
+package gsession
+
+import (
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/util/guid"
+)
+
+var (
+ // ErrorDisabled is used for marking certain interface function not used.
+ ErrorDisabled = gerror.NewOption(gerror.Option{
+ Text: "this feature is disabled in this storage",
+ Code: gcode.CodeNotSupported,
+ })
+)
+
+// NewSessionId creates and returns a new and unique session id string,
+// which is in 36 bytes.
+func NewSessionId() string {
+ return guid.S()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_manager.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_manager.go
new file mode 100644
index 000000000000..daf8254000b3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_manager.go
@@ -0,0 +1,85 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcache"
+)
+
+// Manager for sessions.
+type Manager struct {
+ ttl time.Duration // TTL for sessions.
+ storage Storage // Storage interface for session storage.
+
+ // sessionData is the memory data cache for session TTL,
+ // which is available only if the Storage does not store any session data in synchronizing.
+ // Please refer to the implements of StorageFile, StorageMemory and StorageRedis.
+ sessionData *gcache.Cache
+}
+
+// New creates and returns a new session manager.
+func New(ttl time.Duration, storage ...Storage) *Manager {
+ m := &Manager{
+ ttl: ttl,
+ sessionData: gcache.New(),
+ }
+ if len(storage) > 0 && storage[0] != nil {
+ m.storage = storage[0]
+ } else {
+ m.storage = NewStorageFile()
+ }
+ return m
+}
+
+// New creates or fetches the session for given session id.
+// The parameter `sessionId` is optional, it creates a new one if not it's passed
+// depending on Storage.New.
+func (m *Manager) New(ctx context.Context, sessionId ...string) *Session {
+ var id string
+ if len(sessionId) > 0 && sessionId[0] != "" {
+ id = sessionId[0]
+ }
+ return &Session{
+ id: id,
+ ctx: ctx,
+ manager: m,
+ }
+}
+
+// SetStorage sets the session storage for manager.
+func (m *Manager) SetStorage(storage Storage) {
+ m.storage = storage
+}
+
+// GetStorage returns the session storage of current manager.
+func (m *Manager) GetStorage() Storage {
+ return m.storage
+}
+
+// SetTTL the TTL for the session manager.
+func (m *Manager) SetTTL(ttl time.Duration) {
+ m.ttl = ttl
+}
+
+// TTL returns the TTL of the session manager.
+func (m *Manager) TTL() time.Duration {
+ return m.ttl
+}
+
+// UpdateSessionTTL updates the ttl for given session.
+func (m *Manager) UpdateSessionTTL(sessionId string, data *gmap.StrAnyMap) {
+ ctx := context.Background()
+ err := m.sessionData.Set(ctx, sessionId, data, m.ttl)
+ if err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_session.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_session.go
new file mode 100644
index 000000000000..c083c794855e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_session.go
@@ -0,0 +1,364 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// Session struct for storing single session data, which is bound to a single request.
+// The Session struct is the interface with user, but the Storage is the underlying adapter designed interface
+// for functionality implements.
+type Session struct {
+ id string // Session id. It retrieves the session if id is custom specified.
+ ctx context.Context // Context for current session. Please note that, session live along with context.
+ data *gmap.StrAnyMap // Session data.
+ dirty bool // Used to mark session is modified.
+ start bool // Used to mark session is started.
+ manager *Manager // Parent manager.
+
+ // idFunc is a callback function used for creating custom session id.
+ // This is called if session id is empty ever when session starts.
+ idFunc func(ttl time.Duration) (id string)
+}
+
+// init does the lazy initialization for session, which retrieves the session if session id is specified,
+// or else it creates a new empty session.
+func (s *Session) init() error {
+ if s.start {
+ return nil
+ }
+ var err error
+ if s.id != "" {
+ // Retrieve memory session data from manager.
+ r, err := s.manager.sessionData.Get(s.ctx, s.id)
+ if err != nil && err != ErrorDisabled {
+ return err
+ }
+ if r != nil {
+ s.data = r.Val().(*gmap.StrAnyMap)
+ intlog.Print(s.ctx, "session init data:", s.data)
+ }
+ // Retrieve stored session data from storage.
+ if s.manager.storage != nil {
+ if s.data, err = s.manager.storage.GetSession(s.ctx, s.id, s.manager.ttl, s.data); err != nil && err != ErrorDisabled {
+ intlog.Errorf(s.ctx, `session restoring failed for id "%s": %+v`, s.id, err)
+ return err
+ }
+ }
+ }
+ // Session id creation.
+ if s.id == "" {
+ if s.idFunc != nil {
+ // Use custom session id creating function.
+ s.id = s.idFunc(s.manager.ttl)
+ } else {
+ // Use default session id creating function of storage.
+ s.id, err = s.manager.storage.New(s.ctx, s.manager.ttl)
+ if err != nil && err != ErrorDisabled {
+ intlog.Errorf(s.ctx, "create session id failed: %+v", err)
+ return err
+ }
+ // If session storage does not implements id generating functionality,
+ // it then uses default session id creating function.
+ if s.id == "" {
+ s.id = NewSessionId()
+ }
+ }
+ }
+ if s.data == nil {
+ s.data = gmap.NewStrAnyMap(true)
+ }
+ s.start = true
+ return nil
+}
+
+// Close closes current session and updates its ttl in the session manager.
+// If this session is dirty, it also exports it to storage.
+//
+// NOTE that this function must be called ever after a session request done.
+func (s *Session) Close() error {
+ if s.start && s.id != "" {
+ size := s.data.Size()
+ if s.manager.storage != nil {
+ if s.dirty {
+ if err := s.manager.storage.SetSession(s.ctx, s.id, s.data, s.manager.ttl); err != nil && err != ErrorDisabled {
+ return err
+ }
+ } else if size > 0 {
+ if err := s.manager.storage.UpdateTTL(s.ctx, s.id, s.manager.ttl); err != nil && err != ErrorDisabled {
+ return err
+ }
+ }
+ }
+ if s.dirty || size > 0 {
+ s.manager.UpdateSessionTTL(s.id, s.data)
+ }
+ }
+ return nil
+}
+
+// Set sets key-value pair to this session.
+func (s *Session) Set(key string, value interface{}) error {
+ if err := s.init(); err != nil {
+ return err
+ }
+ if err := s.manager.storage.Set(s.ctx, s.id, key, value, s.manager.ttl); err != nil {
+ if err == ErrorDisabled {
+ s.data.Set(key, value)
+ } else {
+ return err
+ }
+ }
+ s.dirty = true
+ return nil
+}
+
+// SetMap batch sets the session using map.
+func (s *Session) SetMap(data map[string]interface{}) error {
+ if err := s.init(); err != nil {
+ return err
+ }
+ if err := s.manager.storage.SetMap(s.ctx, s.id, data, s.manager.ttl); err != nil {
+ if err == ErrorDisabled {
+ s.data.Sets(data)
+ } else {
+ return err
+ }
+ }
+ s.dirty = true
+ return nil
+}
+
+// Remove removes key along with its value from this session.
+func (s *Session) Remove(keys ...string) error {
+ if s.id == "" {
+ return nil
+ }
+ if err := s.init(); err != nil {
+ return err
+ }
+ for _, key := range keys {
+ if err := s.manager.storage.Remove(s.ctx, s.id, key); err != nil {
+ if err == ErrorDisabled {
+ s.data.Remove(key)
+ } else {
+ return err
+ }
+ }
+ }
+ s.dirty = true
+ return nil
+}
+
+// RemoveAll deletes all key-value pairs from this session.
+func (s *Session) RemoveAll() error {
+ if s.id == "" {
+ return nil
+ }
+ if err := s.init(); err != nil {
+ return err
+ }
+ if err := s.manager.storage.RemoveAll(s.ctx, s.id); err != nil {
+ if err == ErrorDisabled {
+ s.data.Clear()
+ } else {
+ return err
+ }
+ }
+ s.dirty = true
+ return nil
+}
+
+// Id returns the session id for this session.
+// It creates and returns a new session id if the session id is not passed in initialization.
+func (s *Session) Id() (string, error) {
+ if err := s.init(); err != nil {
+ return "", err
+ }
+ return s.id, nil
+}
+
+// SetId sets custom session before session starts.
+// It returns error if it is called after session starts.
+func (s *Session) SetId(id string) error {
+ if s.start {
+ return gerror.NewCode(gcode.CodeInvalidOperation, "session already started")
+ }
+ s.id = id
+ return nil
+}
+
+// SetIdFunc sets custom session id creating function before session starts.
+// It returns error if it is called after session starts.
+func (s *Session) SetIdFunc(f func(ttl time.Duration) string) error {
+ if s.start {
+ return gerror.NewCode(gcode.CodeInvalidOperation, "session already started")
+ }
+ s.idFunc = f
+ return nil
+}
+
+// Data returns all data as map.
+// Note that it's using value copy internally for concurrent-safe purpose.
+func (s *Session) Data() (map[string]interface{}, error) {
+ if s.id == "" {
+ return map[string]interface{}{}, nil
+ }
+ if err := s.init(); err != nil {
+ return nil, err
+ }
+ data, err := s.manager.storage.Data(s.ctx, s.id)
+ if err != nil && err != ErrorDisabled {
+ intlog.Errorf(s.ctx, `%+v`, err)
+ }
+ if data != nil {
+ return data, nil
+ }
+ return s.data.Map(), nil
+}
+
+// Size returns the size of the session.
+func (s *Session) Size() (int, error) {
+ if s.id == "" {
+ return 0, nil
+ }
+ if err := s.init(); err != nil {
+ return 0, err
+ }
+ size, err := s.manager.storage.GetSize(s.ctx, s.id)
+ if err != nil && err != ErrorDisabled {
+ intlog.Errorf(s.ctx, `%+v`, err)
+ }
+ if size >= 0 {
+ return size, nil
+ }
+ return s.data.Size(), nil
+}
+
+// Contains checks whether key exist in the session.
+func (s *Session) Contains(key string) (bool, error) {
+ if s.id == "" {
+ return false, nil
+ }
+ if err := s.init(); err != nil {
+ return false, err
+ }
+ v, err := s.Get(key)
+ if err != nil {
+ return false, err
+ }
+ return !v.IsNil(), nil
+}
+
+// IsDirty checks whether there's any data changes in the session.
+func (s *Session) IsDirty() bool {
+ return s.dirty
+}
+
+// Get retrieves session value with given key.
+// It returns `def` if the key does not exist in the session if `def` is given,
+// or else it returns nil.
+func (s *Session) Get(key string, def ...interface{}) (*gvar.Var, error) {
+ if s.id == "" {
+ return nil, nil
+ }
+ if err := s.init(); err != nil {
+ return nil, err
+ }
+ v, err := s.manager.storage.Get(s.ctx, s.id, key)
+ if err != nil && err != ErrorDisabled {
+ intlog.Errorf(s.ctx, `%+v`, err)
+ return nil, err
+ }
+ if v != nil {
+ return gvar.New(v), nil
+ }
+ if v := s.data.Get(key); v != nil {
+ return gvar.New(v), nil
+ }
+ if len(def) > 0 {
+ return gvar.New(def[0]), nil
+ }
+ return nil, nil
+}
+
+// MustId performs as function Id, but it panics if any error occurs.
+func (s *Session) MustId() string {
+ id, err := s.Id()
+ if err != nil {
+ panic(err)
+ }
+ return id
+}
+
+// MustGet performs as function Get, but it panics if any error occurs.
+func (s *Session) MustGet(key string, def ...interface{}) *gvar.Var {
+ v, err := s.Get(key, def...)
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// MustSet performs as function Set, but it panics if any error occurs.
+func (s *Session) MustSet(key string, value interface{}) {
+ err := s.Set(key, value)
+ if err != nil {
+ panic(err)
+ }
+}
+
+// MustSetMap performs as function SetMap, but it panics if any error occurs.
+func (s *Session) MustSetMap(data map[string]interface{}) {
+ err := s.SetMap(data)
+ if err != nil {
+ panic(err)
+ }
+}
+
+// MustContains performs as function Contains, but it panics if any error occurs.
+func (s *Session) MustContains(key string) bool {
+ b, err := s.Contains(key)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+// MustData performs as function Data, but it panics if any error occurs.
+func (s *Session) MustData() map[string]interface{} {
+ m, err := s.Data()
+ if err != nil {
+ panic(err)
+ }
+ return m
+}
+
+// MustSize performs as function Size, but it panics if any error occurs.
+func (s *Session) MustSize() int {
+ size, err := s.Size()
+ if err != nil {
+ panic(err)
+ }
+ return size
+}
+
+// MustRemove performs as function Remove, but it panics if any error occurs.
+func (s *Session) MustRemove(keys ...string) {
+ err := s.Remove(keys...)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage.go
new file mode 100644
index 000000000000..47459da358fc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage.go
@@ -0,0 +1,63 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+)
+
+// Storage is the interface definition for session storage.
+type Storage interface {
+ // New creates a custom session id.
+ // This function can be used for custom session creation.
+ New(ctx context.Context, ttl time.Duration) (id string, err error)
+
+ // Get retrieves and returns session value with given key.
+ // It returns nil if the key does not exist in the session.
+ Get(ctx context.Context, id string, key string) (value interface{}, err error)
+
+ // GetSize retrieves and returns the size of key-value pairs from storage.
+ GetSize(ctx context.Context, id string) (size int, err error)
+
+ // Data retrieves all key-value pairs as map from storage.
+ Data(ctx context.Context, id string) (data map[string]interface{}, err error)
+
+ // Set sets one key-value session pair to the storage.
+ // The parameter `ttl` specifies the TTL for the session id.
+ Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error
+
+ // SetMap batch sets key-value session pairs as map to the storage.
+ // The parameter `ttl` specifies the TTL for the session id.
+ SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error
+
+ // Remove deletes key with its value from storage.
+ Remove(ctx context.Context, id string, key string) error
+
+ // RemoveAll deletes all key-value pairs from storage.
+ RemoveAll(ctx context.Context, id string) error
+
+ // GetSession returns the session data as `*gmap.StrAnyMap` for given session id from storage.
+ //
+ // The parameter `ttl` specifies the TTL for this session.
+ // The parameter `data` is the current old session data stored in memory,
+ // and for some storage it might be nil if memory storage is disabled.
+ //
+ // This function is called ever when session starts. It returns nil if the TTL is exceeded.
+ GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error)
+
+ // SetSession updates the data for specified session id.
+ // This function is called ever after session, which is changed dirty, is closed.
+ // This copy all session data map from memory to storage.
+ SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error
+
+ // UpdateTTL updates the TTL for specified session id.
+ // This function is called ever after session, which is not dirty, is closed.
+ UpdateTTL(ctx context.Context, id string, ttl time.Duration) error
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_file.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_file.go
new file mode 100644
index 000000000000..ae2411b915c8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_file.go
@@ -0,0 +1,248 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "os"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/container/gset"
+ "github.com/gogf/gf/v2/crypto/gaes"
+ "github.com/gogf/gf/v2/encoding/gbinary"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/os/gtimer"
+)
+
+// StorageFile implements the Session Storage interface with file system.
+type StorageFile struct {
+ path string
+ cryptoKey []byte
+ cryptoEnabled bool
+ updatingIdSet *gset.StrSet
+}
+
+const (
+ DefaultStorageFileCryptoEnabled = false
+ DefaultStorageFileLoopInterval = 10 * time.Second
+)
+
+var (
+ DefaultStorageFilePath = gfile.Temp("gsessions")
+ DefaultStorageFileCryptoKey = []byte("Session storage file crypto key!")
+)
+
+// NewStorageFile creates and returns a file storage object for session.
+func NewStorageFile(path ...string) *StorageFile {
+ storagePath := DefaultStorageFilePath
+ if len(path) > 0 && path[0] != "" {
+ storagePath, _ = gfile.Search(path[0])
+ if storagePath == "" {
+ panic(gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" does not exist`, path[0]))
+ }
+ if !gfile.IsWritable(storagePath) {
+ panic(gerror.NewCodef(gcode.CodeInvalidParameter, `"%s" is not writable`, path[0]))
+ }
+ }
+ if storagePath != "" {
+ if err := gfile.Mkdir(storagePath); err != nil {
+ panic(gerror.Wrapf(err, `Mkdir "%s" failed in PWD "%s"`, path, gfile.Pwd()))
+ }
+ }
+ s := &StorageFile{
+ path: storagePath,
+ cryptoKey: DefaultStorageFileCryptoKey,
+ cryptoEnabled: DefaultStorageFileCryptoEnabled,
+ updatingIdSet: gset.NewStrSet(true),
+ }
+
+ gtimer.AddSingleton(context.Background(), DefaultStorageFileLoopInterval, s.updateSessionTimely)
+ return s
+}
+
+// updateSessionTimely batch updates the TTL for sessions timely.
+func (s *StorageFile) updateSessionTimely(ctx context.Context) {
+ var (
+ id string
+ err error
+ )
+ // Batch updating sessions.
+ for {
+ if id = s.updatingIdSet.Pop(); id == "" {
+ break
+ }
+ if err = s.updateSessionTTl(context.TODO(), id); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+}
+
+// SetCryptoKey sets the crypto key for session storage.
+// The crypto key is used when crypto feature is enabled.
+func (s *StorageFile) SetCryptoKey(key []byte) {
+ s.cryptoKey = key
+}
+
+// SetCryptoEnabled enables/disables the crypto feature for session storage.
+func (s *StorageFile) SetCryptoEnabled(enabled bool) {
+ s.cryptoEnabled = enabled
+}
+
+// sessionFilePath returns the storage file path for given session id.
+func (s *StorageFile) sessionFilePath(id string) string {
+ return gfile.Join(s.path, id)
+}
+
+// New creates a session id.
+// This function can be used for custom session creation.
+func (s *StorageFile) New(ctx context.Context, ttl time.Duration) (id string, err error) {
+ return "", ErrorDisabled
+}
+
+// Get retrieves session value with given key.
+// It returns nil if the key does not exist in the session.
+func (s *StorageFile) Get(ctx context.Context, id string, key string) (value interface{}, err error) {
+ return nil, ErrorDisabled
+}
+
+// Data retrieves all key-value pairs as map from storage.
+func (s *StorageFile) Data(ctx context.Context, id string) (data map[string]interface{}, err error) {
+ return nil, ErrorDisabled
+}
+
+// GetSize retrieves the size of key-value pairs from storage.
+func (s *StorageFile) GetSize(ctx context.Context, id string) (size int, err error) {
+ return -1, ErrorDisabled
+}
+
+// Set sets key-value session pair to the storage.
+// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).
+func (s *StorageFile) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error {
+ return ErrorDisabled
+}
+
+// SetMap batch sets key-value session pairs with map to the storage.
+// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).
+func (s *StorageFile) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error {
+ return ErrorDisabled
+}
+
+// Remove deletes key with its value from storage.
+func (s *StorageFile) Remove(ctx context.Context, id string, key string) error {
+ return ErrorDisabled
+}
+
+// RemoveAll deletes all key-value pairs from storage.
+func (s *StorageFile) RemoveAll(ctx context.Context, id string) error {
+ return ErrorDisabled
+}
+
+// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.
+//
+// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.
+// The parameter `data` is the current old session data stored in memory,
+// and for some storage it might be nil if memory storage is disabled.
+//
+// This function is called ever when session starts.
+func (s *StorageFile) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
+ if data != nil {
+ return data, nil
+ }
+ path := s.sessionFilePath(id)
+ content := gfile.GetBytes(path)
+ if len(content) > 8 {
+ timestampMilli := gbinary.DecodeToInt64(content[:8])
+ if timestampMilli+ttl.Nanoseconds()/1e6 < gtime.TimestampMilli() {
+ return nil, nil
+ }
+ var err error
+ content = content[8:]
+ // Decrypt with AES.
+ if s.cryptoEnabled {
+ content, err = gaes.Decrypt(content, DefaultStorageFileCryptoKey)
+ if err != nil {
+ return nil, err
+ }
+ }
+ var m map[string]interface{}
+ if err = json.UnmarshalUseNumber(content, &m); err != nil {
+ return nil, err
+ }
+ if m == nil {
+ return nil, nil
+ }
+ return gmap.NewStrAnyMapFrom(m, true), nil
+ }
+ return nil, nil
+}
+
+// SetSession updates the data map for specified session id.
+// This function is called ever after session, which is changed dirty, is closed.
+// This copy all session data map from memory to storage.
+func (s *StorageFile) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error {
+ intlog.Printf(ctx, "StorageFile.SetSession: %s, %v, %v", id, data, ttl)
+ path := s.sessionFilePath(id)
+ content, err := json.Marshal(data)
+ if err != nil {
+ return err
+ }
+ // Encrypt with AES.
+ if s.cryptoEnabled {
+ content, err = gaes.Encrypt(content, DefaultStorageFileCryptoKey)
+ if err != nil {
+ return err
+ }
+ }
+ file, err := gfile.OpenWithFlagPerm(
+ path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm,
+ )
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ if _, err = file.Write(gbinary.EncodeInt64(gtime.TimestampMilli())); err != nil {
+ err = gerror.Wrapf(err, `write data failed to file "%s"`, path)
+ return err
+ }
+ if _, err = file.Write(content); err != nil {
+ err = gerror.Wrapf(err, `write data failed to file "%s"`, path)
+ return err
+ }
+ return nil
+}
+
+// UpdateTTL updates the TTL for specified session id.
+// This function is called ever after session, which is not dirty, is closed.
+// It just adds the session id to the async handling queue.
+func (s *StorageFile) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error {
+ intlog.Printf(ctx, "StorageFile.UpdateTTL: %s, %v", id, ttl)
+ if ttl >= DefaultStorageFileLoopInterval {
+ s.updatingIdSet.Add(id)
+ }
+ return nil
+}
+
+// updateSessionTTL updates the TTL for specified session id.
+func (s *StorageFile) updateSessionTTl(ctx context.Context, id string) error {
+ intlog.Printf(ctx, "StorageFile.updateSession: %s", id)
+ path := s.sessionFilePath(id)
+ file, err := gfile.OpenWithFlag(path, os.O_WRONLY)
+ if err != nil {
+ return err
+ }
+ if _, err = file.WriteAt(gbinary.EncodeInt64(gtime.TimestampMilli()), 0); err != nil {
+ err = gerror.Wrapf(err, `write data failed to file "%s"`, path)
+ return err
+ }
+ return file.Close()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_memory.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_memory.go
new file mode 100644
index 000000000000..f34a504765e8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_memory.go
@@ -0,0 +1,91 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+)
+
+// StorageMemory implements the Session Storage interface with memory.
+type StorageMemory struct{}
+
+// NewStorageMemory creates and returns a file storage object for session.
+func NewStorageMemory() *StorageMemory {
+ return &StorageMemory{}
+}
+
+// New creates a session id.
+// This function can be used for custom session creation.
+func (s *StorageMemory) New(ctx context.Context, ttl time.Duration) (id string, err error) {
+ return "", ErrorDisabled
+}
+
+// Get retrieves session value with given key.
+// It returns nil if the key does not exist in the session.
+func (s *StorageMemory) Get(ctx context.Context, id string, key string) (value interface{}, err error) {
+ return nil, ErrorDisabled
+}
+
+// GetMap retrieves all key-value pairs as map from storage.
+func (s *StorageMemory) Data(ctx context.Context, id string) (data map[string]interface{}, err error) {
+ return nil, ErrorDisabled
+}
+
+// GetSize retrieves the size of key-value pairs from storage.
+func (s *StorageMemory) GetSize(ctx context.Context, id string) (size int, err error) {
+ return -1, ErrorDisabled
+}
+
+// Set sets key-value session pair to the storage.
+// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).
+func (s *StorageMemory) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error {
+ return ErrorDisabled
+}
+
+// SetMap batch sets key-value session pairs with map to the storage.
+// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).
+func (s *StorageMemory) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error {
+ return ErrorDisabled
+}
+
+// Remove deletes key with its value from storage.
+func (s *StorageMemory) Remove(ctx context.Context, id string, key string) error {
+ return ErrorDisabled
+}
+
+// RemoveAll deletes all key-value pairs from storage.
+func (s *StorageMemory) RemoveAll(ctx context.Context, id string) error {
+ return ErrorDisabled
+}
+
+// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.
+//
+// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.
+// The parameter `data` is the current old session data stored in memory,
+// and for some storage it might be nil if memory storage is disabled.
+//
+// This function is called ever when session starts.
+func (s *StorageMemory) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
+ return data, nil
+}
+
+// SetSession updates the data map for specified session id.
+// This function is called ever after session, which is changed dirty, is closed.
+// This copy all session data map from memory to storage.
+func (s *StorageMemory) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error {
+ return nil
+}
+
+// UpdateTTL updates the TTL for specified session id.
+// This function is called ever after session, which is not dirty, is closed.
+// It just adds the session id to the async handling queue.
+func (s *StorageMemory) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error {
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_redis.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_redis.go
new file mode 100644
index 000000000000..ed11f3d5ec84
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_redis.go
@@ -0,0 +1,176 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/database/gredis"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gtimer"
+)
+
+// StorageRedis implements the Session Storage interface with redis.
+type StorageRedis struct {
+ redis *gredis.Redis // Redis client for session storage.
+ prefix string // Redis key prefix for session id.
+ updatingIdMap *gmap.StrIntMap // Updating TTL set for session id.
+}
+
+const (
+ // DefaultStorageRedisLoopInterval is the interval updating TTL for session ids
+ // in last duration.
+ DefaultStorageRedisLoopInterval = 10 * time.Second
+)
+
+// NewStorageRedis creates and returns a redis storage object for session.
+func NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis {
+ if redis == nil {
+ panic("redis instance for storage cannot be empty")
+ return nil
+ }
+ s := &StorageRedis{
+ redis: redis,
+ updatingIdMap: gmap.NewStrIntMap(true),
+ }
+ if len(prefix) > 0 && prefix[0] != "" {
+ s.prefix = prefix[0]
+ }
+ // Batch updates the TTL for session ids timely.
+ gtimer.AddSingleton(context.Background(), DefaultStorageRedisLoopInterval, func(ctx context.Context) {
+ intlog.Print(context.TODO(), "StorageRedis.timer start")
+ var (
+ id string
+ err error
+ ttlSeconds int
+ )
+ for {
+ if id, ttlSeconds = s.updatingIdMap.Pop(); id == "" {
+ break
+ } else {
+ if err = s.doUpdateTTL(context.TODO(), id, ttlSeconds); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ }
+ intlog.Print(context.TODO(), "StorageRedis.timer end")
+ })
+ return s
+}
+
+// New creates a session id.
+// This function can be used for custom session creation.
+func (s *StorageRedis) New(ctx context.Context, ttl time.Duration) (id string, err error) {
+ return "", ErrorDisabled
+}
+
+// Get retrieves session value with given key.
+// It returns nil if the key does not exist in the session.
+func (s *StorageRedis) Get(ctx context.Context, id string, key string) (value interface{}, err error) {
+ return nil, ErrorDisabled
+}
+
+// Data retrieves all key-value pairs as map from storage.
+func (s *StorageRedis) Data(ctx context.Context, id string) (data map[string]interface{}, err error) {
+ return nil, ErrorDisabled
+}
+
+// GetSize retrieves the size of key-value pairs from storage.
+func (s *StorageRedis) GetSize(ctx context.Context, id string) (size int, err error) {
+ return -1, ErrorDisabled
+}
+
+// Set sets key-value session pair to the storage.
+// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).
+func (s *StorageRedis) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error {
+ return ErrorDisabled
+}
+
+// SetMap batch sets key-value session pairs with map to the storage.
+// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).
+func (s *StorageRedis) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error {
+ return ErrorDisabled
+}
+
+// Remove deletes key with its value from storage.
+func (s *StorageRedis) Remove(ctx context.Context, id string, key string) error {
+ return ErrorDisabled
+}
+
+// RemoveAll deletes all key-value pairs from storage.
+func (s *StorageRedis) RemoveAll(ctx context.Context, id string) error {
+ return ErrorDisabled
+}
+
+// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.
+//
+// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.
+// The parameter `data` is the current old session data stored in memory,
+// and for some storage it might be nil if memory storage is disabled.
+//
+// This function is called ever when session starts.
+func (s *StorageRedis) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
+ intlog.Printf(ctx, "StorageRedis.GetSession: %s, %v", id, ttl)
+ r, err := s.redis.Do(ctx, "GET", s.key(id))
+ if err != nil {
+ return nil, err
+ }
+ content := r.Bytes()
+ if len(content) == 0 {
+ return nil, nil
+ }
+ var m map[string]interface{}
+ if err = json.UnmarshalUseNumber(content, &m); err != nil {
+ return nil, err
+ }
+ if m == nil {
+ return nil, nil
+ }
+ if data == nil {
+ return gmap.NewStrAnyMapFrom(m, true), nil
+ }
+ data.Replace(m)
+ return data, nil
+}
+
+// SetSession updates the data map for specified session id.
+// This function is called ever after session, which is changed dirty, is closed.
+// This copy all session data map from memory to storage.
+func (s *StorageRedis) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error {
+ intlog.Printf(ctx, "StorageRedis.SetSession: %s, %v, %v", id, data, ttl)
+ content, err := json.Marshal(data)
+ if err != nil {
+ return err
+ }
+ _, err = s.redis.Do(ctx, "SETEX", s.key(id), int64(ttl.Seconds()), content)
+ return err
+}
+
+// UpdateTTL updates the TTL for specified session id.
+// This function is called ever after session, which is not dirty, is closed.
+// It just adds the session id to the async handling queue.
+func (s *StorageRedis) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error {
+ intlog.Printf(ctx, "StorageRedis.UpdateTTL: %s, %v", id, ttl)
+ if ttl >= DefaultStorageRedisLoopInterval {
+ s.updatingIdMap.Set(id, int(ttl.Seconds()))
+ }
+ return nil
+}
+
+// doUpdateTTL updates the TTL for session id.
+func (s *StorageRedis) doUpdateTTL(ctx context.Context, id string, ttlSeconds int) error {
+ intlog.Printf(ctx, "StorageRedis.doUpdateTTL: %s, %d", id, ttlSeconds)
+ _, err := s.redis.Do(ctx, "EXPIRE", s.key(id), ttlSeconds)
+ return err
+}
+
+func (s *StorageRedis) key(id string) string {
+ return s.prefix + id
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_redis_hashtable.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_redis_hashtable.go
new file mode 100644
index 000000000000..b9d740a568b5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gsession/gsession_storage_redis_hashtable.go
@@ -0,0 +1,160 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gsession
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/database/gredis"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// StorageRedisHashTable implements the Session Storage interface with redis hash table.
+type StorageRedisHashTable struct {
+ redis *gredis.Redis // Redis client for session storage.
+ prefix string // Redis key prefix for session id.
+}
+
+// NewStorageRedisHashTable creates and returns a redis hash table storage object for session.
+func NewStorageRedisHashTable(redis *gredis.Redis, prefix ...string) *StorageRedisHashTable {
+ if redis == nil {
+ panic("redis instance for storage cannot be empty")
+ return nil
+ }
+ s := &StorageRedisHashTable{
+ redis: redis,
+ }
+ if len(prefix) > 0 && prefix[0] != "" {
+ s.prefix = prefix[0]
+ }
+ return s
+}
+
+// New creates a session id.
+// This function can be used for custom session creation.
+func (s *StorageRedisHashTable) New(ctx context.Context, ttl time.Duration) (id string, err error) {
+ return "", ErrorDisabled
+}
+
+// Get retrieves session value with given key.
+// It returns nil if the key does not exist in the session.
+func (s *StorageRedisHashTable) Get(ctx context.Context, id string, key string) (value interface{}, err error) {
+ v, err := s.redis.Do(ctx, "HGET", s.key(id), key)
+ if err != nil {
+ return nil, err
+ }
+ if v.IsNil() {
+ return nil, nil
+ }
+ return v.String(), nil
+}
+
+// Data retrieves all key-value pairs as map from storage.
+func (s *StorageRedisHashTable) Data(ctx context.Context, id string) (data map[string]interface{}, err error) {
+ v, err := s.redis.Do(ctx, "HGETALL", s.key(id))
+ if err != nil {
+ return nil, err
+ }
+ data = make(map[string]interface{})
+ array := v.Interfaces()
+ for i := 0; i < len(array); i += 2 {
+ if array[i+1] != nil {
+ data[gconv.String(array[i])] = gconv.String(array[i+1])
+ } else {
+ data[gconv.String(array[i])] = array[i+1]
+ }
+ }
+ return data, nil
+}
+
+// GetSize retrieves the size of key-value pairs from storage.
+func (s *StorageRedisHashTable) GetSize(ctx context.Context, id string) (size int, err error) {
+ r, err := s.redis.Do(ctx, "HLEN", s.key(id))
+ if err != nil {
+ return -1, err
+ }
+ return r.Int(), nil
+}
+
+// Set sets key-value session pair to the storage.
+// The parameter `ttl` specifies the TTL for the session id (not for the key-value pair).
+func (s *StorageRedisHashTable) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error {
+ _, err := s.redis.Do(ctx, "HSET", s.key(id), key, value)
+ return err
+}
+
+// SetMap batch sets key-value session pairs with map to the storage.
+// The parameter `ttl` specifies the TTL for the session id(not for the key-value pair).
+func (s *StorageRedisHashTable) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error {
+ array := make([]interface{}, len(data)*2+1)
+ array[0] = s.key(id)
+
+ index := 1
+ for k, v := range data {
+ array[index] = k
+ array[index+1] = v
+ index += 2
+ }
+ _, err := s.redis.Do(ctx, "HMSET", array...)
+ return err
+}
+
+// Remove deletes key with its value from storage.
+func (s *StorageRedisHashTable) Remove(ctx context.Context, id string, key string) error {
+ _, err := s.redis.Do(ctx, "HDEL", s.key(id), key)
+ return err
+}
+
+// RemoveAll deletes all key-value pairs from storage.
+func (s *StorageRedisHashTable) RemoveAll(ctx context.Context, id string) error {
+ _, err := s.redis.Do(ctx, "DEL", s.key(id))
+ return err
+}
+
+// GetSession returns the session data as *gmap.StrAnyMap for given session id from storage.
+//
+// The parameter `ttl` specifies the TTL for this session, and it returns nil if the TTL is exceeded.
+// The parameter `data` is the current old session data stored in memory,
+// and for some storage it might be nil if memory storage is disabled.
+//
+// This function is called ever when session starts.
+func (s *StorageRedisHashTable) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) {
+ intlog.Printf(ctx, "StorageRedisHashTable.GetSession: %s, %v", id, ttl)
+ r, err := s.redis.Do(ctx, "EXISTS", s.key(id))
+ if err != nil {
+ return nil, err
+ }
+ if r.Bool() {
+ return gmap.NewStrAnyMap(true), nil
+ }
+ return nil, nil
+}
+
+// SetSession updates the data map for specified session id.
+// This function is called ever after session, which is changed dirty, is closed.
+// This copy all session data map from memory to storage.
+func (s *StorageRedisHashTable) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error {
+ intlog.Printf(ctx, "StorageRedisHashTable.SetSession: %s, %v", id, ttl)
+ _, err := s.redis.Do(ctx, "EXPIRE", s.key(id), int64(ttl.Seconds()))
+ return err
+}
+
+// UpdateTTL updates the TTL for specified session id.
+// This function is called ever after session, which is not dirty, is closed.
+// It just adds the session id to the async handling queue.
+func (s *StorageRedisHashTable) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error {
+ intlog.Printf(ctx, "StorageRedisHashTable.UpdateTTL: %s, %v", id, ttl)
+ _, err := s.redis.Do(ctx, "EXPIRE", s.key(id), int64(ttl.Seconds()))
+ return err
+}
+
+func (s *StorageRedisHashTable) key(id string) string {
+ return s.prefix + id
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gspath/gspath.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gspath/gspath.go
new file mode 100644
index 000000000000..f036b75d3e3f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gspath/gspath.go
@@ -0,0 +1,255 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gspath implements file index and search for folders.
+//
+// It searches file internally with high performance in order by the directory adding sequence.
+// Note that:
+// If caching feature enabled, there would be a searching delay after adding/deleting files.
+package gspath
+
+import (
+ "context"
+ "os"
+ "sort"
+ "strings"
+
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// SPath manages the path searching feature.
+type SPath struct {
+ paths *garray.StrArray // The searching directories array.
+ cache *gmap.StrStrMap // Searching cache map, it is not enabled if it's nil.
+}
+
+// SPathCacheItem is a cache item for searching.
+type SPathCacheItem struct {
+ path string // Absolute path for file/dir.
+ isDir bool // Is directory or not.
+}
+
+var (
+ // Path to searching object mapping, used for instance management.
+ pathsMap = gmap.NewStrAnyMap(true)
+)
+
+// New creates and returns a new path searching manager.
+func New(path string, cache bool) *SPath {
+ sp := &SPath{
+ paths: garray.NewStrArray(true),
+ }
+ if cache {
+ sp.cache = gmap.NewStrStrMap(true)
+ }
+ if len(path) > 0 {
+ if _, err := sp.Add(path); err != nil {
+ // intlog.Print(err)
+ }
+ }
+ return sp
+}
+
+// Get creates and returns a instance of searching manager for given path.
+// The parameter `cache` specifies whether using cache feature for this manager.
+// If cache feature is enabled, it asynchronously and recursively scans the path
+// and updates all sub files/folders to the cache using package gfsnotify.
+func Get(root string, cache bool) *SPath {
+ if root == "" {
+ root = "/"
+ }
+ return pathsMap.GetOrSetFuncLock(root, func() interface{} {
+ return New(root, cache)
+ }).(*SPath)
+}
+
+// Search searches file `name` under path `root`.
+// The parameter `root` should be a absolute path. It will not automatically
+// convert `root` to absolute path for performance reason.
+// The optional parameter `indexFiles` specifies the searching index files when the result is a directory.
+// For example, if the result `filePath` is a directory, and `indexFiles` is [index.html, main.html], it will also
+// search [index.html, main.html] under `filePath`. It returns the absolute file path if any of them found,
+// or else it returns `filePath`.
+func Search(root string, name string, indexFiles ...string) (filePath string, isDir bool) {
+ return Get(root, false).Search(name, indexFiles...)
+}
+
+// SearchWithCache searches file `name` under path `root` with cache feature enabled.
+// The parameter `root` should be a absolute path. It will not automatically
+// convert `root` to absolute path for performance reason.
+// The optional parameter `indexFiles` specifies the searching index files when the result is a directory.
+// For example, if the result `filePath` is a directory, and `indexFiles` is [index.html, main.html], it will also
+// search [index.html, main.html] under `filePath`. It returns the absolute file path if any of them found,
+// or else it returns `filePath`.
+func SearchWithCache(root string, name string, indexFiles ...string) (filePath string, isDir bool) {
+ return Get(root, true).Search(name, indexFiles...)
+}
+
+// Set deletes all other searching directories and sets the searching directory for this manager.
+func (sp *SPath) Set(path string) (realPath string, err error) {
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ realPath, _ = sp.Search(path)
+ if realPath == "" {
+ realPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + path)
+ }
+ }
+ if realPath == "" {
+ return realPath, gerror.NewCodef(gcode.CodeInvalidParameter, `path "%s" does not exist`, path)
+ }
+ // The set path must be a directory.
+ if gfile.IsDir(realPath) {
+ realPath = strings.TrimRight(realPath, gfile.Separator)
+ if sp.paths.Search(realPath) != -1 {
+ for _, v := range sp.paths.Slice() {
+ sp.removeMonitorByPath(v)
+ }
+ }
+ intlog.Print(context.TODO(), "paths clear:", sp.paths)
+ sp.paths.Clear()
+ if sp.cache != nil {
+ sp.cache.Clear()
+ }
+ sp.paths.Append(realPath)
+ sp.updateCacheByPath(realPath)
+ sp.addMonitorByPath(realPath)
+ return realPath, nil
+ } else {
+ return "", gerror.NewCode(gcode.CodeInvalidParameter, path+" should be a folder")
+ }
+}
+
+// Add adds more searching directory to the manager.
+// The manager will search file in added order.
+func (sp *SPath) Add(path string) (realPath string, err error) {
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ realPath, _ = sp.Search(path)
+ if realPath == "" {
+ realPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + path)
+ }
+ }
+ if realPath == "" {
+ return realPath, gerror.NewCodef(gcode.CodeInvalidParameter, `path "%s" does not exist`, path)
+ }
+ // The added path must be a directory.
+ if gfile.IsDir(realPath) {
+ // fmt.Println("gspath:", realPath, sp.paths.Search(realPath))
+ // It will not add twice for the same directory.
+ if sp.paths.Search(realPath) < 0 {
+ realPath = strings.TrimRight(realPath, gfile.Separator)
+ sp.paths.Append(realPath)
+ sp.updateCacheByPath(realPath)
+ sp.addMonitorByPath(realPath)
+ }
+ return realPath, nil
+ } else {
+ return "", gerror.NewCode(gcode.CodeInvalidParameter, path+" should be a folder")
+ }
+}
+
+// Search searches file `name` in the manager.
+// The optional parameter `indexFiles` specifies the searching index files when the result is a directory.
+// For example, if the result `filePath` is a directory, and `indexFiles` is [index.html, main.html], it will also
+// search [index.html, main.html] under `filePath`. It returns the absolute file path if any of them found,
+// or else it returns `filePath`.
+func (sp *SPath) Search(name string, indexFiles ...string) (filePath string, isDir bool) {
+ // No cache enabled.
+ if sp.cache == nil {
+ sp.paths.LockFunc(func(array []string) {
+ path := ""
+ for _, v := range array {
+ path = gfile.Join(v, name)
+ if stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {
+ path = gfile.Abs(path)
+ // Security check: the result file path must be under the searching directory.
+ if len(path) >= len(v) && path[:len(v)] == v {
+ filePath = path
+ isDir = stat.IsDir()
+ break
+ }
+ }
+ }
+ })
+ if len(indexFiles) > 0 && isDir {
+ if name == "/" {
+ name = ""
+ }
+ path := ""
+ for _, file := range indexFiles {
+ path = filePath + gfile.Separator + file
+ if gfile.Exists(path) {
+ filePath = path
+ isDir = false
+ break
+ }
+ }
+ }
+ return
+ }
+ // Using cache feature.
+ name = sp.formatCacheName(name)
+ if v := sp.cache.Get(name); v != "" {
+ filePath, isDir = sp.parseCacheValue(v)
+ if len(indexFiles) > 0 && isDir {
+ if name == "/" {
+ name = ""
+ }
+ for _, file := range indexFiles {
+ if v = sp.cache.Get(name + "/" + file); v != "" {
+ return sp.parseCacheValue(v)
+ }
+ }
+ }
+ }
+ return
+}
+
+// Remove deletes the `path` from cache files of the manager.
+// The parameter `path` can be either a absolute path or just a relative file name.
+func (sp *SPath) Remove(path string) {
+ if sp.cache == nil {
+ return
+ }
+ if gfile.Exists(path) {
+ for _, v := range sp.paths.Slice() {
+ name := gstr.Replace(path, v, "")
+ name = sp.formatCacheName(name)
+ sp.cache.Remove(name)
+ }
+ } else {
+ name := sp.formatCacheName(path)
+ sp.cache.Remove(name)
+ }
+}
+
+// Paths returns all searching directories.
+func (sp *SPath) Paths() []string {
+ return sp.paths.Slice()
+}
+
+// AllPaths returns all paths cached in the manager.
+func (sp *SPath) AllPaths() []string {
+ if sp.cache == nil {
+ return nil
+ }
+ paths := sp.cache.Keys()
+ if len(paths) > 0 {
+ sort.Strings(paths)
+ }
+ return paths
+}
+
+// Size returns the count of the searching directories.
+func (sp *SPath) Size() int {
+ return sp.paths.Len()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gspath/gspath_cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gspath/gspath_cache.go
new file mode 100644
index 000000000000..5aba56dd97cc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gspath/gspath_cache.go
@@ -0,0 +1,114 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gspath implements file index and search for folders.
+//
+
+package gspath
+
+import (
+ "runtime"
+ "strings"
+
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gfsnotify"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// updateCacheByPath adds all files under `path` recursively.
+func (sp *SPath) updateCacheByPath(path string) {
+ if sp.cache == nil {
+ return
+ }
+ sp.addToCache(path, path)
+}
+
+// formatCacheName formats `name` with following rules:
+// 1. The separator is unified to char '/'.
+// 2. The name should be started with '/' (similar as HTTP URI).
+func (sp *SPath) formatCacheName(name string) string {
+ if runtime.GOOS != "linux" {
+ name = gstr.Replace(name, "\\", "/")
+ }
+ return "/" + strings.Trim(name, "./")
+}
+
+// nameFromPath converts `filePath` to cache name.
+func (sp *SPath) nameFromPath(filePath, rootPath string) string {
+ name := gstr.Replace(filePath, rootPath, "")
+ name = sp.formatCacheName(name)
+ return name
+}
+
+// makeCacheValue formats `filePath` to cache value.
+func (sp *SPath) makeCacheValue(filePath string, isDir bool) string {
+ if isDir {
+ return filePath + "_D_"
+ }
+ return filePath + "_F_"
+}
+
+// parseCacheValue parses cache value to file path and type.
+func (sp *SPath) parseCacheValue(value string) (filePath string, isDir bool) {
+ if value[len(value)-2 : len(value)-1][0] == 'F' {
+ return value[:len(value)-3], false
+ }
+ return value[:len(value)-3], true
+}
+
+// addToCache adds an item to cache.
+// If `filePath` is a directory, it also adds its all sub files/directories recursively
+// to the cache.
+func (sp *SPath) addToCache(filePath, rootPath string) {
+ // Add itself firstly.
+ idDir := gfile.IsDir(filePath)
+ sp.cache.SetIfNotExist(
+ sp.nameFromPath(filePath, rootPath), sp.makeCacheValue(filePath, idDir),
+ )
+ // If it's a directory, it adds its all sub files/directories recursively.
+ if idDir {
+ if files, err := gfile.ScanDir(filePath, "*", true); err == nil {
+ //fmt.Println("gspath add to cache:", filePath, files)
+ for _, path := range files {
+ sp.cache.SetIfNotExist(sp.nameFromPath(path, rootPath), sp.makeCacheValue(path, gfile.IsDir(path)))
+ }
+ }
+ }
+}
+
+// addMonitorByPath adds gfsnotify monitoring recursively.
+// When the files under the directory are updated, the cache will be updated meanwhile.
+// Note that since the listener is added recursively, if you delete a directory, the files (including the directory)
+// under the directory will also generate delete events, which means it will generate N+1 events in total
+// if a directory deleted and there're N files under it.
+func (sp *SPath) addMonitorByPath(path string) {
+ if sp.cache == nil {
+ return
+ }
+ _, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
+ //glog.Debug(event.String())
+ switch {
+ case event.IsRemove():
+ sp.cache.Remove(sp.nameFromPath(event.Path, path))
+
+ case event.IsRename():
+ if !gfile.Exists(event.Path) {
+ sp.cache.Remove(sp.nameFromPath(event.Path, path))
+ }
+
+ case event.IsCreate():
+ sp.addToCache(event.Path, path)
+ }
+ }, true)
+}
+
+// removeMonitorByPath removes gfsnotify monitoring of `path` recursively.
+func (sp *SPath) removeMonitorByPath(path string) {
+ if sp.cache == nil {
+ return
+ }
+ _ = gfsnotify.Remove(path)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs.go
new file mode 100644
index 000000000000..b44cbccac6fc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs.go
@@ -0,0 +1,60 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gstructs provides functions for struct information retrieving.
+package gstructs
+
+import (
+ "reflect"
+)
+
+// Type wraps reflect.Type for additional features.
+type Type struct {
+ reflect.Type
+}
+
+// Field contains information of a struct field .
+type Field struct {
+ Value reflect.Value // The underlying value of the field.
+ Field reflect.StructField // The underlying field of the field.
+
+ // Retrieved tag name. It depends TagValue.
+ TagName string
+
+ // Retrieved tag value.
+ // There might be more than one tags in the field, but only one can be retrieved according to calling function rules.
+ TagValue string
+}
+
+// FieldsInput is the input parameter struct type for function Fields.
+type FieldsInput struct {
+ // Pointer should be type of struct/*struct.
+ Pointer interface{}
+
+ // RecursiveOption specifies the way retrieving the fields recursively if the attribute
+ // is an embedded struct. It is RecursiveOptionNone in default.
+ RecursiveOption int
+}
+
+// FieldMapInput is the input parameter struct type for function FieldMap.
+type FieldMapInput struct {
+ // Pointer should be type of struct/*struct.
+ Pointer interface{}
+
+ // PriorityTagArray specifies the priority tag array for retrieving from high to low.
+ // If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
+ PriorityTagArray []string
+
+ // RecursiveOption specifies the way retrieving the fields recursively if the attribute
+ // is an embedded struct. It is RecursiveOptionNone in default.
+ RecursiveOption int
+}
+
+const (
+ RecursiveOptionNone = 0 // No recursively retrieving fields as map if the field is an embedded struct.
+ RecursiveOptionEmbedded = 1 // Recursively retrieving fields as map if the field is an embedded struct.
+ RecursiveOptionEmbeddedNoTag = 2 // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag.
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_field.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_field.go
new file mode 100644
index 000000000000..8bc0aa234592
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_field.go
@@ -0,0 +1,252 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstructs
+
+import (
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/util/gtag"
+)
+
+const (
+ jsonTagName = `json`
+)
+
+// Tag returns the value associated with key in the tag string. If there is no
+// such key in the tag, Tag returns the empty string.
+func (f *Field) Tag(key string) string {
+ s := f.Field.Tag.Get(key)
+ if s != "" {
+ s = gtag.Parse(s)
+ }
+ return s
+}
+
+// TagJsonName returns the `json` tag name string of the field.
+func (f *Field) TagJsonName() string {
+ if jsonTag := f.Tag(jsonTagName); jsonTag != "" {
+ return strings.Split(jsonTag, ",")[0]
+ }
+ return ""
+}
+
+// TagLookup returns the value associated with key in the tag string.
+// If the key is present in the tag the value (which may be empty)
+// is returned. Otherwise, the returned value will be the empty string.
+// The ok return value reports whether the value was explicitly set in
+// the tag string. If the tag does not have the conventional format,
+// the value returned by Lookup is unspecified.
+func (f *Field) TagLookup(key string) (value string, ok bool) {
+ value, ok = f.Field.Tag.Lookup(key)
+ if ok && value != "" {
+ value = gtag.Parse(value)
+ }
+ return
+}
+
+// IsEmbedded returns true if the given field is an anonymous field (embedded)
+func (f *Field) IsEmbedded() bool {
+ return f.Field.Anonymous
+}
+
+// TagStr returns the tag string of the field.
+func (f *Field) TagStr() string {
+ return string(f.Field.Tag)
+}
+
+// TagMap returns all the tag of the field along with its value string as map.
+func (f *Field) TagMap() map[string]string {
+ var (
+ data = ParseTag(f.TagStr())
+ )
+ for k, v := range data {
+ data[k] = utils.StripSlashes(gtag.Parse(v))
+ }
+ return data
+}
+
+// IsExported returns true if the given field is exported.
+func (f *Field) IsExported() bool {
+ return f.Field.PkgPath == ""
+}
+
+// Name returns the name of the given field.
+func (f *Field) Name() string {
+ return f.Field.Name
+}
+
+// Type returns the type of the given field.
+// Note that this Type is not reflect.Type. If you need reflect.Type, please use Field.Type().Type.
+func (f *Field) Type() Type {
+ return Type{
+ Type: f.Field.Type,
+ }
+}
+
+// Kind returns the reflect.Kind for Value of Field `f`.
+func (f *Field) Kind() reflect.Kind {
+ return f.Value.Kind()
+}
+
+// OriginalKind retrieves and returns the original reflect.Kind for Value of Field `f`.
+func (f *Field) OriginalKind() reflect.Kind {
+ var (
+ kind = f.Value.Kind()
+ value = f.Value
+ )
+ for kind == reflect.Ptr {
+ value = value.Elem()
+ kind = value.Kind()
+ }
+ return kind
+}
+
+// Fields retrieves and returns the fields of `pointer` as slice.
+func Fields(in FieldsInput) ([]Field, error) {
+ var (
+ ok bool
+ fieldFilterMap = make(map[string]struct{})
+ retrievedFields = make([]Field, 0)
+ currentLevelFieldMap = make(map[string]Field)
+ )
+ rangeFields, err := getFieldValues(in.Pointer)
+ if err != nil {
+ return nil, err
+ }
+
+ for index := 0; index < len(rangeFields); index++ {
+ field := rangeFields[index]
+ if !field.IsExported() {
+ continue
+ }
+ currentLevelFieldMap[field.Name()] = field
+ }
+
+ for index := 0; index < len(rangeFields); index++ {
+ field := rangeFields[index]
+ if _, ok = fieldFilterMap[field.Name()]; ok {
+ continue
+ }
+ // It only retrieves exported attributes.
+ if !field.IsExported() {
+ continue
+ }
+ if field.IsEmbedded() {
+ if in.RecursiveOption != RecursiveOptionNone {
+ switch in.RecursiveOption {
+ case RecursiveOptionEmbeddedNoTag:
+ if field.TagStr() != "" {
+ break
+ }
+ fallthrough
+
+ case RecursiveOptionEmbedded:
+ structFields, err := Fields(FieldsInput{
+ Pointer: field.Value,
+ RecursiveOption: in.RecursiveOption,
+ })
+ if err != nil {
+ return nil, err
+ }
+ // The current level fields can overwrite the sub-struct fields with the same name.
+ for i := 0; i < len(structFields); i++ {
+ var (
+ structField = structFields[i]
+ fieldName = structField.Name()
+ )
+ if _, ok = fieldFilterMap[fieldName]; ok {
+ continue
+ }
+ fieldFilterMap[fieldName] = struct{}{}
+ if v, ok := currentLevelFieldMap[fieldName]; !ok {
+ retrievedFields = append(retrievedFields, structField)
+ } else {
+ retrievedFields = append(retrievedFields, v)
+ }
+ }
+ continue
+ }
+ }
+ continue
+ }
+ fieldFilterMap[field.Name()] = struct{}{}
+ retrievedFields = append(retrievedFields, field)
+ }
+ return retrievedFields, nil
+}
+
+// FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.
+//
+// The parameter `pointer` should be type of struct/*struct.
+//
+// The parameter `priority` specifies the priority tag array for retrieving from high to low.
+// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
+//
+// The parameter `recursive` specifies the whether retrieving the fields recursively if the attribute
+// is an embedded struct.
+//
+// Note that it only retrieves the exported attributes with first letter up-case from struct.
+func FieldMap(in FieldMapInput) (map[string]Field, error) {
+ fields, err := getFieldValues(in.Pointer)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ tagValue = ""
+ mapField = make(map[string]Field)
+ )
+ for _, field := range fields {
+ // Only retrieve exported attributes.
+ if !field.IsExported() {
+ continue
+ }
+ tagValue = ""
+ for _, p := range in.PriorityTagArray {
+ tagValue = field.Tag(p)
+ if tagValue != "" && tagValue != "-" {
+ break
+ }
+ }
+ tempField := field
+ tempField.TagValue = tagValue
+ if tagValue != "" {
+ mapField[tagValue] = tempField
+ } else {
+ if in.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {
+ switch in.RecursiveOption {
+ case RecursiveOptionEmbeddedNoTag:
+ if field.TagStr() != "" {
+ mapField[field.Name()] = tempField
+ break
+ }
+ fallthrough
+
+ case RecursiveOptionEmbedded:
+ m, err := FieldMap(FieldMapInput{
+ Pointer: field.Value,
+ PriorityTagArray: in.PriorityTagArray,
+ RecursiveOption: in.RecursiveOption,
+ })
+ if err != nil {
+ return nil, err
+ }
+ for k, v := range m {
+ if _, ok := mapField[k]; !ok {
+ tempV := v
+ mapField[k] = tempV
+ }
+ }
+ }
+ } else {
+ mapField[field.Name()] = tempField
+ }
+ }
+ }
+ return mapField, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_tag.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_tag.go
new file mode 100644
index 000000000000..fdc563df84d1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_tag.go
@@ -0,0 +1,220 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstructs
+
+import (
+ "reflect"
+ "strconv"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/util/gtag"
+)
+
+// ParseTag parses tag string into map.
+// For example:
+// ParseTag(`v:"required" p:"id" d:"1"`) => map[v:required p:id d:1].
+func ParseTag(tag string) map[string]string {
+ var (
+ key string
+ data = make(map[string]string)
+ )
+ for tag != "" {
+ // Skip leading space.
+ i := 0
+ for i < len(tag) && tag[i] == ' ' {
+ i++
+ }
+ tag = tag[i:]
+ if tag == "" {
+ break
+ }
+ // Scan to colon. A space, a quote or a control character is a syntax error.
+ // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
+ // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
+ // as it is simpler to inspect the tag's bytes than the tag's runes.
+ i = 0
+ for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
+ i++
+ }
+ if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+ break
+ }
+ key = tag[:i]
+ tag = tag[i+1:]
+
+ // Scan quoted string to find value.
+ i = 1
+ for i < len(tag) && tag[i] != '"' {
+ if tag[i] == '\\' {
+ i++
+ }
+ i++
+ }
+ if i >= len(tag) {
+ break
+ }
+ quotedValue := tag[:i+1]
+ tag = tag[i+1:]
+ value, err := strconv.Unquote(quotedValue)
+ if err != nil {
+ panic(err)
+ }
+ data[key] = gtag.Parse(value)
+ }
+ return data
+}
+
+// TagFields retrieves and returns struct tags as []Field from `pointer`.
+//
+// The parameter `pointer` should be type of struct/*struct.
+//
+// Note that,
+// 1. It only retrieves the exported attributes with first letter up-case from struct.
+// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
+func TagFields(pointer interface{}, priority []string) ([]Field, error) {
+ return getFieldValuesByTagPriority(pointer, priority, map[string]struct{}{})
+}
+
+// TagMapName retrieves and returns struct tags as map[tag]attribute from `pointer`.
+//
+// The parameter `pointer` should be type of struct/*struct.
+//
+// Note that,
+// 1. It only retrieves the exported attributes with first letter up-case from struct.
+// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
+func TagMapName(pointer interface{}, priority []string) (map[string]string, error) {
+ fields, err := TagFields(pointer, priority)
+ if err != nil {
+ return nil, err
+ }
+ tagMap := make(map[string]string, len(fields))
+ for _, field := range fields {
+ tagMap[field.TagValue] = field.Name()
+ }
+ return tagMap, nil
+}
+
+// TagMapField retrieves struct tags as map[tag]Field from `pointer`, and returns it.
+// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
+//
+// Note that,
+// 1. It only retrieves the exported attributes with first letter up-case from struct.
+// 2. The parameter `priority` should be given, it only retrieves fields that has given tag.
+func TagMapField(object interface{}, priority []string) (map[string]Field, error) {
+ fields, err := TagFields(object, priority)
+ if err != nil {
+ return nil, err
+ }
+ tagMap := make(map[string]Field, len(fields))
+ for _, field := range fields {
+ tagField := field
+ tagMap[field.TagValue] = tagField
+ }
+ return tagMap, nil
+}
+
+func getFieldValues(value interface{}) ([]Field, error) {
+ var (
+ reflectValue reflect.Value
+ reflectKind reflect.Kind
+ )
+ if v, ok := value.(reflect.Value); ok {
+ reflectValue = v
+ reflectKind = reflectValue.Kind()
+ } else {
+ reflectValue = reflect.ValueOf(value)
+ reflectKind = reflectValue.Kind()
+ }
+ for {
+ switch reflectKind {
+ case reflect.Ptr:
+ if !reflectValue.IsValid() || reflectValue.IsNil() {
+ // If pointer is type of *struct and nil, then automatically create a temporary struct.
+ reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
+ reflectKind = reflectValue.Kind()
+ } else {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ case reflect.Array, reflect.Slice:
+ reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
+ reflectKind = reflectValue.Kind()
+ default:
+ goto exitLoop
+ }
+ }
+
+exitLoop:
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ if reflectKind != reflect.Struct {
+ return nil, gerror.NewCode(
+ gcode.CodeInvalidParameter,
+ "given value should be either type of struct/*struct/[]struct/[]*struct",
+ )
+ }
+ var (
+ structType = reflectValue.Type()
+ length = reflectValue.NumField()
+ fields = make([]Field, length)
+ )
+ for i := 0; i < length; i++ {
+ fields[i] = Field{
+ Value: reflectValue.Field(i),
+ Field: structType.Field(i),
+ }
+ }
+ return fields, nil
+}
+
+func getFieldValuesByTagPriority(pointer interface{}, priority []string, tagMap map[string]struct{}) ([]Field, error) {
+ fields, err := getFieldValues(pointer)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ tagName string
+ tagValue string
+ tagFields = make([]Field, 0)
+ )
+ for _, field := range fields {
+ // Only retrieve exported attributes.
+ if !field.IsExported() {
+ continue
+ }
+ tagValue = ""
+ for _, p := range priority {
+ tagName = p
+ tagValue = field.Tag(p)
+ if tagValue != "" && tagValue != "-" {
+ break
+ }
+ }
+ if tagValue != "" {
+ // Filter repeated tag.
+ if _, ok := tagMap[tagValue]; ok {
+ continue
+ }
+ tagField := field
+ tagField.TagName = tagName
+ tagField.TagValue = tagValue
+ tagFields = append(tagFields, tagField)
+ }
+ // If this is an embedded attribute, it retrieves the tags recursively.
+ if field.IsEmbedded() {
+ if subTagFields, err := getFieldValuesByTagPriority(field.Value, priority, tagMap); err != nil {
+ return nil, err
+ } else {
+ tagFields = append(tagFields, subTagFields...)
+ }
+ }
+ }
+ return tagFields, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_type.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_type.go
new file mode 100644
index 000000000000..82d24de61626
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gstructs/gstructs_type.go
@@ -0,0 +1,75 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstructs
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// StructType retrieves and returns the struct Type of specified struct/*struct.
+// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
+func StructType(object interface{}) (*Type, error) {
+ var (
+ reflectValue reflect.Value
+ reflectKind reflect.Kind
+ reflectType reflect.Type
+ )
+ if rv, ok := object.(reflect.Value); ok {
+ reflectValue = rv
+ } else {
+ reflectValue = reflect.ValueOf(object)
+ }
+ reflectKind = reflectValue.Kind()
+ for {
+ switch reflectKind {
+ case reflect.Ptr:
+ if !reflectValue.IsValid() || reflectValue.IsNil() {
+ // If pointer is type of *struct and nil, then automatically create a temporary struct.
+ reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
+ reflectKind = reflectValue.Kind()
+ } else {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+
+ case reflect.Array, reflect.Slice:
+ reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
+ reflectKind = reflectValue.Kind()
+
+ default:
+ goto exitLoop
+ }
+ }
+
+exitLoop:
+ if reflectKind != reflect.Struct {
+ return nil, gerror.Newf(
+ `invalid object kind "%s", kind of "struct" is required`,
+ reflectKind,
+ )
+ }
+ reflectType = reflectValue.Type()
+ return &Type{
+ Type: reflectType,
+ }, nil
+}
+
+// Signature returns a unique string as this type.
+func (t Type) Signature() string {
+ return t.PkgPath() + "/" + t.String()
+}
+
+// FieldKeys returns the keys of current struct/map.
+func (t Type) FieldKeys() []string {
+ keys := make([]string, t.NumField())
+ for i := 0; i < t.NumField(); i++ {
+ keys[i] = t.Field(i).Name
+ }
+ return keys
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime.go
new file mode 100644
index 000000000000..cdf3ca156276
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime.go
@@ -0,0 +1,473 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtime provides functionality for measuring and displaying time.
+//
+// This package should keep much less dependencies with other packages.
+package gtime
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+const (
+ // Short writes for common usage durations.
+
+ D = 24 * time.Hour
+ H = time.Hour
+ M = time.Minute
+ S = time.Second
+ MS = time.Millisecond
+ US = time.Microsecond
+ NS = time.Nanosecond
+
+ // Regular expression1(datetime separator supports '-', '/', '.').
+ // Eg:
+ // "2017-12-14 04:51:34 +0805 LMT",
+ // "2017-12-14 04:51:34 +0805 LMT",
+ // "2006-01-02T15:04:05Z07:00",
+ // "2014-01-17T01:19:15+08:00",
+ // "2018-02-09T20:46:17.897Z",
+ // "2018-02-09 20:46:17.897",
+ // "2018-02-09T20:46:17Z",
+ // "2018-02-09 20:46:17",
+ // "2018/10/31 - 16:38:46"
+ // "2018-02-09",
+ // "2018.02.09",
+ timeRegexPattern1 = `(\d{4}[-/\.]\d{1,2}[-/\.]\d{1,2})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
+
+ // Regular expression2(datetime separator supports '-', '/', '.').
+ // Eg:
+ // 01-Nov-2018 11:50:28
+ // 01/Nov/2018 11:50:28
+ // 01.Nov.2018 11:50:28
+ // 01.Nov.2018:11:50:28
+ timeRegexPattern2 = `(\d{1,2}[-/\.][A-Za-z]{3,}[-/\.]\d{4})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
+
+ // Regular expression3(time).
+ // Eg:
+ // 11:50:28
+ // 11:50:28.897
+ timeRegexPattern3 = `(\d{2}):(\d{2}):(\d{2})\.{0,1}(\d{0,9})`
+)
+
+var (
+ // It's more high performance using regular expression
+ // than time.ParseInLocation to parse the datetime string.
+ timeRegex1, _ = regexp.Compile(timeRegexPattern1)
+ timeRegex2, _ = regexp.Compile(timeRegexPattern2)
+ timeRegex3, _ = regexp.Compile(timeRegexPattern3)
+
+ // Month words to arabic numerals mapping.
+ monthMap = map[string]int{
+ "jan": 1,
+ "feb": 2,
+ "mar": 3,
+ "apr": 4,
+ "may": 5,
+ "jun": 6,
+ "jul": 7,
+ "aug": 8,
+ "sep": 9,
+ "sept": 9,
+ "oct": 10,
+ "nov": 11,
+ "dec": 12,
+ "january": 1,
+ "february": 2,
+ "march": 3,
+ "april": 4,
+ "june": 6,
+ "july": 7,
+ "august": 8,
+ "september": 9,
+ "october": 10,
+ "november": 11,
+ "december": 12,
+ }
+)
+
+// SetTimeZone sets the time zone for current whole process.
+// The parameter `zone` is an area string specifying corresponding time zone,
+// eg: Asia/Shanghai.
+//
+// This should be called before package "time" import.
+// Please refer to issue: https://github.com/golang/go/issues/34814
+func SetTimeZone(zone string) (err error) {
+ location, err := time.LoadLocation(zone)
+ if err != nil {
+ err = gerror.Wrapf(err, `time.LoadLocation failed for zone "%s"`, zone)
+ return err
+ }
+ var (
+ envKey = "TZ"
+ envValue = location.String()
+ )
+ if err = os.Setenv(envKey, envValue); err != nil {
+ err = gerror.Wrapf(err, `set environment failed with key "%s", value "%s"`, envKey, envValue)
+ }
+ return
+}
+
+// Timestamp retrieves and returns the timestamp in seconds.
+func Timestamp() int64 {
+ return Now().Timestamp()
+}
+
+// TimestampMilli retrieves and returns the timestamp in milliseconds.
+func TimestampMilli() int64 {
+ return Now().TimestampMilli()
+}
+
+// TimestampMicro retrieves and returns the timestamp in microseconds.
+func TimestampMicro() int64 {
+ return Now().TimestampMicro()
+}
+
+// TimestampNano retrieves and returns the timestamp in nanoseconds.
+func TimestampNano() int64 {
+ return Now().TimestampNano()
+}
+
+// TimestampStr is a convenience method which retrieves and returns
+// the timestamp in seconds as string.
+func TimestampStr() string {
+ return Now().TimestampStr()
+}
+
+// TimestampMilliStr is a convenience method which retrieves and returns
+// the timestamp in milliseconds as string.
+func TimestampMilliStr() string {
+ return Now().TimestampMilliStr()
+}
+
+// TimestampMicroStr is a convenience method which retrieves and returns
+// the timestamp in microseconds as string.
+func TimestampMicroStr() string {
+ return Now().TimestampMicroStr()
+}
+
+// TimestampNanoStr is a convenience method which retrieves and returns
+// the timestamp in nanoseconds as string.
+func TimestampNanoStr() string {
+ return Now().TimestampNanoStr()
+}
+
+// Date returns current date in string like "2006-01-02".
+func Date() string {
+ return time.Now().Format("2006-01-02")
+}
+
+// Datetime returns current datetime in string like "2006-01-02 15:04:05".
+func Datetime() string {
+ return time.Now().Format("2006-01-02 15:04:05")
+}
+
+// ISO8601 returns current datetime in ISO8601 format like "2006-01-02T15:04:05-07:00".
+func ISO8601() string {
+ return time.Now().Format("2006-01-02T15:04:05-07:00")
+}
+
+// RFC822 returns current datetime in RFC822 format like "Mon, 02 Jan 06 15:04 MST".
+func RFC822() string {
+ return time.Now().Format("Mon, 02 Jan 06 15:04 MST")
+}
+
+// parseDateStr parses the string to year, month and day numbers.
+func parseDateStr(s string) (year, month, day int) {
+ array := strings.Split(s, "-")
+ if len(array) < 3 {
+ array = strings.Split(s, "/")
+ }
+ if len(array) < 3 {
+ array = strings.Split(s, ".")
+ }
+ // Parsing failed.
+ if len(array) < 3 {
+ return
+ }
+ // Checking the year in head or tail.
+ if utils.IsNumeric(array[1]) {
+ year, _ = strconv.Atoi(array[0])
+ month, _ = strconv.Atoi(array[1])
+ day, _ = strconv.Atoi(array[2])
+ } else {
+ if v, ok := monthMap[strings.ToLower(array[1])]; ok {
+ month = v
+ } else {
+ return
+ }
+ year, _ = strconv.Atoi(array[2])
+ day, _ = strconv.Atoi(array[0])
+ }
+ return
+}
+
+// StrToTime converts string to *Time object. It also supports timestamp string.
+// The parameter `format` is unnecessary, which specifies the format for converting like "Y-m-d H:i:s".
+// If `format` is given, it acts as same as function StrToTimeFormat.
+// If `format` is not given, it converts string as a "standard" datetime string.
+// Note that, it fails and returns error if there's no date string in `str`.
+func StrToTime(str string, format ...string) (*Time, error) {
+ if str == "" {
+ return &Time{wrapper{time.Time{}}}, nil
+ }
+ if len(format) > 0 {
+ return StrToTimeFormat(str, format[0])
+ }
+ if isTimestampStr(str) {
+ timestamp, _ := strconv.ParseInt(str, 10, 64)
+ return NewFromTimeStamp(timestamp), nil
+ }
+ var (
+ year, month, day int
+ hour, min, sec, nsec int
+ match []string
+ local = time.Local
+ )
+ if match = timeRegex1.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
+ year, month, day = parseDateStr(match[1])
+ } else if match = timeRegex2.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
+ year, month, day = parseDateStr(match[1])
+ } else if match = timeRegex3.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
+ s := strings.Replace(match[2], ":", "", -1)
+ if len(s) < 6 {
+ s += strings.Repeat("0", 6-len(s))
+ }
+ hour, _ = strconv.Atoi(match[1])
+ min, _ = strconv.Atoi(match[2])
+ sec, _ = strconv.Atoi(match[3])
+ nsec, _ = strconv.Atoi(match[4])
+ for i := 0; i < 9-len(match[4]); i++ {
+ nsec *= 10
+ }
+ return NewFromTime(time.Date(0, time.Month(1), 1, hour, min, sec, nsec, local)), nil
+ } else {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported time converting for string "%s"`, str)
+ }
+
+ // Time
+ if len(match[2]) > 0 {
+ s := strings.Replace(match[2], ":", "", -1)
+ if len(s) < 6 {
+ s += strings.Repeat("0", 6-len(s))
+ }
+ hour, _ = strconv.Atoi(s[0:2])
+ min, _ = strconv.Atoi(s[2:4])
+ sec, _ = strconv.Atoi(s[4:6])
+ }
+ // Nanoseconds, check and perform bits filling
+ if len(match[3]) > 0 {
+ nsec, _ = strconv.Atoi(match[3])
+ for i := 0; i < 9-len(match[3]); i++ {
+ nsec *= 10
+ }
+ }
+ // If there's zone information in the string,
+ // it then performs time zone conversion, which converts the time zone to UTC.
+ if match[4] != "" && match[6] == "" {
+ match[6] = "000000"
+ }
+ // If there's offset in the string, it then firstly processes the offset.
+ if match[6] != "" {
+ zone := strings.Replace(match[6], ":", "", -1)
+ zone = strings.TrimLeft(zone, "+-")
+ if len(zone) <= 6 {
+ zone += strings.Repeat("0", 6-len(zone))
+ h, _ := strconv.Atoi(zone[0:2])
+ m, _ := strconv.Atoi(zone[2:4])
+ s, _ := strconv.Atoi(zone[4:6])
+ if h > 24 || m > 59 || s > 59 {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid zone string "%s"`, match[6])
+ }
+ // Comparing the given time zone whether equals to current time zone,
+ // it converts it to UTC if they does not equal.
+ _, localOffset := time.Now().Zone()
+ // Comparing in seconds.
+ if (h*3600 + m*60 + s) != localOffset {
+ local = time.UTC
+ // UTC conversion.
+ operation := match[5]
+ if operation != "+" && operation != "-" {
+ operation = "-"
+ }
+ switch operation {
+ case "+":
+ if h > 0 {
+ hour -= h
+ }
+ if m > 0 {
+ min -= m
+ }
+ if s > 0 {
+ sec -= s
+ }
+ case "-":
+ if h > 0 {
+ hour += h
+ }
+ if m > 0 {
+ min += m
+ }
+ if s > 0 {
+ sec += s
+ }
+ }
+ }
+ }
+ }
+ if month <= 0 || day <= 0 {
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid time string "%s"`, str)
+ }
+ return NewFromTime(time.Date(year, time.Month(month), day, hour, min, sec, nsec, local)), nil
+}
+
+// ConvertZone converts time in string `strTime` from `fromZone` to `toZone`.
+// The parameter `fromZone` is unnecessary, it is current time zone in default.
+func ConvertZone(strTime string, toZone string, fromZone ...string) (*Time, error) {
+ t, err := StrToTime(strTime)
+ if err != nil {
+ return nil, err
+ }
+ var l *time.Location
+ if len(fromZone) > 0 {
+ if l, err = time.LoadLocation(fromZone[0]); err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for name "%s"`, fromZone[0])
+ return nil, err
+ } else {
+ t.Time = time.Date(t.Year(), time.Month(t.Month()), t.Day(), t.Hour(), t.Minute(), t.Time.Second(), t.Time.Nanosecond(), l)
+ }
+ }
+ if l, err = time.LoadLocation(toZone); err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for name "%s"`, toZone)
+ return nil, err
+ } else {
+ return t.ToLocation(l), nil
+ }
+}
+
+// StrToTimeFormat parses string `str` to *Time object with given format `format`.
+// The parameter `format` is like "Y-m-d H:i:s".
+func StrToTimeFormat(str string, format string) (*Time, error) {
+ return StrToTimeLayout(str, formatToStdLayout(format))
+}
+
+// StrToTimeLayout parses string `str` to *Time object with given format `layout`.
+// The parameter `layout` is in stdlib format like "2006-01-02 15:04:05".
+func StrToTimeLayout(str string, layout string) (*Time, error) {
+ if t, err := time.ParseInLocation(layout, str, time.Local); err == nil {
+ return NewFromTime(t), nil
+ } else {
+ return nil, gerror.WrapCodef(
+ gcode.CodeInvalidParameter, err,
+ `time.ParseInLocation failed for layout "%s" and value "%s"`,
+ layout, str,
+ )
+ }
+}
+
+// ParseTimeFromContent retrieves time information for content string, it then parses and returns it
+// as *Time object.
+// It returns the first time information if there are more than one time string in the content.
+// It only retrieves and parses the time information with given `format` if it's passed.
+func ParseTimeFromContent(content string, format ...string) *Time {
+ var (
+ err error
+ match []string
+ )
+ if len(format) > 0 {
+ match, err = gregex.MatchString(formatToRegexPattern(format[0]), content)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ if len(match) > 0 {
+ return NewFromStrFormat(match[0], format[0])
+ }
+ } else {
+ if match = timeRegex1.FindStringSubmatch(content); len(match) >= 1 {
+ return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
+ } else if match = timeRegex2.FindStringSubmatch(content); len(match) >= 1 {
+ return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
+ } else if match = timeRegex3.FindStringSubmatch(content); len(match) >= 1 {
+ return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
+ }
+ }
+ return nil
+}
+
+// ParseDuration parses a duration string.
+// A duration string is a possibly signed sequence of
+// decimal numbers, each with optional fraction and a unit suffix,
+// such as "300ms", "-1.5h", "1d" or "2h45m".
+// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h", "d".
+//
+// Very note that it supports unit "d" more than function time.ParseDuration.
+func ParseDuration(s string) (duration time.Duration, err error) {
+ var (
+ num int64
+ )
+ if utils.IsNumeric(s) {
+ num, err = strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.ParseInt failed for string "%s"`, s)
+ return 0, err
+ }
+ return time.Duration(num), nil
+ }
+ match, err := gregex.MatchString(`^([\-\d]+)[dD](.*)$`, s)
+ if err != nil {
+ return 0, err
+ }
+ if len(match) == 3 {
+ num, err = strconv.ParseInt(match[1], 10, 64)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `strconv.ParseInt failed for string "%s"`, match[1])
+ return 0, err
+ }
+ s = fmt.Sprintf(`%dh%s`, num*24, match[2])
+ duration, err = time.ParseDuration(s)
+ if err != nil {
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.ParseDuration failed for string "%s"`, s)
+ }
+ return
+ }
+ duration, err = time.ParseDuration(s)
+ err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.ParseDuration failed for string "%s"`, s)
+ return
+}
+
+// FuncCost calculates the cost time of function `f` in nanoseconds.
+func FuncCost(f func()) int64 {
+ t := TimestampNano()
+ f()
+ return TimestampNano() - t
+}
+
+// isTimestampStr checks and returns whether given string a timestamp string.
+func isTimestampStr(s string) bool {
+ length := len(s)
+ if length == 0 {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if s[i] < '0' || s[i] > '9' {
+ return false
+ }
+ }
+ return true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_format.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_format.go
new file mode 100644
index 000000000000..62aa5dbc31f0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_format.go
@@ -0,0 +1,280 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtime
+
+import (
+ "bytes"
+ "strconv"
+ "strings"
+
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+var (
+ // Refer: http://php.net/manual/en/function.date.php
+ formats = map[byte]string{
+ 'd': "02", // Day: Day of the month, 2 digits with leading zeros. Eg: 01 to 31.
+ 'D': "Mon", // Day: A textual representation of a day, three letters. Eg: Mon through Sun.
+ 'w': "Monday", // Day: Numeric representation of the day of the week. Eg: 0 (for Sunday) through 6 (for Saturday).
+ 'N': "Monday", // Day: ISO-8601 numeric representation of the day of the week. Eg: 1 (for Monday) through 7 (for Sunday).
+ 'j': "=j=02", // Day: Day of the month without leading zeros. Eg: 1 to 31.
+ 'S': "02", // Day: English ordinal suffix for the day of the month, 2 characters. Eg: st, nd, rd or th. Works well with j.
+ 'l': "Monday", // Day: A full textual representation of the day of the week. Eg: Sunday through Saturday.
+ 'z': "", // Day: The day of the year (starting from 0). Eg: 0 through 365.
+ 'W': "", // Week: ISO-8601 week number of year, weeks starting on Monday. Eg: 42 (the 42nd week in the year).
+ 'F': "January", // Month: A full textual representation of a month, such as January or March. Eg: January through December.
+ 'm': "01", // Month: Numeric representation of a month, with leading zeros. Eg: 01 through 12.
+ 'M': "Jan", // Month: A short textual representation of a month, three letters. Eg: Jan through Dec.
+ 'n': "1", // Month: Numeric representation of a month, without leading zeros. Eg: 1 through 12.
+ 't': "", // Month: Number of days in the given month. Eg: 28 through 31.
+ 'Y': "2006", // Year: A full numeric representation of a year, 4 digits. Eg: 1999 or 2003.
+ 'y': "06", // Year: A two digit representation of a year. Eg: 99 or 03.
+ 'a': "pm", // Time: Lowercase Ante meridiem and Post meridiem. Eg: am or pm.
+ 'A': "PM", // Time: Uppercase Ante meridiem and Post meridiem. Eg: AM or PM.
+ 'g': "3", // Time: 12-hour format of an hour without leading zeros. Eg: 1 through 12.
+ 'G': "=G=15", // Time: 24-hour format of an hour without leading zeros. Eg: 0 through 23.
+ 'h': "03", // Time: 12-hour format of an hour with leading zeros. Eg: 01 through 12.
+ 'H': "15", // Time: 24-hour format of an hour with leading zeros. Eg: 00 through 23.
+ 'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59.
+ 's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59.
+ 'u': "=u=.000", // Time: Milliseconds. Eg: 234, 678.
+ 'U': "", // Time: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
+ 'O': "-0700", // Zone: Difference to Greenwich time (GMT) in hours. Eg: +0200.
+ 'P': "-07:00", // Zone: Difference to Greenwich time (GMT) with colon between hours and minutes. Eg: +02:00.
+ 'T': "MST", // Zone: Timezone abbreviation. Eg: UTC, EST, MDT ...
+ 'c': "2006-01-02T15:04:05-07:00", // Format: ISO 8601 date. Eg: 2004-02-12T15:19:21+00:00.
+ 'r': "Mon, 02 Jan 06 15:04 MST", // Format: RFC 2822 formatted date. Eg: Thu, 21 Dec 2000 16:01:07 +0200.
+ }
+
+ // Week to number mapping.
+ weekMap = map[string]string{
+ "Sunday": "0",
+ "Monday": "1",
+ "Tuesday": "2",
+ "Wednesday": "3",
+ "Thursday": "4",
+ "Friday": "5",
+ "Saturday": "6",
+ }
+
+ // Day count of each month which is not in leap year.
+ dayOfMonth = []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}
+)
+
+// Format formats and returns the formatted result with custom `format`.
+func (t *Time) Format(format string) string {
+ if t == nil {
+ return ""
+ }
+ runes := []rune(format)
+ buffer := bytes.NewBuffer(nil)
+ for i := 0; i < len(runes); {
+ switch runes[i] {
+ case '\\':
+ if i < len(runes)-1 {
+ buffer.WriteRune(runes[i+1])
+ i += 2
+ continue
+ } else {
+ return buffer.String()
+ }
+ case 'W':
+ buffer.WriteString(strconv.Itoa(t.WeeksOfYear()))
+ case 'z':
+ buffer.WriteString(strconv.Itoa(t.DayOfYear()))
+ case 't':
+ buffer.WriteString(strconv.Itoa(t.DaysInMonth()))
+ case 'U':
+ buffer.WriteString(strconv.FormatInt(t.Unix(), 10))
+ default:
+ if runes[i] > 255 {
+ buffer.WriteRune(runes[i])
+ break
+ }
+ if f, ok := formats[byte(runes[i])]; ok {
+ result := t.Time.Format(f)
+ // Particular chars should be handled here.
+ switch runes[i] {
+ case 'j':
+ for _, s := range []string{"=j=0", "=j="} {
+ result = strings.Replace(result, s, "", -1)
+ }
+ buffer.WriteString(result)
+ case 'G':
+ for _, s := range []string{"=G=0", "=G="} {
+ result = strings.Replace(result, s, "", -1)
+ }
+ buffer.WriteString(result)
+ case 'u':
+ buffer.WriteString(strings.Replace(result, "=u=.", "", -1))
+ case 'w':
+ buffer.WriteString(weekMap[result])
+ case 'N':
+ buffer.WriteString(strings.Replace(weekMap[result], "0", "7", -1))
+ case 'S':
+ buffer.WriteString(formatMonthDaySuffixMap(result))
+ default:
+ buffer.WriteString(result)
+ }
+ } else {
+ buffer.WriteRune(runes[i])
+ }
+ }
+ i++
+ }
+ return buffer.String()
+}
+
+// FormatNew formats and returns a new Time object with given custom `format`.
+func (t *Time) FormatNew(format string) *Time {
+ if t == nil {
+ return nil
+ }
+ return NewFromStr(t.Format(format))
+}
+
+// FormatTo formats `t` with given custom `format`.
+func (t *Time) FormatTo(format string) *Time {
+ if t == nil {
+ return nil
+ }
+ t.Time = NewFromStr(t.Format(format)).Time
+ return t
+}
+
+// Layout formats the time with stdlib layout and returns the formatted result.
+func (t *Time) Layout(layout string) string {
+ if t == nil {
+ return ""
+ }
+ return t.Time.Format(layout)
+}
+
+// LayoutNew formats the time with stdlib layout and returns the new Time object.
+func (t *Time) LayoutNew(layout string) *Time {
+ if t == nil {
+ return nil
+ }
+ return NewFromStr(t.Layout(layout))
+}
+
+// LayoutTo formats `t` with stdlib layout.
+func (t *Time) LayoutTo(layout string) *Time {
+ if t == nil {
+ return nil
+ }
+ t.Time = NewFromStr(t.Layout(layout)).Time
+ return t
+}
+
+// IsLeapYear checks whether the time is leap year.
+func (t *Time) IsLeapYear() bool {
+ year := t.Year()
+ if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
+ return true
+ }
+ return false
+}
+
+// DayOfYear checks and returns the position of the day for the year.
+func (t *Time) DayOfYear() int {
+ var (
+ day = t.Day()
+ month = t.Month()
+ )
+ if t.IsLeapYear() {
+ if month > 2 {
+ return dayOfMonth[month-1] + day
+ }
+ return dayOfMonth[month-1] + day - 1
+ }
+ return dayOfMonth[month-1] + day - 1
+}
+
+// DaysInMonth returns the day count of current month.
+func (t *Time) DaysInMonth() int {
+ switch t.Month() {
+ case 1, 3, 5, 7, 8, 10, 12:
+ return 31
+ case 4, 6, 9, 11:
+ return 30
+ }
+ if t.IsLeapYear() {
+ return 29
+ }
+ return 28
+}
+
+// WeeksOfYear returns the point of current week for the year.
+func (t *Time) WeeksOfYear() int {
+ _, week := t.ISOWeek()
+ return week
+}
+
+// formatToStdLayout converts custom format to stdlib layout.
+func formatToStdLayout(format string) string {
+ b := bytes.NewBuffer(nil)
+ for i := 0; i < len(format); {
+ switch format[i] {
+ case '\\':
+ if i < len(format)-1 {
+ b.WriteByte(format[i+1])
+ i += 2
+ continue
+ } else {
+ return b.String()
+ }
+
+ default:
+ if f, ok := formats[format[i]]; ok {
+ // Handle particular chars.
+ switch format[i] {
+ case 'j':
+ b.WriteString("2")
+ case 'G':
+ b.WriteString("15")
+ case 'u':
+ if i > 0 && format[i-1] == '.' {
+ b.WriteString("000")
+ } else {
+ b.WriteString(".000")
+ }
+
+ default:
+ b.WriteString(f)
+ }
+ } else {
+ b.WriteByte(format[i])
+ }
+ i++
+ }
+ }
+ return b.String()
+}
+
+// formatToRegexPattern converts the custom format to its corresponding regular expression.
+func formatToRegexPattern(format string) string {
+ s := gregex.Quote(formatToStdLayout(format))
+ s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s)
+ s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s)
+ s, _ = gregex.ReplaceString(`\s+`, `\s+`, s)
+ return s
+}
+
+// formatMonthDaySuffixMap returns the short english word for current day.
+func formatMonthDaySuffixMap(day string) string {
+ switch day {
+ case "01", "21", "31":
+ return "st"
+ case "02", "22":
+ return "nd"
+ case "03", "23":
+ return "rd"
+ default:
+ return "th"
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_sql.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_sql.go
new file mode 100644
index 000000000000..e3c79a81b1b6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_sql.go
@@ -0,0 +1,28 @@
+package gtime
+
+import (
+ "database/sql/driver"
+)
+
+// Scan implements interface used by Scan in package database/sql for Scanning value
+// from database to local golang variable.
+func (t *Time) Scan(value interface{}) error {
+ if t == nil {
+ return nil
+ }
+ newTime := New(value)
+ *t = *newTime
+ return nil
+}
+
+// Value is the interface providing the Value method for package database/sql/driver
+// for retrieving value from golang variable to database.
+func (t *Time) Value() (driver.Value, error) {
+ if t == nil {
+ return nil, nil
+ }
+ if t.IsZero() {
+ return nil, nil
+ }
+ return t.Time, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time.go
new file mode 100644
index 000000000000..2275107f82c3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time.go
@@ -0,0 +1,481 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtime
+
+import (
+ "bytes"
+ "strconv"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Time is a wrapper for time.Time for additional features.
+type Time struct {
+ wrapper
+}
+
+// iUnixNano is an interface definition commonly for custom time.Time wrapper.
+type iUnixNano interface {
+ UnixNano() int64
+}
+
+// New creates and returns a Time object with given parameter.
+// The optional parameter can be type of: time.Time/*time.Time, string or integer.
+func New(param ...interface{}) *Time {
+ if len(param) > 0 {
+ switch r := param[0].(type) {
+ case time.Time:
+ return NewFromTime(r)
+ case *time.Time:
+ return NewFromTime(*r)
+
+ case Time:
+ return &r
+
+ case *Time:
+ return r
+
+ case string:
+ if len(param) > 1 {
+ switch t := param[1].(type) {
+ case string:
+ return NewFromStrFormat(r, t)
+ case []byte:
+ return NewFromStrFormat(r, string(t))
+ }
+ }
+ return NewFromStr(r)
+
+ case []byte:
+ if len(param) > 1 {
+ switch t := param[1].(type) {
+ case string:
+ return NewFromStrFormat(string(r), t)
+ case []byte:
+ return NewFromStrFormat(string(r), string(t))
+ }
+ }
+ return NewFromStr(string(r))
+
+ case int:
+ return NewFromTimeStamp(int64(r))
+
+ case int64:
+ return NewFromTimeStamp(r)
+
+ default:
+ if v, ok := r.(iUnixNano); ok {
+ return NewFromTimeStamp(v.UnixNano())
+ }
+ }
+ }
+ return &Time{
+ wrapper{time.Time{}},
+ }
+}
+
+// Now creates and returns a time object of now.
+func Now() *Time {
+ return &Time{
+ wrapper{time.Now()},
+ }
+}
+
+// NewFromTime creates and returns a Time object with given time.Time object.
+func NewFromTime(t time.Time) *Time {
+ return &Time{
+ wrapper{t},
+ }
+}
+
+// NewFromStr creates and returns a Time object with given string.
+// Note that it returns nil if there's error occurs.
+func NewFromStr(str string) *Time {
+ if t, err := StrToTime(str); err == nil {
+ return t
+ }
+ return nil
+}
+
+// NewFromStrFormat creates and returns a Time object with given string and
+// custom format like: Y-m-d H:i:s.
+// Note that it returns nil if there's error occurs.
+func NewFromStrFormat(str string, format string) *Time {
+ if t, err := StrToTimeFormat(str, format); err == nil {
+ return t
+ }
+ return nil
+}
+
+// NewFromStrLayout creates and returns a Time object with given string and
+// stdlib layout like: 2006-01-02 15:04:05.
+// Note that it returns nil if there's error occurs.
+func NewFromStrLayout(str string, layout string) *Time {
+ if t, err := StrToTimeLayout(str, layout); err == nil {
+ return t
+ }
+ return nil
+}
+
+// NewFromTimeStamp creates and returns a Time object with given timestamp,
+// which can be in seconds to nanoseconds.
+// Eg: 1600443866 and 1600443866199266000 are both considered as valid timestamp number.
+func NewFromTimeStamp(timestamp int64) *Time {
+ if timestamp == 0 {
+ return &Time{}
+ }
+ var sec, nano int64
+ if timestamp > 1e9 {
+ for timestamp < 1e18 {
+ timestamp *= 10
+ }
+ sec = timestamp / 1e9
+ nano = timestamp % 1e9
+ } else {
+ sec = timestamp
+ }
+ return &Time{
+ wrapper{time.Unix(sec, nano)},
+ }
+}
+
+// Timestamp returns the timestamp in seconds.
+func (t *Time) Timestamp() int64 {
+ return t.UnixNano() / 1e9
+}
+
+// TimestampMilli returns the timestamp in milliseconds.
+func (t *Time) TimestampMilli() int64 {
+ return t.UnixNano() / 1e6
+}
+
+// TimestampMicro returns the timestamp in microseconds.
+func (t *Time) TimestampMicro() int64 {
+ return t.UnixNano() / 1e3
+}
+
+// TimestampNano returns the timestamp in nanoseconds.
+func (t *Time) TimestampNano() int64 {
+ return t.UnixNano()
+}
+
+// TimestampStr is a convenience method which retrieves and returns
+// the timestamp in seconds as string.
+func (t *Time) TimestampStr() string {
+ return strconv.FormatInt(t.Timestamp(), 10)
+}
+
+// TimestampMilliStr is a convenience method which retrieves and returns
+// the timestamp in milliseconds as string.
+func (t *Time) TimestampMilliStr() string {
+ return strconv.FormatInt(t.TimestampMilli(), 10)
+}
+
+// TimestampMicroStr is a convenience method which retrieves and returns
+// the timestamp in microseconds as string.
+func (t *Time) TimestampMicroStr() string {
+ return strconv.FormatInt(t.TimestampMicro(), 10)
+}
+
+// TimestampNanoStr is a convenience method which retrieves and returns
+// the timestamp in nanoseconds as string.
+func (t *Time) TimestampNanoStr() string {
+ return strconv.FormatInt(t.TimestampNano(), 10)
+}
+
+// Month returns the month of the year specified by t.
+func (t *Time) Month() int {
+ return int(t.Time.Month())
+}
+
+// Second returns the second offset within the minute specified by t,
+// in the range [0, 59].
+func (t *Time) Second() int {
+ return t.Time.Second()
+}
+
+// Millisecond returns the millisecond offset within the second specified by t,
+// in the range [0, 999].
+func (t *Time) Millisecond() int {
+ return t.Time.Nanosecond() / 1e6
+}
+
+// Microsecond returns the microsecond offset within the second specified by t,
+// in the range [0, 999999].
+func (t *Time) Microsecond() int {
+ return t.Time.Nanosecond() / 1e3
+}
+
+// Nanosecond returns the nanosecond offset within the second specified by t,
+// in the range [0, 999999999].
+func (t *Time) Nanosecond() int {
+ return t.Time.Nanosecond()
+}
+
+// String returns current time object as string.
+func (t *Time) String() string {
+ if t == nil {
+ return ""
+ }
+ if t.IsZero() {
+ return ""
+ }
+ return t.wrapper.String()
+}
+
+// IsZero reports whether t represents the zero time instant,
+// January 1, year 1, 00:00:00 UTC.
+func (t *Time) IsZero() bool {
+ if t == nil {
+ return true
+ }
+ return t.Time.IsZero()
+}
+
+// Clone returns a new Time object which is a clone of current time object.
+func (t *Time) Clone() *Time {
+ return New(t.Time)
+}
+
+// Add adds the duration to current time.
+func (t *Time) Add(d time.Duration) *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.Add(d)
+ return newTime
+}
+
+// AddStr parses the given duration as string and adds it to current time.
+func (t *Time) AddStr(duration string) (*Time, error) {
+ if d, err := time.ParseDuration(duration); err != nil {
+ err = gerror.Wrapf(err, `time.ParseDuration failed for string "%s"`, duration)
+ return nil, err
+ } else {
+ return t.Add(d), nil
+ }
+}
+
+// UTC converts current time to UTC timezone.
+func (t *Time) UTC() *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.UTC()
+ return newTime
+}
+
+// ISO8601 formats the time as ISO8601 and returns it as string.
+func (t *Time) ISO8601() string {
+ return t.Layout("2006-01-02T15:04:05-07:00")
+}
+
+// RFC822 formats the time as RFC822 and returns it as string.
+func (t *Time) RFC822() string {
+ return t.Layout("Mon, 02 Jan 06 15:04 MST")
+}
+
+// AddDate adds year, month and day to the time.
+func (t *Time) AddDate(years int, months int, days int) *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.AddDate(years, months, days)
+ return newTime
+}
+
+// Round returns the result of rounding t to the nearest multiple of d (since the zero time).
+// The rounding behavior for halfway values is to round up.
+// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged.
+//
+// Round operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// time. Thus, Round(Hour) may return a time with a non-zero
+// minute, depending on the time's Location.
+func (t *Time) Round(d time.Duration) *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.Round(d)
+ return newTime
+}
+
+// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
+// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged.
+//
+// Truncate operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// time. Thus, Truncate(Hour) may return a time with a non-zero
+// minute, depending on the time's Location.
+func (t *Time) Truncate(d time.Duration) *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.Truncate(d)
+ return newTime
+}
+
+// Equal reports whether t and u represent the same time instant.
+// Two times can be equal even if they are in different locations.
+// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
+// See the documentation on the Time type for the pitfalls of using == with
+// Time values; most code should use Equal instead.
+func (t *Time) Equal(u *Time) bool {
+ return t.Time.Equal(u.Time)
+}
+
+// Before reports whether the time instant t is before u.
+func (t *Time) Before(u *Time) bool {
+ return t.Time.Before(u.Time)
+}
+
+// After reports whether the time instant t is after u.
+func (t *Time) After(u *Time) bool {
+ return t.Time.After(u.Time)
+}
+
+// Sub returns the duration t-u. If the result exceeds the maximum (or minimum)
+// value that can be stored in a Duration, the maximum (or minimum) duration
+// will be returned.
+// To compute t-d for a duration d, use t.Add(-d).
+func (t *Time) Sub(u *Time) time.Duration {
+ return t.Time.Sub(u.Time)
+}
+
+// StartOfMinute clones and returns a new time of which the seconds is set to 0.
+func (t *Time) StartOfMinute() *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.Truncate(time.Minute)
+ return newTime
+}
+
+// StartOfHour clones and returns a new time of which the hour, minutes and seconds are set to 0.
+func (t *Time) StartOfHour() *Time {
+ y, m, d := t.Date()
+ newTime := t.Clone()
+ newTime.Time = time.Date(y, m, d, newTime.Time.Hour(), 0, 0, 0, newTime.Time.Location())
+ return newTime
+}
+
+// StartOfDay clones and returns a new time which is the start of day, its time is set to 00:00:00.
+func (t *Time) StartOfDay() *Time {
+ y, m, d := t.Date()
+ newTime := t.Clone()
+ newTime.Time = time.Date(y, m, d, 0, 0, 0, 0, newTime.Time.Location())
+ return newTime
+}
+
+// StartOfWeek clones and returns a new time which is the first day of week and its time is set to
+// 00:00:00.
+func (t *Time) StartOfWeek() *Time {
+ weekday := int(t.Weekday())
+ return t.StartOfDay().AddDate(0, 0, -weekday)
+}
+
+// StartOfMonth clones and returns a new time which is the first day of the month and its is set to
+// 00:00:00
+func (t *Time) StartOfMonth() *Time {
+ y, m, _ := t.Date()
+ newTime := t.Clone()
+ newTime.Time = time.Date(y, m, 1, 0, 0, 0, 0, newTime.Time.Location())
+ return newTime
+}
+
+// StartOfQuarter clones and returns a new time which is the first day of the quarter and its time is set
+// to 00:00:00.
+func (t *Time) StartOfQuarter() *Time {
+ month := t.StartOfMonth()
+ offset := (int(month.Month()) - 1) % 3
+ return month.AddDate(0, -offset, 0)
+}
+
+// StartOfHalf clones and returns a new time which is the first day of the half year and its time is set
+// to 00:00:00.
+func (t *Time) StartOfHalf() *Time {
+ month := t.StartOfMonth()
+ offset := (int(month.Month()) - 1) % 6
+ return month.AddDate(0, -offset, 0)
+}
+
+// StartOfYear clones and returns a new time which is the first day of the year and its time is set to
+// 00:00:00.
+func (t *Time) StartOfYear() *Time {
+ y, _, _ := t.Date()
+ newTime := t.Clone()
+ newTime.Time = time.Date(y, time.January, 1, 0, 0, 0, 0, newTime.Time.Location())
+ return newTime
+}
+
+// EndOfMinute clones and returns a new time of which the seconds is set to 59.
+func (t *Time) EndOfMinute() *Time {
+ return t.StartOfMinute().Add(time.Minute - time.Nanosecond)
+}
+
+// EndOfHour clones and returns a new time of which the minutes and seconds are both set to 59.
+func (t *Time) EndOfHour() *Time {
+ return t.StartOfHour().Add(time.Hour - time.Nanosecond)
+}
+
+// EndOfDay clones and returns a new time which is the end of day the and its time is set to 23:59:59.
+func (t *Time) EndOfDay() *Time {
+ y, m, d := t.Date()
+ newTime := t.Clone()
+ newTime.Time = time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), newTime.Time.Location())
+ return newTime
+}
+
+// EndOfWeek clones and returns a new time which is the end of week and its time is set to 23:59:59.
+func (t *Time) EndOfWeek() *Time {
+ return t.StartOfWeek().AddDate(0, 0, 7).Add(-time.Nanosecond)
+}
+
+// EndOfMonth clones and returns a new time which is the end of the month and its time is set to 23:59:59.
+func (t *Time) EndOfMonth() *Time {
+ return t.StartOfMonth().AddDate(0, 1, 0).Add(-time.Nanosecond)
+}
+
+// EndOfQuarter clones and returns a new time which is end of the quarter and its time is set to 23:59:59.
+func (t *Time) EndOfQuarter() *Time {
+ return t.StartOfQuarter().AddDate(0, 3, 0).Add(-time.Nanosecond)
+}
+
+// EndOfHalf clones and returns a new time which is the end of the half year and its time is set to 23:59:59.
+func (t *Time) EndOfHalf() *Time {
+ return t.StartOfHalf().AddDate(0, 6, 0).Add(-time.Nanosecond)
+}
+
+// EndOfYear clones and returns a new time which is the end of the year and its time is set to 23:59:59.
+func (t *Time) EndOfYear() *Time {
+ return t.StartOfYear().AddDate(1, 0, 0).Add(-time.Nanosecond)
+}
+
+// MarshalJSON implements the interface MarshalJSON for json.Marshal.
+// Note that, DO NOT use `(t *Time) MarshalJSON() ([]byte, error)` as it looses interface
+// implement of `MarshalJSON` for struct of Time.
+func (t Time) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + t.String() + `"`), nil
+}
+
+// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+func (t *Time) UnmarshalJSON(b []byte) error {
+ if len(b) == 0 {
+ t.Time = time.Time{}
+ return nil
+ }
+ newTime, err := StrToTime(string(bytes.Trim(b, `"`)))
+ if err != nil {
+ return err
+ }
+ t.Time = newTime.Time
+ return nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// Note that it overwrites the same implementer of `time.Time`.
+func (t *Time) UnmarshalText(data []byte) error {
+ vTime := New(data)
+ if vTime != nil {
+ *t = *vTime
+ return nil
+ }
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid time value: %s`, data)
+}
+
+// NoValidation marks this struct object will not be validated by package gvalid.
+func (t *Time) NoValidation() {}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time_wrapper.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time_wrapper.go
new file mode 100644
index 000000000000..28f8b9bf07a1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time_wrapper.go
@@ -0,0 +1,29 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtime
+
+import (
+ "time"
+)
+
+// wrapper is a wrapper for stdlib struct time.Time.
+// It's used for overwriting some functions of time.Time, for example: String.
+type wrapper struct {
+ time.Time
+}
+
+// String overwrites the String function of time.Time.
+func (t wrapper) String() string {
+ if t.IsZero() {
+ return ""
+ }
+ if t.Year() == 0 {
+ // Only time.
+ return t.Format("15:04:05")
+ }
+ return t.Format("2006-01-02 15:04:05")
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time_zone.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time_zone.go
new file mode 100644
index 000000000000..b67e8e8bd1ae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtime/gtime_time_zone.go
@@ -0,0 +1,64 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtime
+
+import (
+ "sync"
+ "time"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+var (
+ // locationMap is time zone name to its location object.
+ // Time zone name is like: Asia/Shanghai.
+ locationMap = make(map[string]*time.Location)
+
+ // locationMu is used for concurrent safety for `locationMap`.
+ locationMu = sync.RWMutex{}
+)
+
+// ToLocation converts current time to specified location.
+func (t *Time) ToLocation(location *time.Location) *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.In(location)
+ return newTime
+}
+
+// ToZone converts current time to specified zone like: Asia/Shanghai.
+func (t *Time) ToZone(zone string) (*Time, error) {
+ if location, err := t.getLocationByZoneName(zone); err == nil {
+ return t.ToLocation(location), nil
+ } else {
+ return nil, err
+ }
+}
+
+func (t *Time) getLocationByZoneName(name string) (location *time.Location, err error) {
+ locationMu.RLock()
+ location = locationMap[name]
+ locationMu.RUnlock()
+ if location == nil {
+ location, err = time.LoadLocation(name)
+ if err != nil {
+ err = gerror.Wrapf(err, `time.LoadLocation failed for name "%s"`, name)
+ }
+ if location != nil {
+ locationMu.Lock()
+ locationMap[name] = location
+ locationMu.Unlock()
+ }
+ }
+ return
+}
+
+// Local converts the time to local timezone.
+func (t *Time) Local() *Time {
+ newTime := t.Clone()
+ newTime.Time = newTime.Time.Local()
+ return newTime
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer.go
new file mode 100644
index 000000000000..bbe226d5e3bd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer.go
@@ -0,0 +1,158 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtimer implements timer for interval/delayed jobs running and management.
+//
+// This package is designed for management for millions of timing jobs. The differences
+// between gtimer and gcron are as follows:
+// 1. package gcron is implemented based on package gtimer.
+// 2. gtimer is designed for high performance and for millions of timing jobs.
+// 3. gcron supports configuration pattern grammar like linux crontab, which is more manually
+// readable.
+// 4. gtimer's benchmark OP is measured in nanoseconds, and gcron's benchmark OP is measured
+// in microseconds.
+//
+// ALSO VERY NOTE the common delay of the timer: https://github.com/golang/go/issues/14410
+package gtimer
+
+import (
+ "context"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/internal/command"
+)
+
+// Timer is the timer manager, which uses ticks to calculate the timing interval.
+type Timer struct {
+ mu sync.RWMutex
+ queue *priorityQueue // queue is a priority queue based on heap structure.
+ status *gtype.Int // status is the current timer status.
+ ticks *gtype.Int64 // ticks is the proceeded interval number by the timer.
+ options TimerOptions // timer options is used for timer configuration.
+}
+
+// TimerOptions is the configuration object for Timer.
+type TimerOptions struct {
+ Interval time.Duration // Interval is the interval escaped of the timer.
+}
+
+const (
+ StatusReady = 0 // Job or Timer is ready for running.
+ StatusRunning = 1 // Job or Timer is already running.
+ StatusStopped = 2 // Job or Timer is stopped.
+ StatusClosed = -1 // Job or Timer is closed and waiting to be deleted.
+ panicExit = "exit" // panicExit is used for custom job exit with panic.
+ defaultTimerInterval = "100" // defaultTimerInterval is the default timer interval in milliseconds.
+ commandEnvKeyForInterval = "gf.gtimer.interval" // commandEnvKeyForInterval is the key for command argument or environment configuring default interval duration for timer.
+)
+
+var (
+ defaultInterval = getDefaultInterval()
+ defaultTimer = New()
+)
+
+func getDefaultInterval() time.Duration {
+ n, err := strconv.Atoi(command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval))
+ if err != nil {
+ panic(err)
+ }
+ return time.Duration(n) * time.Millisecond
+}
+
+// DefaultOptions creates and returns a default options object for Timer creation.
+func DefaultOptions() TimerOptions {
+ return TimerOptions{
+ Interval: defaultInterval,
+ }
+}
+
+// SetTimeout runs the job once after duration of `delay`.
+// It is like the one in javascript.
+func SetTimeout(ctx context.Context, delay time.Duration, job JobFunc) {
+ AddOnce(ctx, delay, job)
+}
+
+// SetInterval runs the job every duration of `delay`.
+// It is like the one in javascript.
+func SetInterval(ctx context.Context, interval time.Duration, job JobFunc) {
+ Add(ctx, interval, job)
+}
+
+// Add adds a timing job to the default timer, which runs in interval of `interval`.
+func Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
+ return defaultTimer.Add(ctx, interval, job)
+}
+
+// AddEntry adds a timing job to the default timer with detailed parameters.
+//
+// The parameter `interval` specifies the running interval of the job.
+//
+// The parameter `singleton` specifies whether the job running in singleton mode.
+// There's only one of the same job is allowed running when its a singleton mode job.
+//
+// The parameter `times` specifies limit for the job running times, which means the job
+// exits if its run times exceeds the `times`.
+//
+// The parameter `status` specifies the job status when it's firstly added to the timer.
+func AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {
+ return defaultTimer.AddEntry(ctx, interval, job, isSingleton, times, status)
+}
+
+// AddSingleton is a convenience function for add singleton mode job.
+func AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
+ return defaultTimer.AddSingleton(ctx, interval, job)
+}
+
+// AddOnce is a convenience function for adding a job which only runs once and then exits.
+func AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
+ return defaultTimer.AddOnce(ctx, interval, job)
+}
+
+// AddTimes is a convenience function for adding a job which is limited running times.
+func AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {
+ return defaultTimer.AddTimes(ctx, interval, times, job)
+}
+
+// DelayAdd adds a timing job after delay of `interval` duration.
+// Also see Add.
+func DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
+ defaultTimer.DelayAdd(ctx, delay, interval, job)
+}
+
+// DelayAddEntry adds a timing job after delay of `interval` duration.
+// Also see AddEntry.
+func DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {
+ defaultTimer.DelayAddEntry(ctx, delay, interval, job, isSingleton, times, status)
+}
+
+// DelayAddSingleton adds a timing job after delay of `interval` duration.
+// Also see AddSingleton.
+func DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
+ defaultTimer.DelayAddSingleton(ctx, delay, interval, job)
+}
+
+// DelayAddOnce adds a timing job after delay of `interval` duration.
+// Also see AddOnce.
+func DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
+ defaultTimer.DelayAddOnce(ctx, delay, interval, job)
+}
+
+// DelayAddTimes adds a timing job after delay of `interval` duration.
+// Also see AddTimes.
+func DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {
+ defaultTimer.DelayAddTimes(ctx, delay, interval, times, job)
+}
+
+// Exit is used in timing job internally, which exits and marks it closed from timer.
+// The timing job will be automatically removed from timer later. It uses "panic-recover"
+// mechanism internally implementing this feature, which is designed for simplification
+// and convenience.
+func Exit() {
+ panic(panicExit)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_entry.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_entry.go
new file mode 100644
index 000000000000..c057e9951eca
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_entry.go
@@ -0,0 +1,146 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtimer
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Entry is the timing job.
+type Entry struct {
+ job JobFunc // The job function.
+ ctx context.Context // The context for the job, for READ ONLY.
+ timer *Timer // Belonged timer.
+ ticks int64 // The job runs every tick.
+ times *gtype.Int // Limit running times.
+ status *gtype.Int // Job status.
+ isSingleton *gtype.Bool // Singleton mode.
+ nextTicks *gtype.Int64 // Next run ticks of the job.
+ infinite *gtype.Bool // No times limit.
+}
+
+// JobFunc is the job function.
+type JobFunc = func(ctx context.Context)
+
+// Status returns the status of the job.
+func (entry *Entry) Status() int {
+ return entry.status.Val()
+}
+
+// Run runs the timer job asynchronously.
+func (entry *Entry) Run() {
+ if !entry.infinite.Val() {
+ leftRunningTimes := entry.times.Add(-1)
+ // It checks its running times exceeding.
+ if leftRunningTimes < 0 {
+ entry.status.Set(StatusClosed)
+ return
+ }
+ }
+ go func() {
+ defer func() {
+ if exception := recover(); exception != nil {
+ if exception != panicExit {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ panic(v)
+ } else {
+ panic(gerror.Newf(`exception recovered: %+v`, exception))
+ }
+ } else {
+ entry.Close()
+ return
+ }
+ }
+ if entry.Status() == StatusRunning {
+ entry.SetStatus(StatusReady)
+ }
+ }()
+ entry.job(entry.ctx)
+ }()
+}
+
+// doCheckAndRunByTicks checks the if job can run in given timer ticks,
+// it runs asynchronously if the given `currentTimerTicks` meets or else
+// it increments its ticks and waits for next running check.
+func (entry *Entry) doCheckAndRunByTicks(currentTimerTicks int64) {
+ // Ticks check.
+ if currentTimerTicks < entry.nextTicks.Val() {
+ return
+ }
+ entry.nextTicks.Set(currentTimerTicks + entry.ticks)
+ // Perform job checking.
+ switch entry.status.Val() {
+ case StatusRunning:
+ if entry.IsSingleton() {
+ return
+ }
+ case StatusReady:
+ if !entry.status.Cas(StatusReady, StatusRunning) {
+ return
+ }
+ case StatusStopped:
+ return
+ case StatusClosed:
+ return
+ }
+ // Perform job running.
+ entry.Run()
+}
+
+// SetStatus custom sets the status for the job.
+func (entry *Entry) SetStatus(status int) int {
+ return entry.status.Set(status)
+}
+
+// Start starts the job.
+func (entry *Entry) Start() {
+ entry.status.Set(StatusReady)
+}
+
+// Stop stops the job.
+func (entry *Entry) Stop() {
+ entry.status.Set(StatusStopped)
+}
+
+// Close closes the job, and then it will be removed from the timer.
+func (entry *Entry) Close() {
+ entry.status.Set(StatusClosed)
+}
+
+// Reset resets the job, which resets its ticks for next running.
+func (entry *Entry) Reset() {
+ entry.nextTicks.Set(entry.timer.ticks.Val() + entry.ticks)
+}
+
+// IsSingleton checks and returns whether the job in singleton mode.
+func (entry *Entry) IsSingleton() bool {
+ return entry.isSingleton.Val()
+}
+
+// SetSingleton sets the job singleton mode.
+func (entry *Entry) SetSingleton(enabled bool) {
+ entry.isSingleton.Set(enabled)
+}
+
+// Job returns the job function of this job.
+func (entry *Entry) Job() JobFunc {
+ return entry.job
+}
+
+// Ctx returns the initialized context of this job.
+func (entry *Entry) Ctx() context.Context {
+ return entry.ctx
+}
+
+// SetTimes sets the limit running times for the job.
+func (entry *Entry) SetTimes(times int) {
+ entry.times.Set(times)
+ entry.infinite.Set(false)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_queue.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_queue.go
new file mode 100644
index 000000000000..08fdd46f3bb1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_queue.go
@@ -0,0 +1,84 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtimer
+
+import (
+ "container/heap"
+ "math"
+ "sync"
+
+ "github.com/gogf/gf/v2/container/gtype"
+)
+
+// priorityQueue is an abstract data type similar to a regular queue or stack data structure in which
+// each element additionally has a "priority" associated with it. In a priority queue, an element with
+// high priority is served before an element with low priority.
+// priorityQueue is based on heap structure.
+type priorityQueue struct {
+ mu sync.Mutex
+ heap *priorityQueueHeap // the underlying queue items manager using heap.
+ nextPriority *gtype.Int64 // nextPriority stores the next priority value of the heap, which is used to check if necessary to call the Pop of heap by Timer.
+}
+
+// priorityQueueHeap is a heap manager, of which the underlying `array` is a array implementing a heap structure.
+type priorityQueueHeap struct {
+ array []priorityQueueItem
+}
+
+// priorityQueueItem stores the queue item which has a `priority` attribute to sort itself in heap.
+type priorityQueueItem struct {
+ value interface{}
+ priority int64
+}
+
+// newPriorityQueue creates and returns a priority queue.
+func newPriorityQueue() *priorityQueue {
+ queue := &priorityQueue{
+ heap: &priorityQueueHeap{array: make([]priorityQueueItem, 0)},
+ nextPriority: gtype.NewInt64(math.MaxInt64),
+ }
+ heap.Init(queue.heap)
+ return queue
+}
+
+// NextPriority retrieves and returns the minimum and the most priority value of the queue.
+func (q *priorityQueue) NextPriority() int64 {
+ return q.nextPriority.Val()
+}
+
+// Push pushes a value to the queue.
+// The `priority` specifies the priority of the value.
+// The lesser the `priority` value the higher priority of the `value`.
+func (q *priorityQueue) Push(value interface{}, priority int64) {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+ heap.Push(q.heap, priorityQueueItem{
+ value: value,
+ priority: priority,
+ })
+ // Update the minimum priority using atomic operation.
+ nextPriority := q.nextPriority.Val()
+ if priority >= nextPriority {
+ return
+ }
+ q.nextPriority.Set(priority)
+}
+
+// Pop retrieves, removes and returns the most high priority value from the queue.
+func (q *priorityQueue) Pop() interface{} {
+ q.mu.Lock()
+ defer q.mu.Unlock()
+ if v := heap.Pop(q.heap); v != nil {
+ var nextPriority int64 = math.MaxInt64
+ if len(q.heap.array) > 0 {
+ nextPriority = q.heap.array[0].priority
+ }
+ q.nextPriority.Set(nextPriority)
+ return v.(priorityQueueItem).value
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_queue_heap.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_queue_heap.go
new file mode 100644
index 000000000000..c4b2f5dbe3a8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_queue_heap.go
@@ -0,0 +1,42 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtimer
+
+// Len is used to implement the interface of sort.Interface.
+func (h *priorityQueueHeap) Len() int {
+ return len(h.array)
+}
+
+// Less is used to implement the interface of sort.Interface.
+// The least one is placed to the top of the heap.
+func (h *priorityQueueHeap) Less(i, j int) bool {
+ return h.array[i].priority < h.array[j].priority
+}
+
+// Swap is used to implement the interface of sort.Interface.
+func (h *priorityQueueHeap) Swap(i, j int) {
+ if len(h.array) == 0 {
+ return
+ }
+ h.array[i], h.array[j] = h.array[j], h.array[i]
+}
+
+// Push pushes an item to the heap.
+func (h *priorityQueueHeap) Push(x interface{}) {
+ h.array = append(h.array, x.(priorityQueueItem))
+}
+
+// Pop retrieves, removes and returns the most high priority item from the heap.
+func (h *priorityQueueHeap) Pop() interface{} {
+ length := len(h.array)
+ if length == 0 {
+ return nil
+ }
+ item := h.array[length-1]
+ h.array = h.array[0 : length-1]
+ return item
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_timer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_timer.go
new file mode 100644
index 000000000000..88859f9355e5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_timer.go
@@ -0,0 +1,197 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtimer
+
+import (
+ "context"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+)
+
+func New(options ...TimerOptions) *Timer {
+ t := &Timer{
+ queue: newPriorityQueue(),
+ status: gtype.NewInt(StatusRunning),
+ ticks: gtype.NewInt64(),
+ }
+ if len(options) > 0 {
+ t.options = options[0]
+ } else {
+ t.options = DefaultOptions()
+ }
+ go t.loop()
+ return t
+}
+
+// Add adds a timing job to the timer, which runs in interval of `interval`.
+func (t *Timer) Add(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
+ return t.createEntry(createEntryInput{
+ Ctx: ctx,
+ Interval: interval,
+ Job: job,
+ IsSingleton: false,
+ Times: -1,
+ Status: StatusReady,
+ })
+}
+
+// AddEntry adds a timing job to the timer with detailed parameters.
+//
+// The parameter `interval` specifies the running interval of the job.
+//
+// The parameter `singleton` specifies whether the job running in singleton mode.
+// There's only one of the same job is allowed running when it's a singleton mode job.
+//
+// The parameter `times` specifies limit for the job running times, which means the job
+// exits if its run times exceeds the `times`.
+//
+// The parameter `status` specifies the job status when it's firstly added to the timer.
+func (t *Timer) AddEntry(ctx context.Context, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) *Entry {
+ return t.createEntry(createEntryInput{
+ Ctx: ctx,
+ Interval: interval,
+ Job: job,
+ IsSingleton: isSingleton,
+ Times: times,
+ Status: status,
+ })
+}
+
+// AddSingleton is a convenience function for add singleton mode job.
+func (t *Timer) AddSingleton(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
+ return t.createEntry(createEntryInput{
+ Ctx: ctx,
+ Interval: interval,
+ Job: job,
+ IsSingleton: true,
+ Times: -1,
+ Status: StatusReady,
+ })
+}
+
+// AddOnce is a convenience function for adding a job which only runs once and then exits.
+func (t *Timer) AddOnce(ctx context.Context, interval time.Duration, job JobFunc) *Entry {
+ return t.createEntry(createEntryInput{
+ Ctx: ctx,
+ Interval: interval,
+ Job: job,
+ IsSingleton: true,
+ Times: 1,
+ Status: StatusReady,
+ })
+}
+
+// AddTimes is a convenience function for adding a job which is limited running times.
+func (t *Timer) AddTimes(ctx context.Context, interval time.Duration, times int, job JobFunc) *Entry {
+ return t.createEntry(createEntryInput{
+ Ctx: ctx,
+ Interval: interval,
+ Job: job,
+ IsSingleton: true,
+ Times: times,
+ Status: StatusReady,
+ })
+}
+
+// DelayAdd adds a timing job after delay of `interval` duration.
+// Also see Add.
+func (t *Timer) DelayAdd(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
+ t.AddOnce(ctx, delay, func(ctx context.Context) {
+ t.Add(ctx, interval, job)
+ })
+}
+
+// DelayAddEntry adds a timing job after delay of `interval` duration.
+// Also see AddEntry.
+func (t *Timer) DelayAddEntry(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc, isSingleton bool, times int, status int) {
+ t.AddOnce(ctx, delay, func(ctx context.Context) {
+ t.AddEntry(ctx, interval, job, isSingleton, times, status)
+ })
+}
+
+// DelayAddSingleton adds a timing job after delay of `interval` duration.
+// Also see AddSingleton.
+func (t *Timer) DelayAddSingleton(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
+ t.AddOnce(ctx, delay, func(ctx context.Context) {
+ t.AddSingleton(ctx, interval, job)
+ })
+}
+
+// DelayAddOnce adds a timing job after delay of `interval` duration.
+// Also see AddOnce.
+func (t *Timer) DelayAddOnce(ctx context.Context, delay time.Duration, interval time.Duration, job JobFunc) {
+ t.AddOnce(ctx, delay, func(ctx context.Context) {
+ t.AddOnce(ctx, interval, job)
+ })
+}
+
+// DelayAddTimes adds a timing job after delay of `interval` duration.
+// Also see AddTimes.
+func (t *Timer) DelayAddTimes(ctx context.Context, delay time.Duration, interval time.Duration, times int, job JobFunc) {
+ t.AddOnce(ctx, delay, func(ctx context.Context) {
+ t.AddTimes(ctx, interval, times, job)
+ })
+}
+
+// Start starts the timer.
+func (t *Timer) Start() {
+ t.status.Set(StatusRunning)
+}
+
+// Stop stops the timer.
+func (t *Timer) Stop() {
+ t.status.Set(StatusStopped)
+}
+
+// Close closes the timer.
+func (t *Timer) Close() {
+ t.status.Set(StatusClosed)
+}
+
+type createEntryInput struct {
+ Ctx context.Context
+ Interval time.Duration
+ Job JobFunc
+ IsSingleton bool
+ Times int
+ Status int
+}
+
+// createEntry creates and adds a timing job to the timer.
+func (t *Timer) createEntry(in createEntryInput) *Entry {
+ var (
+ infinite = false
+ )
+ if in.Times <= 0 {
+ infinite = true
+ }
+ var (
+ intervalTicksOfJob = int64(in.Interval / t.options.Interval)
+ )
+ if intervalTicksOfJob == 0 {
+ // If the given interval is lesser than the one of the wheel,
+ // then sets it to one tick, which means it will be run in one interval.
+ intervalTicksOfJob = 1
+ }
+ var (
+ nextTicks = t.ticks.Val() + intervalTicksOfJob
+ entry = &Entry{
+ job: in.Job,
+ ctx: in.Ctx,
+ timer: t,
+ ticks: intervalTicksOfJob,
+ times: gtype.NewInt(in.Times),
+ status: gtype.NewInt(in.Status),
+ isSingleton: gtype.NewBool(in.IsSingleton),
+ nextTicks: gtype.NewInt64(nextTicks),
+ infinite: gtype.NewBool(infinite),
+ }
+ )
+ t.queue.Push(entry, nextTicks)
+ return entry
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_timer_loop.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_timer_loop.go
new file mode 100644
index 000000000000..ae94bd31171f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gtimer/gtimer_timer_loop.go
@@ -0,0 +1,67 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gtimer
+
+import "time"
+
+// loop starts the ticker using a standalone goroutine.
+func (t *Timer) loop() {
+ go func() {
+ var (
+ currentTimerTicks int64
+ timerIntervalTicker = time.NewTicker(t.options.Interval)
+ )
+ defer timerIntervalTicker.Stop()
+ for {
+ select {
+ case <-timerIntervalTicker.C:
+ // Check the timer status.
+ switch t.status.Val() {
+ case StatusRunning:
+ // Timer proceeding.
+ if currentTimerTicks = t.ticks.Add(1); currentTimerTicks >= t.queue.NextPriority() {
+ t.proceed(currentTimerTicks)
+ }
+
+ case StatusStopped:
+ // Do nothing.
+
+ case StatusClosed:
+ // Timer exits.
+ return
+ }
+ }
+ }
+ }()
+}
+
+// proceed function proceeds the timer job checking and running logic.
+func (t *Timer) proceed(currentTimerTicks int64) {
+ var (
+ value interface{}
+ )
+ for {
+ value = t.queue.Pop()
+ if value == nil {
+ break
+ }
+ entry := value.(*Entry)
+ // It checks if it meets the ticks' requirement.
+ if jobNextTicks := entry.nextTicks.Val(); currentTimerTicks < jobNextTicks {
+ // It pushes the job back if current ticks does not meet its running ticks requirement.
+ t.queue.Push(entry, entry.nextTicks.Val())
+ break
+ }
+ // It checks the job running requirements and then does asynchronous running.
+ entry.doCheckAndRunByTicks(currentTimerTicks)
+ // Status check: push back or ignore it.
+ if entry.Status() != StatusClosed {
+ // It pushes the job back to queue for next running.
+ t.queue.Push(entry, entry.nextTicks.Val())
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview.go
new file mode 100644
index 000000000000..92871f2dea99
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview.go
@@ -0,0 +1,160 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gview implements a template engine based on text/template.
+//
+// Reserved template variable names:
+// I18nLanguage: Assign this variable to define i18n language for each page.
+package gview
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2"
+ "github.com/gogf/gf/v2/container/garray"
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gcmd"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/glog"
+)
+
+// View object for template engine.
+type View struct {
+ searchPaths *garray.StrArray // Searching array for path, NOT concurrent-safe for performance purpose.
+ data map[string]interface{} // Global template variables.
+ funcMap map[string]interface{} // Global template function map.
+ fileCacheMap *gmap.StrAnyMap // File cache map.
+ config Config // Extra configuration for the view.
+}
+
+type (
+ Params = map[string]interface{} // Params is type for template params.
+ FuncMap = map[string]interface{} // FuncMap is type for custom template functions.
+)
+
+const (
+ commandEnvKeyForPath = "gf.gview.path"
+)
+
+var (
+ // Default view object.
+ defaultViewObj *View
+)
+
+// checkAndInitDefaultView checks and initializes the default view object.
+// The default view object will be initialized just once.
+func checkAndInitDefaultView() {
+ if defaultViewObj == nil {
+ defaultViewObj = New()
+ }
+}
+
+// ParseContent parses the template content directly using the default view object
+// and returns the parsed content.
+func ParseContent(ctx context.Context, content string, params ...Params) (string, error) {
+ checkAndInitDefaultView()
+ return defaultViewObj.ParseContent(ctx, content, params...)
+}
+
+// New returns a new view object.
+// The parameter `path` specifies the template directory path to load template files.
+func New(path ...string) *View {
+ var (
+ ctx = context.TODO()
+ )
+ view := &View{
+ searchPaths: garray.NewStrArray(),
+ data: make(map[string]interface{}),
+ funcMap: make(map[string]interface{}),
+ fileCacheMap: gmap.NewStrAnyMap(true),
+ config: DefaultConfig(),
+ }
+ if len(path) > 0 && len(path[0]) > 0 {
+ if err := view.SetPath(path[0]); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ } else {
+ // Customized dir path from env/cmd.
+ if envPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); envPath != "" {
+ if gfile.Exists(envPath) {
+ if err := view.SetPath(envPath); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ } else {
+ if errorPrint() {
+ glog.Errorf(ctx, "Template directory path does not exist: %s", envPath)
+ }
+ }
+ } else {
+ // Dir path of working dir.
+ if err := view.SetPath(gfile.Pwd()); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ // Dir path of binary.
+ if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) {
+ if err := view.AddPath(selfPath); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ // Dir path of main package.
+ if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) {
+ if err := view.AddPath(mainPath); err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ }
+ }
+ }
+ view.SetDelimiters("{{", "}}")
+ // default build-in variables.
+ view.data["GF"] = map[string]interface{}{
+ "version": gf.VERSION,
+ }
+ // default build-in functions.
+ view.BindFuncMap(FuncMap{
+ "eq": view.buildInFuncEq,
+ "ne": view.buildInFuncNe,
+ "lt": view.buildInFuncLt,
+ "le": view.buildInFuncLe,
+ "gt": view.buildInFuncGt,
+ "ge": view.buildInFuncGe,
+ "text": view.buildInFuncText,
+ "html": view.buildInFuncHtmlEncode,
+ "htmlencode": view.buildInFuncHtmlEncode,
+ "htmldecode": view.buildInFuncHtmlDecode,
+ "encode": view.buildInFuncHtmlEncode,
+ "decode": view.buildInFuncHtmlDecode,
+ "url": view.buildInFuncUrlEncode,
+ "urlencode": view.buildInFuncUrlEncode,
+ "urldecode": view.buildInFuncUrlDecode,
+ "date": view.buildInFuncDate,
+ "substr": view.buildInFuncSubStr,
+ "strlimit": view.buildInFuncStrLimit,
+ "concat": view.buildInFuncConcat,
+ "replace": view.buildInFuncReplace,
+ "compare": view.buildInFuncCompare,
+ "hidestr": view.buildInFuncHideStr,
+ "highlight": view.buildInFuncHighlight,
+ "toupper": view.buildInFuncToUpper,
+ "tolower": view.buildInFuncToLower,
+ "nl2br": view.buildInFuncNl2Br,
+ "include": view.buildInFuncInclude,
+ "dump": view.buildInFuncDump,
+ "map": view.buildInFuncMap,
+ "maps": view.buildInFuncMaps,
+ "json": view.buildInFuncJson,
+ "xml": view.buildInFuncXml,
+ "ini": view.buildInFuncIni,
+ "yaml": view.buildInFuncYaml,
+ "yamli": view.buildInFuncYamlIndent,
+ "toml": view.buildInFuncToml,
+ "plus": view.buildInFuncPlus,
+ "minus": view.buildInFuncMinus,
+ "times": view.buildInFuncTimes,
+ "divide": view.buildInFuncDivide,
+ })
+ return view
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_buildin.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_buildin.go
new file mode 100644
index 000000000000..92ef1fc58d64
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_buildin.go
@@ -0,0 +1,309 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gview
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ htmltpl "html/template"
+ "strings"
+
+ "github.com/gogf/gf/v2/encoding/ghtml"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/encoding/gurl"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// buildInFuncDump implements build-in template function: dump
+func (view *View) buildInFuncDump(values ...interface{}) string {
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteString("\n")
+ buffer.WriteString("\n")
+ return buffer.String()
+}
+
+// buildInFuncMap implements build-in template function: map
+func (view *View) buildInFuncMap(value ...interface{}) map[string]interface{} {
+ if len(value) > 0 {
+ return gconv.Map(value[0])
+ }
+ return map[string]interface{}{}
+}
+
+// buildInFuncMaps implements build-in template function: maps
+func (view *View) buildInFuncMaps(value ...interface{}) []map[string]interface{} {
+ if len(value) > 0 {
+ return gconv.Maps(value[0])
+ }
+ return []map[string]interface{}{}
+}
+
+// buildInFuncEq implements build-in template function: eq
+func (view *View) buildInFuncEq(value interface{}, others ...interface{}) bool {
+ s := gconv.String(value)
+ for _, v := range others {
+ if strings.Compare(s, gconv.String(v)) == 0 {
+ return true
+ }
+ }
+ return false
+}
+
+// buildInFuncNe implements build-in template function: ne
+func (view *View) buildInFuncNe(value, other interface{}) bool {
+ return strings.Compare(gconv.String(value), gconv.String(other)) != 0
+}
+
+// buildInFuncLt implements build-in template function: lt
+func (view *View) buildInFuncLt(value, other interface{}) bool {
+ s1 := gconv.String(value)
+ s2 := gconv.String(other)
+ if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
+ return gconv.Int64(value) < gconv.Int64(other)
+ }
+ return strings.Compare(s1, s2) < 0
+}
+
+// buildInFuncLe implements build-in template function: le
+func (view *View) buildInFuncLe(value, other interface{}) bool {
+ s1 := gconv.String(value)
+ s2 := gconv.String(other)
+ if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
+ return gconv.Int64(value) <= gconv.Int64(other)
+ }
+ return strings.Compare(s1, s2) <= 0
+}
+
+// buildInFuncGt implements build-in template function: gt
+func (view *View) buildInFuncGt(value, other interface{}) bool {
+ s1 := gconv.String(value)
+ s2 := gconv.String(other)
+ if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
+ return gconv.Int64(value) > gconv.Int64(other)
+ }
+ return strings.Compare(s1, s2) > 0
+}
+
+// buildInFuncGe implements build-in template function: ge
+func (view *View) buildInFuncGe(value, other interface{}) bool {
+ s1 := gconv.String(value)
+ s2 := gconv.String(other)
+ if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
+ return gconv.Int64(value) >= gconv.Int64(other)
+ }
+ return strings.Compare(s1, s2) >= 0
+}
+
+// buildInFuncInclude implements build-in template function: include
+// Note that configuration AutoEncode does not affect the output of this function.
+func (view *View) buildInFuncInclude(file interface{}, data ...map[string]interface{}) htmltpl.HTML {
+ var m map[string]interface{} = nil
+ if len(data) > 0 {
+ m = data[0]
+ }
+ path := gconv.String(file)
+ if path == "" {
+ return ""
+ }
+ // It will search the file internally.
+ content, err := view.Parse(context.TODO(), path, m)
+ if err != nil {
+ return htmltpl.HTML(err.Error())
+ }
+ return htmltpl.HTML(content)
+}
+
+// buildInFuncText implements build-in template function: text
+func (view *View) buildInFuncText(html interface{}) string {
+ return ghtml.StripTags(gconv.String(html))
+}
+
+// buildInFuncHtmlEncode implements build-in template function: html
+func (view *View) buildInFuncHtmlEncode(html interface{}) string {
+ return ghtml.Entities(gconv.String(html))
+}
+
+// buildInFuncHtmlDecode implements build-in template function: htmldecode
+func (view *View) buildInFuncHtmlDecode(html interface{}) string {
+ return ghtml.EntitiesDecode(gconv.String(html))
+}
+
+// buildInFuncUrlEncode implements build-in template function: url
+func (view *View) buildInFuncUrlEncode(url interface{}) string {
+ return gurl.Encode(gconv.String(url))
+}
+
+// buildInFuncUrlDecode implements build-in template function: urldecode
+func (view *View) buildInFuncUrlDecode(url interface{}) string {
+ if content, err := gurl.Decode(gconv.String(url)); err == nil {
+ return content
+ } else {
+ return err.Error()
+ }
+}
+
+// buildInFuncDate implements build-in template function: date
+func (view *View) buildInFuncDate(format interface{}, timestamp ...interface{}) string {
+ t := int64(0)
+ if len(timestamp) > 0 {
+ t = gconv.Int64(timestamp[0])
+ }
+ if t == 0 {
+ t = gtime.Timestamp()
+ }
+ return gtime.NewFromTimeStamp(t).Format(gconv.String(format))
+}
+
+// buildInFuncCompare implements build-in template function: compare
+func (view *View) buildInFuncCompare(value1, value2 interface{}) int {
+ return strings.Compare(gconv.String(value1), gconv.String(value2))
+}
+
+// buildInFuncSubStr implements build-in template function: substr
+func (view *View) buildInFuncSubStr(start, end, str interface{}) string {
+ return gstr.SubStrRune(gconv.String(str), gconv.Int(start), gconv.Int(end))
+}
+
+// buildInFuncStrLimit implements build-in template function: strlimit
+func (view *View) buildInFuncStrLimit(length, suffix, str interface{}) string {
+ return gstr.StrLimitRune(gconv.String(str), gconv.Int(length), gconv.String(suffix))
+}
+
+// buildInFuncConcat implements build-in template function: concat
+func (view *View) buildInFuncConcat(str ...interface{}) string {
+ var s string
+ for _, v := range str {
+ s += gconv.String(v)
+ }
+ return s
+}
+
+// buildInFuncReplace implements build-in template function: replace
+func (view *View) buildInFuncReplace(search, replace, str interface{}) string {
+ return gstr.Replace(gconv.String(str), gconv.String(search), gconv.String(replace), -1)
+}
+
+// buildInFuncHighlight implements build-in template function: highlight
+func (view *View) buildInFuncHighlight(key, color, str interface{}) string {
+ return gstr.Replace(gconv.String(str), gconv.String(key), fmt.Sprintf(`%v `, color, key))
+}
+
+// buildInFuncHideStr implements build-in template function: hidestr
+func (view *View) buildInFuncHideStr(percent, hide, str interface{}) string {
+ return gstr.HideStr(gconv.String(str), gconv.Int(percent), gconv.String(hide))
+}
+
+// buildInFuncToUpper implements build-in template function: toupper
+func (view *View) buildInFuncToUpper(str interface{}) string {
+ return gstr.ToUpper(gconv.String(str))
+}
+
+// buildInFuncToLower implements build-in template function: toupper
+func (view *View) buildInFuncToLower(str interface{}) string {
+ return gstr.ToLower(gconv.String(str))
+}
+
+// buildInFuncNl2Br implements build-in template function: nl2br
+func (view *View) buildInFuncNl2Br(str interface{}) string {
+ return gstr.Nl2Br(gconv.String(str))
+}
+
+// buildInFuncJson implements build-in template function: json ,
+// which encodes and returns `value` as JSON string.
+func (view *View) buildInFuncJson(value interface{}) (string, error) {
+ b, err := gjson.Marshal(value)
+ return string(b), err
+}
+
+// buildInFuncXml implements build-in template function: xml ,
+// which encodes and returns `value` as XML string.
+func (view *View) buildInFuncXml(value interface{}, rootTag ...string) (string, error) {
+ b, err := gjson.New(value).ToXml(rootTag...)
+ return string(b), err
+}
+
+// buildInFuncXml implements build-in template function: ini ,
+// which encodes and returns `value` as XML string.
+func (view *View) buildInFuncIni(value interface{}) (string, error) {
+ b, err := gjson.New(value).ToIni()
+ return string(b), err
+}
+
+// buildInFuncYaml implements build-in template function: yaml ,
+// which encodes and returns `value` as YAML string.
+func (view *View) buildInFuncYaml(value interface{}) (string, error) {
+ b, err := gjson.New(value).ToYaml()
+ return string(b), err
+}
+
+// buildInFuncYamlIndent implements build-in template function: yamli ,
+// which encodes and returns `value` as YAML string with custom indent string.
+func (view *View) buildInFuncYamlIndent(value, indent interface{}) (string, error) {
+ b, err := gjson.New(value).ToYamlIndent(gconv.String(indent))
+ return string(b), err
+}
+
+// buildInFuncToml implements build-in template function: toml ,
+// which encodes and returns `value` as TOML string.
+func (view *View) buildInFuncToml(value interface{}) (string, error) {
+ b, err := gjson.New(value).ToToml()
+ return string(b), err
+}
+
+// buildInFuncPlus implements build-in template function: plus ,
+// which returns the result that pluses all `deltas` to `value`.
+func (view *View) buildInFuncPlus(value interface{}, deltas ...interface{}) string {
+ result := gconv.Float64(value)
+ for _, v := range deltas {
+ result += gconv.Float64(v)
+ }
+ return gconv.String(result)
+}
+
+// buildInFuncMinus implements build-in template function: minus ,
+// which returns the result that subtracts all `deltas` from `value`.
+func (view *View) buildInFuncMinus(value interface{}, deltas ...interface{}) string {
+ result := gconv.Float64(value)
+ for _, v := range deltas {
+ result -= gconv.Float64(v)
+ }
+ return gconv.String(result)
+}
+
+// buildInFuncTimes implements build-in template function: times ,
+// which returns the result that multiplies `value` by all of `values`.
+func (view *View) buildInFuncTimes(value interface{}, values ...interface{}) string {
+ result := gconv.Float64(value)
+ for _, v := range values {
+ result *= gconv.Float64(v)
+ }
+ return gconv.String(result)
+}
+
+// buildInFuncDivide implements build-in template function: divide ,
+// which returns the result that divides `value` by all of `values`.
+func (view *View) buildInFuncDivide(value interface{}, values ...interface{}) string {
+ result := gconv.Float64(value)
+ for _, v := range values {
+ value2Float64 := gconv.Float64(v)
+ if value2Float64 == 0 {
+ // Invalid `value2`.
+ return "0"
+ }
+ result /= value2Float64
+ }
+ return gconv.String(result)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_config.go
new file mode 100644
index 000000000000..445829200171
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_config.go
@@ -0,0 +1,266 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gview
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/i18n/gi18n"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gspath"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+// Config is the configuration object for template engine.
+type Config struct {
+ Paths []string `json:"paths"` // Searching array for path, NOT concurrent-safe for performance purpose.
+ Data map[string]interface{} `json:"data"` // Global template variables including configuration.
+ DefaultFile string `json:"defaultFile"` // Default template file for parsing.
+ Delimiters []string `json:"delimiters"` // Custom template delimiters.
+ AutoEncode bool `json:"autoEncode"` // Automatically encodes and provides safe html output, which is good for avoiding XSS.
+ I18nManager *gi18n.Manager `json:"-"` // I18n manager for the view.
+}
+
+const (
+ // Default template file for parsing.
+ defaultParsingFile = "index.html"
+)
+
+// DefaultConfig creates and returns a configuration object with default configurations.
+func DefaultConfig() Config {
+ return Config{
+ DefaultFile: defaultParsingFile,
+ I18nManager: gi18n.Instance(),
+ Delimiters: make([]string, 2),
+ }
+}
+
+// SetConfig sets the configuration for view.
+func (view *View) SetConfig(config Config) error {
+ var err error
+ if len(config.Paths) > 0 {
+ for _, v := range config.Paths {
+ if err = view.AddPath(v); err != nil {
+ return err
+ }
+ }
+ }
+ if len(config.Data) > 0 {
+ view.Assigns(config.Data)
+ }
+ if config.DefaultFile != "" {
+ view.SetDefaultFile(config.DefaultFile)
+ }
+ if len(config.Delimiters) > 1 {
+ view.SetDelimiters(config.Delimiters[0], config.Delimiters[1])
+ }
+ view.config = config
+ // Clear global template object cache.
+ // It's just cache, do not hesitate clearing it.
+ templates.Clear()
+
+ intlog.Printf(context.TODO(), "SetConfig: %+v", view.config)
+ return nil
+}
+
+// SetConfigWithMap set configurations with map for the view.
+func (view *View) SetConfigWithMap(m map[string]interface{}) error {
+ if m == nil || len(m) == 0 {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "configuration cannot be empty")
+ }
+ // The m now is a shallow copy of m.
+ // Any changes to m does not affect the original one.
+ // A little tricky, isn't it?
+ m = gutil.MapCopy(m)
+ // Most common used configuration support for single view path.
+ _, v1 := gutil.MapPossibleItemByKey(m, "paths")
+ _, v2 := gutil.MapPossibleItemByKey(m, "path")
+ if v1 == nil && v2 != nil {
+ m["paths"] = []interface{}{v2}
+ }
+ err := gconv.Struct(m, &view.config)
+ if err != nil {
+ return err
+ }
+ return view.SetConfig(view.config)
+}
+
+// SetPath sets the template directory path for template file search.
+// The parameter `path` can be absolute or relative path, but absolute path is suggested.
+func (view *View) SetPath(path string) error {
+ var (
+ ctx = context.TODO()
+ isDir = false
+ realPath = ""
+ )
+ if file := gres.Get(path); file != nil {
+ realPath = path
+ isDir = file.FileInfo().IsDir()
+ } else {
+ // Absolute path.
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ // Relative path.
+ view.searchPaths.RLockFunc(func(array []string) {
+ for _, v := range array {
+ if path, _ := gspath.Search(v, path); path != "" {
+ realPath = path
+ break
+ }
+ }
+ })
+ }
+ if realPath != "" {
+ isDir = gfile.IsDir(realPath)
+ }
+ }
+ // Path not exist.
+ if realPath == "" {
+ err := gerror.NewCodef(gcode.CodeInvalidParameter, `View.SetPath failed: path "%s" does not exist`, path)
+ if errorPrint() {
+ glog.Error(ctx, err)
+ }
+ return err
+ }
+ // Should be a directory.
+ if !isDir {
+ err := gerror.NewCodef(gcode.CodeInvalidParameter, `View.SetPath failed: path "%s" should be directory type`, path)
+ if errorPrint() {
+ glog.Error(ctx, err)
+ }
+ return err
+ }
+ // Repeated path adding check.
+ if view.searchPaths.Search(realPath) != -1 {
+ return nil
+ }
+ view.searchPaths.Clear()
+ view.searchPaths.Append(realPath)
+ view.fileCacheMap.Clear()
+ return nil
+}
+
+// AddPath adds an absolute or relative path to the search paths.
+func (view *View) AddPath(path string) error {
+ var (
+ ctx = context.TODO()
+ isDir = false
+ realPath = ""
+ )
+ if file := gres.Get(path); file != nil {
+ realPath = path
+ isDir = file.FileInfo().IsDir()
+ } else {
+ // Absolute path.
+ if realPath = gfile.RealPath(path); realPath == "" {
+ // Relative path.
+ view.searchPaths.RLockFunc(func(array []string) {
+ for _, v := range array {
+ if searchedPath, _ := gspath.Search(v, path); searchedPath != "" {
+ realPath = searchedPath
+ break
+ }
+ }
+ })
+ }
+ if realPath != "" {
+ isDir = gfile.IsDir(realPath)
+ }
+ }
+ // Path not exist.
+ if realPath == "" {
+ err := gerror.NewCodef(gcode.CodeInvalidParameter, `View.AddPath failed: path "%s" does not exist`, path)
+ if errorPrint() {
+ glog.Error(ctx, err)
+ }
+ return err
+ }
+ // realPath should be type of folder.
+ if !isDir {
+ err := gerror.NewCodef(gcode.CodeInvalidParameter, `View.AddPath failed: path "%s" should be directory type`, path)
+ if errorPrint() {
+ glog.Error(ctx, err)
+ }
+ return err
+ }
+ // Repeated path adding check.
+ if view.searchPaths.Search(realPath) != -1 {
+ return nil
+ }
+ view.searchPaths.Append(realPath)
+ view.fileCacheMap.Clear()
+ return nil
+}
+
+// Assigns binds multiple global template variables to current view object.
+// Note that it's not concurrent-safe, which means it would panic
+// if it's called in multiple goroutines in runtime.
+func (view *View) Assigns(data Params) {
+ for k, v := range data {
+ view.data[k] = v
+ }
+}
+
+// Assign binds a global template variable to current view object.
+// Note that it's not concurrent-safe, which means it would panic
+// if it's called in multiple goroutines in runtime.
+func (view *View) Assign(key string, value interface{}) {
+ view.data[key] = value
+}
+
+// SetDefaultFile sets default template file for parsing.
+func (view *View) SetDefaultFile(file string) {
+ view.config.DefaultFile = file
+}
+
+// GetDefaultFile returns default template file for parsing.
+func (view *View) GetDefaultFile() string {
+ return view.config.DefaultFile
+}
+
+// SetDelimiters sets customized delimiters for template parsing.
+func (view *View) SetDelimiters(left, right string) {
+ view.config.Delimiters = []string{left, right}
+}
+
+// SetAutoEncode enables/disables automatically html encoding feature.
+// When AutoEncode feature is enables, view engine automatically encodes and provides safe html output,
+// which is good for avoid XSS.
+func (view *View) SetAutoEncode(enable bool) {
+ view.config.AutoEncode = enable
+}
+
+// BindFunc registers customized global template function named `name`
+// with given function `function` to current view object.
+// The `name` is the function name which can be called in template content.
+func (view *View) BindFunc(name string, function interface{}) {
+ view.funcMap[name] = function
+ // Clear global template object cache.
+ templates.Clear()
+}
+
+// BindFuncMap registers customized global template functions by map to current view object.
+// The key of map is the template function name
+// and the value of map is the address of customized function.
+func (view *View) BindFuncMap(funcMap FuncMap) {
+ for k, v := range funcMap {
+ view.funcMap[k] = v
+ }
+ // Clear global template object cache.
+ templates.Clear()
+}
+
+// SetI18n binds i18n manager to current view engine.
+func (view *View) SetI18n(manager *gi18n.Manager) {
+ view.config.I18nManager = manager
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_error.go
new file mode 100644
index 000000000000..b3178167c10c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_error.go
@@ -0,0 +1,22 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gview
+
+import (
+ "github.com/gogf/gf/v2/os/gcmd"
+)
+
+const (
+ // commandEnvKeyForErrorPrint is used to specify the key controlling error printing to stdout.
+ // This error is designed not to be returned by functions.
+ commandEnvKeyForErrorPrint = "gf.gview.errorprint"
+)
+
+// errorPrint checks whether printing error to stdout.
+func errorPrint() bool {
+ return gcmd.GetOptWithEnv(commandEnvKeyForErrorPrint, true).Bool()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_i18n.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_i18n.go
new file mode 100644
index 000000000000..7b3f93cf7991
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_i18n.go
@@ -0,0 +1,39 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gview
+
+import (
+ "context"
+
+ "github.com/gogf/gf/v2/i18n/gi18n"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ i18nLanguageVariableName = "I18nLanguage"
+)
+
+// i18nTranslate translate the content with i18n feature.
+func (view *View) i18nTranslate(ctx context.Context, content string, variables Params) string {
+ if view.config.I18nManager != nil {
+ // Compatible with old version.
+ if language, ok := variables[i18nLanguageVariableName]; ok {
+ ctx = gi18n.WithLanguage(ctx, gconv.String(language))
+ }
+ return view.config.I18nManager.T(ctx, content)
+ }
+ return content
+}
+
+// setI18nLanguageFromCtx retrieves language name from context and sets it to template variables map.
+func (view *View) setI18nLanguageFromCtx(ctx context.Context, variables map[string]interface{}) {
+ if language, ok := variables[i18nLanguageVariableName]; !ok {
+ if language = gi18n.LanguageFromCtx(ctx); language != "" {
+ variables[i18nLanguageVariableName] = language
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_instance.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_instance.go
new file mode 100644
index 000000000000..42bf0fe1af8b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_instance.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gview
+
+import "github.com/gogf/gf/v2/container/gmap"
+
+const (
+ // DefaultName is the default group name for instance usage.
+ DefaultName = "default"
+)
+
+var (
+ // Instances map.
+ instances = gmap.NewStrAnyMap(true)
+)
+
+// Instance returns an instance of View with default settings.
+// The parameter `name` is the name for the instance.
+func Instance(name ...string) *View {
+ key := DefaultName
+ if len(name) > 0 && name[0] != "" {
+ key = name[0]
+ }
+ return instances.GetOrSetFuncLock(key, func() interface{} {
+ return New()
+ }).(*View)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_parse.go
new file mode 100644
index 000000000000..b8309634978f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/os/gview/gview_parse.go
@@ -0,0 +1,402 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gview
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ htmltpl "html/template"
+ "strconv"
+ texttpl "text/template"
+
+ "github.com/gogf/gf/v2/container/gmap"
+ "github.com/gogf/gf/v2/encoding/ghash"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/os/gfile"
+ "github.com/gogf/gf/v2/os/gfsnotify"
+ "github.com/gogf/gf/v2/os/glog"
+ "github.com/gogf/gf/v2/os/gmlock"
+ "github.com/gogf/gf/v2/os/gres"
+ "github.com/gogf/gf/v2/os/gspath"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+const (
+ // Template name for content parsing.
+ templateNameForContentParsing = "TemplateContent"
+)
+
+// fileCacheItem is the cache item for template file.
+type fileCacheItem struct {
+ path string
+ folder string
+ content string
+}
+
+var (
+ // Templates cache map for template folder.
+ // Note that there's no expiring logic for this map.
+ templates = gmap.NewStrAnyMap(true)
+
+ // Try-folders for resource template file searching.
+ resourceTryFolders = []string{
+ "template/", "template", "/template", "/template/",
+ "resource/template/", "resource/template", "/resource/template", "/resource/template/",
+ }
+
+ // Prefix array for trying searching in local system.
+ localSystemTryFolders = []string{"", "template/", "resource/template"}
+)
+
+// Parse parses given template file `file` with given template variables `params`
+// and returns the parsed template content.
+func (view *View) Parse(ctx context.Context, file string, params ...Params) (result string, err error) {
+ var tpl interface{}
+ // It caches the file, folder and its content to enhance performance.
+ r := view.fileCacheMap.GetOrSetFuncLock(file, func() interface{} {
+ var (
+ path string
+ folder string
+ content string
+ resource *gres.File
+ )
+ // Searching the absolute file path for `file`.
+ path, folder, resource, err = view.searchFile(ctx, file)
+ if err != nil {
+ return nil
+ }
+ if resource != nil {
+ content = string(resource.Content())
+ } else {
+ content = gfile.GetContentsWithCache(path)
+ }
+ // Monitor template files changes using fsnotify asynchronously.
+ if resource == nil {
+ if _, err = gfsnotify.AddOnce("gview.Parse:"+folder, folder, func(event *gfsnotify.Event) {
+ // CLEAR THEM ALL.
+ view.fileCacheMap.Clear()
+ templates.Clear()
+ gfsnotify.Exit()
+ }); err != nil {
+ intlog.Errorf(ctx, `%+v`, err)
+ }
+ }
+ return &fileCacheItem{
+ path: path,
+ folder: folder,
+ content: content,
+ }
+ })
+ if r == nil {
+ return
+ }
+ item := r.(*fileCacheItem)
+ // It's not necessary continuing parsing if template content is empty.
+ if item.content == "" {
+ return "", nil
+ }
+ // Get the template object instance for `folder`.
+ tpl, err = view.getTemplate(item.path, item.folder, fmt.Sprintf(`*%s`, gfile.Ext(item.path)))
+ if err != nil {
+ return "", err
+ }
+ // Using memory lock to ensure concurrent safety for template parsing.
+ gmlock.LockFunc("gview.Parse:"+item.path, func() {
+ if view.config.AutoEncode {
+ tpl, err = tpl.(*htmltpl.Template).Parse(item.content)
+ } else {
+ tpl, err = tpl.(*texttpl.Template).Parse(item.content)
+ }
+ if err != nil && item.path != "" {
+ err = gerror.Wrap(err, item.path)
+ }
+ })
+ if err != nil {
+ return "", err
+ }
+ // Note that the template variable assignment cannot change the value
+ // of the existing `params` or view.data because both variables are pointers.
+ // It needs to merge the values of the two maps into a new map.
+ variables := gutil.MapMergeCopy(params...)
+ if len(view.data) > 0 {
+ gutil.MapMerge(variables, view.data)
+ }
+ view.setI18nLanguageFromCtx(ctx, variables)
+
+ buffer := bytes.NewBuffer(nil)
+ if view.config.AutoEncode {
+ newTpl, err := tpl.(*htmltpl.Template).Clone()
+ if err != nil {
+ return "", err
+ }
+ if err = newTpl.Execute(buffer, variables); err != nil {
+ return "", err
+ }
+ } else {
+ if err = tpl.(*texttpl.Template).Execute(buffer, variables); err != nil {
+ return "", err
+ }
+ }
+
+ // TODO any graceful plan to replace ""?
+ result = gstr.Replace(buffer.String(), "", "")
+ result = view.i18nTranslate(ctx, result, variables)
+ return result, nil
+}
+
+// ParseDefault parses the default template file with params.
+func (view *View) ParseDefault(ctx context.Context, params ...Params) (result string, err error) {
+ return view.Parse(ctx, view.config.DefaultFile, params...)
+}
+
+// ParseContent parses given template content `content` with template variables `params`
+// and returns the parsed content in []byte.
+func (view *View) ParseContent(ctx context.Context, content string, params ...Params) (string, error) {
+ // It's not necessary continuing parsing if template content is empty.
+ if content == "" {
+ return "", nil
+ }
+ var (
+ err error
+ key = fmt.Sprintf("%s_%v_%v", templateNameForContentParsing, view.config.Delimiters, view.config.AutoEncode)
+ tpl = templates.GetOrSetFuncLock(key, func() interface{} {
+ if view.config.AutoEncode {
+ return htmltpl.New(templateNameForContentParsing).Delims(
+ view.config.Delimiters[0],
+ view.config.Delimiters[1],
+ ).Funcs(view.funcMap)
+ }
+ return texttpl.New(templateNameForContentParsing).Delims(
+ view.config.Delimiters[0],
+ view.config.Delimiters[1],
+ ).Funcs(view.funcMap)
+ })
+ )
+ // Using memory lock to ensure concurrent safety for content parsing.
+ hash := strconv.FormatUint(ghash.DJB64([]byte(content)), 10)
+ gmlock.LockFunc("gview.ParseContent:"+hash, func() {
+ if view.config.AutoEncode {
+ tpl, err = tpl.(*htmltpl.Template).Parse(content)
+ } else {
+ tpl, err = tpl.(*texttpl.Template).Parse(content)
+ }
+ })
+ if err != nil {
+ err = gerror.Wrapf(err, `template parsing failed`)
+ return "", err
+ }
+ // Note that the template variable assignment cannot change the value
+ // of the existing `params` or view.data because both variables are pointers.
+ // It needs to merge the values of the two maps into a new map.
+ variables := gutil.MapMergeCopy(params...)
+ if len(view.data) > 0 {
+ gutil.MapMerge(variables, view.data)
+ }
+ view.setI18nLanguageFromCtx(ctx, variables)
+
+ buffer := bytes.NewBuffer(nil)
+ if view.config.AutoEncode {
+ var newTpl *htmltpl.Template
+ newTpl, err = tpl.(*htmltpl.Template).Clone()
+ if err != nil {
+ err = gerror.Wrapf(err, `template clone failed`)
+ return "", err
+ }
+ if err = newTpl.Execute(buffer, variables); err != nil {
+ err = gerror.Wrapf(err, `template parsing failed`)
+ return "", err
+ }
+ } else {
+ if err = tpl.(*texttpl.Template).Execute(buffer, variables); err != nil {
+ err = gerror.Wrapf(err, `template parsing failed`)
+ return "", err
+ }
+ }
+ // TODO any graceful plan to replace ""?
+ result := gstr.Replace(buffer.String(), "", "")
+ result = view.i18nTranslate(ctx, result, variables)
+ return result, nil
+}
+
+// getTemplate returns the template object associated with given template file `path`.
+// It uses template cache to enhance performance, that is, it will return the same template object
+// with the same given `path`. It will also automatically refresh the template cache
+// if the template files under `path` changes (recursively).
+func (view *View) getTemplate(filePath, folderPath, pattern string) (tpl interface{}, err error) {
+ var (
+ mapKey = fmt.Sprintf("%s_%v", filePath, view.config.Delimiters)
+ mapFunc = func() interface{} {
+ tplName := filePath
+ if view.config.AutoEncode {
+ tpl = htmltpl.New(tplName).Delims(
+ view.config.Delimiters[0],
+ view.config.Delimiters[1],
+ ).Funcs(view.funcMap)
+ } else {
+ tpl = texttpl.New(tplName).Delims(
+ view.config.Delimiters[0],
+ view.config.Delimiters[1],
+ ).Funcs(view.funcMap)
+ }
+ // Firstly checking the resource manager.
+ if !gres.IsEmpty() {
+ if files := gres.ScanDirFile(folderPath, pattern, true); len(files) > 0 {
+ if view.config.AutoEncode {
+ var t = tpl.(*htmltpl.Template)
+ for _, v := range files {
+ _, err = t.New(v.FileInfo().Name()).Parse(string(v.Content()))
+ if err != nil {
+ err = view.formatTemplateObjectCreatingError(v.Name(), tplName, err)
+ return nil
+ }
+ }
+ } else {
+ var t = tpl.(*texttpl.Template)
+ for _, v := range files {
+ _, err = t.New(v.FileInfo().Name()).Parse(string(v.Content()))
+ if err != nil {
+ err = view.formatTemplateObjectCreatingError(v.Name(), tplName, err)
+ return nil
+ }
+ }
+ }
+ return tpl
+ }
+ }
+
+ // Secondly checking the file system.
+ var (
+ files []string
+ )
+ files, err = gfile.ScanDir(folderPath, pattern, true)
+ if err != nil {
+ return nil
+ }
+ if view.config.AutoEncode {
+ t := tpl.(*htmltpl.Template)
+ for _, file := range files {
+ if _, err = t.Parse(gfile.GetContents(file)); err != nil {
+ err = view.formatTemplateObjectCreatingError(file, tplName, err)
+ return nil
+ }
+ }
+ } else {
+ t := tpl.(*texttpl.Template)
+ for _, file := range files {
+ if _, err = t.Parse(gfile.GetContents(file)); err != nil {
+ err = view.formatTemplateObjectCreatingError(file, tplName, err)
+ return nil
+ }
+ }
+ }
+ return tpl
+ }
+ )
+ result := templates.GetOrSetFuncLock(mapKey, mapFunc)
+ if result != nil {
+ return result, nil
+ }
+ return
+}
+
+// formatTemplateObjectCreatingError formats the error that created from creating template object.
+func (view *View) formatTemplateObjectCreatingError(filePath, tplName string, err error) error {
+ if err != nil {
+ return gerror.NewSkip(1, gstr.Replace(err.Error(), tplName, filePath))
+ }
+ return nil
+}
+
+// searchFile returns the found absolute path for `file` and its template folder path.
+// Note that, the returned `folder` is the template folder path, but not the folder of
+// the returned template file `path`.
+func (view *View) searchFile(ctx context.Context, file string) (path string, folder string, resource *gres.File, err error) {
+ var tempPath string
+ // Firstly checking the resource manager.
+ if !gres.IsEmpty() {
+ // Try folders.
+ for _, tryFolder := range resourceTryFolders {
+ tempPath = tryFolder + file
+ if resource = gres.Get(tempPath); resource != nil {
+ path = resource.Name()
+ folder = tryFolder
+ return
+ }
+ }
+ // Search folders.
+ view.searchPaths.RLockFunc(func(array []string) {
+ for _, searchPath := range array {
+ for _, tryFolder := range resourceTryFolders {
+ tempPath = searchPath + tryFolder + file
+ if resFile := gres.Get(tempPath); resFile != nil {
+ path = resFile.Name()
+ folder = searchPath + tryFolder
+ return
+ }
+ }
+ }
+ })
+ }
+
+ // Secondly checking the file system.
+ if path == "" {
+ // Absolute path.
+ path = gfile.RealPath(file)
+ if path != "" {
+ folder = gfile.Dir(path)
+ return
+ }
+ // In search paths.
+ view.searchPaths.RLockFunc(func(array []string) {
+ for _, searchPath := range array {
+ searchPath = gstr.TrimRight(searchPath, `\/`)
+ for _, tryFolder := range localSystemTryFolders {
+ relativePath := gstr.TrimRight(
+ gfile.Join(tryFolder, file),
+ `\/`,
+ )
+ if path, _ = gspath.Search(searchPath, relativePath); path != "" {
+ folder = gfile.Join(searchPath, tryFolder)
+ return
+ }
+ }
+ }
+ })
+ }
+
+ // Error checking.
+ if path == "" {
+ buffer := bytes.NewBuffer(nil)
+ if view.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf("cannot find template file \"%s\" in following paths:", file))
+ view.searchPaths.RLockFunc(func(array []string) {
+ index := 1
+ for _, searchPath := range array {
+ searchPath = gstr.TrimRight(searchPath, `\/`)
+ for _, tryFolder := range localSystemTryFolders {
+ buffer.WriteString(fmt.Sprintf(
+ "\n%d. %s",
+ index, gfile.Join(searchPath, tryFolder),
+ ))
+ index++
+ }
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf("cannot find template file \"%s\" with no path set/add", file))
+ }
+ if errorPrint() {
+ glog.Error(ctx, buffer.String())
+ }
+ err = gerror.NewCodef(gcode.CodeInvalidParameter, `template file "%s" not found`, file)
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai.go
new file mode 100644
index 000000000000..85409e9220ef
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai.go
@@ -0,0 +1,239 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package goai implements and provides document generating for OpenApi specification.
+//
+// https://editor.swagger.io/
+package goai
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// OpenApiV3 is the structure defined from:
+// https://swagger.io/specification/
+// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md
+type OpenApiV3 struct {
+ Config Config `json:"-" yaml:"-"`
+ OpenAPI string `json:"openapi" yaml:"openapi"`
+ Components Components `json:"components,omitempty" yaml:"components,omitempty"`
+ Info Info `json:"info" yaml:"info"`
+ Paths Paths `json:"paths" yaml:"paths"`
+ Security *SecurityRequirements `json:"security,omitempty" yaml:"security,omitempty"`
+ Servers *Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
+ Tags *Tags `json:"tags,omitempty" yaml:"tags,omitempty"`
+ ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+}
+
+// ExternalDocs is specified by OpenAPI/Swagger standard version 3.0.
+type ExternalDocs struct {
+ URL string `json:"url,omitempty"`
+ Description string `json:"description,omitempty"`
+}
+
+const (
+ HttpMethodAll = `ALL`
+ HttpMethodGet = `GET`
+ HttpMethodPut = `PUT`
+ HttpMethodPost = `POST`
+ HttpMethodDelete = `DELETE`
+ HttpMethodConnect = `CONNECT`
+ HttpMethodHead = `HEAD`
+ HttpMethodOptions = `OPTIONS`
+ HttpMethodPatch = `PATCH`
+ HttpMethodTrace = `TRACE`
+)
+
+const (
+ TypeNumber = `number`
+ TypeBoolean = `boolean`
+ TypeArray = `array`
+ TypeString = `string`
+ TypeObject = `object`
+ FormatInt32 = `int32`
+ FormatInt64 = `int64`
+ FormatDouble = `double`
+ FormatByte = `byte`
+ FormatBinary = `binary`
+ FormatDate = `date`
+ FormatDateTime = `date-time`
+ FormatPassword = `password`
+)
+
+const (
+ ParameterInHeader = `header`
+ ParameterInPath = `path`
+ ParameterInQuery = `query`
+ ParameterInCookie = `cookie`
+)
+
+const (
+ TagNamePath = `path`
+ TagNameMethod = `method`
+ TagNameMime = `mime`
+ TagNameType = `type`
+ TagNameDomain = `domain`
+ TagNameValidate = `v`
+)
+
+var (
+ defaultReadContentTypes = []string{`application/json`}
+ defaultWriteContentTypes = []string{`application/json`}
+ shortTypeMapForTag = map[string]string{
+ "d": "default",
+ "sum": "summary",
+ "sm": "summary",
+ "des": "description",
+ "dc": "description",
+ "eg": "example",
+ "egs": "examples",
+ }
+)
+
+// New creates and returns a OpenApiV3 implements object.
+func New() *OpenApiV3 {
+ oai := &OpenApiV3{}
+ oai.fillWithDefaultValue()
+ return oai
+}
+
+// AddInput is the structured parameter for function OpenApiV3.Add.
+type AddInput struct {
+ Path string // Path specifies the custom path if this is not configured in Meta of struct tag.
+ Prefix string // Prefix specifies the custom route path prefix, which will be added with the path tag in Meta of struct tag.
+ Method string // Method specifies the custom HTTP method if this is not configured in Meta of struct tag.
+ Object interface{} // Object can be an instance of struct or a route function.
+}
+
+// Add adds an instance of struct or a route function to OpenApiV3 definition implements.
+func (oai *OpenApiV3) Add(in AddInput) error {
+ var (
+ reflectValue = reflect.ValueOf(in.Object)
+ )
+ for reflectValue.Kind() == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ }
+ switch reflectValue.Kind() {
+ case reflect.Struct:
+ return oai.addSchema(in.Object)
+
+ case reflect.Func:
+ return oai.addPath(addPathInput{
+ Path: in.Path,
+ Prefix: in.Prefix,
+ Method: in.Method,
+ Function: in.Object,
+ })
+
+ default:
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `unsupported parameter type "%s", only struct/function type is supported`,
+ reflect.TypeOf(in.Object).String(),
+ )
+ }
+}
+
+func (oai OpenApiV3) String() string {
+ b, err := json.Marshal(oai)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ return string(b)
+}
+
+func (oai *OpenApiV3) golangTypeToOAIType(t reflect.Type) string {
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ switch t.Kind() {
+ case reflect.String:
+ return TypeString
+
+ case reflect.Struct:
+ switch t.String() {
+ case `time.Time`, `gtime.Time`:
+ return TypeString
+ }
+ return TypeObject
+
+ case reflect.Slice, reflect.Array:
+ switch t.String() {
+ case `[]uint8`:
+ return TypeString
+ }
+ return TypeArray
+
+ case reflect.Bool:
+ return TypeBoolean
+
+ case
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64,
+ reflect.Complex64, reflect.Complex128:
+ return TypeNumber
+
+ default:
+ return TypeObject
+ }
+}
+
+// golangTypeToOAIFormat converts and returns OpenAPI parameter format for given golang type `t`.
+// Note that it does not return standard OpenAPI parameter format but custom format in golang type.
+func (oai *OpenApiV3) golangTypeToOAIFormat(t reflect.Type) string {
+ format := t.String()
+ switch gstr.TrimLeft(format, "*") {
+ case `[]uint8`:
+ return FormatBinary
+
+ default:
+ return format
+ }
+}
+
+func (oai *OpenApiV3) golangTypeToSchemaName(t reflect.Type) string {
+ var (
+ pkgPath = ""
+ schemaName = gstr.TrimLeft(t.String(), "*")
+ )
+ // Pointer type has no PkgPath.
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ if pkgPath = t.PkgPath(); pkgPath != "" && pkgPath != "." {
+ if !oai.Config.IgnorePkgPath {
+ schemaName = gstr.Replace(pkgPath, `/`, `.`) + gstr.SubStrFrom(schemaName, ".")
+ }
+ }
+ schemaName = gstr.ReplaceByMap(schemaName, map[string]string{
+ ` `: ``,
+ `{`: ``,
+ `}`: ``,
+ })
+ return schemaName
+}
+
+func (oai *OpenApiV3) fileMapWithShortTags(m map[string]string) map[string]string {
+ for k, v := range shortTypeMapForTag {
+ if m[v] == "" && m[k] != "" {
+ m[v] = m[k]
+ }
+ }
+ return m
+}
+
+func formatRefToBytes(ref string) []byte {
+ return []byte(fmt.Sprintf(`{"$ref":"#/components/schemas/%s"}`, ref))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_callback.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_callback.go
new file mode 100644
index 000000000000..b68ce3bcd12d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_callback.go
@@ -0,0 +1,28 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// Callback is specified by OpenAPI/Swagger standard version 3.0.
+type Callback map[string]*Path
+
+type Callbacks map[string]*CallbackRef
+
+type CallbackRef struct {
+ Ref string
+ Value *Callback
+}
+
+func (r CallbackRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_components.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_components.go
new file mode 100644
index 000000000000..465972c84424
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_components.go
@@ -0,0 +1,24 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// Components is specified by OpenAPI/Swagger standard version 3.0.
+type Components struct {
+ Schemas Schemas `json:"schemas,omitempty" yaml:"schemas,omitempty"`
+ Parameters ParametersMap `json:"parameters,omitempty" yaml:"parameters,omitempty"`
+ Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
+ RequestBodies RequestBodies `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
+ Responses Responses `json:"responses,omitempty" yaml:"responses,omitempty"`
+ SecuritySchemes SecuritySchemes `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
+ Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
+ Links Links `json:"links,omitempty" yaml:"links,omitempty"`
+ Callbacks Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
+}
+
+type ParametersMap map[string]*ParameterRef
+
+type RequestBodies map[string]*RequestBodyRef
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_config.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_config.go
new file mode 100644
index 000000000000..9e7e54e05747
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_config.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// Config provides extra configuration feature for OpenApiV3 implements.
+type Config struct {
+ ReadContentTypes []string // ReadContentTypes specifies the default MIME types for consuming if MIME types are not configured.
+ WriteContentTypes []string // WriteContentTypes specifies the default MIME types for producing if MIME types are not configured.
+ CommonRequest interface{} // Common request structure for all paths.
+ CommonRequestDataField string // Common request field name to be replaced with certain business request structure. Eg: `Data`, `Request.`.
+ CommonResponse interface{} // Common response structure for all paths.
+ CommonResponseDataField string // Common response field name to be replaced with certain business response structure. Eg: `Data`, `Response.`.
+ IgnorePkgPath bool // Ignores package name for schema name.
+}
+
+// fillWithDefaultValue fills configuration object of `oai` with default values if these are not configured.
+func (oai *OpenApiV3) fillWithDefaultValue() {
+ if oai.OpenAPI == "" {
+ oai.OpenAPI = `3.0.0`
+ }
+ if len(oai.Config.ReadContentTypes) == 0 {
+ oai.Config.ReadContentTypes = defaultReadContentTypes
+ }
+ if len(oai.Config.WriteContentTypes) == 0 {
+ oai.Config.WriteContentTypes = defaultWriteContentTypes
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_example.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_example.go
new file mode 100644
index 000000000000..8af3005b18f7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_example.go
@@ -0,0 +1,33 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// Example is specified by OpenAPI/Swagger 3.0 standard.
+type Example struct {
+ Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Value interface{} `json:"value,omitempty" yaml:"value,omitempty"`
+ ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
+}
+
+type Examples map[string]*ExampleRef
+
+type ExampleRef struct {
+ Ref string
+ Value *Example
+}
+
+func (r ExampleRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_header.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_header.go
new file mode 100644
index 000000000000..97f472a61816
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_header.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// Header is specified by OpenAPI/Swagger 3.0 standard.
+// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#headerObject
+type Header struct {
+ Parameter
+}
+
+type Headers map[string]HeaderRef
+
+type HeaderRef struct {
+ Ref string
+ Value *Header
+}
+
+func (r HeaderRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_info.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_info.go
new file mode 100644
index 000000000000..3c0738e6760c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_info.go
@@ -0,0 +1,30 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// Info is specified by OpenAPI/Swagger standard version 3.0.
+type Info struct {
+ Title string `json:"title" yaml:"title"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
+ Contact *Contact `json:"contact,omitempty" yaml:"contact,omitempty"`
+ License *License `json:"license,omitempty" yaml:"license,omitempty"`
+ Version string `json:"version" yaml:"version"`
+}
+
+// Contact is specified by OpenAPI/Swagger standard version 3.0.
+type Contact struct {
+ Name string `json:"name,omitempty" yaml:"name,omitempty"`
+ URL string `json:"url,omitempty" yaml:"url,omitempty"`
+ Email string `json:"email,omitempty" yaml:"email,omitempty"`
+}
+
+// License is specified by OpenAPI/Swagger standard version 3.0.
+type License struct {
+ Name string `json:"name" yaml:"name"`
+ URL string `json:"url,omitempty" yaml:"url,omitempty"`
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_link.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_link.go
new file mode 100644
index 000000000000..261fa51ccc50
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_link.go
@@ -0,0 +1,35 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// Link is specified by OpenAPI/Swagger standard version 3.0.
+type Link struct {
+ OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
+ OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
+ Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
+ RequestBody interface{} `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
+}
+
+type Links map[string]LinkRef
+
+type LinkRef struct {
+ Ref string
+ Value *Link
+}
+
+func (r LinkRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_mediatype.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_mediatype.go
new file mode 100644
index 000000000000..d5af61dbae43
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_mediatype.go
@@ -0,0 +1,27 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// MediaType is specified by OpenAPI/Swagger 3.0 standard.
+type MediaType struct {
+ Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
+ Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
+ Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
+ Encoding map[string]*Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"`
+}
+
+// Content is specified by OpenAPI/Swagger 3.0 standard.
+type Content map[string]MediaType
+
+// Encoding is specified by OpenAPI/Swagger 3.0 standard.
+type Encoding struct {
+ ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
+ Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
+ Style string `json:"style,omitempty" yaml:"style,omitempty"`
+ Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
+ AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_operation.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_operation.go
new file mode 100644
index 000000000000..2a896f79e2a4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_operation.go
@@ -0,0 +1,23 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// Operation represents "operation" specified by OpenAPI/Swagger 3.0 standard.
+type Operation struct {
+ Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
+ Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
+ Parameters Parameters `json:"parameters,omitempty" yaml:"parameters,omitempty"`
+ RequestBody *RequestBodyRef `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
+ Responses Responses `json:"responses" yaml:"responses"`
+ Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
+ Callbacks *Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
+ Security *SecurityRequirements `json:"security,omitempty" yaml:"security,omitempty"`
+ Servers *Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
+ ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_parameter.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_parameter.go
new file mode 100644
index 000000000000..082bd60e47af
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_parameter.go
@@ -0,0 +1,110 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "fmt"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Parameter is specified by OpenAPI/Swagger 3.0 standard.
+// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#parameterObject
+type Parameter struct {
+ Name string `json:"name,omitempty" yaml:"name,omitempty"`
+ In string `json:"in,omitempty" yaml:"in,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Style string `json:"style,omitempty" yaml:"style,omitempty"`
+ Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
+ AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
+ AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
+ Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
+ Required bool `json:"required,omitempty" yaml:"required,omitempty"`
+ Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
+ Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
+ Examples *Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
+ Content *Content `json:"content,omitempty" yaml:"content,omitempty"`
+}
+
+// Parameters is specified by OpenAPI/Swagger 3.0 standard.
+type Parameters []ParameterRef
+
+type ParameterRef struct {
+ Ref string
+ Value *Parameter
+}
+
+func (oai *OpenApiV3) newParameterRefWithStructMethod(field gstructs.Field, path, method string) (*ParameterRef, error) {
+ var (
+ tagMap = field.TagMap()
+ parameter = &Parameter{
+ Name: field.TagJsonName(),
+ }
+ )
+ if parameter.Name == "" {
+ parameter.Name = field.Name()
+ }
+ if len(tagMap) > 0 {
+ err := gconv.Struct(oai.fileMapWithShortTags(tagMap), parameter)
+ if err != nil {
+ return nil, gerror.Wrap(err, `mapping struct tags to Parameter failed`)
+ }
+ }
+ if parameter.In == "" {
+ // Automatically detect its "in" attribute.
+ if gstr.ContainsI(path, fmt.Sprintf(`{%s}`, parameter.Name)) {
+ parameter.In = ParameterInPath
+ } else {
+ // Default the parameter input to "query" if method is "GET/DELETE".
+ switch gstr.ToUpper(method) {
+ case HttpMethodGet, HttpMethodDelete:
+ parameter.In = ParameterInQuery
+
+ default:
+ return nil, nil
+ }
+ }
+ }
+
+ switch parameter.In {
+ case ParameterInPath:
+ // Required for path parameter.
+ parameter.Required = true
+
+ case ParameterInCookie, ParameterInHeader, ParameterInQuery:
+ // Check validation tag.
+ if validateTagValue := field.Tag(TagNameValidate); gstr.ContainsI(validateTagValue, `required`) {
+ parameter.Required = true
+ }
+
+ default:
+ return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid tag value "%s" for In`, parameter.In)
+ }
+ // Necessary schema or content.
+ schemaRef, err := oai.newSchemaRefWithGolangType(field.Type().Type, tagMap)
+ if err != nil {
+ return nil, err
+ }
+ parameter.Schema = schemaRef
+
+ return &ParameterRef{
+ Ref: "",
+ Value: parameter,
+ }, nil
+}
+
+func (r ParameterRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_path.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_path.go
new file mode 100644
index 000000000000..d60b912e491e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_path.go
@@ -0,0 +1,283 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gmeta"
+)
+
+type Path struct {
+ Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
+ Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Connect *Operation `json:"connect,omitempty" yaml:"connect,omitempty"`
+ Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"`
+ Get *Operation `json:"get,omitempty" yaml:"get,omitempty"`
+ Head *Operation `json:"head,omitempty" yaml:"head,omitempty"`
+ Options *Operation `json:"options,omitempty" yaml:"options,omitempty"`
+ Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"`
+ Post *Operation `json:"post,omitempty" yaml:"post,omitempty"`
+ Put *Operation `json:"put,omitempty" yaml:"put,omitempty"`
+ Trace *Operation `json:"trace,omitempty" yaml:"trace,omitempty"`
+ Servers Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
+ Parameters Parameters `json:"parameters,omitempty" yaml:"parameters,omitempty"`
+}
+
+// Paths are specified by OpenAPI/Swagger standard version 3.0.
+type Paths map[string]Path
+
+const (
+ responseOkKey = `200`
+)
+
+type addPathInput struct {
+ Path string // Precise route path.
+ Prefix string // Route path prefix.
+ Method string // Route method.
+ Function interface{} // Uniformed function.
+}
+
+func (oai *OpenApiV3) addPath(in addPathInput) error {
+ if oai.Paths == nil {
+ oai.Paths = map[string]Path{}
+ }
+
+ var (
+ reflectType = reflect.TypeOf(in.Function)
+ )
+ if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `unsupported function "%s" for OpenAPI Path register, there should be input & output structures`,
+ reflectType.String(),
+ )
+ }
+ var (
+ inputObject reflect.Value
+ outputObject reflect.Value
+ )
+ // Create instance according input/output types.
+ if reflectType.In(1).Kind() == reflect.Ptr {
+ inputObject = reflect.New(reflectType.In(1).Elem()).Elem()
+ } else {
+ inputObject = reflect.New(reflectType.In(1)).Elem()
+ }
+ if reflectType.Out(0).Kind() == reflect.Ptr {
+ outputObject = reflect.New(reflectType.Out(0).Elem()).Elem()
+ } else {
+ outputObject = reflect.New(reflectType.Out(0)).Elem()
+ }
+
+ var (
+ path = Path{}
+ inputMetaMap = gmeta.Data(inputObject.Interface())
+ outputMetaMap = gmeta.Data(outputObject.Interface())
+ isInputStructEmpty = oai.doesStructHasNoFields(inputObject.Interface())
+ inputStructTypeName = oai.golangTypeToSchemaName(inputObject.Type())
+ outputStructTypeName = oai.golangTypeToSchemaName(outputObject.Type())
+ operation = Operation{
+ Responses: map[string]ResponseRef{},
+ }
+ )
+ // Path check.
+ if in.Path == "" {
+ in.Path = gmeta.Get(inputObject.Interface(), TagNamePath).String()
+ if in.Prefix != "" {
+ in.Path = gstr.TrimRight(in.Prefix, "/") + "/" + gstr.TrimLeft(in.Path, "/")
+ }
+ }
+ if in.Path == "" {
+ return gerror.NewCodef(
+ gcode.CodeMissingParameter,
+ `missing necessary path parameter "%s" for input struct "%s", missing tag in attribute Meta?`,
+ TagNamePath, inputStructTypeName,
+ )
+ }
+
+ if v, ok := oai.Paths[in.Path]; ok {
+ path = v
+ }
+
+ // Method check.
+ if in.Method == "" {
+ in.Method = gmeta.Get(inputObject.Interface(), TagNameMethod).String()
+ }
+ if in.Method == "" {
+ return gerror.NewCodef(
+ gcode.CodeMissingParameter,
+ `missing necessary method parameter "%s" for input struct "%s", missing tag in attribute Meta?`,
+ TagNameMethod, inputStructTypeName,
+ )
+ }
+
+ if err := oai.addSchema(inputObject.Interface(), outputObject.Interface()); err != nil {
+ return err
+ }
+
+ if len(inputMetaMap) > 0 {
+ if err := gconv.Struct(oai.fileMapWithShortTags(inputMetaMap), &path); err != nil {
+ return gerror.Wrap(err, `mapping struct tags to Path failed`)
+ }
+ if err := gconv.Struct(oai.fileMapWithShortTags(inputMetaMap), &operation); err != nil {
+ return gerror.Wrap(err, `mapping struct tags to Operation failed`)
+ }
+ }
+
+ // =================================================================================================================
+ // Request.
+ // =================================================================================================================
+ if operation.RequestBody == nil {
+ operation.RequestBody = &RequestBodyRef{}
+ }
+ if operation.RequestBody.Value == nil {
+ var (
+ requestBody = RequestBody{
+ Required: true,
+ Content: map[string]MediaType{},
+ }
+ )
+ // Supported mime types of request.
+ var (
+ contentTypes = oai.Config.ReadContentTypes
+ tagMimeValue = gmeta.Get(inputObject.Interface(), TagNameMime).String()
+ )
+ if tagMimeValue != "" {
+ contentTypes = gstr.SplitAndTrim(tagMimeValue, ",")
+ }
+ for _, v := range contentTypes {
+ if isInputStructEmpty {
+ requestBody.Content[v] = MediaType{}
+ } else {
+ schemaRef, err := oai.getRequestSchemaRef(getRequestSchemaRefInput{
+ BusinessStructName: inputStructTypeName,
+ RequestObject: oai.Config.CommonRequest,
+ RequestDataField: oai.Config.CommonRequestDataField,
+ })
+ if err != nil {
+ return err
+ }
+ requestBody.Content[v] = MediaType{
+ Schema: schemaRef,
+ }
+ }
+ }
+ operation.RequestBody = &RequestBodyRef{
+ Value: &requestBody,
+ }
+ }
+ // It also sets request parameters.
+ structFields, _ := gstructs.Fields(gstructs.FieldsInput{
+ Pointer: inputObject.Interface(),
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ for _, structField := range structFields {
+ if operation.Parameters == nil {
+ operation.Parameters = []ParameterRef{}
+ }
+ parameterRef, err := oai.newParameterRefWithStructMethod(structField, in.Path, in.Method)
+ if err != nil {
+ return err
+ }
+ if parameterRef != nil {
+ operation.Parameters = append(operation.Parameters, *parameterRef)
+ }
+ }
+
+ // =================================================================================================================
+ // Response.
+ // =================================================================================================================
+ if _, ok := operation.Responses[responseOkKey]; !ok {
+ var (
+ response = Response{
+ Content: map[string]MediaType{},
+ }
+ )
+ if len(outputMetaMap) > 0 {
+ if err := gconv.Struct(oai.fileMapWithShortTags(outputMetaMap), &response); err != nil {
+ return gerror.Wrap(err, `mapping struct tags to Response failed`)
+ }
+ }
+ // Supported mime types of response.
+ var (
+ contentTypes = oai.Config.ReadContentTypes
+ tagMimeValue = gmeta.Get(outputObject.Interface(), TagNameMime).String()
+ refInput = getResponseSchemaRefInput{
+ BusinessStructName: outputStructTypeName,
+ CommonResponseObject: oai.Config.CommonResponse,
+ CommonResponseDataField: oai.Config.CommonResponseDataField,
+ }
+ )
+ if tagMimeValue != "" {
+ contentTypes = gstr.SplitAndTrim(tagMimeValue, ",")
+ }
+ for _, v := range contentTypes {
+ // If customized response mime type, it then ignores common response feature.
+ if tagMimeValue != "" {
+ refInput.CommonResponseObject = nil
+ refInput.CommonResponseDataField = ""
+ }
+ schemaRef, err := oai.getResponseSchemaRef(refInput)
+ if err != nil {
+ return err
+ }
+ response.Content[v] = MediaType{
+ Schema: schemaRef,
+ }
+ }
+ operation.Responses[responseOkKey] = ResponseRef{Value: &response}
+ }
+
+ // Assign to certain operation attribute.
+ switch gstr.ToUpper(in.Method) {
+ case HttpMethodGet:
+ // GET operations cannot have a requestBody.
+ operation.RequestBody = nil
+ path.Get = &operation
+
+ case HttpMethodPut:
+ path.Put = &operation
+
+ case HttpMethodPost:
+ path.Post = &operation
+
+ case HttpMethodDelete:
+ // DELETE operations cannot have a requestBody.
+ operation.RequestBody = nil
+ path.Delete = &operation
+
+ case HttpMethodConnect:
+ // Nothing to do for Connect.
+
+ case HttpMethodHead:
+ path.Head = &operation
+
+ case HttpMethodOptions:
+ path.Options = &operation
+
+ case HttpMethodPatch:
+ path.Patch = &operation
+
+ case HttpMethodTrace:
+ path.Trace = &operation
+
+ default:
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid method "%s"`, in.Method)
+ }
+ oai.Paths[in.Path] = path
+ return nil
+}
+
+func (oai *OpenApiV3) doesStructHasNoFields(s interface{}) bool {
+ return reflect.TypeOf(s).NumField() == 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_requestbody.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_requestbody.go
new file mode 100644
index 000000000000..e3c47aa814ad
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_requestbody.go
@@ -0,0 +1,102 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// RequestBody is specified by OpenAPI/Swagger 3.0 standard.
+type RequestBody struct {
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Required bool `json:"required,omitempty" yaml:"required,omitempty"`
+ Content Content `json:"content,omitempty" yaml:"content,omitempty"`
+}
+
+type RequestBodyRef struct {
+ Ref string
+ Value *RequestBody
+}
+
+func (r RequestBodyRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
+
+type getRequestSchemaRefInput struct {
+ BusinessStructName string
+ RequestObject interface{}
+ RequestDataField string
+}
+
+func (oai *OpenApiV3) getRequestSchemaRef(in getRequestSchemaRefInput) (*SchemaRef, error) {
+ if oai.Config.CommonRequest == nil {
+ return &SchemaRef{
+ Ref: in.BusinessStructName,
+ }, nil
+ }
+
+ var (
+ dataFieldsPartsArray = gstr.Split(in.RequestDataField, ".")
+ bizRequestStructSchemaRef, bizRequestStructSchemaRefExist = oai.Components.Schemas[in.BusinessStructName]
+ schema, err = oai.structToSchema(in.RequestObject)
+ )
+ if err != nil {
+ return nil, err
+ }
+ if in.RequestDataField == "" && bizRequestStructSchemaRefExist {
+ for k, v := range bizRequestStructSchemaRef.Value.Properties {
+ schema.Properties[k] = v
+ }
+ } else {
+ structFields, _ := gstructs.Fields(gstructs.FieldsInput{
+ Pointer: in.RequestObject,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ for _, structField := range structFields {
+ var (
+ fieldName = structField.Name()
+ )
+ if jsonName := structField.TagJsonName(); jsonName != "" {
+ fieldName = jsonName
+ }
+ switch len(dataFieldsPartsArray) {
+ case 1:
+ if structField.Name() == dataFieldsPartsArray[0] {
+ schema.Properties[fieldName] = bizRequestStructSchemaRef
+ break
+ }
+ default:
+ if structField.Name() == dataFieldsPartsArray[0] {
+ var (
+ structFieldInstance = reflect.New(structField.Type().Type).Elem()
+ )
+ schemaRef, err := oai.getRequestSchemaRef(getRequestSchemaRefInput{
+ BusinessStructName: in.BusinessStructName,
+ RequestObject: structFieldInstance,
+ RequestDataField: gstr.Join(dataFieldsPartsArray[1:], "."),
+ })
+ if err != nil {
+ return nil, err
+ }
+ schema.Properties[fieldName] = *schemaRef
+ break
+ }
+ }
+ }
+ }
+
+ return &SchemaRef{
+ Value: schema,
+ }, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_response.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_response.go
new file mode 100644
index 000000000000..a7a73620cf9d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_response.go
@@ -0,0 +1,106 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Response is specified by OpenAPI/Swagger 3.0 standard.
+type Response struct {
+ Description string `json:"description" yaml:"description"`
+ Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
+ Content Content `json:"content,omitempty" yaml:"content,omitempty"`
+ Links Links `json:"links,omitempty" yaml:"links,omitempty"`
+}
+
+// Responses is specified by OpenAPI/Swagger 3.0 standard.
+type Responses map[string]ResponseRef
+
+type ResponseRef struct {
+ Ref string
+ Value *Response
+}
+
+func (r ResponseRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
+
+type getResponseSchemaRefInput struct {
+ BusinessStructName string // The business struct name.
+ CommonResponseObject interface{} // Common response object.
+ CommonResponseDataField string // Common response data field.
+}
+
+func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*SchemaRef, error) {
+ if in.CommonResponseObject == nil {
+ return &SchemaRef{
+ Ref: in.BusinessStructName,
+ }, nil
+ }
+
+ var (
+ dataFieldsPartsArray = gstr.Split(in.CommonResponseDataField, ".")
+ bizResponseStructSchemaRef, bizResponseStructSchemaRefExist = oai.Components.Schemas[in.BusinessStructName]
+ schema, err = oai.structToSchema(in.CommonResponseObject)
+ )
+ if err != nil {
+ return nil, err
+ }
+ if in.CommonResponseDataField == "" && bizResponseStructSchemaRefExist {
+ for k, v := range bizResponseStructSchemaRef.Value.Properties {
+ schema.Properties[k] = v
+ }
+ } else {
+ structFields, _ := gstructs.Fields(gstructs.FieldsInput{
+ Pointer: in.CommonResponseObject,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ for _, structField := range structFields {
+ var (
+ fieldName = structField.Name()
+ )
+ if jsonName := structField.TagJsonName(); jsonName != "" {
+ fieldName = jsonName
+ }
+ switch len(dataFieldsPartsArray) {
+ case 1:
+ if structField.Name() == dataFieldsPartsArray[0] {
+ schema.Properties[fieldName] = bizResponseStructSchemaRef
+ break
+ }
+ default:
+ if structField.Name() == dataFieldsPartsArray[0] {
+ var (
+ structFieldInstance = reflect.New(structField.Type().Type).Elem()
+ )
+ schemaRef, err := oai.getResponseSchemaRef(getResponseSchemaRefInput{
+ BusinessStructName: in.BusinessStructName,
+ CommonResponseObject: structFieldInstance,
+ CommonResponseDataField: gstr.Join(dataFieldsPartsArray[1:], "."),
+ })
+ if err != nil {
+ return nil, err
+ }
+ schema.Properties[fieldName] = *schemaRef
+ break
+ }
+ }
+ }
+ }
+
+ return &SchemaRef{
+ Value: schema,
+ }, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_security.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_security.go
new file mode 100644
index 000000000000..e636b4b04554
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_security.go
@@ -0,0 +1,54 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+type SecurityScheme struct {
+ Type string `json:"type,omitempty" yaml:"type,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Name string `json:"name,omitempty" yaml:"name,omitempty"`
+ In string `json:"in,omitempty" yaml:"in,omitempty"`
+ Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
+ BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"`
+ Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"`
+ OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty" yaml:"openIdConnectUrl,omitempty"`
+}
+
+type SecuritySchemes map[string]SecuritySchemeRef
+
+type SecuritySchemeRef struct {
+ Ref string
+ Value *SecurityScheme
+}
+
+type SecurityRequirements []SecurityRequirement
+
+type SecurityRequirement map[string][]string
+
+type OAuthFlows struct {
+ Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
+ Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
+ ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
+ AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty" yaml:"authorizationCode,omitempty"`
+}
+
+type OAuthFlow struct {
+ AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
+ TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
+ RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
+ Scopes map[string]string `json:"scopes" yaml:"scopes"`
+}
+
+func (r SecuritySchemeRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_server.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_server.go
new file mode 100644
index 000000000000..3a2d0a07a238
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_server.go
@@ -0,0 +1,24 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// Server is specified by OpenAPI/Swagger standard version 3.0.
+type Server struct {
+ URL string `json:"url" yaml:"url"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Variables map[string]*ServerVariable `json:"variables,omitempty" yaml:"variables,omitempty"`
+}
+
+// ServerVariable is specified by OpenAPI/Swagger standard version 3.0.
+type ServerVariable struct {
+ Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"`
+ Default string `json:"default,omitempty" yaml:"default,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+}
+
+// Servers is specified by OpenAPI/Swagger standard version 3.0.
+type Servers []Server
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_shema.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_shema.go
new file mode 100644
index 000000000000..dceebdc5eb8e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_shema.go
@@ -0,0 +1,161 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gmeta"
+)
+
+type Schemas map[string]SchemaRef
+
+// Schema is specified by OpenAPI/Swagger 3.0 standard.
+type Schema struct {
+ OneOf SchemaRefs `json:"oneOf,omitempty" yaml:"oneOf,omitempty"`
+ AnyOf SchemaRefs `json:"anyOf,omitempty" yaml:"anyOf,omitempty"`
+ AllOf SchemaRefs `json:"allOf,omitempty" yaml:"allOf,omitempty"`
+ Not *SchemaRef `json:"not,omitempty" yaml:"not,omitempty"`
+ Type string `json:"type,omitempty" yaml:"type,omitempty"`
+ Title string `json:"title,omitempty" yaml:"title,omitempty"`
+ Format string `json:"format,omitempty" yaml:"format,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ Enum []interface{} `json:"enum,omitempty" yaml:"enum,omitempty"`
+ Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
+ Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
+ ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+ UniqueItems bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
+ ExclusiveMin bool `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"`
+ ExclusiveMax bool `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"`
+ Nullable bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
+ ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"`
+ WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"`
+ AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
+ XML interface{} `json:"xml,omitempty" yaml:"xml,omitempty"`
+ Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
+ Min *float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"`
+ Max *float64 `json:"maximum,omitempty" yaml:"maximum,omitempty"`
+ MultipleOf *float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"`
+ MinLength uint64 `json:"minLength,omitempty" yaml:"minLength,omitempty"`
+ MaxLength *uint64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
+ Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
+ MinItems uint64 `json:"minItems,omitempty" yaml:"minItems,omitempty"`
+ MaxItems *uint64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
+ Items *SchemaRef `json:"items,omitempty" yaml:"items,omitempty"`
+ Required []string `json:"required,omitempty" yaml:"required,omitempty"`
+ Properties Schemas `json:"properties,omitempty" yaml:"properties,omitempty"`
+ MinProps uint64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
+ MaxProps *uint64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
+ AdditionalProperties *SchemaRef `json:"additionalProperties,omitempty" yaml:"additionalProperties"`
+ Discriminator *Discriminator `json:"discriminator,omitempty" yaml:"discriminator,omitempty"`
+}
+
+// Discriminator is specified by OpenAPI/Swagger standard version 3.0.
+type Discriminator struct {
+ PropertyName string `json:"propertyName" yaml:"propertyName"`
+ Mapping map[string]string `json:"mapping,omitempty" yaml:"mapping,omitempty"`
+}
+
+// addSchema creates schemas with objects.
+// Note that the `object` can be array alias like: `type Res []Item`.
+func (oai *OpenApiV3) addSchema(object ...interface{}) error {
+ for _, v := range object {
+ if err := oai.doAddSchemaSingle(v); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (oai *OpenApiV3) doAddSchemaSingle(object interface{}) error {
+ if oai.Components.Schemas == nil {
+ oai.Components.Schemas = map[string]SchemaRef{}
+ }
+
+ var (
+ reflectType = reflect.TypeOf(object)
+ structTypeName = oai.golangTypeToSchemaName(reflectType)
+ )
+
+ // Already added.
+ if _, ok := oai.Components.Schemas[structTypeName]; ok {
+ return nil
+ }
+ // Take the holder first.
+ oai.Components.Schemas[structTypeName] = SchemaRef{}
+
+ schema, err := oai.structToSchema(object)
+ if err != nil {
+ return err
+ }
+
+ oai.Components.Schemas[structTypeName] = SchemaRef{
+ Ref: "",
+ Value: schema,
+ }
+ return nil
+}
+
+// structToSchema converts and returns given struct object as Schema.
+func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) {
+ var (
+ tagMap = gmeta.Data(object)
+ schema = &Schema{
+ Properties: map[string]SchemaRef{},
+ }
+ )
+ if len(tagMap) > 0 {
+ err := gconv.Struct(oai.fileMapWithShortTags(tagMap), schema)
+ if err != nil {
+ return nil, gerror.Wrap(err, `mapping meta data tags to Schema failed`)
+ }
+ }
+ if schema.Type != "" && schema.Type != TypeObject {
+ return schema, nil
+ }
+ // []struct.
+ if utils.IsArray(object) {
+ schema.Type = TypeArray
+ subSchemaRef, err := oai.newSchemaRefWithGolangType(reflect.TypeOf(object).Elem(), nil)
+ if err != nil {
+ return nil, err
+ }
+ schema.Items = subSchemaRef
+ return schema, nil
+ }
+ // struct.
+ structFields, _ := gstructs.Fields(gstructs.FieldsInput{
+ Pointer: object,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ schema.Type = TypeObject
+ for _, structField := range structFields {
+ if !gstr.IsLetterUpper(structField.Name()[0]) {
+ continue
+ }
+ var (
+ fieldName = structField.Name()
+ )
+ if jsonName := structField.TagJsonName(); jsonName != "" {
+ fieldName = jsonName
+ }
+ schemaRef, err := oai.newSchemaRefWithGolangType(
+ structField.Type().Type,
+ structField.TagMap(),
+ )
+ if err != nil {
+ return nil, err
+ }
+ schema.Properties[fieldName] = *schemaRef
+ }
+ return schema, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_shemaref.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_shemaref.go
new file mode 100644
index 000000000000..14d356686cc7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_shemaref.go
@@ -0,0 +1,105 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+type SchemaRefs []SchemaRef
+
+type SchemaRef struct {
+ Ref string
+ Value *Schema
+}
+
+func (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap map[string]string) (*SchemaRef, error) {
+ var (
+ oaiType = oai.golangTypeToOAIType(golangType)
+ oaiFormat = oai.golangTypeToOAIFormat(golangType)
+ schemaRef = &SchemaRef{}
+ schema = &Schema{
+ Type: oaiType,
+ Format: oaiFormat,
+ }
+ )
+ if len(tagMap) > 0 {
+ if err := gconv.Struct(oai.fileMapWithShortTags(tagMap), schema); err != nil {
+ return nil, gerror.Wrap(err, `mapping struct tags to Schema failed`)
+ }
+ }
+ schemaRef.Value = schema
+ switch oaiType {
+ case
+ TypeNumber,
+ TypeString,
+ TypeBoolean:
+ // Nothing to do.
+
+ case
+ TypeArray:
+ subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
+ if err != nil {
+ return nil, err
+ }
+ schema.Items = subSchemaRef
+
+ case
+ TypeObject:
+ for golangType.Kind() == reflect.Ptr {
+ golangType = golangType.Elem()
+ }
+ switch golangType.Kind() {
+ case reflect.Map:
+ // Specially for map type.
+ subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil)
+ if err != nil {
+ return nil, err
+ }
+ schema.AdditionalProperties = subSchemaRef
+ return schemaRef, nil
+
+ case reflect.Interface:
+ // Specially for interface type.
+ var (
+ structTypeName = oai.golangTypeToSchemaName(golangType)
+ )
+ if _, ok := oai.Components.Schemas[structTypeName]; !ok {
+ if err := oai.addSchema(reflect.New(golangType).Interface()); err != nil {
+ return nil, err
+ }
+ }
+ schemaRef.Ref = structTypeName
+ schemaRef.Value = nil
+
+ default:
+ // Normal struct object.
+ var (
+ structTypeName = oai.golangTypeToSchemaName(golangType)
+ )
+ if _, ok := oai.Components.Schemas[structTypeName]; !ok {
+ if err := oai.addSchema(reflect.New(golangType).Elem().Interface()); err != nil {
+ return nil, err
+ }
+ }
+ schemaRef.Ref = structTypeName
+ schemaRef.Value = nil
+ }
+ }
+ return schemaRef, nil
+}
+
+func (r SchemaRef) MarshalJSON() ([]byte, error) {
+ if r.Ref != "" {
+ return formatRefToBytes(r.Ref), nil
+ }
+ return json.Marshal(r.Value)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_tags.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_tags.go
new file mode 100644
index 000000000000..844d9a634a75
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/protocol/goai/goai_tags.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package goai
+
+// Tags is specified by OpenAPI/Swagger 3.0 standard.
+type Tags []Tag
+
+// Tag is specified by OpenAPI/Swagger 3.0 standard.
+type Tag struct {
+ Name string `json:"name,omitempty" yaml:"name,omitempty"`
+ Description string `json:"description,omitempty" yaml:"description,omitempty"`
+ ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gregex/gregex.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gregex/gregex.go
new file mode 100644
index 000000000000..a1dfc96860c8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gregex/gregex.go
@@ -0,0 +1,149 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gregex provides high performance API for regular expression functionality.
+package gregex
+
+import (
+ "regexp"
+)
+
+// Quote quotes `s` by replacing special chars in `s`
+// to match the rules of regular expression pattern.
+// And returns the copy.
+//
+// Eg: Quote(`[foo]`) returns `\[foo\]`.
+func Quote(s string) string {
+ return regexp.QuoteMeta(s)
+}
+
+// Validate checks whether given regular expression pattern `pattern` valid.
+func Validate(pattern string) error {
+ _, err := getRegexp(pattern)
+ return err
+}
+
+// IsMatch checks whether given bytes `src` matches `pattern`.
+func IsMatch(pattern string, src []byte) bool {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.Match(src)
+ }
+ return false
+}
+
+// IsMatchString checks whether given string `src` matches `pattern`.
+func IsMatchString(pattern string, src string) bool {
+ return IsMatch(pattern, []byte(src))
+}
+
+// Match return bytes slice that matched `pattern`.
+func Match(pattern string, src []byte) ([][]byte, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.FindSubmatch(src), nil
+ } else {
+ return nil, err
+ }
+}
+
+// MatchString return strings that matched `pattern`.
+func MatchString(pattern string, src string) ([]string, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.FindStringSubmatch(src), nil
+ } else {
+ return nil, err
+ }
+}
+
+// MatchAll return all bytes slices that matched `pattern`.
+func MatchAll(pattern string, src []byte) ([][][]byte, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.FindAllSubmatch(src, -1), nil
+ } else {
+ return nil, err
+ }
+}
+
+// MatchAllString return all strings that matched `pattern`.
+func MatchAllString(pattern string, src string) ([][]string, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.FindAllStringSubmatch(src, -1), nil
+ } else {
+ return nil, err
+ }
+}
+
+// Replace replaces all matched `pattern` in bytes `src` with bytes `replace`.
+func Replace(pattern string, replace, src []byte) ([]byte, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.ReplaceAll(src, replace), nil
+ } else {
+ return nil, err
+ }
+}
+
+// ReplaceString replace all matched `pattern` in string `src` with string `replace`.
+func ReplaceString(pattern, replace, src string) (string, error) {
+ r, e := Replace(pattern, []byte(replace), []byte(src))
+ return string(r), e
+}
+
+// ReplaceFunc replace all matched `pattern` in bytes `src`
+// with custom replacement function `replaceFunc`.
+func ReplaceFunc(pattern string, src []byte, replaceFunc func(b []byte) []byte) ([]byte, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.ReplaceAllFunc(src, replaceFunc), nil
+ } else {
+ return nil, err
+ }
+}
+
+// ReplaceFuncMatch replace all matched `pattern` in bytes `src`
+// with custom replacement function `replaceFunc`.
+// The parameter `match` type for `replaceFunc` is [][]byte,
+// which is the result contains all sub-patterns of `pattern` using Match function.
+func ReplaceFuncMatch(pattern string, src []byte, replaceFunc func(match [][]byte) []byte) ([]byte, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.ReplaceAllFunc(src, func(bytes []byte) []byte {
+ match, _ := Match(pattern, bytes)
+ return replaceFunc(match)
+ }), nil
+ } else {
+ return nil, err
+ }
+}
+
+// ReplaceStringFunc replace all matched `pattern` in string `src`
+// with custom replacement function `replaceFunc`.
+func ReplaceStringFunc(pattern string, src string, replaceFunc func(s string) string) (string, error) {
+ bytes, err := ReplaceFunc(pattern, []byte(src), func(bytes []byte) []byte {
+ return []byte(replaceFunc(string(bytes)))
+ })
+ return string(bytes), err
+}
+
+// ReplaceStringFuncMatch replace all matched `pattern` in string `src`
+// with custom replacement function `replaceFunc`.
+// The parameter `match` type for `replaceFunc` is []string,
+// which is the result contains all sub-patterns of `pattern` using MatchString function.
+func ReplaceStringFuncMatch(pattern string, src string, replaceFunc func(match []string) string) (string, error) {
+ if r, err := getRegexp(pattern); err == nil {
+ return string(r.ReplaceAllFunc([]byte(src), func(bytes []byte) []byte {
+ match, _ := MatchString(pattern, string(bytes))
+ return []byte(replaceFunc(match))
+ })), nil
+ } else {
+ return "", err
+ }
+}
+
+// Split slices `src` into substrings separated by the expression and returns a slice of
+// the substrings between those expression matches.
+func Split(pattern string, src string) []string {
+ if r, err := getRegexp(pattern); err == nil {
+ return r.Split(src, -1)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gregex/gregex_cache.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gregex/gregex_cache.go
new file mode 100644
index 000000000000..7ceb778e4110
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gregex/gregex_cache.go
@@ -0,0 +1,51 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gregex
+
+import (
+ "regexp"
+ "sync"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+var (
+ regexMu = sync.RWMutex{}
+ // Cache for regex object.
+ // Note that:
+ // 1. It uses sync.RWMutex ensuring the concurrent safety.
+ // 2. There's no expiring logic for this map.
+ regexMap = make(map[string]*regexp.Regexp)
+)
+
+// getRegexp returns *regexp.Regexp object with given `pattern`.
+// It uses cache to enhance the performance for compiling regular expression pattern,
+// which means, it will return the same *regexp.Regexp object with the same regular
+// expression pattern.
+//
+// It is concurrent-safe for multiple goroutines.
+func getRegexp(pattern string) (regex *regexp.Regexp, err error) {
+ // Retrieve the regular expression object using reading lock.
+ regexMu.RLock()
+ regex = regexMap[pattern]
+ regexMu.RUnlock()
+ if regex != nil {
+ return
+ }
+ // If it does not exist in the cache,
+ // it compiles the pattern and creates one.
+ regex, err = regexp.Compile(pattern)
+ if err != nil {
+ err = gerror.Wrapf(err, `regexp.Compile failed for pattern "%s"`, pattern)
+ return
+ }
+ // Cache the result object using writing lock.
+ regexMu.Lock()
+ regexMap[pattern] = regex
+ regexMu.Unlock()
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr.go
new file mode 100644
index 000000000000..9932c5908c26
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr.go
@@ -0,0 +1,17 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gstr provides functions for string handling.
+package gstr
+
+const (
+ // NotFoundIndex is the position index for string not found in searching functions.
+ NotFoundIndex = -1
+)
+
+const (
+ defaultSuffixForStrLimit = "..."
+)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_array.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_array.go
new file mode 100644
index 000000000000..1e467023731e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_array.go
@@ -0,0 +1,31 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+// SearchArray searches string `s` in string slice `a` case-sensitively,
+// returns its index in `a`.
+// If `s` is not found in `a`, it returns -1.
+func SearchArray(a []string, s string) int {
+ for i, v := range a {
+ if s == v {
+ return i
+ }
+ }
+ return NotFoundIndex
+}
+
+// InArray checks whether string `s` in slice `a`.
+func InArray(a []string, s string) bool {
+ return SearchArray(a, s) != NotFoundIndex
+}
+
+// PrefixArray adds `prefix` string for each item of `array`.
+func PrefixArray(array []string, prefix string) {
+ for k, v := range array {
+ array[k] = prefix + v
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_case.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_case.go
new file mode 100644
index 000000000000..c07fff72627e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_case.go
@@ -0,0 +1,184 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+//
+// | Function | Result |
+// |-----------------------------------|--------------------|
+// | CaseSnake(s) | any_kind_of_string |
+// | CaseSnakeScreaming(s) | ANY_KIND_OF_STRING |
+// | CaseSnakeFirstUpper("RGBCodeMd5") | rgb_code_md5 |
+// | CaseKebab(s) | any-kind-of-string |
+// | CaseKebabScreaming(s) | ANY-KIND-OF-STRING |
+// | CaseDelimited(s, '.') | any.kind.of.string |
+// | CaseDelimitedScreaming(s, '.') | ANY.KIND.OF.STRING |
+// | CaseCamel(s) | AnyKindOfString |
+// | CaseCamelLower(s) | anyKindOfString |
+
+package gstr
+
+import (
+ "regexp"
+ "strings"
+)
+
+var (
+ numberSequence = regexp.MustCompile(`([a-zA-Z]{0,1})(\d+)([a-zA-Z]{0,1})`)
+ firstCamelCaseStart = regexp.MustCompile(`([A-Z]+)([A-Z]?[_a-z\d]+)|$`)
+ firstCamelCaseEnd = regexp.MustCompile(`([\w\W]*?)([_]?[A-Z]+)$`)
+)
+
+// CaseCamel converts a string to CamelCase.
+func CaseCamel(s string) string {
+ return toCamelInitCase(s, true)
+}
+
+// CaseCamelLower converts a string to lowerCamelCase.
+func CaseCamelLower(s string) string {
+ if s == "" {
+ return s
+ }
+ if r := rune(s[0]); r >= 'A' && r <= 'Z' {
+ s = strings.ToLower(string(r)) + s[1:]
+ }
+ return toCamelInitCase(s, false)
+}
+
+// CaseSnake converts a string to snake_case.
+func CaseSnake(s string) string {
+ return CaseDelimited(s, '_')
+}
+
+// CaseSnakeScreaming converts a string to SNAKE_CASE_SCREAMING.
+func CaseSnakeScreaming(s string) string {
+ return CaseDelimitedScreaming(s, '_', true)
+}
+
+// CaseSnakeFirstUpper converts a string like "RGBCodeMd5" to "rgb_code_md5".
+// TODO for efficiency should change regexp to traversing string in future.
+func CaseSnakeFirstUpper(word string, underscore ...string) string {
+ replace := "_"
+ if len(underscore) > 0 {
+ replace = underscore[0]
+ }
+
+ m := firstCamelCaseEnd.FindAllStringSubmatch(word, 1)
+ if len(m) > 0 {
+ word = m[0][1] + replace + TrimLeft(ToLower(m[0][2]), replace)
+ }
+
+ for {
+ m = firstCamelCaseStart.FindAllStringSubmatch(word, 1)
+ if len(m) > 0 && m[0][1] != "" {
+ w := strings.ToLower(m[0][1])
+ w = w[:len(w)-1] + replace + string(w[len(w)-1])
+
+ word = strings.Replace(word, m[0][1], w, 1)
+ } else {
+ break
+ }
+ }
+
+ return TrimLeft(word, replace)
+}
+
+// CaseKebab converts a string to kebab-case
+func CaseKebab(s string) string {
+ return CaseDelimited(s, '-')
+}
+
+// CaseKebabScreaming converts a string to KEBAB-CASE-SCREAMING.
+func CaseKebabScreaming(s string) string {
+ return CaseDelimitedScreaming(s, '-', true)
+}
+
+// CaseDelimited converts a string to snake.case.delimited.
+func CaseDelimited(s string, del byte) string {
+ return CaseDelimitedScreaming(s, del, false)
+}
+
+// CaseDelimitedScreaming converts a string to DELIMITED.SCREAMING.CASE or delimited.screaming.case.
+func CaseDelimitedScreaming(s string, del uint8, screaming bool) string {
+ s = addWordBoundariesToNumbers(s)
+ s = strings.Trim(s, " ")
+ n := ""
+ for i, v := range s {
+ // treat acronyms as words, eg for JSONData -> JSON is a whole word
+ nextCaseIsChanged := false
+ if i+1 < len(s) {
+ next := s[i+1]
+ if (v >= 'A' && v <= 'Z' && next >= 'a' && next <= 'z') || (v >= 'a' && v <= 'z' && next >= 'A' && next <= 'Z') {
+ nextCaseIsChanged = true
+ }
+ }
+
+ if i > 0 && n[len(n)-1] != del && nextCaseIsChanged {
+ // add underscore if next letter case type is changed
+ if v >= 'A' && v <= 'Z' {
+ n += string(del) + string(v)
+ } else if v >= 'a' && v <= 'z' {
+ n += string(v) + string(del)
+ }
+ } else if v == ' ' || v == '_' || v == '-' || v == '.' {
+ // replace spaces/underscores with delimiters
+ n += string(del)
+ } else {
+ n = n + string(v)
+ }
+ }
+
+ if screaming {
+ n = strings.ToUpper(n)
+ } else {
+ n = strings.ToLower(n)
+ }
+ return n
+}
+
+func addWordBoundariesToNumbers(s string) string {
+ r := numberSequence.ReplaceAllFunc([]byte(s), func(bytes []byte) []byte {
+ var result []byte
+ match := numberSequence.FindSubmatch(bytes)
+ if len(match[1]) > 0 {
+ result = append(result, match[1]...)
+ result = append(result, []byte(" ")...)
+ }
+ result = append(result, match[2]...)
+ if len(match[3]) > 0 {
+ result = append(result, []byte(" ")...)
+ result = append(result, match[3]...)
+ }
+ return result
+ })
+ return string(r)
+}
+
+// Converts a string to CamelCase
+func toCamelInitCase(s string, initCase bool) string {
+ s = addWordBoundariesToNumbers(s)
+ s = strings.Trim(s, " ")
+ n := ""
+ capNext := initCase
+ for _, v := range s {
+ if v >= 'A' && v <= 'Z' {
+ n += string(v)
+ }
+ if v >= '0' && v <= '9' {
+ n += string(v)
+ }
+ if v >= 'a' && v <= 'z' {
+ if capNext {
+ n += strings.ToUpper(string(v))
+ } else {
+ n += string(v)
+ }
+ }
+ if v == '_' || v == ' ' || v == '-' || v == '.' {
+ capNext = true
+ } else {
+ capNext = false
+ }
+ }
+ return n
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_compare.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_compare.go
new file mode 100644
index 000000000000..ae877f677580
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_compare.go
@@ -0,0 +1,21 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "strings"
+
+// Compare returns an integer comparing two strings lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
+func Compare(a, b string) int {
+ return strings.Compare(a, b)
+}
+
+// Equal reports whether `a` and `b`, interpreted as UTF-8 strings,
+// are equal under Unicode case-folding, case-insensitively.
+func Equal(a, b string) bool {
+ return strings.EqualFold(a, b)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_contain.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_contain.go
new file mode 100644
index 000000000000..829945802d1d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_contain.go
@@ -0,0 +1,24 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "strings"
+
+// Contains reports whether `substr` is within `str`, case-sensitively.
+func Contains(str, substr string) bool {
+ return strings.Contains(str, substr)
+}
+
+// ContainsI reports whether substr is within str, case-insensitively.
+func ContainsI(str, substr string) bool {
+ return PosI(str, substr) != -1
+}
+
+// ContainsAny reports whether any Unicode code points in `chars` are within `s`.
+func ContainsAny(s, chars string) bool {
+ return strings.ContainsAny(s, chars)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_convert.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_convert.go
new file mode 100644
index 000000000000..7c4a6add3334
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_convert.go
@@ -0,0 +1,236 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/gogf/gf/v2/util/grand"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// Chr return the ascii string of a number(0-255).
+func Chr(ascii int) string {
+ return string([]byte{byte(ascii % 256)})
+}
+
+// Ord converts the first byte of a string to a value between 0 and 255.
+func Ord(char string) int {
+ return int(char[0])
+}
+
+var (
+ // octReg is the regular expression object for checks octal string.
+ octReg = regexp.MustCompile(`\\[0-7]{3}`)
+)
+
+// OctStr converts string container octal string to its original string,
+// for example, to Chinese string.
+// Eg: `\346\200\241` -> 怡
+func OctStr(str string) string {
+ return octReg.ReplaceAllStringFunc(
+ str,
+ func(s string) string {
+ i, _ := strconv.ParseInt(s[1:], 8, 0)
+ return string([]byte{byte(i)})
+ },
+ )
+}
+
+// Reverse returns a string which is the reverse of `str`.
+func Reverse(str string) string {
+ runes := []rune(str)
+ for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
+ runes[i], runes[j] = runes[j], runes[i]
+ }
+ return string(runes)
+}
+
+// NumberFormat formats a number with grouped thousands.
+// `decimals`: Sets the number of decimal points.
+// `decPoint`: Sets the separator for the decimal point.
+// `thousandsSep`: Sets the thousands' separator.
+// See http://php.net/manual/en/function.number-format.php.
+func NumberFormat(number float64, decimals int, decPoint, thousandsSep string) string {
+ neg := false
+ if number < 0 {
+ number = -number
+ neg = true
+ }
+ // Will round off
+ str := fmt.Sprintf("%."+strconv.Itoa(decimals)+"F", number)
+ prefix, suffix := "", ""
+ if decimals > 0 {
+ prefix = str[:len(str)-(decimals+1)]
+ suffix = str[len(str)-decimals:]
+ } else {
+ prefix = str
+ }
+ sep := []byte(thousandsSep)
+ n, l1, l2 := 0, len(prefix), len(sep)
+ // thousands sep num
+ c := (l1 - 1) / 3
+ tmp := make([]byte, l2*c+l1)
+ pos := len(tmp) - 1
+ for i := l1 - 1; i >= 0; i, n, pos = i-1, n+1, pos-1 {
+ if l2 > 0 && n > 0 && n%3 == 0 {
+ for j := range sep {
+ tmp[pos] = sep[l2-j-1]
+ pos--
+ }
+ }
+ tmp[pos] = prefix[i]
+ }
+ s := string(tmp)
+ if decimals > 0 {
+ s += decPoint + suffix
+ }
+ if neg {
+ s = "-" + s
+ }
+
+ return s
+}
+
+// Shuffle randomly shuffles a string.
+// It considers parameter `str` as unicode string.
+func Shuffle(str string) string {
+ runes := []rune(str)
+ s := make([]rune, len(runes))
+ for i, v := range grand.Perm(len(runes)) {
+ s[i] = runes[v]
+ }
+ return string(s)
+}
+
+// HideStr replaces part of the string `str` to `hide` by `percentage` from the `middle`.
+// It considers parameter `str` as unicode string.
+func HideStr(str string, percent int, hide string) string {
+ array := strings.Split(str, "@")
+ if len(array) > 1 {
+ str = array[0]
+ }
+ var (
+ rs = []rune(str)
+ length = len(rs)
+ mid = math.Floor(float64(length / 2))
+ hideLen = int(math.Floor(float64(length) * (float64(percent) / 100)))
+ start = int(mid - math.Floor(float64(hideLen)/2))
+ hideStr = []rune("")
+ hideRune = []rune(hide)
+ )
+ for i := 0; i < hideLen; i++ {
+ hideStr = append(hideStr, hideRune...)
+ }
+ buffer := bytes.NewBuffer(nil)
+ buffer.WriteString(string(rs[0:start]))
+ buffer.WriteString(string(hideStr))
+ buffer.WriteString(string(rs[start+hideLen:]))
+ if len(array) > 1 {
+ buffer.WriteString("@" + array[1])
+ }
+ return buffer.String()
+}
+
+// Nl2Br inserts HTML line breaks(`br`| ) before all newlines in a string:
+// \n\r, \r\n, \r, \n.
+// It considers parameter `str` as unicode string.
+func Nl2Br(str string, isXhtml ...bool) string {
+ r, n, runes := '\r', '\n', []rune(str)
+ var br []byte
+ if len(isXhtml) > 0 && isXhtml[0] {
+ br = []byte(" ")
+ } else {
+ br = []byte(" ")
+ }
+ skip := false
+ length := len(runes)
+ var buf bytes.Buffer
+ for i, v := range runes {
+ if skip {
+ skip = false
+ continue
+ }
+ switch v {
+ case n, r:
+ if (i+1 < length) && (v == r && runes[i+1] == n) || (v == n && runes[i+1] == r) {
+ buf.Write(br)
+ skip = true
+ continue
+ }
+ buf.Write(br)
+ default:
+ buf.WriteRune(v)
+ }
+ }
+ return buf.String()
+}
+
+// WordWrap wraps a string to a given number of characters.
+// TODO: Enable cut parameter, see http://php.net/manual/en/function.wordwrap.php.
+func WordWrap(str string, width int, br string) string {
+ if br == "" {
+ br = "\n"
+ }
+ var (
+ current int
+ wordBuf, spaceBuf bytes.Buffer
+ init = make([]byte, 0, len(str))
+ buf = bytes.NewBuffer(init)
+ )
+ for _, char := range []rune(str) {
+ if char == '\n' {
+ if wordBuf.Len() == 0 {
+ if current+spaceBuf.Len() > width {
+ current = 0
+ } else {
+ current += spaceBuf.Len()
+ spaceBuf.WriteTo(buf)
+ }
+ spaceBuf.Reset()
+ } else {
+ current += spaceBuf.Len() + wordBuf.Len()
+ spaceBuf.WriteTo(buf)
+ spaceBuf.Reset()
+ wordBuf.WriteTo(buf)
+ wordBuf.Reset()
+ }
+ buf.WriteRune(char)
+ current = 0
+ } else if unicode.IsSpace(char) {
+ if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
+ current += spaceBuf.Len() + wordBuf.Len()
+ spaceBuf.WriteTo(buf)
+ spaceBuf.Reset()
+ wordBuf.WriteTo(buf)
+ wordBuf.Reset()
+ }
+ spaceBuf.WriteRune(char)
+ } else {
+ wordBuf.WriteRune(char)
+ if current+spaceBuf.Len()+wordBuf.Len() > width && wordBuf.Len() < width {
+ buf.WriteString(br)
+ current = 0
+ spaceBuf.Reset()
+ }
+ }
+ }
+
+ if wordBuf.Len() == 0 {
+ if current+spaceBuf.Len() <= width {
+ spaceBuf.WriteTo(buf)
+ }
+ } else {
+ spaceBuf.WriteTo(buf)
+ wordBuf.WriteTo(buf)
+ }
+ return buf.String()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_count.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_count.go
new file mode 100644
index 000000000000..cd0f0a19ecfa
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_count.go
@@ -0,0 +1,63 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+// Count counts the number of `substr` appears in `s`.
+// It returns 0 if no `substr` found in `s`.
+func Count(s, substr string) int {
+ return strings.Count(s, substr)
+}
+
+// CountI counts the number of `substr` appears in `s`, case-insensitively.
+// It returns 0 if no `substr` found in `s`.
+func CountI(s, substr string) int {
+ return strings.Count(ToLower(s), ToLower(substr))
+}
+
+// CountWords returns information about words' count used in a string.
+// It considers parameter `str` as unicode string.
+func CountWords(str string) map[string]int {
+ m := make(map[string]int)
+ buffer := bytes.NewBuffer(nil)
+ for _, r := range []rune(str) {
+ if unicode.IsSpace(r) {
+ if buffer.Len() > 0 {
+ m[buffer.String()]++
+ buffer.Reset()
+ }
+ } else {
+ buffer.WriteRune(r)
+ }
+ }
+ if buffer.Len() > 0 {
+ m[buffer.String()]++
+ }
+ return m
+}
+
+// CountChars returns information about chars' count used in a string.
+// It considers parameter `str` as unicode string.
+func CountChars(str string, noSpace ...bool) map[string]int {
+ m := make(map[string]int)
+ countSpace := true
+ if len(noSpace) > 0 && noSpace[0] {
+ countSpace = false
+ }
+ for _, r := range []rune(str) {
+ if !countSpace && unicode.IsSpace(r) {
+ continue
+ }
+ m[string(r)]++
+ }
+ return m
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_create.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_create.go
new file mode 100644
index 000000000000..8e5ff31294ae
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_create.go
@@ -0,0 +1,14 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "strings"
+
+// Repeat returns a new string consisting of multiplier copies of the string input.
+func Repeat(input string, multiplier int) string {
+ return strings.Repeat(input, multiplier)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_domain.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_domain.go
new file mode 100644
index 000000000000..45f31bb723b1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_domain.go
@@ -0,0 +1,44 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "strings"
+
+// IsSubDomain checks whether `subDomain` is sub-domain of mainDomain.
+// It supports '*' in `mainDomain`.
+func IsSubDomain(subDomain string, mainDomain string) bool {
+ if p := strings.IndexByte(subDomain, ':'); p != -1 {
+ subDomain = subDomain[0:p]
+ }
+ if p := strings.IndexByte(mainDomain, ':'); p != -1 {
+ mainDomain = mainDomain[0:p]
+ }
+ subArray := strings.Split(subDomain, ".")
+ mainArray := strings.Split(mainDomain, ".")
+ subLength := len(subArray)
+ mainLength := len(mainArray)
+ // Eg:
+ // "s.s.goframe.org" is not sub-domain of "*.goframe.org"
+ // but
+ // "s.s.goframe.org" is sub-domain of "goframe.org"
+ if mainLength > 2 && subLength > mainLength {
+ return false
+ }
+ minLength := subLength
+ if mainLength < minLength {
+ minLength = mainLength
+ }
+ for i := minLength; i > 0; i-- {
+ if mainArray[mainLength-i] == "*" {
+ continue
+ }
+ if mainArray[mainLength-i] != subArray[subLength-i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_is.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_is.go
new file mode 100644
index 000000000000..2f52e94952a2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_is.go
@@ -0,0 +1,14 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "github.com/gogf/gf/v2/internal/utils"
+
+// IsNumeric tests whether the given string s is numeric.
+func IsNumeric(s string) bool {
+ return utils.IsNumeric(s)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_length.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_length.go
new file mode 100644
index 000000000000..9e5b915b46dc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_length.go
@@ -0,0 +1,14 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "unicode/utf8"
+
+// LenRune returns string length of unicode.
+func LenRune(str string) int {
+ return utf8.RuneCountInString(str)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_parse.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_parse.go
new file mode 100644
index 000000000000..4a95780a32cb
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_parse.go
@@ -0,0 +1,181 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "net/url"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+)
+
+// Parse parses the string into map[string]interface{}.
+//
+// v1=m&v2=n -> map[v1:m v2:n]
+// v[a]=m&v[b]=n -> map[v:map[a:m b:n]]
+// v[a][a]=m&v[a][b]=n -> map[v:map[a:map[a:m b:n]]]
+// v[]=m&v[]=n -> map[v:[m n]]
+// v[a][]=m&v[a][]=n -> map[v:map[a:[m n]]]
+// v[][]=m&v[][]=n -> map[v:[map[]]] // Currently does not support nested slice.
+// v=m&v[a]=n -> error
+// a .[[b=c -> map[a___[b:c]
+//
+func Parse(s string) (result map[string]interface{}, err error) {
+ if s == "" {
+ return nil, nil
+ }
+ result = make(map[string]interface{})
+ parts := strings.Split(s, "&")
+ for _, part := range parts {
+ pos := strings.Index(part, "=")
+ if pos <= 0 {
+ continue
+ }
+ key, err := url.QueryUnescape(part[:pos])
+ if err != nil {
+ err = gerror.Wrapf(err, `url.QueryUnescape failed for string "%s"`, part[:pos])
+ return nil, err
+ }
+ for key[0] == ' ' {
+ key = key[1:]
+ }
+ if key == "" || key[0] == '[' {
+ continue
+ }
+ value, err := url.QueryUnescape(part[pos+1:])
+ if err != nil {
+ err = gerror.Wrapf(err, `url.QueryUnescape failed for string "%s"`, part[pos+1:])
+ return nil, err
+ }
+ // split into multiple keys
+ var keys []string
+ left := 0
+ for i, k := range key {
+ if k == '[' && left == 0 {
+ left = i
+ } else if k == ']' {
+ if left > 0 {
+ if len(keys) == 0 {
+ keys = append(keys, key[:left])
+ }
+ keys = append(keys, key[left+1:i])
+ left = 0
+ if i+1 < len(key) && key[i+1] != '[' {
+ break
+ }
+ }
+ }
+ }
+ if len(keys) == 0 {
+ keys = append(keys, key)
+ }
+ // first key
+ first := ""
+ for i, chr := range keys[0] {
+ if chr == ' ' || chr == '.' || chr == '[' {
+ first += "_"
+ } else {
+ first += string(chr)
+ }
+ if chr == '[' {
+ first += keys[0][i+1:]
+ break
+ }
+ }
+ keys[0] = first
+
+ // build nested map
+ if err = build(result, keys, value); err != nil {
+ return nil, err
+ }
+ }
+ return result, nil
+}
+
+// build nested map.
+func build(result map[string]interface{}, keys []string, value interface{}) error {
+ var (
+ length = len(keys)
+ key = strings.Trim(keys[0], "'\"")
+ )
+ if length == 1 {
+ result[key] = value
+ return nil
+ }
+
+ // The end is slice. like f[], f[a][]
+ if keys[1] == "" && length == 2 {
+ // TODO nested slice
+ if key == "" {
+ return nil
+ }
+ val, ok := result[key]
+ if !ok {
+ result[key] = []interface{}{value}
+ return nil
+ }
+ children, ok := val.([]interface{})
+ if !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "expected type '[]interface{}' for key '%s', but got '%T'",
+ key, val,
+ )
+ }
+ result[key] = append(children, value)
+ return nil
+ }
+
+ // The end is slice + map. like v[][a]
+ if keys[1] == "" && length > 2 && keys[2] != "" {
+ val, ok := result[key]
+ if !ok {
+ result[key] = []interface{}{}
+ val = result[key]
+ }
+ children, ok := val.([]interface{})
+ if !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "expected type '[]interface{}' for key '%s', but got '%T'",
+ key, val,
+ )
+ }
+ if l := len(children); l > 0 {
+ if child, ok := children[l-1].(map[string]interface{}); ok {
+ if _, ok := child[keys[2]]; !ok {
+ _ = build(child, keys[2:], value)
+ return nil
+ }
+ }
+ }
+ child := map[string]interface{}{}
+ _ = build(child, keys[2:], value)
+ result[key] = append(children, child)
+ return nil
+ }
+
+ // map, like v[a], v[a][b]
+ val, ok := result[key]
+ if !ok {
+ result[key] = map[string]interface{}{}
+ val = result[key]
+ }
+ children, ok := val.(map[string]interface{})
+ if !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "expected type 'map[string]interface{}' for key '%s', but got '%T'",
+ key, val,
+ )
+ }
+ if err := build(children, keys[1:], value); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_pos.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_pos.go
new file mode 100644
index 000000000000..bf76a6294c6a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_pos.go
@@ -0,0 +1,140 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "strings"
+
+// Pos returns the position of the first occurrence of `needle`
+// in `haystack` from `startOffset`, case-sensitively.
+// It returns -1, if not found.
+func Pos(haystack, needle string, startOffset ...int) int {
+ length := len(haystack)
+ offset := 0
+ if len(startOffset) > 0 {
+ offset = startOffset[0]
+ }
+ if length == 0 || offset > length || -offset > length {
+ return -1
+ }
+ if offset < 0 {
+ offset += length
+ }
+ pos := strings.Index(haystack[offset:], needle)
+ if pos == NotFoundIndex {
+ return NotFoundIndex
+ }
+ return pos + offset
+}
+
+// PosRune acts like function Pos but considers `haystack` and `needle` as unicode string.
+func PosRune(haystack, needle string, startOffset ...int) int {
+ pos := Pos(haystack, needle, startOffset...)
+ if pos < 3 {
+ return pos
+ }
+ return len([]rune(haystack[:pos]))
+}
+
+// PosI returns the position of the first occurrence of `needle`
+// in `haystack` from `startOffset`, case-insensitively.
+// It returns -1, if not found.
+func PosI(haystack, needle string, startOffset ...int) int {
+ length := len(haystack)
+ offset := 0
+ if len(startOffset) > 0 {
+ offset = startOffset[0]
+ }
+ if length == 0 || offset > length || -offset > length {
+ return -1
+ }
+
+ if offset < 0 {
+ offset += length
+ }
+ pos := strings.Index(strings.ToLower(haystack[offset:]), strings.ToLower(needle))
+ if pos == -1 {
+ return -1
+ }
+ return pos + offset
+}
+
+// PosIRune acts like function PosI but considers `haystack` and `needle` as unicode string.
+func PosIRune(haystack, needle string, startOffset ...int) int {
+ pos := PosI(haystack, needle, startOffset...)
+ if pos < 3 {
+ return pos
+ }
+ return len([]rune(haystack[:pos]))
+}
+
+// PosR returns the position of the last occurrence of `needle`
+// in `haystack` from `startOffset`, case-sensitively.
+// It returns -1, if not found.
+func PosR(haystack, needle string, startOffset ...int) int {
+ offset := 0
+ if len(startOffset) > 0 {
+ offset = startOffset[0]
+ }
+ pos, length := 0, len(haystack)
+ if length == 0 || offset > length || -offset > length {
+ return -1
+ }
+
+ if offset < 0 {
+ haystack = haystack[:offset+length+1]
+ } else {
+ haystack = haystack[offset:]
+ }
+ pos = strings.LastIndex(haystack, needle)
+ if offset > 0 && pos != -1 {
+ pos += offset
+ }
+ return pos
+}
+
+// PosRRune acts like function PosR but considers `haystack` and `needle` as unicode string.
+func PosRRune(haystack, needle string, startOffset ...int) int {
+ pos := PosR(haystack, needle, startOffset...)
+ if pos < 3 {
+ return pos
+ }
+ return len([]rune(haystack[:pos]))
+}
+
+// PosRI returns the position of the last occurrence of `needle`
+// in `haystack` from `startOffset`, case-insensitively.
+// It returns -1, if not found.
+func PosRI(haystack, needle string, startOffset ...int) int {
+ offset := 0
+ if len(startOffset) > 0 {
+ offset = startOffset[0]
+ }
+ pos, length := 0, len(haystack)
+ if length == 0 || offset > length || -offset > length {
+ return -1
+ }
+
+ if offset < 0 {
+ haystack = haystack[:offset+length+1]
+ } else {
+ haystack = haystack[offset:]
+ }
+ pos = strings.LastIndex(strings.ToLower(haystack), strings.ToLower(needle))
+ if offset > 0 && pos != -1 {
+ pos += offset
+ }
+ return pos
+}
+
+// PosRIRune acts like function PosRI but considers `haystack` and `needle` as unicode string.
+func PosRIRune(haystack, needle string, startOffset ...int) int {
+ pos := PosRI(haystack, needle, startOffset...)
+ if pos < 3 {
+ return pos
+ }
+ return len([]rune(haystack[:pos]))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_replace.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_replace.go
new file mode 100644
index 000000000000..713fc02c747b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_replace.go
@@ -0,0 +1,98 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// Replace returns a copy of the string `origin`
+// in which string `search` replaced by `replace` case-sensitively.
+func Replace(origin, search, replace string, count ...int) string {
+ n := -1
+ if len(count) > 0 {
+ n = count[0]
+ }
+ return strings.Replace(origin, search, replace, n)
+}
+
+// ReplaceI returns a copy of the string `origin`
+// in which string `search` replaced by `replace` case-insensitively.
+func ReplaceI(origin, search, replace string, count ...int) string {
+ n := -1
+ if len(count) > 0 {
+ n = count[0]
+ }
+ if n == 0 {
+ return origin
+ }
+ var (
+ searchLength = len(search)
+ searchLower = strings.ToLower(search)
+ originLower string
+ pos int
+ diff = len(replace) - searchLength
+ )
+ for {
+ originLower = strings.ToLower(origin)
+ if pos = Pos(originLower, searchLower, pos); pos != -1 {
+ origin = origin[:pos] + replace + origin[pos+searchLength:]
+ if diff < 0 {
+ pos += -diff
+ } else {
+ pos += diff + 1
+ }
+ if n--; n == 0 {
+ break
+ }
+ } else {
+ break
+ }
+ }
+ return origin
+}
+
+// ReplaceByArray returns a copy of `origin`,
+// which is replaced by a slice in order, case-sensitively.
+func ReplaceByArray(origin string, array []string) string {
+ for i := 0; i < len(array); i += 2 {
+ if i+1 >= len(array) {
+ break
+ }
+ origin = Replace(origin, array[i], array[i+1])
+ }
+ return origin
+}
+
+// ReplaceIByArray returns a copy of `origin`,
+// which is replaced by a slice in order, case-insensitively.
+func ReplaceIByArray(origin string, array []string) string {
+ for i := 0; i < len(array); i += 2 {
+ if i+1 >= len(array) {
+ break
+ }
+ origin = ReplaceI(origin, array[i], array[i+1])
+ }
+ return origin
+}
+
+// ReplaceByMap returns a copy of `origin`,
+// which is replaced by a map in unordered way, case-sensitively.
+func ReplaceByMap(origin string, replaces map[string]string) string {
+ return utils.ReplaceByMap(origin, replaces)
+}
+
+// ReplaceIByMap returns a copy of `origin`,
+// which is replaced by a map in unordered way, case-insensitively.
+func ReplaceIByMap(origin string, replaces map[string]string) string {
+ for k, v := range replaces {
+ origin = ReplaceI(origin, k, v)
+ }
+ return origin
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_similar.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_similar.go
new file mode 100644
index 000000000000..7c19618fb6c6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_similar.go
@@ -0,0 +1,158 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+// Levenshtein calculates Levenshtein distance between two strings.
+// costIns: Defines the cost of insertion.
+// costRep: Defines the cost of replacement.
+// costDel: Defines the cost of deletion.
+// See http://php.net/manual/en/function.levenshtein.php.
+func Levenshtein(str1, str2 string, costIns, costRep, costDel int) int {
+ var maxLen = 255
+ l1 := len(str1)
+ l2 := len(str2)
+ if l1 == 0 {
+ return l2 * costIns
+ }
+ if l2 == 0 {
+ return l1 * costDel
+ }
+ if l1 > maxLen || l2 > maxLen {
+ return -1
+ }
+
+ tmp := make([]int, l2+1)
+ p1 := make([]int, l2+1)
+ p2 := make([]int, l2+1)
+ var c0, c1, c2 int
+ var i1, i2 int
+ for i2 := 0; i2 <= l2; i2++ {
+ p1[i2] = i2 * costIns
+ }
+ for i1 = 0; i1 < l1; i1++ {
+ p2[0] = p1[0] + costDel
+ for i2 = 0; i2 < l2; i2++ {
+ if str1[i1] == str2[i2] {
+ c0 = p1[i2]
+ } else {
+ c0 = p1[i2] + costRep
+ }
+ c1 = p1[i2+1] + costDel
+ if c1 < c0 {
+ c0 = c1
+ }
+ c2 = p2[i2] + costIns
+ if c2 < c0 {
+ c0 = c2
+ }
+ p2[i2+1] = c0
+ }
+ tmp = p1
+ p1 = p2
+ p2 = tmp
+ }
+ c0 = p1[l2]
+
+ return c0
+}
+
+// SimilarText calculates the similarity between two strings.
+// See http://php.net/manual/en/function.similar-text.php.
+func SimilarText(first, second string, percent *float64) int {
+ var similarText func(string, string, int, int) int
+ similarText = func(str1, str2 string, len1, len2 int) int {
+ var sum, max int
+ pos1, pos2 := 0, 0
+
+ // Find the longest segment of the same section in two strings
+ for i := 0; i < len1; i++ {
+ for j := 0; j < len2; j++ {
+ for l := 0; (i+l < len1) && (j+l < len2) && (str1[i+l] == str2[j+l]); l++ {
+ if l+1 > max {
+ max = l + 1
+ pos1 = i
+ pos2 = j
+ }
+ }
+ }
+ }
+
+ if sum = max; sum > 0 {
+ if pos1 > 0 && pos2 > 0 {
+ sum += similarText(str1, str2, pos1, pos2)
+ }
+ if (pos1+max < len1) && (pos2+max < len2) {
+ s1 := []byte(str1)
+ s2 := []byte(str2)
+ sum += similarText(string(s1[pos1+max:]), string(s2[pos2+max:]), len1-pos1-max, len2-pos2-max)
+ }
+ }
+
+ return sum
+ }
+
+ l1, l2 := len(first), len(second)
+ if l1+l2 == 0 {
+ return 0
+ }
+ sim := similarText(first, second, l1, l2)
+ if percent != nil {
+ *percent = float64(sim*200) / float64(l1+l2)
+ }
+ return sim
+}
+
+// Soundex calculates the soundex key of a string.
+// See http://php.net/manual/en/function.soundex.php.
+func Soundex(str string) string {
+ if str == "" {
+ panic("str: cannot be an empty string")
+ }
+ table := [26]rune{
+ '0', '1', '2', '3', // A, B, C, D
+ '0', '1', '2', // E, F, G
+ '0', // H
+ '0', '2', '2', '4', '5', '5', // I, J, K, L, M, N
+ '0', '1', '2', '6', '2', '3', // O, P, Q, R, S, T
+ '0', '1', // U, V
+ '0', '2', // W, X
+ '0', '2', // Y, Z
+ }
+ last, code, small := -1, 0, 0
+ sd := make([]rune, 4)
+ // build soundex string
+ for i := 0; i < len(str) && small < 4; i++ {
+ // ToUpper
+ char := str[i]
+ if char < '\u007F' && 'a' <= char && char <= 'z' {
+ code = int(char - 'a' + 'A')
+ } else {
+ code = int(char)
+ }
+ if code >= 'A' && code <= 'Z' {
+ if small == 0 {
+ sd[small] = rune(code)
+ small++
+ last = int(table[code-'A'])
+ } else {
+ code = int(table[code-'A'])
+ if code != last {
+ if code != 0 {
+ sd[small] = rune(code)
+ small++
+ }
+ last = code
+ }
+ }
+ }
+ }
+ // pad with "0"
+ for ; small < 4; small++ {
+ sd[small] = '0'
+ }
+ return string(sd)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_slashes.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_slashes.go
new file mode 100644
index 000000000000..e897673ba2d4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_slashes.go
@@ -0,0 +1,53 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "bytes"
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// AddSlashes quotes chars('"\) with slashes.
+func AddSlashes(str string) string {
+ var buf bytes.Buffer
+ for _, char := range str {
+ switch char {
+ case '\'', '"', '\\':
+ buf.WriteRune('\\')
+ }
+ buf.WriteRune(char)
+ }
+ return buf.String()
+}
+
+// StripSlashes un-quotes a quoted string by AddSlashes.
+func StripSlashes(str string) string {
+ return utils.StripSlashes(str)
+}
+
+// QuoteMeta returns a version of str with a backslash character (\)
+// before every character that is among: .\+*?[^]($)
+func QuoteMeta(str string, chars ...string) string {
+ var buf bytes.Buffer
+ for _, char := range str {
+ if len(chars) > 0 {
+ for _, c := range chars[0] {
+ if c == char {
+ buf.WriteRune('\\')
+ break
+ }
+ }
+ } else {
+ switch char {
+ case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?':
+ buf.WriteRune('\\')
+ }
+ }
+ buf.WriteRune(char)
+ }
+ return buf.String()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_split_join.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_split_join.go
new file mode 100644
index 000000000000..737f85c21a50
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_split_join.go
@@ -0,0 +1,82 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/util/gconv"
+ "strings"
+)
+
+// Split splits string `str` by a string `delimiter`, to an array.
+func Split(str, delimiter string) []string {
+ return strings.Split(str, delimiter)
+}
+
+// SplitAndTrim splits string `str` by a string `delimiter` to an array,
+// and calls Trim to every element of this array. It ignores the elements
+// which are empty after Trim.
+func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
+ return utils.SplitAndTrim(str, delimiter, characterMask...)
+}
+
+// Join concatenates the elements of `array` to create a single string. The separator string
+// `sep` is placed between elements in the resulting string.
+func Join(array []string, sep string) string {
+ return strings.Join(array, sep)
+}
+
+// JoinAny concatenates the elements of `array` to create a single string. The separator string
+// `sep` is placed between elements in the resulting string.
+//
+// The parameter `array` can be any type of slice, which be converted to string array.
+func JoinAny(array interface{}, sep string) string {
+ return strings.Join(gconv.Strings(array), sep)
+}
+
+// Explode splits string `str` by a string `delimiter`, to an array.
+// See http://php.net/manual/en/function.explode.php.
+func Explode(delimiter, str string) []string {
+ return Split(str, delimiter)
+}
+
+// Implode joins array elements `pieces` with a string `glue`.
+// http://php.net/manual/en/function.implode.php
+func Implode(glue string, pieces []string) string {
+ return strings.Join(pieces, glue)
+}
+
+// ChunkSplit splits a string into smaller chunks.
+// Can be used to split a string into smaller chunks which is useful for
+// e.g. converting BASE64 string output to match RFC 2045 semantics.
+// It inserts end every chunkLen characters.
+// It considers parameter `body` and `end` as unicode string.
+func ChunkSplit(body string, chunkLen int, end string) string {
+ if end == "" {
+ end = "\r\n"
+ }
+ runes, endRunes := []rune(body), []rune(end)
+ l := len(runes)
+ if l <= 1 || l < chunkLen {
+ return body + end
+ }
+ ns := make([]rune, 0, len(runes)+len(endRunes))
+ for i := 0; i < l; i += chunkLen {
+ if i+chunkLen > l {
+ ns = append(ns, runes[i:]...)
+ } else {
+ ns = append(ns, runes[i:i+chunkLen]...)
+ }
+ ns = append(ns, endRunes...)
+ }
+ return string(ns)
+}
+
+// Fields returns the words used in a string as slice.
+func Fields(str string) []string {
+ return strings.Fields(str)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_sub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_sub.go
new file mode 100644
index 000000000000..8eef7edc68dd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_sub.go
@@ -0,0 +1,174 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import "strings"
+
+// Str returns part of `haystack` string starting from and including
+// the first occurrence of `needle` to the end of `haystack`.
+// See http://php.net/manual/en/function.strstr.php.
+func Str(haystack string, needle string) string {
+ if needle == "" {
+ return ""
+ }
+ pos := strings.Index(haystack, needle)
+ if pos == NotFoundIndex {
+ return ""
+ }
+ return haystack[pos+len([]byte(needle))-1:]
+}
+
+// StrEx returns part of `haystack` string starting from and excluding
+// the first occurrence of `needle` to the end of `haystack`.
+func StrEx(haystack string, needle string) string {
+ if s := Str(haystack, needle); s != "" {
+ return s[1:]
+ }
+ return ""
+}
+
+// StrTill returns part of `haystack` string ending to and including
+// the first occurrence of `needle` from the start of `haystack`.
+func StrTill(haystack string, needle string) string {
+ pos := strings.Index(haystack, needle)
+ if pos == NotFoundIndex || pos == 0 {
+ return ""
+ }
+ return haystack[:pos+1]
+}
+
+// StrTillEx returns part of `haystack` string ending to and excluding
+// the first occurrence of `needle` from the start of `haystack`.
+func StrTillEx(haystack string, needle string) string {
+ pos := strings.Index(haystack, needle)
+ if pos == NotFoundIndex || pos == 0 {
+ return ""
+ }
+ return haystack[:pos]
+}
+
+// SubStr returns a portion of string `str` specified by the `start` and `length` parameters.
+// The parameter `length` is optional, it uses the length of `str` in default.
+func SubStr(str string, start int, length ...int) (substr string) {
+ strLength := len(str)
+ // Simple border checks.
+ if start < 0 {
+ start = 0
+ }
+ if start >= strLength {
+ start = strLength
+ }
+ end := strLength
+ if len(length) > 0 {
+ end = start + length[0]
+ if end < start {
+ end = strLength
+ }
+ }
+ if end > strLength {
+ end = strLength
+ }
+ return str[start:end]
+}
+
+// SubStrRune returns a portion of string `str` specified by the `start` and `length` parameters.
+// SubStrRune considers parameter `str` as unicode string.
+// The parameter `length` is optional, it uses the length of `str` in default.
+func SubStrRune(str string, start int, length ...int) (substr string) {
+ // Converting to []rune to support unicode.
+ var (
+ runes = []rune(str)
+ runesLength = len(runes)
+ )
+
+ // Simple border checks.
+ if start < 0 {
+ start = 0
+ }
+ if start >= runesLength {
+ start = runesLength
+ }
+ end := runesLength
+ if len(length) > 0 {
+ end = start + length[0]
+ if end < start {
+ end = runesLength
+ }
+ }
+ if end > runesLength {
+ end = runesLength
+ }
+ return string(runes[start:end])
+}
+
+// StrLimit returns a portion of string `str` specified by `length` parameters, if the length
+// of `str` is greater than `length`, then the `suffix` will be appended to the result string.
+func StrLimit(str string, length int, suffix ...string) string {
+ if len(str) < length {
+ return str
+ }
+ suffixStr := defaultSuffixForStrLimit
+ if len(suffix) > 0 {
+ suffixStr = suffix[0]
+ }
+ return str[0:length] + suffixStr
+}
+
+// StrLimitRune returns a portion of string `str` specified by `length` parameters, if the length
+// of `str` is greater than `length`, then the `suffix` will be appended to the result string.
+// StrLimitRune considers parameter `str` as unicode string.
+func StrLimitRune(str string, length int, suffix ...string) string {
+ runes := []rune(str)
+ if len(runes) < length {
+ return str
+ }
+ suffixStr := defaultSuffixForStrLimit
+ if len(suffix) > 0 {
+ suffixStr = suffix[0]
+ }
+ return string(runes[0:length]) + suffixStr
+}
+
+// SubStrFrom returns a portion of string `str` starting from first occurrence of and including `need`
+// to the end of `str`.
+func SubStrFrom(str string, need string) (substr string) {
+ pos := Pos(str, need)
+ if pos < 0 {
+ return ""
+ }
+ return str[pos:]
+}
+
+// SubStrFromEx returns a portion of string `str` starting from first occurrence of and excluding `need`
+// to the end of `str`.
+func SubStrFromEx(str string, need string) (substr string) {
+ pos := Pos(str, need)
+ if pos < 0 {
+ return ""
+ }
+ return str[pos+len(need):]
+}
+
+// SubStrFromR returns a portion of string `str` starting from last occurrence of and including `need`
+// to the end of `str`.
+func SubStrFromR(str string, need string) (substr string) {
+ pos := PosR(str, need)
+ if pos < 0 {
+ return ""
+ }
+ return str[pos:]
+}
+
+// SubStrFromREx returns a portion of string `str` starting from last occurrence of and excluding `need`
+// to the end of `str`.
+func SubStrFromREx(str string, need string) (substr string) {
+ pos := PosR(str, need)
+ if pos < 0 {
+ return ""
+ }
+ return str[pos+len(need):]
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_trim.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_trim.go
new file mode 100644
index 000000000000..f7701505e0a5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_trim.go
@@ -0,0 +1,114 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// Trim strips whitespace (or other characters) from the beginning and end of a string.
+// The optional parameter `characterMask` specifies the additional stripped characters.
+func Trim(str string, characterMask ...string) string {
+ return utils.Trim(str, characterMask...)
+}
+
+// TrimStr strips all the given `cut` string from the beginning and end of a string.
+// Note that it does not strip the whitespaces of its beginning or end.
+func TrimStr(str string, cut string, count ...int) string {
+ return TrimLeftStr(TrimRightStr(str, cut, count...), cut, count...)
+}
+
+// TrimLeft strips whitespace (or other characters) from the beginning of a string.
+func TrimLeft(str string, characterMask ...string) string {
+ trimChars := utils.DefaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
+ }
+ return strings.TrimLeft(str, trimChars)
+}
+
+// TrimLeftStr strips all the given `cut` string from the beginning of a string.
+// Note that it does not strip the whitespaces of its beginning.
+func TrimLeftStr(str string, cut string, count ...int) string {
+ var (
+ lenCut = len(cut)
+ cutCount = 0
+ )
+ for len(str) >= lenCut && str[0:lenCut] == cut {
+ str = str[lenCut:]
+ cutCount++
+ if len(count) > 0 && count[0] != -1 && cutCount >= count[0] {
+ break
+ }
+ }
+ return str
+}
+
+// TrimRight strips whitespace (or other characters) from the end of a string.
+func TrimRight(str string, characterMask ...string) string {
+ trimChars := utils.DefaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
+ }
+ return strings.TrimRight(str, trimChars)
+}
+
+// TrimRightStr strips all the given `cut` string from the end of a string.
+// Note that it does not strip the whitespaces of its end.
+func TrimRightStr(str string, cut string, count ...int) string {
+ var (
+ lenStr = len(str)
+ lenCut = len(cut)
+ cutCount = 0
+ )
+ for lenStr >= lenCut && str[lenStr-lenCut:lenStr] == cut {
+ lenStr = lenStr - lenCut
+ str = str[:lenStr]
+ cutCount++
+ if len(count) > 0 && count[0] != -1 && cutCount >= count[0] {
+ break
+ }
+ }
+ return str
+}
+
+// TrimAll trims all characters in string `str`.
+func TrimAll(str string, characterMask ...string) string {
+ trimChars := utils.DefaultTrimChars
+ if len(characterMask) > 0 {
+ trimChars += characterMask[0]
+ }
+ var (
+ filtered bool
+ slice = make([]rune, 0, len(str))
+ )
+ for _, char := range str {
+ filtered = false
+ for _, trimChar := range trimChars {
+ if char == trimChar {
+ filtered = true
+ break
+ }
+ }
+ if !filtered {
+ slice = append(slice, char)
+ }
+ }
+ return string(slice)
+}
+
+// HasPrefix tests whether the string s begins with prefix.
+func HasPrefix(s, prefix string) bool {
+ return strings.HasPrefix(s, prefix)
+}
+
+// HasSuffix tests whether the string s ends with suffix.
+func HasSuffix(s, suffix string) bool {
+ return strings.HasSuffix(s, suffix)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_upper_lower.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_upper_lower.go
new file mode 100644
index 000000000000..3d6c75ad90b6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_upper_lower.go
@@ -0,0 +1,53 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "github.com/gogf/gf/v2/internal/utils"
+ "strings"
+)
+
+// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
+func ToLower(s string) string {
+ return strings.ToLower(s)
+}
+
+// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
+func ToUpper(s string) string {
+ return strings.ToUpper(s)
+}
+
+// UcFirst returns a copy of the string s with the first letter mapped to its upper case.
+func UcFirst(s string) string {
+ return utils.UcFirst(s)
+}
+
+// LcFirst returns a copy of the string s with the first letter mapped to its lower case.
+func LcFirst(s string) string {
+ if len(s) == 0 {
+ return s
+ }
+ if IsLetterUpper(s[0]) {
+ return string(s[0]+32) + s[1:]
+ }
+ return s
+}
+
+// UcWords uppercase the first character of each word in a string.
+func UcWords(str string) string {
+ return strings.Title(str)
+}
+
+// IsLetterLower tests whether the given byte b is in lower case.
+func IsLetterLower(b byte) bool {
+ return utils.IsLetterLower(b)
+}
+
+// IsLetterUpper tests whether the given byte b is in upper case.
+func IsLetterUpper(b byte) bool {
+ return utils.IsLetterUpper(b)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_version.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_version.go
new file mode 100644
index 000000000000..f5d478c637e4
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/text/gstr/gstr_version.go
@@ -0,0 +1,148 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gstr
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// CompareVersion compares `a` and `b` as standard GNU version.
+// It returns 1 if `a` > `b`.
+// It returns -1 if `a` < `b`.
+// It returns 0 if `a` = `b`.
+// GNU standard version is like:
+// v1.0
+// 1
+// 1.0.0
+// v1.0.1
+// v2.10.8
+// 10.2.0
+// etc.
+func CompareVersion(a, b string) int {
+ if a != "" && a[0] == 'v' {
+ a = a[1:]
+ }
+ if b != "" && b[0] == 'v' {
+ b = b[1:]
+ }
+ var (
+ array1 = strings.Split(a, ".")
+ array2 = strings.Split(b, ".")
+ diff = 0
+ )
+ diff = len(array2) - len(array1)
+ for i := 0; i < diff; i++ {
+ array1 = append(array1, "0")
+ }
+ diff = len(array1) - len(array2)
+ for i := 0; i < diff; i++ {
+ array2 = append(array2, "0")
+ }
+ v1 := 0
+ v2 := 0
+ for i := 0; i < len(array1); i++ {
+ v1 = gconv.Int(array1[i])
+ v2 = gconv.Int(array2[i])
+ if v1 > v2 {
+ return 1
+ }
+ if v1 < v2 {
+ return -1
+ }
+ }
+ return 0
+}
+
+// CompareVersionGo compares `a` and `b` as standard Golang version.
+// It returns 1 if `a` > `b`.
+// It returns -1 if `a` < `b`.
+// It returns 0 if `a` = `b`.
+// Golang standard version is like:
+// 1.0.0
+// v1.0.1
+// v2.10.8
+// 10.2.0
+// v0.0.0-20190626092158-b2ccc519800e
+// v4.20.0+incompatible
+// etc.
+func CompareVersionGo(a, b string) int {
+ a = Trim(a)
+ b = Trim(b)
+ if a != "" && a[0] == 'v' {
+ a = a[1:]
+ }
+ if b != "" && b[0] == 'v' {
+ b = b[1:]
+ }
+ var (
+ rawA = a
+ rawB = b
+ )
+ if Count(a, "-") > 1 {
+ if i := PosR(a, "-"); i > 0 {
+ a = a[:i]
+ }
+ }
+ if Count(b, "-") > 1 {
+ if i := PosR(b, "-"); i > 0 {
+ b = b[:i]
+ }
+ }
+ if i := Pos(a, "+"); i > 0 {
+ a = a[:i]
+ }
+ if i := Pos(b, "+"); i > 0 {
+ b = b[:i]
+ }
+ a = Replace(a, "-", ".")
+ b = Replace(b, "-", ".")
+ var (
+ array1 = strings.Split(a, ".")
+ array2 = strings.Split(b, ".")
+ diff = 0
+ )
+ // Specially in Golang:
+ // "v1.12.2-0.20200413154443-b17e3a6804fa" < "v1.12.2"
+ if len(array1) > 3 && len(array2) <= 3 {
+ return -1
+ }
+ if len(array1) <= 3 && len(array2) > 3 {
+ return 1
+ }
+
+ diff = len(array2) - len(array1)
+ for i := 0; i < diff; i++ {
+ array1 = append(array1, "0")
+ }
+ diff = len(array1) - len(array2)
+ for i := 0; i < diff; i++ {
+ array2 = append(array2, "0")
+ }
+ v1 := 0
+ v2 := 0
+ for i := 0; i < len(array1); i++ {
+ v1 = gconv.Int(array1[i])
+ v2 = gconv.Int(array2[i])
+ if v1 > v2 {
+ return 1
+ }
+ if v1 < v2 {
+ return -1
+ }
+ }
+ // Specially in Golang:
+ // "v4.20.1+incompatible" < "v4.20.1"
+ if Contains(rawA, "incompatible") {
+ return -1
+ }
+ if Contains(rawB, "incompatible") {
+ return 1
+ }
+ return 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv.go
new file mode 100644
index 000000000000..8ca25c5476d3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv.go
@@ -0,0 +1,531 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gconv implements powerful and convenient converting functionality for any types of variables.
+//
+// This package should keep much less dependencies with other packages.
+package gconv
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/encoding/gbinary"
+ "github.com/gogf/gf/v2/internal/intlog"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gtime"
+)
+
+var (
+ // Empty strings.
+ emptyStringMap = map[string]struct{}{
+ "": {},
+ "0": {},
+ "no": {},
+ "off": {},
+ "false": {},
+ }
+
+ // StructTagPriority defines the default priority tags for Map*/Struct* functions.
+ // Note, the `gconv/param/params` tags are used by old version of package.
+ // It is strongly recommended using short tag `c/p` instead in the future.
+ StructTagPriority = []string{"gconv", "param", "params", "c", "p", "json"}
+)
+
+// Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
+// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
+// It supports common types conversion as its conversion based on type name string.
+func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} {
+ return doConvert(doConvertInput{
+ FromValue: fromValue,
+ ToTypeName: toTypeName,
+ ReferValue: nil,
+ Extra: extraParams,
+ })
+}
+
+type doConvertInput struct {
+ FromValue interface{} // Value that is converted from.
+ ToTypeName string // Target value type name in string.
+ ReferValue interface{} // Referred value, a value in type `ToTypeName`.
+ Extra []interface{} // Extra values for implementing the converting.
+}
+
+// doConvert does commonly use types converting.
+func doConvert(in doConvertInput) interface{} {
+ switch in.ToTypeName {
+ case "int":
+ return Int(in.FromValue)
+ case "*int":
+ if _, ok := in.FromValue.(*int); ok {
+ return in.FromValue
+ }
+ v := Int(in.FromValue)
+ return &v
+
+ case "int8":
+ return Int8(in.FromValue)
+ case "*int8":
+ if _, ok := in.FromValue.(*int8); ok {
+ return in.FromValue
+ }
+ v := Int8(in.FromValue)
+ return &v
+
+ case "int16":
+ return Int16(in.FromValue)
+ case "*int16":
+ if _, ok := in.FromValue.(*int16); ok {
+ return in.FromValue
+ }
+ v := Int16(in.FromValue)
+ return &v
+
+ case "int32":
+ return Int32(in.FromValue)
+ case "*int32":
+ if _, ok := in.FromValue.(*int32); ok {
+ return in.FromValue
+ }
+ v := Int32(in.FromValue)
+ return &v
+
+ case "int64":
+ return Int64(in.FromValue)
+ case "*int64":
+ if _, ok := in.FromValue.(*int64); ok {
+ return in.FromValue
+ }
+ v := Int64(in.FromValue)
+ return &v
+
+ case "uint":
+ return Uint(in.FromValue)
+ case "*uint":
+ if _, ok := in.FromValue.(*uint); ok {
+ return in.FromValue
+ }
+ v := Uint(in.FromValue)
+ return &v
+
+ case "uint8":
+ return Uint8(in.FromValue)
+ case "*uint8":
+ if _, ok := in.FromValue.(*uint8); ok {
+ return in.FromValue
+ }
+ v := Uint8(in.FromValue)
+ return &v
+
+ case "uint16":
+ return Uint16(in.FromValue)
+ case "*uint16":
+ if _, ok := in.FromValue.(*uint16); ok {
+ return in.FromValue
+ }
+ v := Uint16(in.FromValue)
+ return &v
+
+ case "uint32":
+ return Uint32(in.FromValue)
+ case "*uint32":
+ if _, ok := in.FromValue.(*uint32); ok {
+ return in.FromValue
+ }
+ v := Uint32(in.FromValue)
+ return &v
+
+ case "uint64":
+ return Uint64(in.FromValue)
+ case "*uint64":
+ if _, ok := in.FromValue.(*uint64); ok {
+ return in.FromValue
+ }
+ v := Uint64(in.FromValue)
+ return &v
+
+ case "float32":
+ return Float32(in.FromValue)
+ case "*float32":
+ if _, ok := in.FromValue.(*float32); ok {
+ return in.FromValue
+ }
+ v := Float32(in.FromValue)
+ return &v
+
+ case "float64":
+ return Float64(in.FromValue)
+ case "*float64":
+ if _, ok := in.FromValue.(*float64); ok {
+ return in.FromValue
+ }
+ v := Float64(in.FromValue)
+ return &v
+
+ case "bool":
+ return Bool(in.FromValue)
+ case "*bool":
+ if _, ok := in.FromValue.(*bool); ok {
+ return in.FromValue
+ }
+ v := Bool(in.FromValue)
+ return &v
+
+ case "string":
+ return String(in.FromValue)
+ case "*string":
+ if _, ok := in.FromValue.(*string); ok {
+ return in.FromValue
+ }
+ v := String(in.FromValue)
+ return &v
+
+ case "[]byte":
+ return Bytes(in.FromValue)
+ case "[]int":
+ return Ints(in.FromValue)
+ case "[]int32":
+ return Int32s(in.FromValue)
+ case "[]int64":
+ return Int64s(in.FromValue)
+ case "[]uint":
+ return Uints(in.FromValue)
+ case "[]uint8":
+ return Bytes(in.FromValue)
+ case "[]uint32":
+ return Uint32s(in.FromValue)
+ case "[]uint64":
+ return Uint64s(in.FromValue)
+ case "[]float32":
+ return Float32s(in.FromValue)
+ case "[]float64":
+ return Float64s(in.FromValue)
+ case "[]string":
+ return Strings(in.FromValue)
+
+ case "Time", "time.Time":
+ if len(in.Extra) > 0 {
+ return Time(in.FromValue, String(in.Extra[0]))
+ }
+ return Time(in.FromValue)
+ case "*time.Time":
+ var v interface{}
+ if len(in.Extra) > 0 {
+ v = Time(in.FromValue, String(in.Extra[0]))
+ } else {
+ if _, ok := in.FromValue.(*time.Time); ok {
+ return in.FromValue
+ }
+ v = Time(in.FromValue)
+ }
+ return &v
+
+ case "GTime", "gtime.Time":
+ if len(in.Extra) > 0 {
+ if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
+ return *v
+ } else {
+ return *gtime.New()
+ }
+ }
+ if v := GTime(in.FromValue); v != nil {
+ return *v
+ } else {
+ return *gtime.New()
+ }
+ case "*gtime.Time":
+ if len(in.Extra) > 0 {
+ if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
+ return v
+ } else {
+ return gtime.New()
+ }
+ }
+ if v := GTime(in.FromValue); v != nil {
+ return v
+ } else {
+ return gtime.New()
+ }
+
+ case "Duration", "time.Duration":
+ return Duration(in.FromValue)
+ case "*time.Duration":
+ if _, ok := in.FromValue.(*time.Duration); ok {
+ return in.FromValue
+ }
+ v := Duration(in.FromValue)
+ return &v
+
+ case "map[string]string":
+ return MapStrStr(in.FromValue)
+
+ case "map[string]interface{}":
+ return Map(in.FromValue)
+
+ case "[]map[string]interface{}":
+ return Maps(in.FromValue)
+
+ case "json.RawMessage":
+ return Bytes(in.FromValue)
+
+ default:
+ if in.ReferValue != nil {
+ var referReflectValue reflect.Value
+ if v, ok := in.ReferValue.(reflect.Value); ok {
+ referReflectValue = v
+ } else {
+ referReflectValue = reflect.ValueOf(in.ReferValue)
+ }
+ in.ToTypeName = referReflectValue.Kind().String()
+ in.ReferValue = nil
+ return reflect.ValueOf(doConvert(in)).Convert(referReflectValue.Type()).Interface()
+ }
+ return in.FromValue
+ }
+}
+
+// Byte converts `any` to byte.
+func Byte(any interface{}) byte {
+ if v, ok := any.(byte); ok {
+ return v
+ }
+ return Uint8(any)
+}
+
+// Bytes converts `any` to []byte.
+func Bytes(any interface{}) []byte {
+ if any == nil {
+ return nil
+ }
+ switch value := any.(type) {
+ case string:
+ return []byte(value)
+
+ case []byte:
+ return value
+
+ default:
+ if f, ok := value.(iBytes); ok {
+ return f.Bytes()
+ }
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Map:
+ bytes, err := json.Marshal(any)
+ if err != nil {
+ intlog.Errorf(context.TODO(), `%+v`, err)
+ }
+ return bytes
+
+ case reflect.Array, reflect.Slice:
+ var (
+ ok = true
+ bytes = make([]byte, originValueAndKind.OriginValue.Len())
+ )
+ for i, _ := range bytes {
+ int32Value := Int32(originValueAndKind.OriginValue.Index(i).Interface())
+ if int32Value < 0 || int32Value > math.MaxUint8 {
+ ok = false
+ break
+ }
+ bytes[i] = byte(int32Value)
+ }
+ if ok {
+ return bytes
+ }
+ }
+ return gbinary.Encode(any)
+ }
+}
+
+// Rune converts `any` to rune.
+func Rune(any interface{}) rune {
+ if v, ok := any.(rune); ok {
+ return v
+ }
+ return Int32(any)
+}
+
+// Runes converts `any` to []rune.
+func Runes(any interface{}) []rune {
+ if v, ok := any.([]rune); ok {
+ return v
+ }
+ return []rune(String(any))
+}
+
+// String converts `any` to string.
+// It's most commonly used converting function.
+func String(any interface{}) string {
+ if any == nil {
+ return ""
+ }
+ switch value := any.(type) {
+ case int:
+ return strconv.Itoa(value)
+ case int8:
+ return strconv.Itoa(int(value))
+ case int16:
+ return strconv.Itoa(int(value))
+ case int32:
+ return strconv.Itoa(int(value))
+ case int64:
+ return strconv.FormatInt(value, 10)
+ case uint:
+ return strconv.FormatUint(uint64(value), 10)
+ case uint8:
+ return strconv.FormatUint(uint64(value), 10)
+ case uint16:
+ return strconv.FormatUint(uint64(value), 10)
+ case uint32:
+ return strconv.FormatUint(uint64(value), 10)
+ case uint64:
+ return strconv.FormatUint(value, 10)
+ case float32:
+ return strconv.FormatFloat(float64(value), 'f', -1, 32)
+ case float64:
+ return strconv.FormatFloat(value, 'f', -1, 64)
+ case bool:
+ return strconv.FormatBool(value)
+ case string:
+ return value
+ case []byte:
+ return string(value)
+ case time.Time:
+ if value.IsZero() {
+ return ""
+ }
+ return value.String()
+ case *time.Time:
+ if value == nil {
+ return ""
+ }
+ return value.String()
+ case gtime.Time:
+ if value.IsZero() {
+ return ""
+ }
+ return value.String()
+ case *gtime.Time:
+ if value == nil {
+ return ""
+ }
+ return value.String()
+ default:
+ // Empty checks.
+ if value == nil {
+ return ""
+ }
+ if f, ok := value.(iString); ok {
+ // If the variable implements the String() interface,
+ // then use that interface to perform the conversion
+ return f.String()
+ }
+ if f, ok := value.(iError); ok {
+ // If the variable implements the Error() interface,
+ // then use that interface to perform the conversion
+ return f.Error()
+ }
+ // Reflect checks.
+ var (
+ rv = reflect.ValueOf(value)
+ kind = rv.Kind()
+ )
+ switch kind {
+ case reflect.Chan,
+ reflect.Map,
+ reflect.Slice,
+ reflect.Func,
+ reflect.Ptr,
+ reflect.Interface,
+ reflect.UnsafePointer:
+ if rv.IsNil() {
+ return ""
+ }
+ case reflect.String:
+ return rv.String()
+ }
+ if kind == reflect.Ptr {
+ return String(rv.Elem().Interface())
+ }
+ // Finally, we use json.Marshal to convert.
+ if jsonContent, err := json.Marshal(value); err != nil {
+ return fmt.Sprint(value)
+ } else {
+ return string(jsonContent)
+ }
+ }
+}
+
+// Bool converts `any` to bool.
+// It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map.
+func Bool(any interface{}) bool {
+ if any == nil {
+ return false
+ }
+ switch value := any.(type) {
+ case bool:
+ return value
+ case []byte:
+ if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {
+ return false
+ }
+ return true
+ case string:
+ if _, ok := emptyStringMap[strings.ToLower(value)]; ok {
+ return false
+ }
+ return true
+ default:
+ if f, ok := value.(iBool); ok {
+ return f.Bool()
+ }
+ rv := reflect.ValueOf(any)
+ switch rv.Kind() {
+ case reflect.Ptr:
+ return !rv.IsNil()
+ case reflect.Map:
+ fallthrough
+ case reflect.Array:
+ fallthrough
+ case reflect.Slice:
+ return rv.Len() != 0
+ case reflect.Struct:
+ return true
+ default:
+ s := strings.ToLower(String(any))
+ if _, ok := emptyStringMap[s]; ok {
+ return false
+ }
+ return true
+ }
+ }
+}
+
+// checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`.
+func checkJsonAndUnmarshalUseNumber(any interface{}, target interface{}) bool {
+ switch r := any.(type) {
+ case []byte:
+ if json.Valid(r) {
+ _ = json.UnmarshalUseNumber(r, &target)
+ return true
+ }
+
+ case string:
+ anyAsBytes := []byte(r)
+ if json.Valid(anyAsBytes) {
+ _ = json.UnmarshalUseNumber(anyAsBytes, &target)
+ return true
+ }
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_float.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_float.go
new file mode 100644
index 000000000000..41cfb1cc76ac
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_float.go
@@ -0,0 +1,55 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "strconv"
+
+ "github.com/gogf/gf/v2/encoding/gbinary"
+)
+
+// Float32 converts `any` to float32.
+func Float32(any interface{}) float32 {
+ if any == nil {
+ return 0
+ }
+ switch value := any.(type) {
+ case float32:
+ return value
+ case float64:
+ return float32(value)
+ case []byte:
+ return gbinary.DecodeToFloat32(value)
+ default:
+ if f, ok := value.(iFloat32); ok {
+ return f.Float32()
+ }
+ v, _ := strconv.ParseFloat(String(any), 64)
+ return float32(v)
+ }
+}
+
+// Float64 converts `any` to float64.
+func Float64(any interface{}) float64 {
+ if any == nil {
+ return 0
+ }
+ switch value := any.(type) {
+ case float32:
+ return float64(value)
+ case float64:
+ return value
+ case []byte:
+ return gbinary.DecodeToFloat64(value)
+ default:
+ if f, ok := value.(iFloat64); ok {
+ return f.Float64()
+ }
+ v, _ := strconv.ParseFloat(String(any), 64)
+ return v
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_int.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_int.go
new file mode 100644
index 000000000000..63bd7752998f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_int.go
@@ -0,0 +1,138 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "strconv"
+
+ "github.com/gogf/gf/v2/encoding/gbinary"
+)
+
+// Int converts `any` to int.
+func Int(any interface{}) int {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(int); ok {
+ return v
+ }
+ return int(Int64(any))
+}
+
+// Int8 converts `any` to int8.
+func Int8(any interface{}) int8 {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(int8); ok {
+ return v
+ }
+ return int8(Int64(any))
+}
+
+// Int16 converts `any` to int16.
+func Int16(any interface{}) int16 {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(int16); ok {
+ return v
+ }
+ return int16(Int64(any))
+}
+
+// Int32 converts `any` to int32.
+func Int32(any interface{}) int32 {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(int32); ok {
+ return v
+ }
+ return int32(Int64(any))
+}
+
+// Int64 converts `any` to int64.
+func Int64(any interface{}) int64 {
+ if any == nil {
+ return 0
+ }
+ switch value := any.(type) {
+ case int:
+ return int64(value)
+ case int8:
+ return int64(value)
+ case int16:
+ return int64(value)
+ case int32:
+ return int64(value)
+ case int64:
+ return value
+ case uint:
+ return int64(value)
+ case uint8:
+ return int64(value)
+ case uint16:
+ return int64(value)
+ case uint32:
+ return int64(value)
+ case uint64:
+ return int64(value)
+ case float32:
+ return int64(value)
+ case float64:
+ return int64(value)
+ case bool:
+ if value {
+ return 1
+ }
+ return 0
+ case []byte:
+ return gbinary.DecodeToInt64(value)
+ default:
+ if f, ok := value.(iInt64); ok {
+ return f.Int64()
+ }
+ s := String(value)
+ isMinus := false
+ if len(s) > 0 {
+ if s[0] == '-' {
+ isMinus = true
+ s = s[1:]
+ } else if s[0] == '+' {
+ s = s[1:]
+ }
+ }
+ // Hexadecimal
+ if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
+ if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil {
+ if isMinus {
+ return -v
+ }
+ return v
+ }
+ }
+ // Octal
+ if len(s) > 1 && s[0] == '0' {
+ if v, e := strconv.ParseInt(s[1:], 8, 64); e == nil {
+ if isMinus {
+ return -v
+ }
+ return v
+ }
+ }
+ // Decimal
+ if v, e := strconv.ParseInt(s, 10, 64); e == nil {
+ if isMinus {
+ return -v
+ }
+ return v
+ }
+ // Float64
+ return int64(Float64(value))
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_interface.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_interface.go
new file mode 100644
index 000000000000..9440e978f9a6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_interface.go
@@ -0,0 +1,112 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import "github.com/gogf/gf/v2/os/gtime"
+
+// iString is used for type assert api for String().
+type iString interface {
+ String() string
+}
+
+// iBool is used for type assert api for Bool().
+type iBool interface {
+ Bool() bool
+}
+
+// iInt64 is used for type assert api for Int64().
+type iInt64 interface {
+ Int64() int64
+}
+
+// iUint64 is used for type assert api for Uint64().
+type iUint64 interface {
+ Uint64() uint64
+}
+
+// iFloat32 is used for type assert api for Float32().
+type iFloat32 interface {
+ Float32() float32
+}
+
+// iFloat64 is used for type assert api for Float64().
+type iFloat64 interface {
+ Float64() float64
+}
+
+// iError is used for type assert api for Error().
+type iError interface {
+ Error() string
+}
+
+// iBytes is used for type assert api for Bytes().
+type iBytes interface {
+ Bytes() []byte
+}
+
+// iInterface is used for type assert api for Interface().
+type iInterface interface {
+ Interface() interface{}
+}
+
+// iInterfaces is used for type assert api for Interfaces().
+type iInterfaces interface {
+ Interfaces() []interface{}
+}
+
+// iFloats is used for type assert api for Floats().
+type iFloats interface {
+ Floats() []float64
+}
+
+// iInts is used for type assert api for Ints().
+type iInts interface {
+ Ints() []int
+}
+
+// iStrings is used for type assert api for Strings().
+type iStrings interface {
+ Strings() []string
+}
+
+// iUints is used for type assert api for Uints().
+type iUints interface {
+ Uints() []uint
+}
+
+// iMapStrAny is the interface support for converting struct parameter to map.
+type iMapStrAny interface {
+ MapStrAny() map[string]interface{}
+}
+
+// iUnmarshalValue is the interface for custom defined types customizing value assignment.
+// Note that only pointer can implement interface iUnmarshalValue.
+type iUnmarshalValue interface {
+ UnmarshalValue(interface{}) error
+}
+
+// iUnmarshalText is the interface for custom defined types customizing value assignment.
+// Note that only pointer can implement interface iUnmarshalText.
+type iUnmarshalText interface {
+ UnmarshalText(text []byte) error
+}
+
+// iUnmarshalText is the interface for custom defined types customizing value assignment.
+// Note that only pointer can implement interface iUnmarshalJSON.
+type iUnmarshalJSON interface {
+ UnmarshalJSON(b []byte) error
+}
+
+// iSet is the interface for custom value assignment.
+type iSet interface {
+ Set(value interface{}) (old interface{})
+}
+
+// iGTime is the interface for gtime.Time converting.
+type iGTime interface {
+ GTime(format ...string) *gtime.Time
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_map.go
new file mode 100644
index 000000000000..3c2093283254
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_map.go
@@ -0,0 +1,412 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
+// map/struct/*struct type, then the conversion will fail and returns nil.
+//
+// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
+// tags that will be detected, otherwise it detects the tags in order of:
+// gconv, json, field name.
+func Map(value interface{}, tags ...string) map[string]interface{} {
+ return doMapConvert(value, false, tags...)
+}
+
+// MapDeep does Map function recursively, which means if the attribute of `value`
+// is also a struct/*struct, calls Map function on this attribute converting it to
+// a map[string]interface{} type variable.
+// Also see Map.
+func MapDeep(value interface{}, tags ...string) map[string]interface{} {
+ return doMapConvert(value, true, tags...)
+}
+
+// doMapConvert implements the map converting.
+// It automatically checks and converts json string to map if `value` is string/[]byte.
+//
+// TODO completely implement the recursive converting for all types, especially the map.
+func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]interface{} {
+ if value == nil {
+ return nil
+ }
+ newTags := StructTagPriority
+ switch len(tags) {
+ case 0:
+ // No need handling.
+ case 1:
+ newTags = append(strings.Split(tags[0], ","), StructTagPriority...)
+ default:
+ newTags = append(tags, StructTagPriority...)
+ }
+ // Assert the common combination of types, and finally it uses reflection.
+ dataMap := make(map[string]interface{})
+ switch r := value.(type) {
+ case string:
+ // If it is a JSON string, automatically unmarshal it!
+ if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
+ if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {
+ return nil
+ }
+ } else {
+ return nil
+ }
+ case []byte:
+ // If it is a JSON string, automatically unmarshal it!
+ if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
+ if err := json.UnmarshalUseNumber(r, &dataMap); err != nil {
+ return nil
+ }
+ } else {
+ return nil
+ }
+ case map[interface{}]interface{}:
+ for k, v := range r {
+ dataMap[String(k)] = doMapConvertForMapOrStructValue(false, v, recursive, newTags...)
+ }
+ case map[interface{}]string:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+ case map[interface{}]int:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+ case map[interface{}]uint:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+ case map[interface{}]float32:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+ case map[interface{}]float64:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+ case map[string]bool:
+ for k, v := range r {
+ dataMap[k] = v
+ }
+ case map[string]int:
+ for k, v := range r {
+ dataMap[k] = v
+ }
+ case map[string]uint:
+ for k, v := range r {
+ dataMap[k] = v
+ }
+ case map[string]float32:
+ for k, v := range r {
+ dataMap[k] = v
+ }
+ case map[string]float64:
+ for k, v := range r {
+ dataMap[k] = v
+ }
+ case map[string]string:
+ for k, v := range r {
+ dataMap[k] = v
+ }
+ case map[string]interface{}:
+ if recursive {
+ // A copy of current map.
+ for k, v := range r {
+ dataMap[k] = doMapConvertForMapOrStructValue(false, v, recursive, newTags...)
+ }
+ } else {
+ // It returns the map directly without any changing.
+ return r
+ }
+ case map[int]interface{}:
+ for k, v := range r {
+ dataMap[String(k)] = doMapConvertForMapOrStructValue(false, v, recursive, newTags...)
+ }
+ case map[int]string:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+ case map[uint]string:
+ for k, v := range r {
+ dataMap[String(k)] = v
+ }
+
+ default:
+ // Not a common type, it then uses reflection for conversion.
+ var reflectValue reflect.Value
+ if v, ok := value.(reflect.Value); ok {
+ reflectValue = v
+ } else {
+ reflectValue = reflect.ValueOf(value)
+ }
+ reflectKind := reflectValue.Kind()
+ // If it is a pointer, we should find its real data type.
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ // If `value` is type of array, it converts the value of even number index as its key and
+ // the value of odd number index as its corresponding value, for example:
+ // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
+ // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
+ case reflect.Slice, reflect.Array:
+ length := reflectValue.Len()
+ for i := 0; i < length; i += 2 {
+ if i+1 < length {
+ dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
+ } else {
+ dataMap[String(reflectValue.Index(i).Interface())] = nil
+ }
+ }
+ case reflect.Map, reflect.Struct, reflect.Interface:
+ convertedValue := doMapConvertForMapOrStructValue(true, value, recursive, newTags...)
+ if m, ok := convertedValue.(map[string]interface{}); ok {
+ return m
+ }
+ return nil
+ default:
+ return nil
+ }
+ }
+ return dataMap
+}
+
+func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive bool, tags ...string) interface{} {
+ if isRoot == false && recursive == false {
+ return value
+ }
+ var reflectValue reflect.Value
+ if v, ok := value.(reflect.Value); ok {
+ reflectValue = v
+ value = v.Interface()
+ } else {
+ reflectValue = reflect.ValueOf(value)
+ }
+ reflectKind := reflectValue.Kind()
+ // If it is a pointer, we should find its real data type.
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Map:
+ var (
+ mapKeys = reflectValue.MapKeys()
+ dataMap = make(map[string]interface{})
+ )
+ for _, k := range mapKeys {
+ dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
+ false,
+ reflectValue.MapIndex(k).Interface(),
+ recursive,
+ tags...,
+ )
+ }
+ return dataMap
+
+ case reflect.Struct:
+ var dataMap = make(map[string]interface{})
+ // Map converting interface check.
+ if v, ok := value.(iMapStrAny); ok {
+ // Value copy, in case of concurrent safety.
+ for mapK, mapV := range v.MapStrAny() {
+ if recursive {
+ dataMap[mapK] = doMapConvertForMapOrStructValue(false, mapV, recursive, tags...)
+ } else {
+ dataMap[mapK] = mapV
+ }
+ }
+ return dataMap
+ }
+ // Using reflect for converting.
+ var (
+ rtField reflect.StructField
+ rvField reflect.Value
+ reflectType = reflectValue.Type() // attribute value type.
+ mapKey = "" // mapKey may be the tag name or the struct attribute name.
+ )
+ for i := 0; i < reflectValue.NumField(); i++ {
+ rtField = reflectType.Field(i)
+ rvField = reflectValue.Field(i)
+ // Only convert the public attributes.
+ fieldName := rtField.Name
+ if !utils.IsLetterUpper(fieldName[0]) {
+ continue
+ }
+ mapKey = ""
+ fieldTag := rtField.Tag
+ for _, tag := range tags {
+ if mapKey = fieldTag.Get(tag); mapKey != "" {
+ break
+ }
+ }
+ if mapKey == "" {
+ mapKey = fieldName
+ } else {
+ // Support json tag feature: -, omitempty
+ mapKey = strings.TrimSpace(mapKey)
+ if mapKey == "-" {
+ continue
+ }
+ array := strings.Split(mapKey, ",")
+ if len(array) > 1 {
+ switch strings.TrimSpace(array[1]) {
+ case "omitempty":
+ if empty.IsEmpty(rvField.Interface()) {
+ continue
+ } else {
+ mapKey = strings.TrimSpace(array[0])
+ }
+ default:
+ mapKey = strings.TrimSpace(array[0])
+ }
+ }
+ }
+ if recursive || rtField.Anonymous {
+ // Do map converting recursively.
+ var (
+ rvAttrField = rvField
+ rvAttrKind = rvField.Kind()
+ )
+ if rvAttrKind == reflect.Ptr {
+ rvAttrField = rvField.Elem()
+ rvAttrKind = rvAttrField.Kind()
+ }
+ switch rvAttrKind {
+ case reflect.Struct:
+ // Embedded struct and has no fields, just ignores it.
+ // Eg: gmeta.Meta
+ if rvAttrField.Type().NumField() == 0 {
+ continue
+ }
+ var (
+ hasNoTag = mapKey == fieldName
+ rvAttrInterface = rvAttrField.Interface()
+ )
+ if hasNoTag && rtField.Anonymous {
+ // It means this attribute field has no tag.
+ // Overwrite the attribute with sub-struct attribute fields.
+ anonymousValue := doMapConvertForMapOrStructValue(false, rvAttrInterface, true, tags...)
+ if m, ok := anonymousValue.(map[string]interface{}); ok {
+ for k, v := range m {
+ dataMap[k] = v
+ }
+ } else {
+ dataMap[mapKey] = rvAttrInterface
+ }
+ } else if !hasNoTag && rtField.Anonymous {
+ // It means this attribute field has desired tag.
+ dataMap[mapKey] = doMapConvertForMapOrStructValue(false, rvAttrInterface, true, tags...)
+ } else {
+ dataMap[mapKey] = doMapConvertForMapOrStructValue(false, rvAttrInterface, recursive, tags...)
+ }
+
+ // The struct attribute is type of slice.
+ case reflect.Array, reflect.Slice:
+ length := rvAttrField.Len()
+ if length == 0 {
+ dataMap[mapKey] = rvAttrField.Interface()
+ break
+ }
+ array := make([]interface{}, length)
+ for arrayIndex := 0; arrayIndex < length; arrayIndex++ {
+ array[arrayIndex] = doMapConvertForMapOrStructValue(
+ false, rvAttrField.Index(arrayIndex), recursive, tags...,
+ )
+ }
+ dataMap[mapKey] = array
+ case reflect.Map:
+ var (
+ mapKeys = rvAttrField.MapKeys()
+ nestedMap = make(map[string]interface{})
+ )
+ for _, k := range mapKeys {
+ nestedMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
+ false,
+ rvAttrField.MapIndex(k).Interface(),
+ recursive,
+ tags...,
+ )
+ }
+ dataMap[mapKey] = nestedMap
+ default:
+ if rvField.IsValid() {
+ dataMap[mapKey] = reflectValue.Field(i).Interface()
+ } else {
+ dataMap[mapKey] = nil
+ }
+ }
+ } else {
+ // No recursive map value converting
+ if rvField.IsValid() {
+ dataMap[mapKey] = reflectValue.Field(i).Interface()
+ } else {
+ dataMap[mapKey] = nil
+ }
+ }
+ }
+ if len(dataMap) == 0 {
+ return value
+ }
+ return dataMap
+
+ // The given value is type of slice.
+ case reflect.Array, reflect.Slice:
+ length := reflectValue.Len()
+ if length == 0 {
+ break
+ }
+ array := make([]interface{}, reflectValue.Len())
+ for i := 0; i < length; i++ {
+ array[i] = doMapConvertForMapOrStructValue(false, reflectValue.Index(i), recursive, tags...)
+ }
+ return array
+ }
+ return value
+}
+
+// MapStrStr converts `value` to map[string]string.
+// Note that there might be data copy for this map type converting.
+func MapStrStr(value interface{}, tags ...string) map[string]string {
+ if r, ok := value.(map[string]string); ok {
+ return r
+ }
+ m := Map(value, tags...)
+ if len(m) > 0 {
+ vMap := make(map[string]string, len(m))
+ for k, v := range m {
+ vMap[k] = String(v)
+ }
+ return vMap
+ }
+ return nil
+}
+
+// MapStrStrDeep converts `value` to map[string]string recursively.
+// Note that there might be data copy for this map type converting.
+func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
+ if r, ok := value.(map[string]string); ok {
+ return r
+ }
+ m := MapDeep(value, tags...)
+ if len(m) > 0 {
+ vMap := make(map[string]string, len(m))
+ for k, v := range m {
+ vMap[k] = String(v)
+ }
+ return vMap
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maps.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maps.go
new file mode 100644
index 000000000000..3efe2386f90f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maps.go
@@ -0,0 +1,119 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import "github.com/gogf/gf/v2/internal/json"
+
+// SliceMap is alias of Maps.
+func SliceMap(any interface{}) []map[string]interface{} {
+ return Maps(any)
+}
+
+// SliceMapDeep is alias of MapsDeep.
+func SliceMapDeep(any interface{}) []map[string]interface{} {
+ return MapsDeep(any)
+}
+
+// SliceStruct is alias of Structs.
+func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
+ return Structs(params, pointer, mapping...)
+}
+
+// Maps converts `value` to []map[string]interface{}.
+// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.
+func Maps(value interface{}, tags ...string) []map[string]interface{} {
+ if value == nil {
+ return nil
+ }
+ switch r := value.(type) {
+ case string:
+ list := make([]map[string]interface{}, 0)
+ if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
+ if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {
+ return nil
+ }
+ return list
+ } else {
+ return nil
+ }
+
+ case []byte:
+ list := make([]map[string]interface{}, 0)
+ if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
+ if err := json.UnmarshalUseNumber(r, &list); err != nil {
+ return nil
+ }
+ return list
+ } else {
+ return nil
+ }
+
+ case []map[string]interface{}:
+ return r
+
+ default:
+ array := Interfaces(value)
+ if len(array) == 0 {
+ return nil
+ }
+ list := make([]map[string]interface{}, len(array))
+ for k, v := range array {
+ list[k] = Map(v, tags...)
+ }
+ return list
+ }
+}
+
+// MapsDeep converts `value` to []map[string]interface{} recursively.
+//
+// TODO completely implement the recursive converting for all types.
+func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
+ if value == nil {
+ return nil
+ }
+ switch r := value.(type) {
+ case string:
+ list := make([]map[string]interface{}, 0)
+ if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
+ if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {
+ return nil
+ }
+ return list
+ } else {
+ return nil
+ }
+
+ case []byte:
+ list := make([]map[string]interface{}, 0)
+ if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
+ if err := json.UnmarshalUseNumber(r, &list); err != nil {
+ return nil
+ }
+ return list
+ } else {
+ return nil
+ }
+
+ case []map[string]interface{}:
+ list := make([]map[string]interface{}, len(r))
+ for k, v := range r {
+ list[k] = MapDeep(v, tags...)
+ }
+ return list
+
+ default:
+ array := Interfaces(value)
+ if len(array) == 0 {
+ return nil
+ }
+ list := make([]map[string]interface{}, len(array))
+ for k, v := range array {
+ list[k] = MapDeep(v, tags...)
+ }
+ return list
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maptomap.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maptomap.go
new file mode 100644
index 000000000000..51eb0efda8f1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maptomap.go
@@ -0,0 +1,147 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// MapToMap converts any map type variable `params` to another map type variable `pointer`
+// using reflect.
+// See doMapToMap.
+func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error {
+ return doMapToMap(params, pointer, mapping...)
+}
+
+// doMapToMap converts any map type variable `params` to another map type variable `pointer`.
+//
+// The parameter `params` can be any type of map, like:
+// map[string]string, map[string]struct, map[string]*struct, etc.
+//
+// The parameter `pointer` should be type of *map, like:
+// map[int]string, map[string]struct, map[string]*struct, etc.
+//
+// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
+// sense only if the items of original map `params` is type struct.
+func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
+ // If given `params` is JSON, it then uses json.Unmarshal doing the converting.
+ switch r := params.(type) {
+ case []byte:
+ if json.Valid(r) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ return json.UnmarshalUseNumber(r, rv.Interface())
+ }
+ } else {
+ return json.UnmarshalUseNumber(r, pointer)
+ }
+ }
+ case string:
+ if paramsBytes := []byte(r); json.Valid(paramsBytes) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
+ }
+ } else {
+ return json.UnmarshalUseNumber(paramsBytes, pointer)
+ }
+ }
+ }
+ var (
+ paramsRv reflect.Value
+ paramsKind reflect.Kind
+ keyToAttributeNameMapping map[string]string
+ )
+ if len(mapping) > 0 {
+ keyToAttributeNameMapping = mapping[0]
+ }
+ if v, ok := params.(reflect.Value); ok {
+ paramsRv = v
+ } else {
+ paramsRv = reflect.ValueOf(params)
+ }
+ paramsKind = paramsRv.Kind()
+ if paramsKind == reflect.Ptr {
+ paramsRv = paramsRv.Elem()
+ paramsKind = paramsRv.Kind()
+ }
+ if paramsKind != reflect.Map {
+ return doMapToMap(Map(params), pointer, mapping...)
+ }
+ // Empty params map, no need continue.
+ if paramsRv.Len() == 0 {
+ return nil
+ }
+ var pointerRv reflect.Value
+ if v, ok := pointer.(reflect.Value); ok {
+ pointerRv = v
+ } else {
+ pointerRv = reflect.ValueOf(pointer)
+ }
+ pointerKind := pointerRv.Kind()
+ for pointerKind == reflect.Ptr {
+ pointerRv = pointerRv.Elem()
+ pointerKind = pointerRv.Kind()
+ }
+ if pointerKind != reflect.Map {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "pointer should be type of *map, but got:%s", pointerKind)
+ }
+ defer func() {
+ // Catch the panic, especially the reflect operation panics.
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
+ }
+ }
+ }()
+ var (
+ paramsKeys = paramsRv.MapKeys()
+ pointerKeyType = pointerRv.Type().Key()
+ pointerValueType = pointerRv.Type().Elem()
+ pointerValueKind = pointerValueType.Kind()
+ dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
+ )
+ // Retrieve the true element type of target map.
+ if pointerValueKind == reflect.Ptr {
+ pointerValueKind = pointerValueType.Elem().Kind()
+ }
+ for _, key := range paramsKeys {
+ e := reflect.New(pointerValueType).Elem()
+ switch pointerValueKind {
+ case reflect.Map, reflect.Struct:
+ if err = doStruct(paramsRv.MapIndex(key).Interface(), e, keyToAttributeNameMapping, ""); err != nil {
+ return err
+ }
+ default:
+ e.Set(
+ reflect.ValueOf(
+ Convert(
+ paramsRv.MapIndex(key).Interface(),
+ pointerValueType.String(),
+ ),
+ ),
+ )
+ }
+ dataMap.SetMapIndex(
+ reflect.ValueOf(
+ Convert(
+ key.Interface(),
+ pointerKeyType.Name(),
+ ),
+ ),
+ e,
+ )
+ }
+ pointerRv.Set(dataMap)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maptomaps.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maptomaps.go
new file mode 100644
index 000000000000..6ab8e2199419
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_maptomaps.go
@@ -0,0 +1,141 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`.
+// See doMapToMaps.
+func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error {
+ return doMapToMaps(params, pointer, mapping...)
+}
+
+// doMapToMaps converts any map type variable `params` to another map slice variable `pointer`.
+//
+// The parameter `params` can be type of []map, []*map, []struct, []*struct.
+//
+// The parameter `pointer` should be type of []map, []*map.
+//
+// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
+// sense only if the item of `params` is type struct.
+func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
+ // If given `params` is JSON, it then uses json.Unmarshal doing the converting.
+ switch r := params.(type) {
+ case []byte:
+ if json.Valid(r) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ return json.UnmarshalUseNumber(r, rv.Interface())
+ }
+ } else {
+ return json.UnmarshalUseNumber(r, pointer)
+ }
+ }
+ case string:
+ if paramsBytes := []byte(r); json.Valid(paramsBytes) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
+ }
+ } else {
+ return json.UnmarshalUseNumber(paramsBytes, pointer)
+ }
+ }
+ }
+ // Params and its element type check.
+ var (
+ paramsRv reflect.Value
+ paramsKind reflect.Kind
+ )
+ if v, ok := params.(reflect.Value); ok {
+ paramsRv = v
+ } else {
+ paramsRv = reflect.ValueOf(params)
+ }
+ paramsKind = paramsRv.Kind()
+ if paramsKind == reflect.Ptr {
+ paramsRv = paramsRv.Elem()
+ paramsKind = paramsRv.Kind()
+ }
+ if paramsKind != reflect.Array && paramsKind != reflect.Slice {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "params should be type of slice, eg: []map/[]*map/[]struct/[]*struct")
+ }
+ var (
+ paramsElem = paramsRv.Type().Elem()
+ paramsElemKind = paramsElem.Kind()
+ )
+ if paramsElemKind == reflect.Ptr {
+ paramsElem = paramsElem.Elem()
+ paramsElemKind = paramsElem.Kind()
+ }
+ if paramsElemKind != reflect.Map && paramsElemKind != reflect.Struct && paramsElemKind != reflect.Interface {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "params element should be type of map/*map/struct/*struct, but got: %s", paramsElemKind)
+ }
+ // Empty slice, no need continue.
+ if paramsRv.Len() == 0 {
+ return nil
+ }
+ // Pointer and its element type check.
+ var (
+ pointerRv = reflect.ValueOf(pointer)
+ pointerKind = pointerRv.Kind()
+ )
+ for pointerKind == reflect.Ptr {
+ pointerRv = pointerRv.Elem()
+ pointerKind = pointerRv.Kind()
+ }
+ if pointerKind != reflect.Array && pointerKind != reflect.Slice {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map")
+ }
+ var (
+ pointerElemType = pointerRv.Type().Elem()
+ pointerElemKind = pointerElemType.Kind()
+ )
+ if pointerElemKind == reflect.Ptr {
+ pointerElemKind = pointerElemType.Elem().Kind()
+ }
+ if pointerElemKind != reflect.Map {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map")
+ }
+ defer func() {
+ // Catch the panic, especially the reflection operation panics.
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
+ }
+ }
+ }()
+ var (
+ pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len())
+ )
+ for i := 0; i < paramsRv.Len(); i++ {
+ var item reflect.Value
+ if pointerElemType.Kind() == reflect.Ptr {
+ item = reflect.New(pointerElemType.Elem())
+ if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
+ return err
+ }
+ pointerSlice.Index(i).Set(item)
+ } else {
+ item = reflect.New(pointerElemType)
+ if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
+ return err
+ }
+ pointerSlice.Index(i).Set(item.Elem())
+ }
+ }
+ pointerRv.Set(pointerSlice)
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_scan.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_scan.go
new file mode 100644
index 000000000000..426b699e8de8
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_scan.go
@@ -0,0 +1,517 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "database/sql"
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gstructs"
+)
+
+// Scan automatically checks the type of `pointer` and converts `params` to `pointer`. It supports `pointer`
+// with type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.
+//
+// It calls function `doMapToMap` internally if `pointer` is type of *map for converting.
+// It calls function `doMapToMaps` internally if `pointer` is type of *[]map/*[]*map for converting.
+// It calls function `doStruct` internally if `pointer` is type of *struct/**struct for converting.
+// It calls function `doStructs` internally if `pointer` is type of *[]struct/*[]*struct for converting.
+func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
+ var (
+ pointerType reflect.Type
+ pointerKind reflect.Kind
+ pointerValue reflect.Value
+ )
+ if v, ok := pointer.(reflect.Value); ok {
+ pointerValue = v
+ pointerType = v.Type()
+ } else {
+ pointerValue = reflect.ValueOf(pointer)
+ pointerType = reflect.TypeOf(pointer) // Do not use pointerValue.Type() as pointerValue might be zero.
+ }
+
+ if pointerType == nil {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "parameter pointer should not be nil")
+ }
+ pointerKind = pointerType.Kind()
+ if pointerKind != reflect.Ptr {
+ if pointerValue.CanAddr() {
+ pointerValue = pointerValue.Addr()
+ pointerType = pointerValue.Type()
+ pointerKind = pointerType.Kind()
+ } else {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "params should be type of pointer, but got type: %v",
+ pointerType,
+ )
+ }
+
+ }
+ // Direct assignment checks!
+ var (
+ paramsType reflect.Type
+ paramsValue reflect.Value
+ )
+ if v, ok := params.(reflect.Value); ok {
+ paramsValue = v
+ paramsType = paramsValue.Type()
+ } else {
+ paramsValue = reflect.ValueOf(params)
+ paramsType = reflect.TypeOf(params) // Do not use paramsValue.Type() as paramsValue might be zero.
+ }
+ // If `params` and `pointer` are the same type, the do directly assignment.
+ // For performance enhancement purpose.
+ var (
+ pointerValueElem = pointerValue.Elem()
+ )
+ if pointerValueElem.CanSet() && paramsType == pointerValueElem.Type() {
+ pointerValueElem.Set(paramsValue)
+ return nil
+ }
+
+ // Converting.
+ var (
+ pointerElem = pointerType.Elem()
+ pointerElemKind = pointerElem.Kind()
+ keyToAttributeNameMapping map[string]string
+ )
+ if len(mapping) > 0 {
+ keyToAttributeNameMapping = mapping[0]
+ }
+ switch pointerElemKind {
+ case reflect.Map:
+ return doMapToMap(params, pointer, mapping...)
+
+ case reflect.Array, reflect.Slice:
+ var (
+ sliceElem = pointerElem.Elem()
+ sliceElemKind = sliceElem.Kind()
+ )
+ for sliceElemKind == reflect.Ptr {
+ sliceElem = sliceElem.Elem()
+ sliceElemKind = sliceElem.Kind()
+ }
+ if sliceElemKind == reflect.Map {
+ return doMapToMaps(params, pointer, mapping...)
+ }
+ return doStructs(params, pointer, keyToAttributeNameMapping, "")
+
+ default:
+ return doStruct(params, pointer, keyToAttributeNameMapping, "")
+ }
+}
+
+// ScanList converts `structSlice` to struct slice which contains other complex struct attributes.
+// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
+//
+// Usage example 1: Normal attribute struct relation:
+// type EntityUser struct {
+// Uid int
+// Name string
+// }
+// type EntityUserDetail struct {
+// Uid int
+// Address string
+// }
+// type EntityUserScores struct {
+// Id int
+// Uid int
+// Score int
+// Course string
+// }
+// type Entity struct {
+// User *EntityUser
+// UserDetail *EntityUserDetail
+// UserScores []*EntityUserScores
+// }
+// var users []*Entity
+// ScanList(records, &users, "User")
+// ScanList(records, &users, "User", "uid")
+// ScanList(records, &users, "UserDetail", "User", "uid:Uid")
+// ScanList(records, &users, "UserScores", "User", "uid:Uid")
+// ScanList(records, &users, "UserScores", "User", "uid")
+//
+//
+// Usage example 2: Embedded attribute struct relation:
+// type EntityUser struct {
+// Uid int
+// Name string
+// }
+// type EntityUserDetail struct {
+// Uid int
+// Address string
+// }
+// type EntityUserScores struct {
+// Id int
+// Uid int
+// Score int
+// }
+// type Entity struct {
+// EntityUser
+// UserDetail EntityUserDetail
+// UserScores []EntityUserScores
+// }
+//
+// var users []*Entity
+// ScanList(records, &users)
+// ScanList(records, &users, "UserDetail", "uid")
+// ScanList(records, &users, "UserScores", "uid")
+//
+//
+// The parameters "User/UserDetail/UserScores" in the example codes specify the target attribute struct
+// that current result will be bound to.
+//
+// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational
+// struct attribute name - not the attribute name of the bound to target. In the example codes, it's attribute
+// name "Uid" of "User" of entity "Entity". It automatically calculates the HasOne/HasMany relationship with
+// given `relation` parameter.
+//
+// See the example or unit testing cases for clear understanding for this function.
+func ScanList(structSlice interface{}, structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
+ var (
+ relationAttrName string
+ relationFields string
+ )
+ switch len(relationAttrNameAndFields) {
+ case 2:
+ relationAttrName = relationAttrNameAndFields[0]
+ relationFields = relationAttrNameAndFields[1]
+ case 1:
+ relationFields = relationAttrNameAndFields[0]
+ }
+ return doScanList(structSlice, structSlicePointer, bindToAttrName, relationAttrName, relationFields)
+}
+
+// doScanList converts `structSlice` to struct slice which contains other complex struct attributes recursively.
+// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
+func doScanList(structSlice interface{}, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string) (err error) {
+ var (
+ maps = Maps(structSlice)
+ )
+ if len(maps) == 0 {
+ return nil
+ }
+ // Necessary checks for parameters.
+ if bindToAttrName == "" {
+ return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
+ }
+
+ if relationAttrName == "." {
+ relationAttrName = ""
+ }
+
+ var (
+ reflectValue = reflect.ValueOf(structSlicePointer)
+ reflectKind = reflectValue.Kind()
+ )
+ if reflectKind == reflect.Interface {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ if reflectKind != reflect.Ptr {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
+ reflectKind,
+ )
+ }
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ if reflectKind != reflect.Slice && reflectKind != reflect.Array {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ "structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
+ reflectKind,
+ )
+ }
+ length := len(maps)
+ if length == 0 {
+ // The pointed slice is not empty.
+ if reflectValue.Len() > 0 {
+ // It here checks if it has struct item, which is already initialized.
+ // It then returns error to warn the developer its empty and no conversion.
+ if v := reflectValue.Index(0); v.Kind() != reflect.Ptr {
+ return sql.ErrNoRows
+ }
+ }
+ // Do nothing for empty struct slice.
+ return nil
+ }
+ var (
+ arrayValue reflect.Value // Like: []*Entity
+ arrayItemType reflect.Type // Like: *Entity
+ reflectType = reflect.TypeOf(structSlicePointer)
+ )
+ if reflectValue.Len() > 0 {
+ arrayValue = reflectValue
+ } else {
+ arrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)
+ }
+
+ // Slice element item.
+ arrayItemType = arrayValue.Index(0).Type()
+
+ // Relation variables.
+ var (
+ relationDataMap map[string]interface{}
+ relationFromFieldName string // Eg: relationKV: id:uid -> id
+ relationBindToFieldName string // Eg: relationKV: id:uid -> uid
+ )
+ if len(relationFields) > 0 {
+ // The relation key string of table filed name and attribute name
+ // can be joined with char '=' or ':'.
+ array := utils.SplitAndTrim(relationFields, "=")
+ if len(array) == 1 {
+ // Compatible with old splitting char ':'.
+ array = utils.SplitAndTrim(relationFields, ":")
+ }
+ if len(array) == 1 {
+ // The relation names are the same.
+ array = []string{relationFields, relationFields}
+ }
+ if len(array) == 2 {
+ // Defined table field to relation attribute name.
+ // Like:
+ // uid:Uid
+ // uid:UserId
+ relationFromFieldName = array[0]
+ relationBindToFieldName = array[1]
+ if key, _ := utils.MapPossibleItemByKey(maps[0], relationFromFieldName); key == "" {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find possible related table field name "%s" from given relation fields "%s"`,
+ relationFromFieldName,
+ relationFields,
+ )
+ } else {
+ relationFromFieldName = key
+ }
+ } else {
+ return gerror.NewCode(
+ gcode.CodeInvalidParameter,
+ `parameter relationKV should be format of "ResultFieldName:BindToAttrName"`,
+ )
+ }
+ if relationFromFieldName != "" {
+ // Note that the value might be type of slice.
+ relationDataMap = utils.ListToMapByKey(maps, relationFromFieldName)
+ }
+ if len(relationDataMap) == 0 {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find the relation data map, maybe invalid relation fields given "%v"`,
+ relationFields,
+ )
+ }
+ }
+ // Bind to target attribute.
+ var (
+ ok bool
+ bindToAttrValue reflect.Value
+ bindToAttrKind reflect.Kind
+ bindToAttrType reflect.Type
+ bindToAttrField reflect.StructField
+ )
+ if arrayItemType.Kind() == reflect.Ptr {
+ if bindToAttrField, ok = arrayItemType.Elem().FieldByName(bindToAttrName); !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
+ bindToAttrName,
+ )
+ }
+ } else {
+ if bindToAttrField, ok = arrayItemType.FieldByName(bindToAttrName); !ok {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
+ bindToAttrName,
+ )
+ }
+ }
+ bindToAttrType = bindToAttrField.Type
+ bindToAttrKind = bindToAttrType.Kind()
+
+ // Bind to relation conditions.
+ var (
+ relationFromAttrValue reflect.Value
+ relationFromAttrField reflect.Value
+ relationBindToFieldNameChecked bool
+ )
+ for i := 0; i < arrayValue.Len(); i++ {
+ arrayElemValue := arrayValue.Index(i)
+ // The FieldByName should be called on non-pointer reflect.Value.
+ if arrayElemValue.Kind() == reflect.Ptr {
+ // Like: []*Entity
+ arrayElemValue = arrayElemValue.Elem()
+ if !arrayElemValue.IsValid() {
+ // The element is nil, then create one and set it to the slice.
+ // The "reflect.New(itemType.Elem())" creates a new element and returns the address of it.
+ // For example:
+ // reflect.New(itemType.Elem()) => *Entity
+ // reflect.New(itemType.Elem()).Elem() => Entity
+ arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
+ arrayValue.Index(i).Set(arrayElemValue.Addr())
+ }
+ } else {
+ // Like: []Entity
+ }
+ bindToAttrValue = arrayElemValue.FieldByName(bindToAttrName)
+ if relationAttrName != "" {
+ // Attribute value of current slice element.
+ relationFromAttrValue = arrayElemValue.FieldByName(relationAttrName)
+ if relationFromAttrValue.Kind() == reflect.Ptr {
+ relationFromAttrValue = relationFromAttrValue.Elem()
+ }
+ } else {
+ // Current slice element.
+ relationFromAttrValue = arrayElemValue
+ }
+ if len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
+ }
+ // Check and find possible bind to attribute name.
+ if relationFields != "" && !relationBindToFieldNameChecked {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if !relationFromAttrField.IsValid() {
+ var (
+ filedMap, _ = gstructs.FieldMap(gstructs.FieldMapInput{
+ Pointer: relationFromAttrValue,
+ RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
+ })
+ )
+ if key, _ := utils.MapPossibleItemByKey(Map(filedMap), relationBindToFieldName); key == "" {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `cannot find possible related attribute name "%s" from given relation fields "%s"`,
+ relationBindToFieldName,
+ relationFields,
+ )
+ } else {
+ relationBindToFieldName = key
+ }
+ }
+ relationBindToFieldNameChecked = true
+ }
+ switch bindToAttrKind {
+ case reflect.Array, reflect.Slice:
+ if len(relationDataMap) > 0 {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if relationFromAttrField.IsValid() {
+ // results := make(Result, 0)
+ results := make([]interface{}, 0)
+ for _, v := range SliceAny(relationDataMap[String(relationFromAttrField.Interface())]) {
+ item := v
+ results = append(results, item)
+ }
+ if err = Structs(results, bindToAttrValue.Addr()); err != nil {
+ return err
+ }
+ } else {
+ // Maybe the attribute does not exist yet.
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
+ }
+ } else {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `relationKey should not be empty as field "%s" is slice`,
+ bindToAttrName,
+ )
+ }
+
+ case reflect.Ptr:
+ var element reflect.Value
+ if bindToAttrValue.IsNil() {
+ element = reflect.New(bindToAttrType.Elem()).Elem()
+ } else {
+ element = bindToAttrValue.Elem()
+ }
+ if len(relationDataMap) > 0 {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if relationFromAttrField.IsValid() {
+ v := relationDataMap[String(relationFromAttrField.Interface())]
+ if v == nil {
+ // There's no relational data.
+ continue
+ }
+ if utils.IsSlice(v) {
+ if err = Struct(SliceAny(v)[0], element); err != nil {
+ return err
+ }
+ } else {
+ if err = Struct(v, element); err != nil {
+ return err
+ }
+ }
+ } else {
+ // Maybe the attribute does not exist yet.
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
+ }
+ } else {
+ if i >= len(maps) {
+ // There's no relational data.
+ continue
+ }
+ v := maps[i]
+ if v == nil {
+ // There's no relational data.
+ continue
+ }
+ if err = Struct(v, element); err != nil {
+ return err
+ }
+ }
+ bindToAttrValue.Set(element.Addr())
+
+ case reflect.Struct:
+ if len(relationDataMap) > 0 {
+ relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
+ if relationFromAttrField.IsValid() {
+ relationDataItem := relationDataMap[String(relationFromAttrField.Interface())]
+ if relationDataItem == nil {
+ // There's no relational data.
+ continue
+ }
+ if utils.IsSlice(relationDataItem) {
+ if err = Struct(SliceAny(relationDataItem)[0], bindToAttrValue); err != nil {
+ return err
+ }
+ } else {
+ if err = Struct(relationDataItem, bindToAttrValue); err != nil {
+ return err
+ }
+ }
+ } else {
+ // Maybe the attribute does not exist yet.
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
+ }
+ } else {
+ if i >= len(maps) {
+ // There's no relational data.
+ continue
+ }
+ relationDataItem := maps[i]
+ if relationDataItem == nil {
+ // There's no relational data.
+ continue
+ }
+ if err = Struct(relationDataItem, bindToAttrValue); err != nil {
+ return err
+ }
+ }
+
+ default:
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())
+ }
+ }
+ reflect.ValueOf(structSlicePointer).Elem().Set(arrayValue)
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_any.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_any.go
new file mode 100644
index 000000000000..d4f73f610aec
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_any.go
@@ -0,0 +1,131 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// SliceAny is alias of Interfaces.
+func SliceAny(any interface{}) []interface{} {
+ return Interfaces(any)
+}
+
+// Interfaces converts `any` to []interface{}.
+func Interfaces(any interface{}) []interface{} {
+ if any == nil {
+ return nil
+ }
+ if r, ok := any.([]interface{}); ok {
+ return r
+ }
+ var (
+ array []interface{} = nil
+ )
+ switch value := any.(type) {
+ case []string:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []int:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []int8:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []int16:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []int32:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []int64:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []uint:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []uint8:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []uint16:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []uint32:
+ for _, v := range value {
+ array = append(array, v)
+ }
+ case []uint64:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []bool:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []float32:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ case []float64:
+ array = make([]interface{}, len(value))
+ for k, v := range value {
+ array[k] = v
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return v.Interfaces()
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]interface{}, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = originValueAndKind.OriginValue.Index(i).Interface()
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []interface{}{}
+ }
+ return []interface{}{any}
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_float.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_float.go
new file mode 100644
index 000000000000..56c774e33537
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_float.go
@@ -0,0 +1,273 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// SliceFloat is alias of Floats.
+func SliceFloat(any interface{}) []float64 {
+ return Floats(any)
+}
+
+// SliceFloat32 is alias of Float32s.
+func SliceFloat32(any interface{}) []float32 {
+ return Float32s(any)
+}
+
+// SliceFloat64 is alias of Float64s.
+func SliceFloat64(any interface{}) []float64 {
+ return Floats(any)
+}
+
+// Floats converts `any` to []float64.
+func Floats(any interface{}) []float64 {
+ return Float64s(any)
+}
+
+// Float32s converts `any` to []float32.
+func Float32s(any interface{}) []float32 {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []float32 = nil
+ )
+ switch value := any.(type) {
+ case string:
+ if value == "" {
+ return []float32{}
+ }
+ return []float32{Float32(value)}
+ case []string:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []int:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []int8:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []int16:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []int32:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []int64:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []uint:
+ for _, v := range value {
+ array = append(array, Float32(v))
+ }
+ case []uint8:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []uint16:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []uint32:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []uint64:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []bool:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []float32:
+ array = value
+ case []float64:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ case []interface{}:
+ array = make([]float32, len(value))
+ for k, v := range value {
+ array[k] = Float32(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iFloats); ok {
+ return Float32s(v.Floats())
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Float32s(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]float32, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Float32(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []float32{}
+ }
+ return []float32{Float32(any)}
+ }
+}
+
+// Float64s converts `any` to []float64.
+func Float64s(any interface{}) []float64 {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []float64 = nil
+ )
+ switch value := any.(type) {
+ case string:
+ if value == "" {
+ return []float64{}
+ }
+ return []float64{Float64(value)}
+ case []string:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []int:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []int8:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []int16:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []int32:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []int64:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []uint:
+ for _, v := range value {
+ array = append(array, Float64(v))
+ }
+ case []uint8:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []uint16:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []uint32:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []uint64:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []bool:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []float32:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ case []float64:
+ array = value
+ case []interface{}:
+ array = make([]float64, len(value))
+ for k, v := range value {
+ array[k] = Float64(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iFloats); ok {
+ return v.Floats()
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Floats(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]float64, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Float64(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []float64{}
+ }
+ return []float64{Float64(any)}
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_int.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_int.go
new file mode 100644
index 000000000000..c34701bb9869
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_int.go
@@ -0,0 +1,403 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// SliceInt is alias of Ints.
+func SliceInt(any interface{}) []int {
+ return Ints(any)
+}
+
+// SliceInt32 is alias of Int32s.
+func SliceInt32(any interface{}) []int32 {
+ return Int32s(any)
+}
+
+// SliceInt64 is alias of Int64s.
+func SliceInt64(any interface{}) []int64 {
+ return Int64s(any)
+}
+
+// Ints converts `any` to []int.
+func Ints(any interface{}) []int {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []int = nil
+ )
+ switch value := any.(type) {
+ case []string:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = Int(v)
+ }
+ case []int:
+ array = value
+ case []int8:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []int16:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []int32:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []int64:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []uint:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []uint8:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []uint16:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []uint32:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []uint64:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = int(v)
+ }
+ case []bool:
+ array = make([]int, len(value))
+ for k, v := range value {
+ if v {
+ array[k] = 1
+ } else {
+ array[k] = 0
+ }
+ }
+ case []float32:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = Int(v)
+ }
+ case []float64:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = Int(v)
+ }
+ case []interface{}:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = Int(v)
+ }
+ case [][]byte:
+ array = make([]int, len(value))
+ for k, v := range value {
+ array[k] = Int(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iInts); ok {
+ return v.Ints()
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Ints(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]int, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Int(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []int{}
+ }
+ return []int{Int(any)}
+ }
+}
+
+// Int32s converts `any` to []int32.
+func Int32s(any interface{}) []int32 {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []int32 = nil
+ )
+ switch value := any.(type) {
+ case []string:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = Int32(v)
+ }
+ case []int:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []int8:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []int16:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []int32:
+ array = value
+ case []int64:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []uint:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []uint8:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []uint16:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []uint32:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []uint64:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = int32(v)
+ }
+ case []bool:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ if v {
+ array[k] = 1
+ } else {
+ array[k] = 0
+ }
+ }
+ case []float32:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = Int32(v)
+ }
+ case []float64:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = Int32(v)
+ }
+ case []interface{}:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = Int32(v)
+ }
+ case [][]byte:
+ array = make([]int32, len(value))
+ for k, v := range value {
+ array[k] = Int32(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iInts); ok {
+ return Int32s(v.Ints())
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Int32s(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]int32, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Int32(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []int32{}
+ }
+ return []int32{Int32(any)}
+ }
+}
+
+// Int64s converts `any` to []int64.
+func Int64s(any interface{}) []int64 {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []int64 = nil
+ )
+ switch value := any.(type) {
+ case []string:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = Int64(v)
+ }
+ case []int:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []int8:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []int16:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []int32:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []int64:
+ array = value
+ case []uint:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []uint8:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []uint16:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []uint32:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []uint64:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = int64(v)
+ }
+ case []bool:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ if v {
+ array[k] = 1
+ } else {
+ array[k] = 0
+ }
+ }
+ case []float32:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = Int64(v)
+ }
+ case []float64:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = Int64(v)
+ }
+ case []interface{}:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = Int64(v)
+ }
+ case [][]byte:
+ array = make([]int64, len(value))
+ for k, v := range value {
+ array[k] = Int64(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iInts); ok {
+ return Int64s(v.Ints())
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Int64s(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]int64, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Int64(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []int64{}
+ }
+ return []int64{Int64(any)}
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_str.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_str.go
new file mode 100644
index 000000000000..9118bd5221b3
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_str.go
@@ -0,0 +1,139 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// SliceStr is alias of Strings.
+func SliceStr(any interface{}) []string {
+ return Strings(any)
+}
+
+// Strings converts `any` to []string.
+func Strings(any interface{}) []string {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []string = nil
+ )
+ switch value := any.(type) {
+ case []int:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []int8:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []int16:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []int32:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []int64:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []uint:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []uint8:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []uint16:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []uint32:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []uint64:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []bool:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []float32:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []float64:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []interface{}:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ case []string:
+ array = value
+ case [][]byte:
+ array = make([]string, len(value))
+ for k, v := range value {
+ array[k] = String(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ if v, ok := any.(iStrings); ok {
+ return v.Strings()
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Strings(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]string, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = String(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []string{}
+ }
+ return []string{String(any)}
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_uint.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_uint.go
new file mode 100644
index 000000000000..01d7a1d973db
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_slice_uint.go
@@ -0,0 +1,422 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// SliceUint is alias of Uints.
+func SliceUint(any interface{}) []uint {
+ return Uints(any)
+}
+
+// SliceUint32 is alias of Uint32s.
+func SliceUint32(any interface{}) []uint32 {
+ return Uint32s(any)
+}
+
+// SliceUint64 is alias of Uint64s.
+func SliceUint64(any interface{}) []uint64 {
+ return Uint64s(any)
+}
+
+// Uints converts `any` to []uint.
+func Uints(any interface{}) []uint {
+ if any == nil {
+ return nil
+ }
+
+ var (
+ array []uint = nil
+ )
+ switch value := any.(type) {
+ case string:
+ value = strings.TrimSpace(value)
+ if value == "" {
+ return []uint{}
+ }
+ if utils.IsNumeric(value) {
+ return []uint{Uint(value)}
+ }
+
+ case []string:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = Uint(v)
+ }
+ case []int8:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []int16:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []int32:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []int64:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []uint:
+ array = value
+ case []uint8:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []uint16:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []uint32:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []uint64:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = uint(v)
+ }
+ case []bool:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ if v {
+ array[k] = 1
+ } else {
+ array[k] = 0
+ }
+ }
+ case []float32:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = Uint(v)
+ }
+ case []float64:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = Uint(v)
+ }
+ case []interface{}:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = Uint(v)
+ }
+ case [][]byte:
+ array = make([]uint, len(value))
+ for k, v := range value {
+ array[k] = Uint(v)
+ }
+ }
+
+ if array != nil {
+ return array
+ }
+
+ // Default handler.
+ if v, ok := any.(iUints); ok {
+ return v.Uints()
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Uints(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]uint, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Uint(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []uint{}
+ }
+ return []uint{Uint(any)}
+ }
+}
+
+// Uint32s converts `any` to []uint32.
+func Uint32s(any interface{}) []uint32 {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []uint32 = nil
+ )
+ switch value := any.(type) {
+ case string:
+ value = strings.TrimSpace(value)
+ if value == "" {
+ return []uint32{}
+ }
+ if utils.IsNumeric(value) {
+ return []uint32{Uint32(value)}
+ }
+ case []string:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = Uint32(v)
+ }
+ case []int8:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []int16:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []int32:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []int64:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []uint:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []uint8:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []uint16:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []uint32:
+ array = value
+ case []uint64:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = uint32(v)
+ }
+ case []bool:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ if v {
+ array[k] = 1
+ } else {
+ array[k] = 0
+ }
+ }
+ case []float32:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = Uint32(v)
+ }
+ case []float64:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = Uint32(v)
+ }
+ case []interface{}:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = Uint32(v)
+ }
+ case [][]byte:
+ array = make([]uint32, len(value))
+ for k, v := range value {
+ array[k] = Uint32(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+
+ // Default handler.
+ if v, ok := any.(iUints); ok {
+ return Uint32s(v.Uints())
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Uint32s(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]uint32, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Uint32(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []uint32{}
+ }
+ return []uint32{Uint32(any)}
+ }
+}
+
+// Uint64s converts `any` to []uint64.
+func Uint64s(any interface{}) []uint64 {
+ if any == nil {
+ return nil
+ }
+ var (
+ array []uint64 = nil
+ )
+ switch value := any.(type) {
+ case string:
+ value = strings.TrimSpace(value)
+ if value == "" {
+ return []uint64{}
+ }
+ if utils.IsNumeric(value) {
+ return []uint64{Uint64(value)}
+ }
+
+ case []string:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = Uint64(v)
+ }
+ case []int8:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []int16:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []int32:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []int64:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []uint:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []uint8:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []uint16:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []uint32:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = uint64(v)
+ }
+ case []uint64:
+ array = value
+ case []bool:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ if v {
+ array[k] = 1
+ } else {
+ array[k] = 0
+ }
+ }
+ case []float32:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = Uint64(v)
+ }
+ case []float64:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = Uint64(v)
+ }
+ case []interface{}:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = Uint64(v)
+ }
+ case [][]byte:
+ array = make([]uint64, len(value))
+ for k, v := range value {
+ array[k] = Uint64(v)
+ }
+ }
+ if array != nil {
+ return array
+ }
+ // Default handler.
+ if v, ok := any.(iUints); ok {
+ return Uint64s(v.Uints())
+ }
+ if v, ok := any.(iInterfaces); ok {
+ return Uint64s(v.Interfaces())
+ }
+ // JSON format string value converting.
+ if checkJsonAndUnmarshalUseNumber(any, &array) {
+ return array
+ }
+ // Not a common type, it then uses reflection for conversion.
+ originValueAndKind := utils.OriginValueAndKind(any)
+ switch originValueAndKind.OriginKind {
+ case reflect.Slice, reflect.Array:
+ var (
+ length = originValueAndKind.OriginValue.Len()
+ slice = make([]uint64, length)
+ )
+ for i := 0; i < length; i++ {
+ slice[i] = Uint64(originValueAndKind.OriginValue.Index(i).Interface())
+ }
+ return slice
+
+ default:
+ if originValueAndKind.OriginValue.IsZero() {
+ return []uint64{}
+ }
+ return []uint64{Uint64(any)}
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_struct.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_struct.go
new file mode 100644
index 000000000000..b24d9d7113aa
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_struct.go
@@ -0,0 +1,578 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gstructs"
+)
+
+// Struct maps the params key-value pairs to the corresponding struct object's attributes.
+// The third parameter `mapping` is unnecessary, indicating the mapping rules between the
+// custom key name and the attribute name(case-sensitive).
+//
+// Note:
+// 1. The `params` can be any type of map/struct, usually a map.
+// 2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object
+// or struct pointer.
+// 3. Only the public attributes of struct object can be mapped.
+// 4. If `params` is a map, the key of the map `params` can be lowercase.
+// It will automatically convert the first letter of the key to uppercase
+// in mapping procedure to do the matching.
+// It ignores the map key, if it does not match.
+func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
+ return Scan(params, pointer, mapping...)
+}
+
+// StructTag acts as Struct but also with support for priority tag feature, which retrieves the
+// specified tags for `params` key-value items to struct attribute names mapping.
+// The parameter `priorityTag` supports multiple tags that can be joined with char ','.
+func StructTag(params interface{}, pointer interface{}, priorityTag string) (err error) {
+ return doStruct(params, pointer, nil, priorityTag)
+}
+
+// doStructWithJsonCheck checks if given `params` is JSON, it then uses json.Unmarshal doing the converting.
+func doStructWithJsonCheck(params interface{}, pointer interface{}) (err error, ok bool) {
+ switch r := params.(type) {
+ case []byte:
+ if json.Valid(r) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ if rv.IsNil() {
+ return nil, false
+ }
+ return json.UnmarshalUseNumber(r, rv.Interface()), true
+ } else if rv.CanAddr() {
+ return json.UnmarshalUseNumber(r, rv.Addr().Interface()), true
+ }
+ } else {
+ return json.UnmarshalUseNumber(r, pointer), true
+ }
+ }
+ case string:
+ if paramsBytes := []byte(r); json.Valid(paramsBytes) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ if rv.IsNil() {
+ return nil, false
+ }
+ return json.UnmarshalUseNumber(paramsBytes, rv.Interface()), true
+ } else if rv.CanAddr() {
+ return json.UnmarshalUseNumber(paramsBytes, rv.Addr().Interface()), true
+ }
+ } else {
+ return json.UnmarshalUseNumber(paramsBytes, pointer), true
+ }
+ }
+ default:
+ // The `params` might be struct that implements interface function Interface, eg: gvar.Var.
+ if v, ok := params.(iInterface); ok {
+ return doStructWithJsonCheck(v.Interface(), pointer)
+ }
+ }
+ return nil, false
+}
+
+// doStruct is the core internal converting function for any data to struct.
+func doStruct(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
+ if params == nil {
+ // If `params` is nil, no conversion.
+ return nil
+ }
+ if pointer == nil {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil")
+ }
+
+ defer func() {
+ // Catch the panic, especially the reflection operation panics.
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
+ }
+ }
+ }()
+
+ // JSON content converting.
+ err, ok := doStructWithJsonCheck(params, pointer)
+ if err != nil {
+ return err
+ }
+ if ok {
+ return nil
+ }
+
+ var (
+ paramsReflectValue reflect.Value
+ paramsInterface interface{} // DO NOT use `params` directly as it might be type `reflect.Value`
+ pointerReflectValue reflect.Value
+ pointerReflectKind reflect.Kind
+ pointerElemReflectValue reflect.Value // The pointed element.
+ )
+ if v, ok := params.(reflect.Value); ok {
+ paramsReflectValue = v
+ } else {
+ paramsReflectValue = reflect.ValueOf(params)
+ }
+ paramsInterface = paramsReflectValue.Interface()
+ if v, ok := pointer.(reflect.Value); ok {
+ pointerReflectValue = v
+ pointerElemReflectValue = v
+ } else {
+ pointerReflectValue = reflect.ValueOf(pointer)
+ pointerReflectKind = pointerReflectValue.Kind()
+ if pointerReflectKind != reflect.Ptr {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "object pointer should be type of '*struct', but got '%v'", pointerReflectKind)
+ }
+ // Using IsNil on reflect.Ptr variable is OK.
+ if !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil")
+ }
+ pointerElemReflectValue = pointerReflectValue.Elem()
+ }
+
+ // If `params` and `pointer` are the same type, the do directly assignment.
+ // For performance enhancement purpose.
+ if pointerElemReflectValue.IsValid() && pointerElemReflectValue.Type() == paramsReflectValue.Type() {
+ pointerElemReflectValue.Set(paramsReflectValue)
+ return nil
+ }
+
+ // Normal unmarshalling interfaces checks.
+ if err, ok = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok {
+ return err
+ }
+
+ // It automatically creates struct object if necessary.
+ // For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User.
+ if pointerElemReflectValue.Kind() == reflect.Ptr {
+ if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {
+ e := reflect.New(pointerElemReflectValue.Type().Elem()).Elem()
+ pointerElemReflectValue.Set(e.Addr())
+ }
+ // if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok {
+ // return v.UnmarshalValue(params)
+ // }
+ // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`.
+ if err, ok = bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok {
+ return err
+ }
+ // Retrieve its element, may be struct at last.
+ pointerElemReflectValue = pointerElemReflectValue.Elem()
+ }
+
+ // paramsMap is the map[string]interface{} type variable for params.
+ // DO NOT use MapDeep here.
+ paramsMap := Map(paramsInterface)
+ if paramsMap == nil {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `convert params from "%#v" to "map[string]interface{}" failed`,
+ params,
+ )
+ }
+
+ // It only performs one converting to the same attribute.
+ // doneMap is used to check repeated converting, its key is the real attribute name
+ // of the struct.
+ doneMap := make(map[string]struct{})
+
+ // The key of the attrMap is the attribute name of the struct,
+ // and the value is its replaced name for later comparison to improve performance.
+ var (
+ tempName string
+ elemFieldType reflect.StructField
+ elemFieldValue reflect.Value
+ elemType = pointerElemReflectValue.Type()
+ attrMap = make(map[string]string) // Attribute name to its check name which has no symbols.
+ )
+ for i := 0; i < pointerElemReflectValue.NumField(); i++ {
+ elemFieldType = elemType.Field(i)
+ // Only do converting to public attributes.
+ if !utils.IsLetterUpper(elemFieldType.Name[0]) {
+ continue
+ }
+ // Maybe it's struct/*struct embedded.
+ if elemFieldType.Anonymous {
+ elemFieldValue = pointerElemReflectValue.Field(i)
+ // Ignore the interface attribute if it's nil.
+ if elemFieldValue.Kind() == reflect.Interface {
+ elemFieldValue = elemFieldValue.Elem()
+ if !elemFieldValue.IsValid() {
+ continue
+ }
+ }
+ if err = doStruct(paramsMap, elemFieldValue, mapping, priorityTag); err != nil {
+ return err
+ }
+ } else {
+ tempName = elemFieldType.Name
+ attrMap[tempName] = utils.RemoveSymbols(tempName)
+ }
+ }
+ if len(attrMap) == 0 {
+ return nil
+ }
+
+ // The key of the tagMap is the attribute name of the struct,
+ // and the value is its replaced tag name for later comparison to improve performance.
+ var (
+ tagMap = make(map[string]string) // Tag name to its check name which has no symbols.
+ priorityTagArray []string
+ )
+ if priorityTag != "" {
+ priorityTagArray = append(utils.SplitAndTrim(priorityTag, ","), StructTagPriority...)
+ } else {
+ priorityTagArray = StructTagPriority
+ }
+ tagToNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray)
+ if err != nil {
+ return err
+ }
+ for tagName, attributeName := range tagToNameMap {
+ // If there's something else in the tag string,
+ // it uses the first part which is split using char ','.
+ // Eg:
+ // orm:"id, priority"
+ // orm:"name, with:uid=id"
+ tagMap[attributeName] = utils.RemoveSymbols(strings.Split(tagName, ",")[0])
+ // If tag and attribute values both exist in `paramsMap`,
+ // it then uses the tag value overwriting the attribute value in `paramsMap`.
+ if paramsMap[tagName] != nil {
+ for paramsKey, _ := range paramsMap {
+ if paramsKey == tagName {
+ continue
+ }
+ if utils.EqualFoldWithoutChars(paramsKey, attributeName) {
+ paramsMap[paramsKey] = paramsMap[tagName]
+ }
+ }
+ }
+ }
+
+ var (
+ attrName string
+ checkName string
+ )
+ for mapK, mapV := range paramsMap {
+ attrName = ""
+ // It firstly checks the passed mapping rules.
+ if len(mapping) > 0 {
+ if passedAttrKey, ok := mapping[mapK]; ok {
+ attrName = passedAttrKey
+ }
+ }
+ // It secondly checks the predefined tags and matching rules.
+ if attrName == "" {
+ checkName = utils.RemoveSymbols(mapK)
+ // Loop to find the matched attribute name with or without
+ // string cases and chars like '-'/'_'/'.'/' '.
+
+ // Matching the parameters to struct tag names.
+ // The `attrKey` is the attribute name of the struct.
+ for attrKey, cmpKey := range tagMap {
+ if strings.EqualFold(checkName, cmpKey) {
+ attrName = attrKey
+ break
+ }
+ }
+ // Matching the parameters to struct attributes.
+ if attrName == "" {
+ for attrKey, cmpKey := range attrMap {
+ // Eg:
+ // UserName eq user_name
+ // User-Name eq username
+ // username eq userName
+ // etc.
+ if strings.EqualFold(checkName, cmpKey) {
+ attrName = attrKey
+ break
+ }
+ }
+ }
+ }
+
+ // No matching, it gives up this attribute converting.
+ if attrName == "" {
+ continue
+ }
+ // If the attribute name is already checked converting, then skip it.
+ if _, ok = doneMap[attrName]; ok {
+ continue
+ }
+ // Mark it done.
+ doneMap[attrName] = struct{}{}
+ if err = bindVarToStructAttr(pointerElemReflectValue, attrName, mapV, mapping); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// bindVarToStructAttr sets value to struct object attribute by name.
+func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping map[string]string) (err error) {
+ structFieldValue := elem.FieldByName(name)
+ if !structFieldValue.IsValid() {
+ return nil
+ }
+ // CanSet checks whether attribute is public accessible.
+ if !structFieldValue.CanSet() {
+ return nil
+ }
+ defer func() {
+ if exception := recover(); exception != nil {
+ if err = bindVarToReflectValue(structFieldValue, value, mapping); err != nil {
+ err = gerror.Wrapf(err, `error binding value to attribute "%s"`, name)
+ }
+ }
+ }()
+ // Directly converting.
+ if empty.IsNil(value) {
+ structFieldValue.Set(reflect.Zero(structFieldValue.Type()))
+ } else {
+ // Common interface check.
+ var ok bool
+ if err, ok = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
+ return err
+ }
+ // Default converting.
+ structFieldValue.Set(reflect.ValueOf(doConvert(
+ doConvertInput{
+ FromValue: value,
+ ToTypeName: structFieldValue.Type().String(),
+ ReferValue: structFieldValue,
+ },
+ )))
+ }
+ return nil
+}
+
+// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks.
+func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (err error, ok bool) {
+ var pointer interface{}
+ if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() {
+ reflectValueAddr := reflectValue.Addr()
+ if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() {
+ return nil, false
+ }
+ // Not a pointer, but can token address, that makes it can be unmarshalled.
+ pointer = reflectValue.Addr().Interface()
+ } else {
+ if reflectValue.IsNil() || !reflectValue.IsValid() {
+ return nil, false
+ }
+ pointer = reflectValue.Interface()
+ }
+ // UnmarshalValue.
+ if v, ok := pointer.(iUnmarshalValue); ok {
+ return v.UnmarshalValue(value), ok
+ }
+ // UnmarshalText.
+ if v, ok := pointer.(iUnmarshalText); ok {
+ var valueBytes []byte
+ if b, ok := value.([]byte); ok {
+ valueBytes = b
+ } else if s, ok := value.(string); ok {
+ valueBytes = []byte(s)
+ }
+ if len(valueBytes) > 0 {
+ return v.UnmarshalText(valueBytes), ok
+ }
+ }
+ // UnmarshalJSON.
+ if v, ok := pointer.(iUnmarshalJSON); ok {
+ var valueBytes []byte
+ if b, ok := value.([]byte); ok {
+ valueBytes = b
+ } else if s, ok := value.(string); ok {
+ valueBytes = []byte(s)
+ }
+
+ if len(valueBytes) > 0 {
+ // If it is not a valid JSON string, it then adds char `"` on its both sides to make it is.
+ if !json.Valid(valueBytes) {
+ newValueBytes := make([]byte, len(valueBytes)+2)
+ newValueBytes[0] = '"'
+ newValueBytes[len(newValueBytes)-1] = '"'
+ copy(newValueBytes[1:], valueBytes)
+ valueBytes = newValueBytes
+ }
+ return v.UnmarshalJSON(valueBytes), ok
+ }
+ }
+ if v, ok := pointer.(iSet); ok {
+ v.Set(value)
+ return nil, ok
+ }
+ return nil, false
+}
+
+// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
+func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string) (err error) {
+ // JSON content converting.
+ err, ok := doStructWithJsonCheck(value, structFieldValue)
+ if err != nil {
+ return err
+ }
+ if ok {
+ return nil
+ }
+
+ kind := structFieldValue.Kind()
+ // Converting using interface, for some kinds.
+ switch kind {
+ case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface:
+ if !structFieldValue.IsNil() {
+ if v, ok := structFieldValue.Interface().(iSet); ok {
+ v.Set(value)
+ return nil
+ }
+ }
+ }
+
+ // Converting by kind.
+ switch kind {
+ case reflect.Map:
+ return doMapToMap(value, structFieldValue, mapping)
+
+ case reflect.Struct:
+ // Recursively converting for struct attribute.
+ if err = doStruct(value, structFieldValue, nil, ""); err != nil {
+ // Note there's reflect conversion mechanism here.
+ structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
+ }
+
+ // Note that the slice element might be type of struct,
+ // so it uses Struct function doing the converting internally.
+ case reflect.Slice, reflect.Array:
+ var (
+ reflectArray reflect.Value
+ reflectValue = reflect.ValueOf(value)
+ )
+ if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array {
+ reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len())
+ if reflectValue.Len() > 0 {
+ var (
+ elemType = reflectArray.Index(0).Type()
+ elemTypeName string
+ converted bool
+ )
+ for i := 0; i < reflectValue.Len(); i++ {
+ converted = false
+ elemTypeName = elemType.Name()
+ if elemTypeName == "" {
+ elemTypeName = elemType.String()
+ }
+ var elem reflect.Value
+ if elemType.Kind() == reflect.Ptr {
+ elem = reflect.New(elemType.Elem()).Elem()
+ } else {
+ elem = reflect.New(elemType).Elem()
+ }
+ if elem.Kind() == reflect.Struct {
+ if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil {
+ converted = true
+ }
+ }
+ if !converted {
+ elem.Set(reflect.ValueOf(doConvert(doConvertInput{
+ FromValue: reflectValue.Index(i).Interface(),
+ ToTypeName: elemTypeName,
+ ReferValue: elem,
+ })))
+ }
+ if elemType.Kind() == reflect.Ptr {
+ // Before it sets the `elem` to array, do pointer converting if necessary.
+ elem = elem.Addr()
+ }
+ reflectArray.Index(i).Set(elem)
+ }
+ }
+ } else {
+ reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
+ var (
+ elem reflect.Value
+ elemType = reflectArray.Index(0).Type()
+ elemTypeName = elemType.Name()
+ converted bool
+ )
+ if elemTypeName == "" {
+ elemTypeName = elemType.String()
+ }
+ if elemType.Kind() == reflect.Ptr {
+ elem = reflect.New(elemType.Elem()).Elem()
+ } else {
+ elem = reflect.New(elemType).Elem()
+ }
+ if elem.Kind() == reflect.Struct {
+ if err = doStruct(value, elem, nil, ""); err == nil {
+ converted = true
+ }
+ }
+ if !converted {
+ elem.Set(reflect.ValueOf(doConvert(doConvertInput{
+ FromValue: value,
+ ToTypeName: elemTypeName,
+ ReferValue: elem,
+ })))
+ }
+ if elemType.Kind() == reflect.Ptr {
+ // Before it sets the `elem` to array, do pointer converting if necessary.
+ elem = elem.Addr()
+ }
+ reflectArray.Index(0).Set(elem)
+ }
+ structFieldValue.Set(reflectArray)
+
+ case reflect.Ptr:
+ item := reflect.New(structFieldValue.Type().Elem())
+ if err, ok = bindVarToReflectValueWithInterfaceCheck(item, value); ok {
+ structFieldValue.Set(item)
+ return err
+ }
+ elem := item.Elem()
+ if err = bindVarToReflectValue(elem, value, mapping); err == nil {
+ structFieldValue.Set(elem.Addr())
+ }
+
+ // It mainly and specially handles the interface of nil value.
+ case reflect.Interface:
+ if value == nil {
+ // Specially.
+ structFieldValue.Set(reflect.ValueOf((*interface{})(nil)))
+ } else {
+ // Note there's reflect conversion mechanism here.
+ structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
+ }
+
+ default:
+ defer func() {
+ if exception := recover(); exception != nil {
+ err = gerror.NewCodef(
+ gcode.CodeInternalError,
+ `cannot convert value "%+v" to type "%s":%+v`,
+ value,
+ structFieldValue.Type().String(),
+ exception,
+ )
+ }
+ }()
+ // It here uses reflect converting `value` to type of the attribute and assigns
+ // the result value to the attribute. It might fail and panic if the usual Go
+ // conversion rules do not allow conversion.
+ structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_structs.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_structs.go
new file mode 100644
index 000000000000..be1322a72ff2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_structs.go
@@ -0,0 +1,172 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+)
+
+// Structs converts any slice to given struct slice.
+// Also see Scan, Struct.
+func Structs(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
+ return Scan(params, pointer, mapping...)
+}
+
+// StructsTag acts as Structs but also with support for priority tag feature, which retrieves the
+// specified tags for `params` key-value items to struct attribute names mapping.
+// The parameter `priorityTag` supports multiple tags that can be joined with char ','.
+func StructsTag(params interface{}, pointer interface{}, priorityTag string) (err error) {
+ return doStructs(params, pointer, nil, priorityTag)
+}
+
+// doStructs converts any slice to given struct slice.
+//
+// It automatically checks and converts json string to []map if `params` is string/[]byte.
+//
+// The parameter `pointer` should be type of pointer to slice of struct.
+// Note that if `pointer` is a pointer to another pointer of type of slice of struct,
+// it will create the struct/pointer internally.
+func doStructs(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
+ if params == nil {
+ // If `params` is nil, no conversion.
+ return nil
+ }
+ if pointer == nil {
+ return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil")
+ }
+
+ if doStructsByDirectReflectSet(params, pointer) {
+ return nil
+ }
+
+ defer func() {
+ // Catch the panic, especially the reflection operation panics.
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
+ }
+ }
+ }()
+ // If given `params` is JSON, it then uses json.Unmarshal doing the converting.
+ switch r := params.(type) {
+ case []byte:
+ if json.Valid(r) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ return json.UnmarshalUseNumber(r, rv.Interface())
+ }
+ } else {
+ return json.UnmarshalUseNumber(r, pointer)
+ }
+ }
+ case string:
+ if paramsBytes := []byte(r); json.Valid(paramsBytes) {
+ if rv, ok := pointer.(reflect.Value); ok {
+ if rv.Kind() == reflect.Ptr {
+ return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
+ }
+ } else {
+ return json.UnmarshalUseNumber(paramsBytes, pointer)
+ }
+ }
+ }
+ // Pointer type check.
+ pointerRv, ok := pointer.(reflect.Value)
+ if !ok {
+ pointerRv = reflect.ValueOf(pointer)
+ if kind := pointerRv.Kind(); kind != reflect.Ptr {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, "pointer should be type of pointer, but got: %v", kind)
+ }
+ }
+ // Converting `params` to map slice.
+ var (
+ paramsList []interface{}
+ paramsRv = reflect.ValueOf(params)
+ paramsKind = paramsRv.Kind()
+ )
+ for paramsKind == reflect.Ptr {
+ paramsRv = paramsRv.Elem()
+ paramsKind = paramsRv.Kind()
+ }
+ switch paramsKind {
+ case reflect.Slice, reflect.Array:
+ paramsList = make([]interface{}, paramsRv.Len())
+ for i := 0; i < paramsRv.Len(); i++ {
+ paramsList[i] = paramsRv.Index(i).Interface()
+ }
+ default:
+ var paramsMaps = Maps(params)
+ paramsList = make([]interface{}, len(paramsMaps))
+ for i := 0; i < len(paramsMaps); i++ {
+ paramsList[i] = paramsMaps[i]
+ }
+ }
+ // If `params` is an empty slice, no conversion.
+ if len(paramsList) == 0 {
+ return nil
+ }
+ var (
+ reflectElemArray = reflect.MakeSlice(pointerRv.Type().Elem(), len(paramsList), len(paramsList))
+ itemType = reflectElemArray.Index(0).Type()
+ itemTypeKind = itemType.Kind()
+ pointerRvElem = pointerRv.Elem()
+ pointerRvLength = pointerRvElem.Len()
+ )
+ if itemTypeKind == reflect.Ptr {
+ // Pointer element.
+ for i := 0; i < len(paramsList); i++ {
+ var tempReflectValue reflect.Value
+ if i < pointerRvLength {
+ // Might be nil.
+ tempReflectValue = pointerRvElem.Index(i).Elem()
+ }
+ if !tempReflectValue.IsValid() {
+ tempReflectValue = reflect.New(itemType.Elem()).Elem()
+ }
+ if err = doStruct(paramsList[i], tempReflectValue, mapping, priorityTag); err != nil {
+ return err
+ }
+ reflectElemArray.Index(i).Set(tempReflectValue.Addr())
+ }
+ } else {
+ // Struct element.
+ for i := 0; i < len(paramsList); i++ {
+ var tempReflectValue reflect.Value
+ if i < pointerRvLength {
+ tempReflectValue = pointerRvElem.Index(i)
+ } else {
+ tempReflectValue = reflect.New(itemType).Elem()
+ }
+ if err = doStruct(paramsList[i], tempReflectValue, mapping, priorityTag); err != nil {
+ return err
+ }
+ reflectElemArray.Index(i).Set(tempReflectValue)
+ }
+ }
+ pointerRv.Elem().Set(reflectElemArray)
+ return nil
+}
+
+// doStructsByDirectReflectSet do the converting directly using reflect Set.
+// It returns true if success, or else false.
+func doStructsByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) {
+ v1 := reflect.ValueOf(pointer)
+ v2 := reflect.ValueOf(params)
+ if v1.Kind() == reflect.Ptr {
+ if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() {
+ elem.Set(v2)
+ ok = true
+ }
+ }
+ return ok
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_time.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_time.go
new file mode 100644
index 000000000000..a5269cad53bf
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_time.go
@@ -0,0 +1,84 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "time"
+
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/os/gtime"
+)
+
+// Time converts `any` to time.Time.
+func Time(any interface{}, format ...string) time.Time {
+ // It's already this type.
+ if len(format) == 0 {
+ if v, ok := any.(time.Time); ok {
+ return v
+ }
+ }
+ if t := GTime(any, format...); t != nil {
+ return t.Time
+ }
+ return time.Time{}
+}
+
+// Duration converts `any` to time.Duration.
+// If `any` is string, then it uses time.ParseDuration to convert it.
+// If `any` is numeric, then it converts `any` as nanoseconds.
+func Duration(any interface{}) time.Duration {
+ // It's already this type.
+ if v, ok := any.(time.Duration); ok {
+ return v
+ }
+ s := String(any)
+ if !utils.IsNumeric(s) {
+ d, _ := gtime.ParseDuration(s)
+ return d
+ }
+ return time.Duration(Int64(any))
+}
+
+// GTime converts `any` to *gtime.Time.
+// The parameter `format` can be used to specify the format of `any`.
+// If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric,
+// or using gtime.StrToTime if `any` is string.
+func GTime(any interface{}, format ...string) *gtime.Time {
+ if any == nil {
+ return nil
+ }
+ if v, ok := any.(iGTime); ok {
+ return v.GTime(format...)
+ }
+ // It's already this type.
+ if len(format) == 0 {
+ if v, ok := any.(*gtime.Time); ok {
+ return v
+ }
+ if t, ok := any.(time.Time); ok {
+ return gtime.New(t)
+ }
+ if t, ok := any.(*time.Time); ok {
+ return gtime.New(t)
+ }
+ }
+ s := String(any)
+ if len(s) == 0 {
+ return gtime.New()
+ }
+ // Priority conversion using given format.
+ if len(format) > 0 {
+ t, _ := gtime.StrToTimeFormat(s, format[0])
+ return t
+ }
+ if utils.IsNumeric(s) {
+ return gtime.NewFromTimeStamp(Int64(s))
+ } else {
+ t, _ := gtime.StrToTime(s)
+ return t
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_uint.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_uint.go
new file mode 100644
index 000000000000..4f8d3b63a7ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_uint.go
@@ -0,0 +1,120 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import (
+ "strconv"
+
+ "github.com/gogf/gf/v2/encoding/gbinary"
+)
+
+// Uint converts `any` to uint.
+func Uint(any interface{}) uint {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(uint); ok {
+ return v
+ }
+ return uint(Uint64(any))
+}
+
+// Uint8 converts `any` to uint8.
+func Uint8(any interface{}) uint8 {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(uint8); ok {
+ return v
+ }
+ return uint8(Uint64(any))
+}
+
+// Uint16 converts `any` to uint16.
+func Uint16(any interface{}) uint16 {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(uint16); ok {
+ return v
+ }
+ return uint16(Uint64(any))
+}
+
+// Uint32 converts `any` to uint32.
+func Uint32(any interface{}) uint32 {
+ if any == nil {
+ return 0
+ }
+ if v, ok := any.(uint32); ok {
+ return v
+ }
+ return uint32(Uint64(any))
+}
+
+// Uint64 converts `any` to uint64.
+func Uint64(any interface{}) uint64 {
+ if any == nil {
+ return 0
+ }
+ switch value := any.(type) {
+ case int:
+ return uint64(value)
+ case int8:
+ return uint64(value)
+ case int16:
+ return uint64(value)
+ case int32:
+ return uint64(value)
+ case int64:
+ return uint64(value)
+ case uint:
+ return uint64(value)
+ case uint8:
+ return uint64(value)
+ case uint16:
+ return uint64(value)
+ case uint32:
+ return uint64(value)
+ case uint64:
+ return value
+ case float32:
+ return uint64(value)
+ case float64:
+ return uint64(value)
+ case bool:
+ if value {
+ return 1
+ }
+ return 0
+ case []byte:
+ return gbinary.DecodeToUint64(value)
+ default:
+ if f, ok := value.(iUint64); ok {
+ return f.Uint64()
+ }
+ s := String(value)
+ // Hexadecimal
+ if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
+ if v, e := strconv.ParseUint(s[2:], 16, 64); e == nil {
+ return v
+ }
+ }
+ // Octal
+ if len(s) > 1 && s[0] == '0' {
+ if v, e := strconv.ParseUint(s[1:], 8, 64); e == nil {
+ return v
+ }
+ }
+ // Decimal
+ if v, e := strconv.ParseUint(s, 10, 64); e == nil {
+ return v
+ }
+ // Float64
+ return uint64(Float64(value))
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_unsafe.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_unsafe.go
new file mode 100644
index 000000000000..e4b24fdfc8d2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gconv/gconv_unsafe.go
@@ -0,0 +1,23 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gconv
+
+import "unsafe"
+
+// UnsafeStrToBytes converts string to []byte without memory copy.
+// Note that, if you completely sure you will never use `s` variable in the feature,
+// you can use this unsafe function to implement type conversion in high performance.
+func UnsafeStrToBytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(&s))
+}
+
+// UnsafeBytesToStr converts []byte to string without memory copy.
+// Note that, if you completely sure you will never use `b` variable in the feature,
+// you can use this unsafe function to implement type conversion in high performance.
+func UnsafeBytesToStr(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gmeta/gmeta.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gmeta/gmeta.go
new file mode 100644
index 000000000000..9ee4d8610361
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gmeta/gmeta.go
@@ -0,0 +1,42 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gmeta provides embedded meta data feature for struct.
+package gmeta
+
+import (
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/os/gstructs"
+)
+
+// Meta is used as an embedded attribute for struct to enabled metadata feature.
+type Meta struct{}
+
+const (
+ // metaAttributeName is the attribute name of metadata in struct.
+ metaAttributeName = "Meta"
+)
+
+// Data retrieves and returns all metadata from `object`.
+func Data(object interface{}) map[string]string {
+ reflectType, err := gstructs.StructType(object)
+ if err != nil {
+ return nil
+ }
+ if field, ok := reflectType.FieldByName(metaAttributeName); ok {
+ return gstructs.ParseTag(string(field.Tag))
+ }
+ return map[string]string{}
+}
+
+// Get retrieves and returns specified metadata by `key` from `object`.
+func Get(object interface{}, key string) *gvar.Var {
+ v, ok := Data(object)[key]
+ if !ok {
+ return nil
+ }
+ return gvar.New(v)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gmode/gmode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gmode/gmode.go
new file mode 100644
index 000000000000..624bb91b1d8f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gmode/gmode.go
@@ -0,0 +1,94 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gmode provides release mode management for project.
+//
+// It uses string to mark the mode instead of integer, which is convenient for configuration.
+package gmode
+
+import (
+ "github.com/gogf/gf/v2/debug/gdebug"
+ "github.com/gogf/gf/v2/internal/command"
+ "github.com/gogf/gf/v2/os/gfile"
+)
+
+const (
+ NOT_SET = "not-set"
+ DEVELOP = "develop"
+ TESTING = "testing"
+ STAGING = "staging"
+ PRODUCT = "product"
+ commandEnvKey = "gf.gmode"
+)
+
+var (
+ // Note that `currentMode` is not concurrent safe.
+ currentMode = NOT_SET
+)
+
+// Set sets the mode for current application.
+func Set(mode string) {
+ currentMode = mode
+}
+
+// SetDevelop sets current mode DEVELOP for current application.
+func SetDevelop() {
+ Set(DEVELOP)
+}
+
+// SetTesting sets current mode TESTING for current application.
+func SetTesting() {
+ Set(TESTING)
+}
+
+// SetStaging sets current mode STAGING for current application.
+func SetStaging() {
+ Set(STAGING)
+}
+
+// SetProduct sets current mode PRODUCT for current application.
+func SetProduct() {
+ Set(PRODUCT)
+}
+
+// Mode returns current application mode set.
+func Mode() string {
+ // If current mode is not set, do this auto check.
+ if currentMode == NOT_SET {
+ if v := command.GetOptWithEnv(commandEnvKey); v != "" {
+ // Mode configured from command argument of environment.
+ currentMode = v
+ } else {
+ // If there are source codes found, it's in develop mode, or else in product mode.
+ if gfile.Exists(gdebug.CallerFilePath()) {
+ currentMode = DEVELOP
+ } else {
+ currentMode = PRODUCT
+ }
+ }
+ }
+ return currentMode
+}
+
+// IsDevelop checks and returns whether current application is running in DEVELOP mode.
+func IsDevelop() bool {
+ return Mode() == DEVELOP
+}
+
+// IsTesting checks and returns whether current application is running in TESTING mode.
+func IsTesting() bool {
+ return Mode() == TESTING
+}
+
+// IsStaging checks and returns whether current application is running in STAGING mode.
+func IsStaging() bool {
+ return Mode() == STAGING
+}
+
+// IsProduct checks and returns whether current application is running in PRODUCT mode.
+func IsProduct() bool {
+ return Mode() == PRODUCT
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gpage/gpage.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gpage/gpage.go
new file mode 100644
index 000000000000..af400d9b7385
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gpage/gpage.go
@@ -0,0 +1,226 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gpage provides useful paging functionality for web pages.
+package gpage
+
+import (
+ "fmt"
+ "math"
+
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Page is the pagination implementer.
+// All the attributes are public, you can change them when necessary.
+type Page struct {
+ TotalSize int // Total size.
+ TotalPage int // Total page, which is automatically calculated.
+ CurrentPage int // Current page number >= 1.
+ UrlTemplate string // Custom url template for page url producing.
+ LinkStyle string // CSS style name for HTML link tag `a`.
+ SpanStyle string // CSS style name for HTML span tag `span`, which is used for first, current and last page tag.
+ SelectStyle string // CSS style name for HTML select tag `select`.
+ NextPageTag string // Tag name for next p.
+ PrevPageTag string // Tag name for prev p.
+ FirstPageTag string // Tag name for first p.
+ LastPageTag string // Tag name for last p.
+ PrevBarTag string // Tag string for prev bar.
+ NextBarTag string // Tag string for next bar.
+ PageBarNum int // Page bar number for displaying.
+ AjaxActionName string // Ajax function name. Ajax is enabled if this attribute is not empty.
+}
+
+const (
+ DefaultPageName = "page" // DefaultPageName defines the default page name.
+ DefaultPagePlaceHolder = "{.page}" // DefaultPagePlaceHolder defines the place holder for the url template.
+)
+
+// New creates and returns a pagination manager.
+// Note that the parameter `urlTemplate` specifies the URL producing template, like:
+// /user/list/{.page}, /user/list/{.page}.html, /user/list?page={.page}&type=1, etc.
+// The build-in variable in `urlTemplate` "{.page}" specifies the page number, which will be replaced by certain
+// page number when producing.
+func New(totalSize, pageSize, currentPage int, urlTemplate string) *Page {
+ p := &Page{
+ LinkStyle: "GPageLink",
+ SpanStyle: "GPageSpan",
+ SelectStyle: "GPageSelect",
+ PrevPageTag: "<",
+ NextPageTag: ">",
+ FirstPageTag: "|<",
+ LastPageTag: ">|",
+ PrevBarTag: "<<",
+ NextBarTag: ">>",
+ TotalSize: totalSize,
+ TotalPage: int(math.Ceil(float64(totalSize) / float64(pageSize))),
+ CurrentPage: currentPage,
+ PageBarNum: 10,
+ UrlTemplate: urlTemplate,
+ }
+ if currentPage == 0 {
+ p.CurrentPage = 1
+ }
+ return p
+}
+
+// NextPage returns the HTML content for the next page.
+func (p *Page) NextPage() string {
+ if p.CurrentPage < p.TotalPage {
+ return p.GetLink(p.CurrentPage+1, p.NextPageTag, "")
+ }
+ return fmt.Sprintf(`%s `, p.SpanStyle, p.NextPageTag)
+}
+
+// PrevPage returns the HTML content for the previous page.
+func (p *Page) PrevPage() string {
+ if p.CurrentPage > 1 {
+ return p.GetLink(p.CurrentPage-1, p.PrevPageTag, "")
+ }
+ return fmt.Sprintf(`%s `, p.SpanStyle, p.PrevPageTag)
+}
+
+// FirstPage returns the HTML content for the first page.
+func (p *Page) FirstPage() string {
+ if p.CurrentPage == 1 {
+ return fmt.Sprintf(`%s `, p.SpanStyle, p.FirstPageTag)
+ }
+ return p.GetLink(1, p.FirstPageTag, "")
+}
+
+// LastPage returns the HTML content for the last page.
+func (p *Page) LastPage() string {
+ if p.CurrentPage == p.TotalPage {
+ return fmt.Sprintf(`%s `, p.SpanStyle, p.LastPageTag)
+ }
+ return p.GetLink(p.TotalPage, p.LastPageTag, "")
+}
+
+// PageBar returns the HTML page bar content with link and span tags.
+func (p *Page) PageBar() string {
+ plus := int(math.Ceil(float64(p.PageBarNum / 2)))
+ if p.PageBarNum-plus+p.CurrentPage > p.TotalPage {
+ plus = p.PageBarNum - p.TotalPage + p.CurrentPage
+ }
+ begin := p.CurrentPage - plus + 1
+ if begin < 1 {
+ begin = 1
+ }
+ barContent := ""
+ for i := begin; i < begin+p.PageBarNum; i++ {
+ if i <= p.TotalPage {
+ if i != p.CurrentPage {
+ barText := gconv.String(i)
+ barContent += p.GetLink(i, barText, barText)
+ } else {
+ barContent += fmt.Sprintf(`%d `, p.SpanStyle, i)
+ }
+ } else {
+ break
+ }
+ }
+ return barContent
+}
+
+// SelectBar returns the select HTML content for pagination.
+func (p *Page) SelectBar() string {
+ barContent := fmt.Sprintf(``, p.SelectStyle)
+ for i := 1; i <= p.TotalPage; i++ {
+ if i == p.CurrentPage {
+ barContent += fmt.Sprintf(`%d `, p.GetUrl(i), i)
+ } else {
+ barContent += fmt.Sprintf(`%d `, p.GetUrl(i), i)
+ }
+ }
+ barContent += " "
+ return barContent
+}
+
+// GetContent returns the page content for predefined mode.
+// These predefined contents are mainly for chinese localization purpose. You can defines your own
+// page function retrieving the page content according to the implementation of this function.
+func (p *Page) GetContent(mode int) string {
+ switch mode {
+ case 1:
+ p.NextPageTag = "下一页"
+ p.PrevPageTag = "上一页"
+ return fmt.Sprintf(
+ `%s %d %s`,
+ p.PrevPage(),
+ p.CurrentPage,
+ p.NextPage(),
+ )
+
+ case 2:
+ p.NextPageTag = "下一页>>"
+ p.PrevPageTag = "<<上一页"
+ p.FirstPageTag = "首页"
+ p.LastPageTag = "尾页"
+ return fmt.Sprintf(
+ `%s%s[第%d页] %s%s第%s页`,
+ p.FirstPage(),
+ p.PrevPage(),
+ p.CurrentPage,
+ p.NextPage(),
+ p.LastPage(),
+ p.SelectBar(),
+ )
+
+ case 3:
+ p.NextPageTag = "下一页"
+ p.PrevPageTag = "上一页"
+ p.FirstPageTag = "首页"
+ p.LastPageTag = "尾页"
+ pageStr := p.FirstPage()
+ pageStr += p.PrevPage()
+ pageStr += p.PageBar()
+ pageStr += p.NextPage()
+ pageStr += p.LastPage()
+ pageStr += fmt.Sprintf(
+ `当前页%d/%d 共%d条 `,
+ p.CurrentPage,
+ p.TotalPage,
+ p.TotalSize,
+ )
+ return pageStr
+
+ case 4:
+ p.NextPageTag = "下一页"
+ p.PrevPageTag = "上一页"
+ p.FirstPageTag = "首页"
+ p.LastPageTag = "尾页"
+ pageStr := p.FirstPage()
+ pageStr += p.PrevPage()
+ pageStr += p.PageBar()
+ pageStr += p.NextPage()
+ pageStr += p.LastPage()
+ return pageStr
+ }
+ return ""
+}
+
+// GetUrl parses the UrlTemplate with given page number and returns the URL string.
+// Note that the UrlTemplate attribute can be either an URL or a URI string with "{.page}"
+// place holder specifying the page number position.
+func (p *Page) GetUrl(page int) string {
+ return gstr.Replace(p.UrlTemplate, DefaultPagePlaceHolder, gconv.String(page))
+}
+
+// GetLink returns the HTML link tag `a` content for given page number.
+func (p *Page) GetLink(page int, text, title string) string {
+ if len(p.AjaxActionName) > 0 {
+ return fmt.Sprintf(
+ `%s `,
+ p.LinkStyle, p.AjaxActionName, p.GetUrl(page), title, text,
+ )
+ } else {
+ return fmt.Sprintf(
+ `%s `,
+ p.LinkStyle, p.GetUrl(page), title, text,
+ )
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/grand/grand.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/grand/grand.go
new file mode 100644
index 000000000000..77478cee4499
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/grand/grand.go
@@ -0,0 +1,202 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package grand provides high performance random bytes/number/string generation functionality.
+package grand
+
+import (
+ "encoding/binary"
+ "time"
+)
+
+var (
+ letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 52
+ symbols = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // 32
+ digits = "0123456789" // 10
+ characters = letters + digits + symbols // 94
+)
+
+// Intn returns an int number which is between 0 and max: [0, max).
+//
+// Note that:
+// 1. The `max` can only be greater than 0, or else it returns `max` directly;
+// 2. The result is greater than or equal to 0, but less than `max`;
+// 3. The result number is 32bit and less than math.MaxUint32.
+func Intn(max int) int {
+ if max <= 0 {
+ return max
+ }
+ n := int(binary.LittleEndian.Uint32(<-bufferChan)) % max
+ if (max > 0 && n < 0) || (max < 0 && n > 0) {
+ return -n
+ }
+ return n
+}
+
+// B retrieves and returns random bytes of given length `n`.
+func B(n int) []byte {
+ if n <= 0 {
+ return nil
+ }
+ i := 0
+ b := make([]byte, n)
+ for {
+ copy(b[i:], <-bufferChan)
+ i += 4
+ if i >= n {
+ break
+ }
+ }
+ return b
+}
+
+// N returns a random int between min and max: [min, max].
+// The `min` and `max` also support negative numbers.
+func N(min, max int) int {
+ if min >= max {
+ return min
+ }
+ if min >= 0 {
+ // Because Intn dose not support negative number,
+ // so we should first shift the value to left,
+ // then call Intn to produce the random number,
+ // and finally shift the result back to right.
+ return Intn(max-(min-0)+1) + (min - 0)
+ }
+ if min < 0 {
+ // Because Intn dose not support negative number,
+ // so we should first shift the value to right,
+ // then call Intn to produce the random number,
+ // and finally shift the result back to left.
+ return Intn(max+(0-min)+1) - (0 - min)
+ }
+ return 0
+}
+
+// S returns a random string which contains digits and letters, and its length is `n`.
+// The optional parameter `symbols` specifies whether the result could contain symbols,
+// which is false in default.
+func S(n int, symbols ...bool) string {
+ if n <= 0 {
+ return ""
+ }
+ var (
+ b = make([]byte, n)
+ numberBytes = B(n)
+ )
+ for i := range b {
+ if len(symbols) > 0 && symbols[0] {
+ b[i] = characters[numberBytes[i]%94]
+ } else {
+ b[i] = characters[numberBytes[i]%62]
+ }
+ }
+ return string(b)
+}
+
+// D returns a random time.Duration between min and max: [min, max].
+func D(min, max time.Duration) time.Duration {
+ multiple := int64(1)
+ if min != 0 {
+ for min%10 == 0 {
+ multiple *= 10
+ min /= 10
+ max /= 10
+ }
+ }
+ n := int64(N(int(min), int(max)))
+ return time.Duration(n * multiple)
+}
+
+// Str randomly picks and returns `n` count of chars from given string `s`.
+// It also supports unicode string like Chinese/Russian/Japanese, etc.
+func Str(s string, n int) string {
+ if n <= 0 {
+ return ""
+ }
+ var (
+ b = make([]rune, n)
+ runes = []rune(s)
+ )
+ if len(runes) <= 255 {
+ numberBytes := B(n)
+ for i := range b {
+ b[i] = runes[int(numberBytes[i])%len(runes)]
+ }
+ } else {
+ for i := range b {
+ b[i] = runes[Intn(len(runes))]
+ }
+ }
+ return string(b)
+}
+
+// Digits returns a random string which contains only digits, and its length is `n`.
+func Digits(n int) string {
+ if n <= 0 {
+ return ""
+ }
+ var (
+ b = make([]byte, n)
+ numberBytes = B(n)
+ )
+ for i := range b {
+ b[i] = digits[numberBytes[i]%10]
+ }
+ return string(b)
+}
+
+// Letters returns a random string which contains only letters, and its length is `n`.
+func Letters(n int) string {
+ if n <= 0 {
+ return ""
+ }
+ var (
+ b = make([]byte, n)
+ numberBytes = B(n)
+ )
+ for i := range b {
+ b[i] = letters[numberBytes[i]%52]
+ }
+ return string(b)
+}
+
+// Symbols returns a random string which contains only symbols, and its length is `n`.
+func Symbols(n int) string {
+ if n <= 0 {
+ return ""
+ }
+ var (
+ b = make([]byte, n)
+ numberBytes = B(n)
+ )
+ for i := range b {
+ b[i] = symbols[numberBytes[i]%32]
+ }
+ return string(b)
+}
+
+// Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).
+// TODO performance improving for large slice producing.
+func Perm(n int) []int {
+ m := make([]int, n)
+ for i := 0; i < n; i++ {
+ j := Intn(i + 1)
+ m[i] = m[j]
+ m[j] = i
+ }
+ return m
+}
+
+// Meet randomly calculate whether the given probability `num`/`total` is met.
+func Meet(num, total int) bool {
+ return Intn(total) < num
+}
+
+// MeetProb randomly calculate whether the given probability is met.
+func MeetProb(prob float32) bool {
+ return Intn(1e7) < int(prob*1e7)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/grand/grand_buffer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/grand/grand_buffer.go
new file mode 100644
index 000000000000..07861a515d3b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/grand/grand_buffer.go
@@ -0,0 +1,50 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package grand
+
+import (
+ "crypto/rand"
+)
+
+const (
+ // Buffer size for uint32 random number.
+ bufferChanSize = 10000
+)
+
+var (
+ // bufferChan is the buffer for random bytes,
+ // every item storing 4 bytes.
+ bufferChan = make(chan []byte, bufferChanSize)
+)
+
+func init() {
+ go asyncProducingRandomBufferBytesLoop()
+}
+
+// asyncProducingRandomBufferBytes is a named goroutine, which uses a asynchronous goroutine
+// to produce the random bytes, and a buffer chan to store the random bytes.
+// So it has high performance to generate random numbers.
+func asyncProducingRandomBufferBytesLoop() {
+ var step int
+ for {
+ buffer := make([]byte, 1024)
+ if n, err := rand.Read(buffer); err != nil {
+ panic(err)
+ } else {
+ // The random buffer from system is very expensive,
+ // so fully reuse the random buffer by changing
+ // the step with a different number can
+ // improve the performance a lot.
+ // for _, step = range []int{4, 5, 6, 7} {
+ for _, step = range []int{4} {
+ for i := 0; i <= n-4; i += step {
+ bufferChan <- buffer[i : i+4]
+ }
+ }
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gtag/gtag.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gtag/gtag.go
new file mode 100644
index 000000000000..68d915806589
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gtag/gtag.go
@@ -0,0 +1,58 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gtag providing tag content storing for struct.
+//
+// Note that calling functions of this package is not concurrently safe,
+// which means you cannot call them in runtime but in boot procedure.
+package gtag
+
+import (
+ "fmt"
+ "regexp"
+)
+
+var (
+ data = make(map[string]string)
+ regex = regexp.MustCompile(`\{(.+?)\}`)
+)
+
+// Set sets tag content for specified name.
+func Set(name, value string) {
+ if _, ok := data[name]; ok {
+ panic(fmt.Sprintf(`value for tag "%s" already exists`, name))
+ }
+ data[name] = value
+}
+
+// Sets sets multiple tag content by map.
+func Sets(m map[string]string) {
+ for k, v := range m {
+ if _, ok := data[k]; ok {
+ panic(fmt.Sprintf(`value for tag "%s" already exists`, k))
+ }
+ data[k] = v
+ }
+}
+
+// Get retrieves and returns the stored tag content for specified name.
+func Get(name string) string {
+ return data[name]
+}
+
+// Parse parses and returns the content by replacing all tag name variable to
+// its content for given `content`.
+// Eg:
+// If "Demo:content" in tag mapping,
+// Parse(`This is {Demo}`) -> `This is content`.
+func Parse(content string) string {
+ return regex.ReplaceAllStringFunc(content, func(s string) string {
+ if v, ok := data[s[1:len(s)-1]]; ok {
+ return v
+ }
+ return s
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/guid/guid.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/guid/guid.go
new file mode 100644
index 000000000000..cea74ab19012
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/guid/guid.go
@@ -0,0 +1,130 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package guid
+
+import (
+ "os"
+ "strconv"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gtype"
+ "github.com/gogf/gf/v2/encoding/ghash"
+ "github.com/gogf/gf/v2/net/gipv4"
+ "github.com/gogf/gf/v2/util/grand"
+)
+
+const (
+ sequenceMax = uint32(46655) // Sequence max("zzz").
+ randomStrBase = "0123456789abcdefghijklmnopqrstuvwxyz" // Random chars string(36 bytes).
+)
+
+var (
+ sequence gtype.Uint32 // Sequence for unique purpose of current process.
+ macAddrStr = "0000000" // MAC addresses hash result in 7 bytes.
+ processIdStr = "0000" // Process id in 4 bytes.
+)
+
+// init initializes several fixed local variable.
+func init() {
+ // MAC addresses hash result in 7 bytes.
+ macs, _ := gipv4.GetMacArray()
+ if len(macs) > 0 {
+ var macAddrBytes []byte
+ for _, mac := range macs {
+ macAddrBytes = append(macAddrBytes, []byte(mac)...)
+ }
+ b := []byte{'0', '0', '0', '0', '0', '0', '0'}
+ s := strconv.FormatUint(uint64(ghash.DJB(macAddrBytes)), 36)
+ copy(b, s)
+ macAddrStr = string(b)
+ }
+ // Process id in 4 bytes.
+ {
+ b := []byte{'0', '0', '0', '0'}
+ s := strconv.FormatInt(int64(os.Getpid()), 36)
+ copy(b, s)
+ processIdStr = string(b)
+ }
+}
+
+// S creates and returns a global unique string in 32 bytes that meets most common
+// usages without strict UUID algorithm. It returns a unique string using default
+// unique algorithm if no `data` is given.
+//
+// The specified `data` can be no more than 2 parts. No matter how long each of the
+// `data` size is, each of them will be hashed into 7 bytes as part of the result.
+// If given `data` parts is less than 2, the leftover size of the result bytes will
+// be token by random string.
+//
+// The returned string is composed with:
+// 1. Default: MAC(7) + PID(4) + TimestampNano(12) + Sequence(3) + RandomString(6)
+// 2. CustomData: Data(7/14) + TimestampNano(12) + Sequence(3) + RandomString(3/10)
+//
+// Note that:
+// 1. The returned length is fixed to 32 bytes for performance purpose.
+// 2. The custom parameter `data` composed should have unique attribute in your
+// business situation.
+func S(data ...[]byte) string {
+ var (
+ b = make([]byte, 32)
+ nanoStr = strconv.FormatInt(time.Now().UnixNano(), 36)
+ )
+ if len(data) == 0 {
+ copy(b, macAddrStr)
+ copy(b[7:], processIdStr)
+ copy(b[11:], nanoStr)
+ copy(b[23:], getSequence())
+ copy(b[26:], getRandomStr(6))
+ } else if len(data) <= 2 {
+ n := 0
+ for i, v := range data {
+ // Ignore empty data item bytes.
+ if len(v) > 0 {
+ copy(b[i*7:], getDataHashStr(v))
+ n += 7
+ }
+ }
+ copy(b[n:], nanoStr)
+ copy(b[n+12:], getSequence())
+ copy(b[n+12+3:], getRandomStr(32-n-12-3))
+ } else {
+ panic("too many data parts, it should be no more than 2 parts")
+ }
+ return string(b)
+}
+
+// getSequence increases and returns the sequence string in 3 bytes.
+// The sequence is less than "zzz"(46655).
+func getSequence() []byte {
+ b := []byte{'0', '0', '0'}
+ s := strconv.FormatUint(uint64(sequence.Add(1)%sequenceMax), 36)
+ copy(b, s)
+ return b
+}
+
+// getRandomStr randomly picks and returns `n` count of chars from randomStrBase.
+func getRandomStr(n int) []byte {
+ if n <= 0 {
+ return []byte{}
+ }
+ var (
+ b = make([]byte, n)
+ numberBytes = grand.B(n)
+ )
+ for i := range b {
+ b[i] = randomStrBase[numberBytes[i]%36]
+ }
+ return b
+}
+
+// getDataHashStr creates and returns hash bytes in 7 bytes with given data bytes.
+func getDataHashStr(data []byte) []byte {
+ b := []byte{'0', '0', '0', '0', '0', '0', '0'}
+ s := strconv.FormatUint(uint64(ghash.DJB(data)), 36)
+ copy(b, s)
+ return b
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil.go
new file mode 100644
index 000000000000..09c5046bee6b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil.go
@@ -0,0 +1,158 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gutil provides utility functions.
+package gutil
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+const (
+ dumpIndent = ` `
+)
+
+// Throw throws out an exception, which can be caught be TryCatch or recover.
+func Throw(exception interface{}) {
+ panic(exception)
+}
+
+// Try implements try... logistics using internal panic...recover.
+// It returns error if any exception occurs, or else it returns nil.
+func Try(try func()) (err error) {
+ defer func() {
+ if exception := recover(); exception != nil {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ err = v
+ } else {
+ err = gerror.Newf(`%+v`, exception)
+ }
+ }
+ }()
+ try()
+ return
+}
+
+// TryCatch implements try...catch... logistics using internal panic...recover.
+// It automatically calls function `catch` if any exception occurs ans passes the exception as an error.
+func TryCatch(try func(), catch ...func(exception error)) {
+ defer func() {
+ if exception := recover(); exception != nil && len(catch) > 0 {
+ if v, ok := exception.(error); ok && gerror.HasStack(v) {
+ catch[0](v)
+ } else {
+ catch[0](gerror.Newf(`%+v`, exception))
+ }
+ }
+ }()
+ try()
+}
+
+// IsEmpty checks given `value` empty or not.
+// It returns false if `value` is: integer(0), bool(false), slice/map(len=0), nil;
+// or else returns true.
+func IsEmpty(value interface{}) bool {
+ return empty.IsEmpty(value)
+}
+
+// Keys retrieves and returns the keys from given map or struct.
+func Keys(mapOrStruct interface{}) (keysOrAttrs []string) {
+ keysOrAttrs = make([]string, 0)
+ if m, ok := mapOrStruct.(map[string]interface{}); ok {
+ for k, _ := range m {
+ keysOrAttrs = append(keysOrAttrs, k)
+ }
+ return
+ }
+ var (
+ reflectValue reflect.Value
+ reflectKind reflect.Kind
+ )
+ if v, ok := mapOrStruct.(reflect.Value); ok {
+ reflectValue = v
+ } else {
+ reflectValue = reflect.ValueOf(mapOrStruct)
+ }
+ reflectKind = reflectValue.Kind()
+ for reflectKind == reflect.Ptr {
+ if !reflectValue.IsValid() || reflectValue.IsNil() {
+ reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
+ reflectKind = reflectValue.Kind()
+ } else {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ }
+ switch reflectKind {
+ case reflect.Map:
+ for _, k := range reflectValue.MapKeys() {
+ keysOrAttrs = append(keysOrAttrs, gconv.String(k.Interface()))
+ }
+ case reflect.Struct:
+ var (
+ fieldType reflect.StructField
+ reflectType = reflectValue.Type()
+ )
+ for i := 0; i < reflectValue.NumField(); i++ {
+ fieldType = reflectType.Field(i)
+ if fieldType.Anonymous {
+ keysOrAttrs = append(keysOrAttrs, Keys(reflectValue.Field(i))...)
+ } else {
+ keysOrAttrs = append(keysOrAttrs, fieldType.Name)
+ }
+ }
+ }
+ return
+}
+
+// Values retrieves and returns the values from given map or struct.
+func Values(mapOrStruct interface{}) (values []interface{}) {
+ values = make([]interface{}, 0)
+ if m, ok := mapOrStruct.(map[string]interface{}); ok {
+ for _, v := range m {
+ values = append(values, v)
+ }
+ return
+ }
+ var (
+ reflectValue reflect.Value
+ reflectKind reflect.Kind
+ )
+ if v, ok := mapOrStruct.(reflect.Value); ok {
+ reflectValue = v
+ } else {
+ reflectValue = reflect.ValueOf(mapOrStruct)
+ }
+ reflectKind = reflectValue.Kind()
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Map:
+ for _, k := range reflectValue.MapKeys() {
+ values = append(values, reflectValue.MapIndex(k).Interface())
+ }
+ case reflect.Struct:
+ var (
+ fieldType reflect.StructField
+ reflectType = reflectValue.Type()
+ )
+ for i := 0; i < reflectValue.NumField(); i++ {
+ fieldType = reflectType.Field(i)
+ if fieldType.Anonymous {
+ values = append(values, Values(reflectValue.Field(i))...)
+ } else {
+ values = append(values, reflectValue.Field(i).Interface())
+ }
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_comparator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_comparator.go
new file mode 100644
index 000000000000..3ef7b51be21d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_comparator.go
@@ -0,0 +1,126 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gutil
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Comparator is a function that compare a and b, and returns the result as int.
+//
+// Should return a number:
+// negative , if a < b
+// zero , if a == b
+// positive , if a > b
+type Comparator func(a, b interface{}) int
+
+// ComparatorString provides a fast comparison on strings.
+func ComparatorString(a, b interface{}) int {
+ return strings.Compare(gconv.String(a), gconv.String(b))
+}
+
+// ComparatorInt provides a basic comparison on int.
+func ComparatorInt(a, b interface{}) int {
+ return gconv.Int(a) - gconv.Int(b)
+}
+
+// ComparatorInt8 provides a basic comparison on int8.
+func ComparatorInt8(a, b interface{}) int {
+ return int(gconv.Int8(a) - gconv.Int8(b))
+}
+
+// ComparatorInt16 provides a basic comparison on int16.
+func ComparatorInt16(a, b interface{}) int {
+ return int(gconv.Int16(a) - gconv.Int16(b))
+}
+
+// ComparatorInt32 provides a basic comparison on int32.
+func ComparatorInt32(a, b interface{}) int {
+ return int(gconv.Int32(a) - gconv.Int32(b))
+}
+
+// ComparatorInt64 provides a basic comparison on int64.
+func ComparatorInt64(a, b interface{}) int {
+ return int(gconv.Int64(a) - gconv.Int64(b))
+}
+
+// ComparatorUint provides a basic comparison on uint.
+func ComparatorUint(a, b interface{}) int {
+ return int(gconv.Uint(a) - gconv.Uint(b))
+}
+
+// ComparatorUint8 provides a basic comparison on uint8.
+func ComparatorUint8(a, b interface{}) int {
+ return int(gconv.Uint8(a) - gconv.Uint8(b))
+}
+
+// ComparatorUint16 provides a basic comparison on uint16.
+func ComparatorUint16(a, b interface{}) int {
+ return int(gconv.Uint16(a) - gconv.Uint16(b))
+}
+
+// ComparatorUint32 provides a basic comparison on uint32.
+func ComparatorUint32(a, b interface{}) int {
+ return int(gconv.Uint32(a) - gconv.Uint32(b))
+}
+
+// ComparatorUint64 provides a basic comparison on uint64.
+func ComparatorUint64(a, b interface{}) int {
+ return int(gconv.Uint64(a) - gconv.Uint64(b))
+}
+
+// ComparatorFloat32 provides a basic comparison on float32.
+func ComparatorFloat32(a, b interface{}) int {
+ aFloat := gconv.Float32(a)
+ bFloat := gconv.Float32(b)
+ if aFloat == bFloat {
+ return 0
+ }
+ if aFloat > bFloat {
+ return 1
+ }
+ return -1
+}
+
+// ComparatorFloat64 provides a basic comparison on float64.
+func ComparatorFloat64(a, b interface{}) int {
+ aFloat := gconv.Float64(a)
+ bFloat := gconv.Float64(b)
+ if aFloat == bFloat {
+ return 0
+ }
+ if aFloat > bFloat {
+ return 1
+ }
+ return -1
+}
+
+// ComparatorByte provides a basic comparison on byte.
+func ComparatorByte(a, b interface{}) int {
+ return int(gconv.Byte(a) - gconv.Byte(b))
+}
+
+// ComparatorRune provides a basic comparison on rune.
+func ComparatorRune(a, b interface{}) int {
+ return int(gconv.Rune(a) - gconv.Rune(b))
+}
+
+// ComparatorTime provides a basic comparison on time.Time.
+func ComparatorTime(a, b interface{}) int {
+ aTime := gconv.Time(a)
+ bTime := gconv.Time(b)
+ switch {
+ case aTime.After(bTime):
+ return 1
+ case aTime.Before(bTime):
+ return -1
+ default:
+ return 0
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_dump.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_dump.go
new file mode 100644
index 000000000000..f22ab31a3b77
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_dump.go
@@ -0,0 +1,390 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gutil
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// iString is used for type assert api for String().
+type iString interface {
+ String() string
+}
+
+// iError is used for type assert api for Error().
+type iError interface {
+ Error() string
+}
+
+// iMarshalJSON is the interface for custom Json marshaling.
+type iMarshalJSON interface {
+ MarshalJSON() ([]byte, error)
+}
+
+// DumpOption specifies the behavior of function Export.
+type DumpOption struct {
+ WithType bool // WithType specifies dumping content with type information.
+}
+
+// Dump prints variables `values` to stdout with more manually readable.
+func Dump(values ...interface{}) {
+ for _, value := range values {
+ DumpWithOption(value, DumpOption{
+ WithType: false,
+ })
+ }
+}
+
+// DumpWithType acts like Dump, but with type information.
+// Also see Dump.
+func DumpWithType(values ...interface{}) {
+ for _, value := range values {
+ DumpWithOption(value, DumpOption{
+ WithType: true,
+ })
+ }
+}
+
+// DumpWithOption returns variables `values` as a string with more manually readable.
+func DumpWithOption(value interface{}, option DumpOption) {
+ buffer := bytes.NewBuffer(nil)
+ DumpTo(buffer, value, DumpOption{
+ WithType: option.WithType,
+ })
+ fmt.Println(buffer.String())
+}
+
+// DumpTo writes variables `values` as a string in to `writer` with more manually readable
+func DumpTo(writer io.Writer, value interface{}, option DumpOption) {
+ buffer := bytes.NewBuffer(nil)
+ doDump(value, "", buffer, doDumpOption{
+ WithType: option.WithType,
+ })
+ _, _ = writer.Write(buffer.Bytes())
+}
+
+type doDumpOption struct {
+ WithType bool
+}
+
+func doDump(value interface{}, indent string, buffer *bytes.Buffer, option doDumpOption) {
+ if value == nil {
+ buffer.WriteString(``)
+ return
+ }
+ var (
+ reflectValue = reflect.ValueOf(value)
+ reflectKind = reflectValue.Kind()
+ reflectTypeName = reflect.TypeOf(value).String()
+ newIndent = indent + dumpIndent
+ )
+ reflectTypeName = strings.ReplaceAll(reflectTypeName, `[]uint8`, `[]byte`)
+ if !option.WithType {
+ reflectTypeName = ""
+ }
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ var (
+ exportInternalInput = doDumpInternalInput{
+ Value: value,
+ Indent: indent,
+ NewIndent: newIndent,
+ Buffer: buffer,
+ Option: option,
+ ReflectValue: reflectValue,
+ ReflectTypeName: reflectTypeName,
+ }
+ )
+ switch reflectKind {
+ case reflect.Slice, reflect.Array:
+ doDumpSlice(exportInternalInput)
+
+ case reflect.Map:
+ doDumpMap(exportInternalInput)
+
+ case reflect.Struct:
+ doDumpStruct(exportInternalInput)
+
+ case reflect.String:
+ doDumpString(exportInternalInput)
+
+ case reflect.Bool:
+ doDumpBool(exportInternalInput)
+
+ case
+ reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64,
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64,
+ reflect.Float32,
+ reflect.Float64,
+ reflect.Complex64,
+ reflect.Complex128:
+ doDumpNumber(exportInternalInput)
+
+ case reflect.Chan:
+ buffer.WriteString(fmt.Sprintf(`<%s>`, reflect.TypeOf(value).String()))
+
+ case reflect.Func:
+ if reflectValue.IsNil() || !reflectValue.IsValid() {
+ buffer.WriteString(``)
+ } else {
+ buffer.WriteString(fmt.Sprintf(`<%s>`, reflect.TypeOf(value).String()))
+ }
+
+ default:
+ doDumpDefault(exportInternalInput)
+ }
+}
+
+type doDumpInternalInput struct {
+ Value interface{}
+ Indent string
+ NewIndent string
+ Buffer *bytes.Buffer
+ Option doDumpOption
+ ReflectValue reflect.Value
+ ReflectTypeName string
+}
+
+func doDumpSlice(in doDumpInternalInput) {
+ if b, ok := in.Value.([]byte); ok {
+ if !in.Option.WithType {
+ in.Buffer.WriteString(fmt.Sprintf(`"%s"`, addSlashesForString(string(b))))
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf(
+ `%s(%d) "%s"`,
+ in.ReflectTypeName,
+ len(string(b)),
+ string(b),
+ ))
+ }
+ return
+ }
+ if in.ReflectValue.Len() == 0 {
+ if !in.Option.WithType {
+ in.Buffer.WriteString("[]")
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf("%s(0) []", in.ReflectTypeName))
+ }
+ return
+ }
+ if !in.Option.WithType {
+ in.Buffer.WriteString("[\n")
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf("%s(%d) [\n", in.ReflectTypeName, in.ReflectValue.Len()))
+ }
+ for i := 0; i < in.ReflectValue.Len(); i++ {
+ in.Buffer.WriteString(in.NewIndent)
+ doDump(in.ReflectValue.Index(i).Interface(), in.NewIndent, in.Buffer, in.Option)
+ in.Buffer.WriteString(",\n")
+ }
+ in.Buffer.WriteString(fmt.Sprintf("%s]", in.Indent))
+}
+
+func doDumpMap(in doDumpInternalInput) {
+ var (
+ mapKeys = in.ReflectValue.MapKeys()
+ )
+ if len(mapKeys) == 0 {
+ if !in.Option.WithType {
+ in.Buffer.WriteString("{}")
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf("%s(0) {}", in.ReflectTypeName))
+ }
+ return
+ }
+ var (
+ maxSpaceNum = 0
+ tmpSpaceNum = 0
+ mapKeyStr = ""
+ )
+ for _, key := range mapKeys {
+ tmpSpaceNum = len(fmt.Sprintf(`%v`, key.Interface()))
+ if tmpSpaceNum > maxSpaceNum {
+ maxSpaceNum = tmpSpaceNum
+ }
+ }
+ if !in.Option.WithType {
+ in.Buffer.WriteString("{\n")
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf("%s(%d) {\n", in.ReflectTypeName, len(mapKeys)))
+ }
+ for _, mapKey := range mapKeys {
+ tmpSpaceNum = len(fmt.Sprintf(`%v`, mapKey.Interface()))
+ if mapKey.Kind() == reflect.String {
+ mapKeyStr = fmt.Sprintf(`"%v"`, mapKey.Interface())
+ } else {
+ mapKeyStr = fmt.Sprintf(`%v`, mapKey.Interface())
+ }
+ // Map key and indent string dump.
+ if !in.Option.WithType {
+ in.Buffer.WriteString(fmt.Sprintf(
+ "%s%v:%s",
+ in.NewIndent,
+ mapKeyStr,
+ strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
+ ))
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf(
+ "%s%s(%v):%s",
+ in.NewIndent,
+ mapKey.Type().String(),
+ mapKeyStr,
+ strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
+ ))
+ }
+ // Map value dump.
+ doDump(in.ReflectValue.MapIndex(mapKey).Interface(), in.NewIndent, in.Buffer, in.Option)
+ in.Buffer.WriteString(",\n")
+ }
+ in.Buffer.WriteString(fmt.Sprintf("%s}", in.Indent))
+}
+
+func doDumpStruct(in doDumpInternalInput) {
+ structFields, _ := gstructs.Fields(gstructs.FieldsInput{
+ Pointer: in.Value,
+ RecursiveOption: gstructs.RecursiveOptionEmbedded,
+ })
+ if len(structFields) == 0 {
+ var (
+ structContentStr = ""
+ attributeCountStr = "0"
+ )
+ if v, ok := in.Value.(iString); ok {
+ structContentStr = v.String()
+ } else if v, ok := in.Value.(iError); ok {
+ structContentStr = v.Error()
+ } else if v, ok := in.Value.(iMarshalJSON); ok {
+ b, _ := v.MarshalJSON()
+ structContentStr = string(b)
+ }
+ if structContentStr == "" {
+ structContentStr = "{}"
+ } else {
+ structContentStr = fmt.Sprintf(`"%s"`, addSlashesForString(structContentStr))
+ attributeCountStr = fmt.Sprintf(`%d`, len(structContentStr)-2)
+ }
+ if !in.Option.WithType {
+ in.Buffer.WriteString(structContentStr)
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf(
+ "%s(%s) %s",
+ in.ReflectTypeName,
+ attributeCountStr,
+ structContentStr,
+ ))
+ }
+ return
+ }
+ var (
+ maxSpaceNum = 0
+ tmpSpaceNum = 0
+ )
+ for _, field := range structFields {
+ tmpSpaceNum = len(field.Name())
+ if tmpSpaceNum > maxSpaceNum {
+ maxSpaceNum = tmpSpaceNum
+ }
+ }
+ if !in.Option.WithType {
+ in.Buffer.WriteString("{\n")
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf("%s(%d) {\n", in.ReflectTypeName, len(structFields)))
+ }
+ for _, field := range structFields {
+ tmpSpaceNum = len(fmt.Sprintf(`%v`, field.Name()))
+ in.Buffer.WriteString(fmt.Sprintf(
+ "%s%s:%s",
+ in.NewIndent,
+ field.Name(),
+ strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
+ ))
+ doDump(field.Value.Interface(), in.NewIndent, in.Buffer, in.Option)
+ in.Buffer.WriteString(",\n")
+ }
+ in.Buffer.WriteString(fmt.Sprintf("%s}", in.Indent))
+}
+
+func doDumpNumber(in doDumpInternalInput) {
+ if v, ok := in.Value.(iString); ok {
+ s := v.String()
+ if !in.Option.WithType {
+ in.Buffer.WriteString(fmt.Sprintf(`"%v"`, addSlashesForString(s)))
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf(
+ `%s(%d) "%v"`,
+ in.ReflectTypeName,
+ len(s),
+ addSlashesForString(s),
+ ))
+ }
+ } else {
+ doDumpDefault(in)
+ }
+}
+
+func doDumpString(in doDumpInternalInput) {
+ s := in.ReflectValue.String()
+ if !in.Option.WithType {
+ in.Buffer.WriteString(fmt.Sprintf(`"%v"`, addSlashesForString(s)))
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf(
+ `%s(%d) "%v"`,
+ in.ReflectTypeName,
+ len(s),
+ addSlashesForString(s),
+ ))
+ }
+}
+
+func doDumpBool(in doDumpInternalInput) {
+ var s string
+ if in.ReflectValue.Bool() {
+ s = `true`
+ } else {
+ s = `false`
+ }
+ if in.Option.WithType {
+ s = fmt.Sprintf(`bool(%s)`, s)
+ }
+ in.Buffer.WriteString(s)
+}
+
+func doDumpDefault(in doDumpInternalInput) {
+ s := fmt.Sprintf("%v", in.Value)
+ s = gstr.Trim(s, `<>`)
+ if !in.Option.WithType {
+ in.Buffer.WriteString(s)
+ } else {
+ in.Buffer.WriteString(fmt.Sprintf("%s(%s)", in.ReflectTypeName, s))
+ }
+}
+
+func addSlashesForString(s string) string {
+ return gstr.ReplaceByMap(s, map[string]string{
+ `"`: `\"`,
+ "\r": `\r`,
+ "\t": `\t`,
+ "\n": `\n`,
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_list.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_list.go
new file mode 100644
index 000000000000..9a60a31823da
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_list.go
@@ -0,0 +1,140 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gutil
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
+// or else it returns an empty slice.
+//
+// The parameter `list` supports types like:
+// []map[string]interface{}
+// []map[string]sub-map
+// []struct
+// []struct:sub-struct
+// Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.
+func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) {
+ var reflectValue reflect.Value
+ if v, ok := list.(reflect.Value); ok {
+ reflectValue = v
+ } else {
+ reflectValue = reflect.ValueOf(list)
+ }
+ reflectKind := reflectValue.Kind()
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Slice, reflect.Array:
+ if reflectValue.Len() == 0 {
+ return
+ }
+ values = []interface{}{}
+ for i := 0; i < reflectValue.Len(); i++ {
+ if value, ok := ItemValue(reflectValue.Index(i), key); ok {
+ if len(subKey) > 0 && subKey[0] != nil {
+ if subValue, ok := ItemValue(value, subKey[0]); ok {
+ value = subValue
+ } else {
+ continue
+ }
+ }
+ if array, ok := value.([]interface{}); ok {
+ values = append(values, array...)
+ } else {
+ values = append(values, value)
+ }
+ }
+ }
+ }
+ return
+}
+
+// ItemValue retrieves and returns its value of which name/attribute specified by `key`.
+// The parameter `item` can be type of map/*map/struct/*struct.
+func ItemValue(item interface{}, key interface{}) (value interface{}, found bool) {
+ var reflectValue reflect.Value
+ if v, ok := item.(reflect.Value); ok {
+ reflectValue = v
+ } else {
+ reflectValue = reflect.ValueOf(item)
+ }
+ reflectKind := reflectValue.Kind()
+ if reflectKind == reflect.Interface {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ var keyValue reflect.Value
+ if v, ok := key.(reflect.Value); ok {
+ keyValue = v
+ } else {
+ keyValue = reflect.ValueOf(key)
+ }
+ switch reflectKind {
+ case reflect.Array, reflect.Slice:
+ // The `key` must be type of string.
+ values := ListItemValues(reflectValue, keyValue.String())
+ if values == nil {
+ return nil, false
+ }
+ return values, true
+
+ case reflect.Map:
+ v := reflectValue.MapIndex(keyValue)
+ if v.IsValid() {
+ found = true
+ value = v.Interface()
+ }
+
+ case reflect.Struct:
+ // The `mapKey` must be type of string.
+ v := reflectValue.FieldByName(keyValue.String())
+ if v.IsValid() {
+ found = true
+ value = v.Interface()
+ }
+ }
+ return
+}
+
+// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.
+// Note that the parameter `list` should be type of slice which contains elements of map or struct,
+// or else it returns an empty slice.
+func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} {
+ values := ListItemValues(list, key, subKey...)
+ if len(values) > 0 {
+ var (
+ ok bool
+ m = make(map[interface{}]struct{}, len(values))
+ )
+ for i := 0; i < len(values); {
+ if _, ok = m[values[i]]; ok {
+ values = SliceDelete(values, i)
+ } else {
+ m[values[i]] = struct{}{}
+ i++
+ }
+ }
+ }
+ return values
+}
+
+// ListToMapByKey converts `list` to a map[string]interface{} of which key is specified by `key`.
+// Note that the item value may be type of slice.
+func ListToMapByKey(list []map[string]interface{}, key string) map[string]interface{} {
+ return utils.ListToMapByKey(list, key)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_map.go
new file mode 100644
index 000000000000..92e470434c57
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_map.go
@@ -0,0 +1,115 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gutil
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/internal/utils"
+)
+
+// MapCopy does a shallow copy from map `data` to `copy` for most commonly used map type
+// map[string]interface{}.
+func MapCopy(data map[string]interface{}) (copy map[string]interface{}) {
+ copy = make(map[string]interface{}, len(data))
+ for k, v := range data {
+ copy[k] = v
+ }
+ return
+}
+
+// MapContains checks whether map `data` contains `key`.
+func MapContains(data map[string]interface{}, key string) (ok bool) {
+ if len(data) == 0 {
+ return
+ }
+ _, ok = data[key]
+ return
+}
+
+// MapDelete deletes all `keys` from map `data`.
+func MapDelete(data map[string]interface{}, keys ...string) {
+ if len(data) == 0 {
+ return
+ }
+ for _, key := range keys {
+ delete(data, key)
+ }
+}
+
+// MapMerge merges all map from `src` to map `dst`.
+func MapMerge(dst map[string]interface{}, src ...map[string]interface{}) {
+ if dst == nil {
+ return
+ }
+ for _, m := range src {
+ for k, v := range m {
+ dst[k] = v
+ }
+ }
+}
+
+// MapMergeCopy creates and returns a new map which merges all map from `src`.
+func MapMergeCopy(src ...map[string]interface{}) (copy map[string]interface{}) {
+ copy = make(map[string]interface{})
+ for _, m := range src {
+ for k, v := range m {
+ copy[k] = v
+ }
+ }
+ return
+}
+
+// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.
+//
+// Note that this function might be of low performance.
+func MapPossibleItemByKey(data map[string]interface{}, key string) (foundKey string, foundValue interface{}) {
+ return utils.MapPossibleItemByKey(data, key)
+}
+
+// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.
+// It checks the key ignoring cases and symbols.
+//
+// Note that this function might be of low performance.
+func MapContainsPossibleKey(data map[string]interface{}, key string) bool {
+ return utils.MapContainsPossibleKey(data, key)
+}
+
+// MapOmitEmpty deletes all empty values from given map.
+func MapOmitEmpty(data map[string]interface{}) {
+ if len(data) == 0 {
+ return
+ }
+ for k, v := range data {
+ if IsEmpty(v) {
+ delete(data, k)
+ }
+ }
+}
+
+// MapToSlice converts map to slice of which all keys and values are its items.
+// Eg: {"K1": "v1", "K2": "v2"} => ["K1", "v1", "K2", "v2"]
+func MapToSlice(data interface{}) []interface{} {
+ var (
+ reflectValue = reflect.ValueOf(data)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Map:
+ array := make([]interface{}, 0)
+ for _, key := range reflectValue.MapKeys() {
+ array = append(array, key.Interface())
+ array = append(array, reflectValue.MapIndex(key).Interface())
+ }
+ return array
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_slice.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_slice.go
new file mode 100644
index 000000000000..a9af3422009b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_slice.go
@@ -0,0 +1,94 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gutil
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// SliceCopy does a shallow copy of slice `data` for most commonly used slice type
+// []interface{}.
+func SliceCopy(data []interface{}) []interface{} {
+ newData := make([]interface{}, len(data))
+ copy(newData, data)
+ return newData
+}
+
+// SliceDelete deletes an element at `index` and returns the new slice.
+// It does nothing if the given `index` is invalid.
+func SliceDelete(data []interface{}, index int) (newSlice []interface{}) {
+ if index < 0 || index >= len(data) {
+ return data
+ }
+ // Determine array boundaries when deleting to improve deletion efficiency.
+ if index == 0 {
+ return data[1:]
+ } else if index == len(data)-1 {
+ return data[:index]
+ }
+ // If it is a non-boundary delete,
+ // it will involve the creation of an array,
+ // then the deletion is less efficient.
+ return append(data[:index], data[index+1:]...)
+}
+
+// SliceToMap converts slice type variable `slice` to `map[string]interface{}`.
+// Note that if the length of `slice` is not an even number, it returns nil.
+// Eg:
+// ["K1", "v1", "K2", "v2"] => {"K1": "v1", "K2": "v2"}
+// ["K1", "v1", "K2"] => nil
+func SliceToMap(slice interface{}) map[string]interface{} {
+ var (
+ reflectValue = reflect.ValueOf(slice)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Slice, reflect.Array:
+ length := reflectValue.Len()
+ if length%2 != 0 {
+ return nil
+ }
+ data := make(map[string]interface{})
+ for i := 0; i < reflectValue.Len(); i += 2 {
+ data[gconv.String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
+ }
+ return data
+ }
+ return nil
+}
+
+// SliceToMapWithColumnAsKey converts slice type variable `slice` to `map[interface{}]interface{}`
+// The value of specified column use as the key for returned map.
+// Eg:
+// SliceToMapWithColumnAsKey([{"K1": "v1", "K2": 1}, {"K1": "v2", "K2": 2}], "K1") => {"v1": {"K1": "v1", "K2": 1}, "v2": {"K1": "v2", "K2": 2}}
+// SliceToMapWithColumnAsKey([{"K1": "v1", "K2": 1}, {"K1": "v2", "K2": 2}], "K2") => {1: {"K1": "v1", "K2": 1}, 2: {"K1": "v2", "K2": 2}}
+func SliceToMapWithColumnAsKey(slice interface{}, key interface{}) map[interface{}]interface{} {
+ var (
+ reflectValue = reflect.ValueOf(slice)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ data := make(map[interface{}]interface{})
+ switch reflectKind {
+ case reflect.Slice, reflect.Array:
+ for i := 0; i < reflectValue.Len(); i++ {
+ if k, ok := ItemValue(reflectValue.Index(i), key); ok {
+ data[k] = reflectValue.Index(i).Interface()
+ }
+ }
+ }
+ return data
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_struct.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_struct.go
new file mode 100644
index 000000000000..bd856fc4be83
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gutil/gutil_struct.go
@@ -0,0 +1,38 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gutil
+
+import (
+ "reflect"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// StructToSlice converts struct to slice of which all keys and values are its items.
+// Eg: {"K1": "v1", "K2": "v2"} => ["K1", "v1", "K2", "v2"]
+func StructToSlice(data interface{}) []interface{} {
+ var (
+ reflectValue = reflect.ValueOf(data)
+ reflectKind = reflectValue.Kind()
+ )
+ for reflectKind == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ reflectKind = reflectValue.Kind()
+ }
+ switch reflectKind {
+ case reflect.Struct:
+ array := make([]interface{}, 0)
+ // Note that, it uses the gconv tag name instead of the attribute name if
+ // the gconv tag is fined in the struct attributes.
+ for k, v := range gconv.Map(reflectValue) {
+ array = append(array, k)
+ array = append(array, v)
+ }
+ return array
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid.go
new file mode 100644
index 000000000000..fed037efe138
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid.go
@@ -0,0 +1,208 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+// Package gvalid implements powerful and useful data/form validation functionality.
+package gvalid
+
+import (
+ "regexp"
+ "strings"
+
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+// CustomMsg is the custom error message type,
+// like: map[field] => string|map[rule]string
+type CustomMsg = map[string]interface{}
+
+// fieldRule defined the alias name and rule string for specified field.
+type fieldRule struct {
+ Name string // Alias name for the field.
+ Rule string // Rule string like: "max:6"
+ IsMeta bool // Is this rule is from gmeta.Meta, which marks it as whole struct rule.
+}
+
+// iNoValidation is an interface that marks current struct not validated by package `gvalid`.
+type iNoValidation interface {
+ NoValidation()
+}
+
+const (
+ singleRulePattern = `^([\w-]+):{0,1}(.*)` // regular expression pattern for single validation rule.
+ internalRulesErrRuleName = "InvalidRules" // rule name for internal invalid rules validation error.
+ internalParamsErrRuleName = "InvalidParams" // rule name for internal invalid params validation error.
+ internalObjectErrRuleName = "InvalidObject" // rule name for internal invalid object validation error.
+ internalErrorMapKey = "__InternalError__" // error map key for internal errors.
+ internalDefaultRuleName = "__default__" // default rule name for i18n error message format if no i18n message found for specified error rule.
+ ruleMessagePrefixForI18n = "gf.gvalid.rule." // prefix string for each rule configuration in i18n content.
+ noValidationTagName = "nv" // no validation tag name for struct attribute.
+ ruleNameBail = "bail" // the name for rule "bail"
+ ruleNameCi = "ci" // the name for rule "ci"
+)
+
+var (
+ // allSupportedRules defines all supported rules that is used for quick checks.
+ // Refer to Laravel validation:
+ // https://laravel.com/docs/5.5/validation#available-validation-rules
+ // https://learnku.com/docs/laravel/5.4/validation
+ allSupportedRules = map[string]struct{}{
+ "required": {}, // format: required brief: Required.
+ "required-if": {}, // format: required-if:field,value,... brief: Required unless all given field and its value are equal.
+ "required-unless": {}, // format: required-unless:field,value,... brief: Required unless all given field and its value are not equal.
+ "required-with": {}, // format: required-with:field1,field2,... brief: Required if any of given fields are not empty.
+ "required-with-all": {}, // format: required-with-all:field1,field2,... brief: Required if all given fields are not empty.
+ "required-without": {}, // format: required-without:field1,field2,... brief: Required if any of given fields are empty.
+ "required-without-all": {}, // format: required-without-all:field1,field2,...brief: Required if all given fields are empty.
+ "bail": {}, // format: bail brief: Stop validating when this field's validation failed.
+ "ci": {}, // format: ci brief: Case-Insensitive configuration for those rules that need value comparison like: same, different, in, not-in, etc.
+ "date": {}, // format: date brief: Standard date, like: 2006-01-02, 20060102, 2006.01.02
+ "datetime": {}, // format: datetime brief: Standard datetime, like: 2006-01-02 12:00:00
+ "date-format": {}, // format: date-format:format brief: Custom date format.
+ "email": {}, // format: email brief: Email address.
+ "phone": {}, // format: phone brief: Phone number.
+ "phone-loose": {}, // format: phone-loose brief: Loose phone number validation.
+ "telephone": {}, // format: telephone brief: Telephone number, like: "XXXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"、"XXXXXXXX"
+ "passport": {}, // format: passport brief: Universal passport format rule: Starting with letter, containing only numbers or underscores, length between 6 and 18
+ "password": {}, // format: password brief: Universal password format rule1: Containing any visible chars, length between 6 and 18.
+ "password2": {}, // format: password2 brief: Universal password format rule2: Must meet password rule1, must contain lower and upper letters and numbers.
+ "password3": {}, // format: password3 brief: Universal password format rule3: Must meet password rule1, must contain lower and upper letters, numbers and special chars.
+ "postcode": {}, // format: postcode brief: Postcode number.
+ "resident-id": {}, // format: resident-id brief: Resident id number.
+ "bank-card": {}, // format: bank-card brief: Bank card number.
+ "qq": {}, // format: qq brief: Tencent QQ number.
+ "ip": {}, // format: ip brief: IPv4/IPv6.
+ "ipv4": {}, // format: ipv4 brief: IPv4.
+ "ipv6": {}, // format: ipv6 brief: IPv6.
+ "mac": {}, // format: mac brief: MAC.
+ "url": {}, // format: url brief: URL.
+ "domain": {}, // format: domain brief: Domain.
+ "length": {}, // format: length:min,max brief: Length between :min and :max. The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.
+ "min-length": {}, // format: min-length:min brief: Length is equal or greater than :min. The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.
+ "max-length": {}, // format: max-length:max brief: Length is equal or lesser than :max. The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.
+ "size": {}, // format: size:size brief: Length must be :size. The length is calculated using unicode string, which means one chinese character or letter both has the length of 1.
+ "between": {}, // format: between:min,max brief: Range between :min and :max. It supports both integer and float.
+ "min": {}, // format: min:min brief: Equal or greater than :min. It supports both integer and float.
+ "max": {}, // format: max:max brief: Equal or lesser than :max. It supports both integer and float.
+ "json": {}, // format: json brief: JSON.
+ "integer": {}, // format: integer brief: Integer.
+ "float": {}, // format: float brief: Float. Note that an integer is actually a float number.
+ "boolean": {}, // format: boolean brief: Boolean(1,true,on,yes:true | 0,false,off,no,"":false)
+ "same": {}, // format: same:field brief: Value should be the same as value of field.
+ "different": {}, // format: different:field brief: Value should be different from value of field.
+ "in": {}, // format: in:value1,value2,... brief: Value should be in: value1,value2,...
+ "not-in": {}, // format: not-in:value1,value2,... brief: Value should not be in: value1,value2,...
+ "regex": {}, // format: regex:pattern brief: Value should match custom regular expression pattern.
+ }
+
+ // defaultMessages is the default error messages.
+ // Note that these messages are synchronized from ./i18n/en/validation.toml .
+ defaultMessages = map[string]string{
+ "required": "The {attribute} field is required",
+ "required-if": "The {attribute} field is required",
+ "required-unless": "The {attribute} field is required",
+ "required-with": "The {attribute} field is required",
+ "required-with-all": "The {attribute} field is required",
+ "required-without": "The {attribute} field is required",
+ "required-without-all": "The {attribute} field is required",
+ "date": "The {attribute} value `{value}` is not a valid date",
+ "datetime": "The {attribute} value `{value}` is not a valid datetime",
+ "date-format": "The {attribute} value `{value}` does not match the format: {pattern}",
+ "email": "The {attribute} value `{value}` is not a valid email address",
+ "phone": "The {attribute} value `{value}` is not a valid phone number",
+ "telephone": "The {attribute} value `{value}` is not a valid telephone number",
+ "passport": "The {attribute} value `{value}` is not a valid passport format",
+ "password": "The {attribute} value `{value}` is not a valid password format",
+ "password2": "The {attribute} value `{value}` is not a valid password format",
+ "password3": "The {attribute} value `{value}` is not a valid password format",
+ "postcode": "The {attribute} value `{value}` is not a valid postcode format",
+ "resident-id": "The {attribute} value `{value}` is not a valid resident id number",
+ "bank-card": "The {attribute} value `{value}` is not a valid bank card number",
+ "qq": "The {attribute} value `{value}` is not a valid QQ number",
+ "ip": "The {attribute} value `{value}` is not a valid IP address",
+ "ipv4": "The {attribute} value `{value}` is not a valid IPv4 address",
+ "ipv6": "The {attribute} value `{value}` is not a valid IPv6 address",
+ "mac": "The {attribute} value `{value}` is not a valid MAC address",
+ "url": "The {attribute} value `{value}` is not a valid URL address",
+ "domain": "The {attribute} value `{value}` is not a valid domain format",
+ "length": "The {attribute} value `{value}` length must be between {min} and {max}",
+ "min-length": "The {attribute} value `{value}` length must be equal or greater than {min}",
+ "max-length": "The {attribute} value `{value}` length must be equal or lesser than {max}",
+ "size": "The {attribute} value `{value}` length must be {size}",
+ "between": "The {attribute} value `{value}` must be between {min} and {max}",
+ "min": "The {attribute} value `{value}` must be equal or greater than {min}",
+ "max": "The {attribute} value `{value}` must be equal or lesser than {max}",
+ "json": "The {attribute} value `{value}` is not a valid JSON string",
+ "xml": "The {attribute} value `{value}` is not a valid XML string",
+ "array": "The {attribute} value `{value}` is not an array",
+ "integer": "The {attribute} value `{value}` is not an integer",
+ "boolean": "The {attribute} value `{value}` field must be true or false",
+ "same": "The {attribute} value `{value}` must be the same as field {pattern}",
+ "different": "The {attribute} value `{value}` must be different from field {pattern}",
+ "in": "The {attribute} value `{value}` is not in acceptable range: {pattern}",
+ "not-in": "The {attribute} value `{value}` must not be in range: {pattern}",
+ "regex": "The {attribute} value `{value}` must be in regex of: {pattern}",
+ internalDefaultRuleName: "The {attribute} value `{value}` is invalid",
+ }
+
+ // mustCheckRulesEvenValueEmpty specifies some rules that must be validated
+ // even the value is empty (nil or empty).
+ mustCheckRulesEvenValueEmpty = map[string]struct{}{
+ "required": {},
+ "required-if": {},
+ "required-unless": {},
+ "required-with": {},
+ "required-with-all": {},
+ "required-without": {},
+ "required-without-all": {},
+ //"same": {},
+ //"different": {},
+ //"in": {},
+ //"not-in": {},
+ //"regex": {},
+ }
+
+ // boolMap defines the boolean values.
+ boolMap = map[string]struct{}{
+ "1": {},
+ "true": {},
+ "on": {},
+ "yes": {},
+ "": {},
+ "0": {},
+ "false": {},
+ "off": {},
+ "no": {},
+ }
+
+ structTagPriority = []string{"gvalid", "valid", "v"} // structTagPriority specifies the validation tag priority array.
+ aliasNameTagPriority = []string{"param", "params", "p"} // aliasNameTagPriority specifies the alias tag priority array.
+
+ // all internal error keys.
+ internalErrKeyMap = map[string]string{
+ internalRulesErrRuleName: internalRulesErrRuleName,
+ internalParamsErrRuleName: internalParamsErrRuleName,
+ internalObjectErrRuleName: internalObjectErrRuleName,
+ }
+ // regular expression object for single rule
+ // which is compiled just once and of repeatable usage.
+ ruleRegex, _ = regexp.Compile(singleRulePattern)
+
+ // markedRuleMap defines all rules that are just marked rules which have neither functional meaning
+ // nor error messages.
+ markedRuleMap = map[string]bool{
+ ruleNameBail: true,
+ ruleNameCi: true,
+ }
+)
+
+// parseSequenceTag parses one sequence tag to field, rule and error message.
+// The sequence tag is like: [alias@]rule[...#msg...]
+func parseSequenceTag(tag string) (field, rule, msg string) {
+ // Complete sequence tag.
+ // Example: name@required|length:2,20|password3|same:password1#||密码强度不足|两次密码不一致
+ match, _ := gregex.MatchString(`\s*((\w+)\s*@){0,1}\s*([^#]+)\s*(#\s*(.*)){0,1}\s*`, tag)
+ return strings.TrimSpace(match[2]), strings.TrimSpace(match[3]), strings.TrimSpace(match[5])
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_custom_rule.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_custom_rule.go
new file mode 100644
index 000000000000..2521eb4bff71
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_custom_rule.go
@@ -0,0 +1,81 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "runtime"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/internal/intlog"
+)
+
+// RuleFunc is the custom function for data validation.
+type RuleFunc func(ctx context.Context, in RuleFuncInput) error
+
+// RuleFuncInput holds the input parameters that passed to custom rule function RuleFunc.
+type RuleFuncInput struct {
+ // Rule specifies the validation rule string, like "required", "between:1,100", etc.
+ Rule string
+
+ // Message specifies the custom error message or configured i18n message for this rule.
+ Message string
+
+ // Value specifies the value for this rule to validate.
+ Value *gvar.Var
+
+ // Data specifies the `data` which is passed to the Validator. It might be a type of map/struct or a nil value.
+ // You can ignore the parameter `Data` if you do not really need it in your custom validation rule.
+ Data *gvar.Var
+}
+
+var (
+ // customRuleFuncMap stores the custom rule functions.
+ // map[Rule]RuleFunc
+ customRuleFuncMap = make(map[string]RuleFunc)
+)
+
+// RegisterRule registers custom validation rule and function for package.
+func RegisterRule(rule string, f RuleFunc) {
+ if customRuleFuncMap[rule] != nil {
+ intlog.PrintFunc(context.TODO(), func() string {
+ return fmt.Sprintf(
+ `rule "%s" is overwrotten by function "%s"`,
+ rule, runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(),
+ )
+ })
+ }
+ customRuleFuncMap[rule] = f
+}
+
+// RegisterRuleByMap registers custom validation rules using map for package.
+func RegisterRuleByMap(m map[string]RuleFunc) {
+ for k, v := range m {
+ customRuleFuncMap[k] = v
+ }
+}
+
+// GetRegisteredRuleMap returns all the custom registered rules and associated functions.
+func GetRegisteredRuleMap() map[string]RuleFunc {
+ if len(customRuleFuncMap) == 0 {
+ return nil
+ }
+ ruleMap := make(map[string]RuleFunc)
+ for k, v := range customRuleFuncMap {
+ ruleMap[k] = v
+ }
+ return ruleMap
+}
+
+// DeleteRule deletes custom defined validation one or more rules and associated functions from global package.
+func DeleteRule(rules ...string) {
+ for _, rule := range rules {
+ delete(customRuleFuncMap, rule)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_error.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_error.go
new file mode 100644
index 000000000000..ba252d8c6427
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_error.go
@@ -0,0 +1,247 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/text/gstr"
+)
+
+// Error is the validation error for validation result.
+type Error interface {
+ Code() gcode.Code
+ Current() error
+ Error() string
+ FirstItem() (key string, messages map[string]error)
+ FirstRule() (rule string, err error)
+ FirstError() (err error)
+ Items() (items []map[string]map[string]error)
+ Map() map[string]error
+ Maps() map[string]map[string]error
+ String() string
+ Strings() (errs []string)
+}
+
+// validationError is the validation error for validation result.
+type validationError struct {
+ code gcode.Code // Error code.
+ rules []fieldRule // Rules by sequence, which is used for keeping error sequence.
+ errors map[string]map[string]error // Error map:map[field]map[rule]message
+ firstKey string // The first error rule key(empty in default).
+ firstItem map[string]error // The first error rule value(nil in default).
+}
+
+// newValidationError creates and returns a validation error.
+func newValidationError(code gcode.Code, rules []fieldRule, fieldRuleErrorMap map[string]map[string]error) *validationError {
+ for field, ruleErrorMap := range fieldRuleErrorMap {
+ for rule, err := range ruleErrorMap {
+ if !gerror.HasStack(err) {
+ ruleErrorMap[rule] = gerror.NewOption(gerror.Option{
+ Stack: false,
+ Text: gstr.Trim(err.Error()),
+ Code: code,
+ })
+ }
+ }
+ fieldRuleErrorMap[field] = ruleErrorMap
+ }
+ return &validationError{
+ code: code,
+ rules: rules,
+ errors: fieldRuleErrorMap,
+ }
+}
+
+// newValidationErrorByStr creates and returns a validation error by string.
+func newValidationErrorByStr(key string, err error) *validationError {
+ return newValidationError(
+ gcode.CodeInternalError,
+ nil,
+ map[string]map[string]error{
+ internalErrorMapKey: {
+ key: err,
+ },
+ },
+ )
+}
+
+// Code returns the error code of current validation error.
+func (e *validationError) Code() gcode.Code {
+ if e == nil {
+ return gcode.CodeNil
+ }
+ return e.code
+}
+
+// Map returns the first error message as map.
+func (e *validationError) Map() map[string]error {
+ if e == nil {
+ return map[string]error{}
+ }
+ _, m := e.FirstItem()
+ return m
+}
+
+// Maps returns all error messages as map.
+func (e *validationError) Maps() map[string]map[string]error {
+ if e == nil {
+ return nil
+ }
+ return e.errors
+}
+
+// Items retrieves and returns error items array in sequence if possible,
+// or else it returns error items with no sequence .
+func (e *validationError) Items() (items []map[string]map[string]error) {
+ if e == nil {
+ return []map[string]map[string]error{}
+ }
+ items = make([]map[string]map[string]error, 0)
+ // By sequence.
+ if len(e.rules) > 0 {
+ for _, v := range e.rules {
+ if errorItemMap, ok := e.errors[v.Name]; ok {
+ items = append(items, map[string]map[string]error{
+ v.Name: errorItemMap,
+ })
+ }
+ }
+ return items
+ }
+ // No sequence.
+ for name, errorRuleMap := range e.errors {
+ items = append(items, map[string]map[string]error{
+ name: errorRuleMap,
+ })
+ }
+ return
+}
+
+// FirstItem returns the field name and error messages for the first validation rule error.
+func (e *validationError) FirstItem() (key string, messages map[string]error) {
+ if e == nil {
+ return "", map[string]error{}
+ }
+ if e.firstItem != nil {
+ return e.firstKey, e.firstItem
+ }
+ // By sequence.
+ if len(e.rules) > 0 {
+ for _, v := range e.rules {
+ if errorItemMap, ok := e.errors[v.Name]; ok {
+ e.firstKey = v.Name
+ e.firstItem = errorItemMap
+ return v.Name, errorItemMap
+ }
+ }
+ }
+ // No sequence.
+ for k, m := range e.errors {
+ e.firstKey = k
+ e.firstItem = m
+ return k, m
+ }
+ return "", nil
+}
+
+// FirstRule returns the first error rule and message string.
+func (e *validationError) FirstRule() (rule string, err error) {
+ if e == nil {
+ return "", nil
+ }
+ // By sequence.
+ if len(e.rules) > 0 {
+ for _, v := range e.rules {
+ if errorItemMap, ok := e.errors[v.Name]; ok {
+ for _, ruleItem := range strings.Split(v.Rule, "|") {
+ array := strings.Split(ruleItem, ":")
+ ruleItem = strings.TrimSpace(array[0])
+ if err, ok = errorItemMap[ruleItem]; ok {
+ return ruleItem, err
+ }
+ }
+ }
+ }
+ }
+ // No sequence.
+ for _, errorItemMap := range e.errors {
+ for k, v := range errorItemMap {
+ return k, v
+ }
+ }
+ return "", nil
+}
+
+// FirstError returns the first error message as string.
+// Note that the returned message might be different if it has no sequence.
+func (e *validationError) FirstError() (err error) {
+ if e == nil {
+ return nil
+ }
+ _, err = e.FirstRule()
+ return
+}
+
+// Current is alis of FirstError, which implements interface gerror.iCurrent.
+func (e *validationError) Current() error {
+ return e.FirstError()
+}
+
+// String returns all error messages as string, multiple error messages joined using char ';'.
+func (e *validationError) String() string {
+ if e == nil {
+ return ""
+ }
+ return strings.Join(e.Strings(), "; ")
+}
+
+// Error implements interface of error.Error.
+func (e *validationError) Error() string {
+ if e == nil {
+ return ""
+ }
+ return e.String()
+}
+
+// Strings returns all error messages as string array.
+func (e *validationError) Strings() (errs []string) {
+ if e == nil {
+ return []string{}
+ }
+ errs = make([]string, 0)
+ // By sequence.
+ if len(e.rules) > 0 {
+ for _, v := range e.rules {
+ if errorItemMap, ok := e.errors[v.Name]; ok {
+ // validation error checks.
+ for _, ruleItem := range strings.Split(v.Rule, "|") {
+ ruleItem = strings.TrimSpace(strings.Split(ruleItem, ":")[0])
+ if err, ok := errorItemMap[ruleItem]; ok {
+ errs = append(errs, err.Error())
+ }
+ }
+ // internal error checks.
+ for k, _ := range internalErrKeyMap {
+ if err, ok := errorItemMap[k]; ok {
+ errs = append(errs, err.Error())
+ }
+ }
+ }
+ }
+ return errs
+ }
+ // No sequence.
+ for _, errorItemMap := range e.errors {
+ for _, err := range errorItemMap {
+ errs = append(errs, err.Error())
+ }
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator.go
new file mode 100644
index 000000000000..80ac39d9a344
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator.go
@@ -0,0 +1,186 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "errors"
+ "reflect"
+
+ "github.com/gogf/gf/v2/i18n/gi18n"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// Validator is the validation manager for chaining operations.
+type Validator struct {
+ i18nManager *gi18n.Manager // I18n manager for error message translation.
+ data interface{} // Validation data, which can be a map, struct or a certain value to be validated.
+ assoc interface{} // Associated data, which is usually a map, for union validation.
+ rules interface{} // Custom validation data.
+ messages interface{} // Custom validation error messages, which can be string or type of CustomMsg.
+ ruleFuncMap map[string]RuleFunc // ruleFuncMap stores custom rule functions for current Validator.
+ useDataInsteadOfObjectAttributes bool // Using `data` as its validation source instead of attribute values from `Object`.
+ bail bool // Stop validation after the first validation error.
+ caseInsensitive bool // Case-Insensitive configuration for those rules that need value comparison.
+}
+
+// New creates and returns a new Validator.
+func New() *Validator {
+ return &Validator{
+ i18nManager: gi18n.Instance(), // Use default i18n manager.
+ ruleFuncMap: make(map[string]RuleFunc), // Custom rule function storing map.
+ }
+}
+
+// Run starts validating the given data with rules and messages.
+func (v *Validator) Run(ctx context.Context) Error {
+ if v.data == nil {
+ return newValidationErrorByStr(
+ internalParamsErrRuleName,
+ errors.New(`no data passed for validation`),
+ )
+ }
+
+ originValueAndKind := utils.OriginValueAndKind(v.data)
+ switch originValueAndKind.OriginKind {
+ case reflect.Map:
+ isMapValidation := false
+ if v.rules == nil {
+ isMapValidation = true
+ } else if utils.IsMap(v.rules) || utils.IsSlice(v.rules) {
+ isMapValidation = true
+ }
+ if isMapValidation {
+ return v.doCheckMap(ctx, v.data)
+ }
+
+ case reflect.Struct:
+ isStructValidation := false
+ if v.rules == nil {
+ isStructValidation = true
+ } else if utils.IsMap(v.rules) || utils.IsSlice(v.rules) {
+ isStructValidation = true
+ }
+ if isStructValidation {
+ return v.doCheckStruct(ctx, v.data)
+ }
+ }
+
+ return v.doCheckValue(ctx, doCheckValueInput{
+ Name: "",
+ Value: v.data,
+ Rule: gconv.String(v.rules),
+ Messages: v.messages,
+ DataRaw: v.assoc,
+ DataMap: gconv.Map(v.assoc),
+ })
+}
+
+// Clone creates and returns a new Validator which is a shallow copy of current one.
+func (v *Validator) Clone() *Validator {
+ newValidator := New()
+ *newValidator = *v
+ return newValidator
+}
+
+// I18n sets the i18n manager for the validator.
+func (v *Validator) I18n(i18nManager *gi18n.Manager) *Validator {
+ if i18nManager == nil {
+ return v
+ }
+ newValidator := v.Clone()
+ newValidator.i18nManager = i18nManager
+ return newValidator
+}
+
+// Bail sets the mark for stopping validation after the first validation error.
+func (v *Validator) Bail() *Validator {
+ newValidator := v.Clone()
+ newValidator.bail = true
+ return newValidator
+}
+
+// Ci sets the mark for Case-Insensitive for those rules that need value comparison.
+func (v *Validator) Ci() *Validator {
+ newValidator := v.Clone()
+ newValidator.caseInsensitive = true
+ return newValidator
+}
+
+// Data is a chaining operation function, which sets validation data for current operation.
+func (v *Validator) Data(data interface{}) *Validator {
+ if data == nil {
+ return v
+ }
+ newValidator := v.Clone()
+ newValidator.data = data
+ return newValidator
+}
+
+// Assoc is a chaining operation function, which sets associated validation data for current operation.
+// The optional parameter `assoc` is usually type of map, which specifies the parameter map used in union validation.
+// Calling this function with `assoc` also sets `useDataInsteadOfObjectAttributes` true
+func (v *Validator) Assoc(assoc interface{}) *Validator {
+ if assoc == nil {
+ return v
+ }
+ newValidator := v.Clone()
+ newValidator.assoc = assoc
+ newValidator.useDataInsteadOfObjectAttributes = true
+ return newValidator
+}
+
+// Rules is a chaining operation function, which sets custom validation rules for current operation.
+func (v *Validator) Rules(rules interface{}) *Validator {
+ if rules == nil {
+ return v
+ }
+ newValidator := v.Clone()
+ newValidator.rules = rules
+ return newValidator
+}
+
+// Messages is a chaining operation function, which sets custom error messages for current operation.
+// The parameter `messages` can be type of string/[]string/map[string]string. It supports sequence in error result
+// if `rules` is type of []string.
+func (v *Validator) Messages(messages interface{}) *Validator {
+ if messages == nil {
+ return v
+ }
+ newValidator := v.Clone()
+ newValidator.messages = messages
+ return newValidator
+}
+
+// RuleFunc registers one custom rule function to current Validator.
+func (v *Validator) RuleFunc(rule string, f RuleFunc) *Validator {
+ newValidator := v.Clone()
+ newValidator.ruleFuncMap[rule] = f
+ return newValidator
+}
+
+// RuleFuncMap registers multiple custom rule functions to current Validator.
+func (v *Validator) RuleFuncMap(m map[string]RuleFunc) *Validator {
+ if m == nil {
+ return v
+ }
+ newValidator := v.Clone()
+ for k, v := range m {
+ newValidator.ruleFuncMap[k] = v
+ }
+ return newValidator
+}
+
+// getRuleFunc retrieves and returns the custom rule function for specified rule.
+func (v *Validator) getRuleFunc(rule string) RuleFunc {
+ ruleFunc := v.ruleFuncMap[rule]
+ if ruleFunc == nil {
+ ruleFunc = customRuleFuncMap[rule]
+ }
+ return ruleFunc
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_map.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_map.go
new file mode 100644
index 000000000000..83b7d4d17446
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_map.go
@@ -0,0 +1,172 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "errors"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+func (v *Validator) doCheckMap(ctx context.Context, params interface{}) Error {
+ if params == nil {
+ return nil
+ }
+ var (
+ checkRules = make([]fieldRule, 0)
+ customMessage = make(CustomMsg) // map[RuleKey]ErrorMsg.
+ errorMaps = make(map[string]map[string]error)
+ )
+ switch assertValue := v.rules.(type) {
+ // Sequence tag: []sequence tag
+ // Sequence has order for error results.
+ case []string:
+ for _, tag := range assertValue {
+ name, rule, msg := parseSequenceTag(tag)
+ if len(name) == 0 {
+ continue
+ }
+ if len(msg) > 0 {
+ var (
+ msgArray = strings.Split(msg, "|")
+ ruleArray = strings.Split(rule, "|")
+ )
+ for k, ruleItem := range ruleArray {
+ // If length of custom messages is lesser than length of rules,
+ // the rest rules use the default error messages.
+ if len(msgArray) <= k {
+ continue
+ }
+ if len(msgArray[k]) == 0 {
+ continue
+ }
+ array := strings.Split(ruleItem, ":")
+ if _, ok := customMessage[name]; !ok {
+ customMessage[name] = make(map[string]string)
+ }
+ customMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])
+ }
+ }
+ checkRules = append(checkRules, fieldRule{
+ Name: name,
+ Rule: rule,
+ })
+ }
+
+ // No sequence rules: map[field]rule
+ case map[string]string:
+ for name, rule := range assertValue {
+ checkRules = append(checkRules, fieldRule{
+ Name: name,
+ Rule: rule,
+ })
+ }
+ }
+ inputParamMap := gconv.Map(params)
+ if inputParamMap == nil {
+ return newValidationErrorByStr(
+ internalParamsErrRuleName,
+ errors.New("invalid params type: convert to map failed"),
+ )
+ }
+ if msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 {
+ if len(customMessage) > 0 {
+ for k, v := range msg {
+ customMessage[k] = v
+ }
+ } else {
+ customMessage = msg
+ }
+ }
+ var (
+ value interface{}
+ validator = v.Clone()
+ )
+
+ // It checks the struct recursively if its attribute is an embedded struct.
+ // Ignore inputParamMap, rules and messages from parent.
+ validator.rules = nil
+ validator.messages = nil
+ for _, item := range inputParamMap {
+ originTypeAndKind := utils.OriginTypeAndKind(item)
+ switch originTypeAndKind.OriginKind {
+ case reflect.Map, reflect.Struct, reflect.Slice, reflect.Array:
+ v.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{
+ Value: item,
+ Type: originTypeAndKind.InputType,
+ OriginKind: originTypeAndKind.OriginKind,
+ ErrorMaps: errorMaps,
+ })
+ }
+ // Bail feature.
+ if v.bail && len(errorMaps) > 0 {
+ break
+ }
+ }
+ if v.bail && len(errorMaps) > 0 {
+ return newValidationError(gcode.CodeValidationFailed, nil, errorMaps)
+ }
+
+ // The following logic is the same as some of CheckStruct but without sequence support.
+ for _, checkRuleItem := range checkRules {
+ if len(checkRuleItem.Rule) == 0 {
+ continue
+ }
+ value = nil
+ if valueItem, ok := inputParamMap[checkRuleItem.Name]; ok {
+ value = valueItem
+ }
+ // It checks each rule and its value in loop.
+ if validatedError := v.doCheckValue(ctx, doCheckValueInput{
+ Name: checkRuleItem.Name,
+ Value: value,
+ Rule: checkRuleItem.Rule,
+ Messages: customMessage[checkRuleItem.Name],
+ DataRaw: params,
+ DataMap: inputParamMap,
+ }); validatedError != nil {
+ _, errorItem := validatedError.FirstItem()
+ // ===========================================================
+ // Only in map and struct validations:
+ // If value is nil or empty string and has no required* rules,
+ // it clears the error message.
+ // ===========================================================
+ if gconv.String(value) == "" {
+ required := false
+ // rule => error
+ for ruleKey := range errorItem {
+ // Default required rules.
+ if _, ok := mustCheckRulesEvenValueEmpty[ruleKey]; ok {
+ required = true
+ break
+ }
+ }
+ if !required {
+ continue
+ }
+ }
+ if _, ok := errorMaps[checkRuleItem.Name]; !ok {
+ errorMaps[checkRuleItem.Name] = make(map[string]error)
+ }
+ for ruleKey, ruleError := range errorItem {
+ errorMaps[checkRuleItem.Name][ruleKey] = ruleError
+ }
+ if v.bail {
+ break
+ }
+ }
+ }
+ if len(errorMaps) > 0 {
+ return newValidationError(gcode.CodeValidationFailed, checkRules, errorMaps)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_struct.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_struct.go
new file mode 100644
index 000000000000..dda5e49da3ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_struct.go
@@ -0,0 +1,329 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/os/gstructs"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gmeta"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error {
+ var (
+ errorMaps = make(map[string]map[string]error) // Returning error.
+ fieldToAliasNameMap = make(map[string]string) // Field names to alias name map.
+ resultSequenceRules = make([]fieldRule, 0)
+ )
+ fieldMap, err := gstructs.FieldMap(gstructs.FieldMapInput{
+ Pointer: object,
+ PriorityTagArray: aliasNameTagPriority,
+ RecursiveOption: gstructs.RecursiveOptionEmbedded,
+ })
+ if err != nil {
+ return newValidationErrorByStr(internalObjectErrRuleName, err)
+ }
+
+ // It here must use gstructs.TagFields not gstructs.FieldMap to ensure error sequence.
+ tagFields, err := gstructs.TagFields(object, structTagPriority)
+ if err != nil {
+ return newValidationErrorByStr(internalObjectErrRuleName, err)
+ }
+ // If there's no struct tag and validation rules, it does nothing and returns quickly.
+ if len(tagFields) == 0 && v.messages == nil {
+ return nil
+ }
+
+ var (
+ inputParamMap map[string]interface{}
+ checkRules = make([]fieldRule, 0)
+ nameToRuleMap = make(map[string]string) // just for internally searching index purpose.
+ customMessage = make(CustomMsg) // Custom rule error message map.
+ checkValueData = v.assoc // Ready to be validated data, which can be type of .
+ )
+ if checkValueData == nil {
+ checkValueData = object
+ }
+ switch assertValue := v.rules.(type) {
+ // Sequence tag: []sequence tag
+ // Sequence has order for error results.
+ case []string:
+ for _, tag := range assertValue {
+ name, rule, msg := parseSequenceTag(tag)
+ if len(name) == 0 {
+ continue
+ }
+ if len(msg) > 0 {
+ var (
+ msgArray = strings.Split(msg, "|")
+ ruleArray = strings.Split(rule, "|")
+ )
+ for k, ruleKey := range ruleArray {
+ // If length of custom messages is lesser than length of rules,
+ // the rest rules use the default error messages.
+ if len(msgArray) <= k {
+ continue
+ }
+ if len(msgArray[k]) == 0 {
+ continue
+ }
+ array := strings.Split(ruleKey, ":")
+ if _, ok := customMessage[name]; !ok {
+ customMessage[name] = make(map[string]string)
+ }
+ customMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])
+ }
+ }
+ nameToRuleMap[name] = rule
+ checkRules = append(checkRules, fieldRule{
+ Name: name,
+ Rule: rule,
+ })
+ }
+
+ // Map type rules does not support sequence.
+ // Format: map[key]rule
+ case map[string]string:
+ nameToRuleMap = assertValue
+ for name, rule := range assertValue {
+ checkRules = append(checkRules, fieldRule{
+ Name: name,
+ Rule: rule,
+ })
+ }
+ }
+ // If there's no struct tag and validation rules, it does nothing and returns quickly.
+ if len(tagFields) == 0 && len(checkRules) == 0 {
+ return nil
+ }
+ // Input parameter map handling.
+ if v.assoc == nil || !v.useDataInsteadOfObjectAttributes {
+ inputParamMap = make(map[string]interface{})
+ } else {
+ inputParamMap = gconv.Map(v.assoc)
+ }
+ // Checks and extends the parameters map with struct alias tag.
+ if !v.useDataInsteadOfObjectAttributes {
+ for nameOrTag, field := range fieldMap {
+ inputParamMap[nameOrTag] = field.Value.Interface()
+ if nameOrTag != field.Name() {
+ inputParamMap[field.Name()] = field.Value.Interface()
+ }
+ }
+ }
+
+ // Merge the custom validation rules with rules in struct tag.
+ // The custom rules has the most high priority that can overwrite the struct tag rules.
+ for _, field := range tagFields {
+ var (
+ isMeta bool
+ fieldName = field.Name() // Attribute name.
+ name, rule, msg = parseSequenceTag(field.TagValue) // The `name` is different from `attribute alias`, which is used for validation only.
+ )
+ if len(name) == 0 {
+ if value, ok := fieldToAliasNameMap[fieldName]; ok {
+ // It uses alias name of the attribute if its alias name tag exists.
+ name = value
+ } else {
+ // It or else uses the attribute name directly.
+ name = fieldName
+ }
+ } else {
+ // It uses the alias name from validation rule.
+ fieldToAliasNameMap[fieldName] = name
+ }
+ // It here extends the params map using alias names.
+ // Note that the variable `name` might be alias name or attribute name.
+ if _, ok := inputParamMap[name]; !ok {
+ if !v.useDataInsteadOfObjectAttributes {
+ inputParamMap[name] = field.Value.Interface()
+ } else {
+ if name != fieldName {
+ if foundKey, foundValue := gutil.MapPossibleItemByKey(inputParamMap, fieldName); foundKey != "" {
+ inputParamMap[name] = foundValue
+ }
+ }
+ }
+ }
+
+ if _, ok := nameToRuleMap[name]; !ok {
+ if _, ok = nameToRuleMap[fieldName]; ok {
+ // If there's alias name,
+ // use alias name as its key and remove the field name key.
+ nameToRuleMap[name] = nameToRuleMap[fieldName]
+ delete(nameToRuleMap, fieldName)
+ for index, checkRuleItem := range checkRules {
+ if fieldName == checkRuleItem.Name {
+ checkRuleItem.Name = name
+ checkRules[index] = checkRuleItem
+ break
+ }
+ }
+ } else {
+ nameToRuleMap[name] = rule
+ if fieldValue := field.Value.Interface(); fieldValue != nil {
+ _, isMeta = fieldValue.(gmeta.Meta)
+ }
+ checkRules = append(checkRules, fieldRule{
+ Name: name,
+ Rule: rule,
+ IsMeta: isMeta,
+ })
+ }
+ } else {
+ // The input rules can overwrite the rules in struct tag.
+ continue
+ }
+
+ if len(msg) > 0 {
+ var (
+ msgArray = strings.Split(msg, "|")
+ ruleArray = strings.Split(rule, "|")
+ )
+ for k, ruleKey := range ruleArray {
+ // If length of custom messages is lesser than length of rules,
+ // the rest rules use the default error messages.
+ if len(msgArray) <= k {
+ continue
+ }
+ if len(msgArray[k]) == 0 {
+ continue
+ }
+ array := strings.Split(ruleKey, ":")
+ if _, ok := customMessage[name]; !ok {
+ customMessage[name] = make(map[string]string)
+ }
+ customMessage[name].(map[string]string)[strings.TrimSpace(array[0])] = strings.TrimSpace(msgArray[k])
+ }
+ }
+ }
+
+ // Custom error messages,
+ // which have the most priority than `rules` and struct tag.
+ if msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 {
+ for k, msgName := range msg {
+ if a, ok := fieldToAliasNameMap[k]; ok {
+ // Overwrite the key of field name.
+ customMessage[a] = msgName
+ } else {
+ customMessage[k] = msgName
+ }
+ }
+ }
+
+ // Temporary variable for value.
+ var (
+ value interface{}
+ )
+
+ // It checks the struct recursively if its attribute is an embedded struct.
+ for _, field := range fieldMap {
+ // No validation interface implements check.
+ if _, ok := field.Value.Interface().(iNoValidation); ok {
+ continue
+ }
+ // No validation field tag check.
+ if _, ok := field.TagLookup(noValidationTagName); ok {
+ continue
+ }
+ if field.IsEmbedded() {
+ if err = v.doCheckStruct(ctx, field.Value); err != nil {
+ // It merges the errors into single error map.
+ for k, m := range err.(*validationError).errors {
+ errorMaps[k] = m
+ }
+ }
+ } else {
+ if field.TagValue != "" {
+ fieldToAliasNameMap[field.Name()] = field.TagValue
+ }
+ switch field.OriginalKind() {
+ case reflect.Map, reflect.Struct, reflect.Slice, reflect.Array:
+ // Recursively check attribute struct/[]string/map/[]map.
+ _, value = gutil.MapPossibleItemByKey(inputParamMap, field.Name())
+ v.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{
+ Value: value,
+ OriginKind: field.OriginalKind(),
+ Type: field.Type().Type,
+ ErrorMaps: errorMaps,
+ ResultSequenceRules: &resultSequenceRules,
+ })
+ }
+ }
+ if v.bail && len(errorMaps) > 0 {
+ break
+ }
+ }
+ if v.bail && len(errorMaps) > 0 {
+ return newValidationError(gcode.CodeValidationFailed, resultSequenceRules, errorMaps)
+ }
+
+ // The following logic is the same as some of CheckMap but with sequence support.
+ for _, checkRuleItem := range checkRules {
+ if !checkRuleItem.IsMeta {
+ _, value = gutil.MapPossibleItemByKey(inputParamMap, checkRuleItem.Name)
+ if value == nil {
+ if aliasName := fieldToAliasNameMap[checkRuleItem.Name]; aliasName != "" {
+ _, value = gutil.MapPossibleItemByKey(inputParamMap, aliasName)
+ }
+ }
+ }
+ // It checks each rule and its value in loop.
+ if validatedError := v.doCheckValue(ctx, doCheckValueInput{
+ Name: checkRuleItem.Name,
+ Value: value,
+ Rule: checkRuleItem.Rule,
+ Messages: customMessage[checkRuleItem.Name],
+ DataRaw: checkValueData,
+ DataMap: inputParamMap,
+ }); validatedError != nil {
+ _, errorItem := validatedError.FirstItem()
+ // ============================================================
+ // Only in map and struct validations:
+ // If value is nil or empty string and has no required* rules,
+ // it clears the error message.
+ // ============================================================
+ if !checkRuleItem.IsMeta && (value == nil || gconv.String(value) == "") {
+ required := false
+ // rule => error
+ for ruleKey := range errorItem {
+ // Default required rules.
+ if _, ok := mustCheckRulesEvenValueEmpty[ruleKey]; ok {
+ required = true
+ break
+ }
+ }
+ if !required {
+ continue
+ }
+ }
+ if _, ok := errorMaps[checkRuleItem.Name]; !ok {
+ errorMaps[checkRuleItem.Name] = make(map[string]error)
+ }
+ for ruleKey, errorItemMsgMap := range errorItem {
+ errorMaps[checkRuleItem.Name][ruleKey] = errorItemMsgMap
+ }
+ // Bail feature.
+ if v.bail {
+ break
+ }
+ }
+ }
+ if len(errorMaps) > 0 {
+ return newValidationError(
+ gcode.CodeValidationFailed,
+ append(checkRules, resultSequenceRules...),
+ errorMaps,
+ )
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_value.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_value.go
new file mode 100644
index 000000000000..6d0d46978a27
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_check_value.go
@@ -0,0 +1,604 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "errors"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gogf/gf/v2/container/gvar"
+ "github.com/gogf/gf/v2/errors/gcode"
+ "github.com/gogf/gf/v2/errors/gerror"
+ "github.com/gogf/gf/v2/internal/json"
+ "github.com/gogf/gf/v2/internal/utils"
+ "github.com/gogf/gf/v2/net/gipv4"
+ "github.com/gogf/gf/v2/net/gipv6"
+ "github.com/gogf/gf/v2/os/gtime"
+ "github.com/gogf/gf/v2/text/gregex"
+ "github.com/gogf/gf/v2/text/gstr"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+type iTime interface {
+ Date() (year int, month time.Month, day int)
+ IsZero() bool
+}
+
+type doCheckValueInput struct {
+ Name string // Name specifies the name of parameter `value`.
+ Value interface{} // Value specifies the value for the rules to be validated.
+ Rule string // Rule specifies the validation rules string, like "required", "required|between:1,100", etc.
+ Messages interface{} // Messages specifies the custom error messages for this rule from parameters input, which is usually type of map/slice.
+ DataRaw interface{} // DataRaw specifies the `raw data` which is passed to the Validator. It might be type of map/struct or a nil value.
+ DataMap map[string]interface{} // DataMap specifies the map that is converted from `dataRaw`. It is usually used internally
+}
+
+// doCheckSingleValue does the really rules validation for single key-value.
+func (v *Validator) doCheckValue(ctx context.Context, in doCheckValueInput) Error {
+ // If there's no validation rules, it does nothing and returns quickly.
+ if in.Rule == "" {
+ return nil
+ }
+ // It converts value to string and then does the validation.
+ var (
+ // Do not trim it as the space is also part of the value.
+ ruleErrorMap = make(map[string]error)
+ )
+ // Custom error messages handling.
+ var (
+ msgArray = make([]string, 0)
+ customMsgMap = make(map[string]string)
+ )
+ switch messages := in.Messages.(type) {
+ case string:
+ msgArray = strings.Split(messages, "|")
+
+ default:
+ for k, message := range gconv.Map(in.Messages) {
+ customMsgMap[k] = gconv.String(message)
+ }
+ }
+ // Handle the char '|' in the rule,
+ // which makes this rule separated into multiple rules.
+ ruleItems := strings.Split(strings.TrimSpace(in.Rule), "|")
+ for i := 0; ; {
+ array := strings.Split(ruleItems[i], ":")
+ _, ok := allSupportedRules[array[0]]
+ if !ok && v.getRuleFunc(array[0]) == nil {
+ if i > 0 && ruleItems[i-1][:5] == "regex" {
+ ruleItems[i-1] += "|" + ruleItems[i]
+ ruleItems = append(ruleItems[:i], ruleItems[i+1:]...)
+ } else {
+ return newValidationErrorByStr(
+ internalRulesErrRuleName,
+ errors.New(internalRulesErrRuleName+": "+ruleItems[i]),
+ )
+ }
+ } else {
+ i++
+ }
+ if i == len(ruleItems) {
+ break
+ }
+ }
+ var (
+ hasBailRule = v.bail
+ hasCaseInsensitive = v.caseInsensitive
+ )
+ for index := 0; index < len(ruleItems); {
+ var (
+ err error
+ match = false // whether this rule is matched(has no error)
+ results = ruleRegex.FindStringSubmatch(ruleItems[index]) // split single rule.
+ ruleKey = gstr.Trim(results[1]) // rule key like "max" in rule "max: 6"
+ rulePattern = gstr.Trim(results[2]) // rule pattern is like "6" in rule:"max:6"
+ customRuleFunc RuleFunc
+ )
+
+ if !hasBailRule && ruleKey == ruleNameBail {
+ hasBailRule = true
+ }
+
+ if !hasCaseInsensitive && ruleKey == ruleNameCi {
+ hasCaseInsensitive = true
+ }
+
+ // Ignore logic executing for marked rules.
+ if markedRuleMap[ruleKey] {
+ index++
+ continue
+ }
+
+ if len(msgArray) > index {
+ customMsgMap[ruleKey] = strings.TrimSpace(msgArray[index])
+ }
+
+ // ===========================================================================================
+ // Custom rule handling
+ // ===========================================================================================
+ // 1. It firstly checks and uses the custom registered rules functions in the current Validator.
+ // 2. It secondly checks and uses the globally registered rules functions.
+ // 3. It finally checks and uses the build-in rules functions.
+ customRuleFunc = v.getRuleFunc(ruleKey)
+ if customRuleFunc != nil {
+ // It checks custom validation rules with most priority.
+ message := v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ if err = customRuleFunc(ctx, RuleFuncInput{
+ Rule: ruleItems[index],
+ Message: message,
+ Value: gvar.New(in.Value),
+ Data: gvar.New(in.DataRaw),
+ }); err != nil {
+ match = false
+ // The error should have stack info to indicate the error position.
+ if !gerror.HasStack(err) {
+ err = gerror.NewCodeSkip(gcode.CodeValidationFailed, 1, err.Error())
+ }
+ // The error should have error code that is `gcode.CodeValidationFailed`.
+ if gerror.Code(err) == gcode.CodeNil {
+ if e, ok := err.(*gerror.Error); ok {
+ e.SetCode(gcode.CodeValidationFailed)
+ }
+ }
+ ruleErrorMap[ruleKey] = err
+ } else {
+ match = true
+ }
+ } else {
+ // It checks build-in validation rules if there's no custom rule.
+ match, err = v.doCheckSingleBuildInRules(
+ ctx,
+ doCheckBuildInRulesInput{
+ Index: index,
+ Value: in.Value,
+ RuleKey: ruleKey,
+ RulePattern: rulePattern,
+ RuleItems: ruleItems,
+ DataMap: in.DataMap,
+ CustomMsgMap: customMsgMap,
+ CaseInsensitive: hasCaseInsensitive,
+ },
+ )
+ if !match && err != nil {
+ ruleErrorMap[ruleKey] = err
+ }
+ }
+
+ // Error message handling.
+ if !match {
+ // It does nothing if the error message for this rule
+ // is already set in previous validation.
+ if _, ok := ruleErrorMap[ruleKey]; !ok {
+ ruleErrorMap[ruleKey] = errors.New(v.getErrorMessageByRule(ctx, ruleKey, customMsgMap))
+ }
+
+ // Error variable replacement for error message.
+ if err = ruleErrorMap[ruleKey]; !gerror.HasStack(err) {
+ var s string
+ s = gstr.ReplaceByMap(err.Error(), map[string]string{
+ "{value}": gconv.String(in.Value),
+ "{pattern}": rulePattern,
+ "{attribute}": in.Name,
+ })
+ s, _ = gregex.ReplaceString(`\s{2,}`, ` `, s)
+ ruleErrorMap[ruleKey] = errors.New(s)
+ }
+
+ // If it is with error and there's bail rule,
+ // it then does not continue validating for left rules.
+ if hasBailRule {
+ break
+ }
+ }
+ index++
+ }
+ if len(ruleErrorMap) > 0 {
+ return newValidationError(
+ gcode.CodeValidationFailed,
+ []fieldRule{{Name: in.Name, Rule: in.Rule}},
+ map[string]map[string]error{
+ in.Name: ruleErrorMap,
+ },
+ )
+ }
+ return nil
+}
+
+type doCheckBuildInRulesInput struct {
+ Index int // Index of RuleKey in RuleItems.
+ Value interface{} // Value to be validated.
+ RuleKey string // RuleKey is like the "max" in rule "max: 6"
+ RulePattern string // RulePattern is like "6" in rule:"max:6"
+ RuleItems []string // RuleItems are all the rules that should be validated on single field, like: []string{"required", "min:1"}
+ DataMap map[string]interface{} // Parameter map.
+ CustomMsgMap map[string]string // Custom error message map.
+ CaseInsensitive bool // Case-Insensitive comparison.
+}
+
+func (v *Validator) doCheckSingleBuildInRules(ctx context.Context, in doCheckBuildInRulesInput) (match bool, err error) {
+ valueStr := gconv.String(in.Value)
+ switch in.RuleKey {
+ // Required rules.
+ case
+ "required",
+ "required-if",
+ "required-unless",
+ "required-with",
+ "required-with-all",
+ "required-without",
+ "required-without-all":
+ match = v.checkRequired(checkRequiredInput{
+ Value: in.Value,
+ RuleKey: in.RuleKey,
+ RulePattern: in.RulePattern,
+ DataMap: in.DataMap,
+ CaseInsensitive: in.CaseInsensitive,
+ })
+
+ // Length rules.
+ // It also supports length of unicode string.
+ case
+ "length",
+ "min-length",
+ "max-length",
+ "size":
+ if msg := v.checkLength(ctx, valueStr, in.RuleKey, in.RulePattern, in.CustomMsgMap); msg != "" {
+ return match, errors.New(msg)
+ } else {
+ match = true
+ }
+
+ // Range rules.
+ case
+ "min",
+ "max",
+ "between":
+ if msg := v.checkRange(ctx, valueStr, in.RuleKey, in.RulePattern, in.CustomMsgMap); msg != "" {
+ return match, errors.New(msg)
+ } else {
+ match = true
+ }
+
+ // Custom regular expression.
+ case "regex":
+ // It here should check the rule as there might be special char '|' in it.
+ for i := in.Index + 1; i < len(in.RuleItems); i++ {
+ if !gregex.IsMatchString(singleRulePattern, in.RuleItems[i]) {
+ in.RulePattern += "|" + in.RuleItems[i]
+ in.Index++
+ }
+ }
+ match = gregex.IsMatchString(in.RulePattern, valueStr)
+
+ // Date rules.
+ case "date":
+ // support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time.
+ if value, ok := in.Value.(iTime); ok {
+ return !value.IsZero(), nil
+ }
+ match = gregex.IsMatchString(`\d{4}[\.\-\_/]{0,1}\d{2}[\.\-\_/]{0,1}\d{2}`, valueStr)
+
+ // Datetime rule.
+ case "datetime":
+ // support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time.
+ if value, ok := in.Value.(iTime); ok {
+ return !value.IsZero(), nil
+ }
+ if _, err = gtime.StrToTimeFormat(valueStr, `Y-m-d H:i:s`); err == nil {
+ match = true
+ }
+
+ // Date rule with specified format.
+ case "date-format":
+ // support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time.
+ if value, ok := in.Value.(iTime); ok {
+ return !value.IsZero(), nil
+ }
+ if _, err = gtime.StrToTimeFormat(valueStr, in.RulePattern); err == nil {
+ match = true
+ } else {
+ var (
+ msg string
+ )
+ msg = v.getErrorMessageByRule(ctx, in.RuleKey, in.CustomMsgMap)
+ return match, errors.New(msg)
+ }
+
+ // Values of two fields should be equal as string.
+ case "same":
+ _, foundValue := gutil.MapPossibleItemByKey(in.DataMap, in.RulePattern)
+ if foundValue != nil {
+ if in.CaseInsensitive {
+ match = strings.EqualFold(valueStr, gconv.String(foundValue))
+ } else {
+ match = strings.Compare(valueStr, gconv.String(foundValue)) == 0
+ }
+ }
+ if !match {
+ var msg string
+ msg = v.getErrorMessageByRule(ctx, in.RuleKey, in.CustomMsgMap)
+ return match, errors.New(msg)
+ }
+
+ // Values of two fields should not be equal as string.
+ case "different":
+ match = true
+ _, foundValue := gutil.MapPossibleItemByKey(in.DataMap, in.RulePattern)
+ if foundValue != nil {
+ if in.CaseInsensitive {
+ match = !strings.EqualFold(valueStr, gconv.String(foundValue))
+ } else {
+ match = strings.Compare(valueStr, gconv.String(foundValue)) != 0
+ }
+ }
+ if !match {
+ var msg string
+ msg = v.getErrorMessageByRule(ctx, in.RuleKey, in.CustomMsgMap)
+ return match, errors.New(msg)
+ }
+
+ // Field value should be in range of.
+ case "in":
+ for _, value := range gstr.SplitAndTrim(in.RulePattern, ",") {
+ if in.CaseInsensitive {
+ match = strings.EqualFold(valueStr, strings.TrimSpace(value))
+ } else {
+ match = strings.Compare(valueStr, strings.TrimSpace(value)) == 0
+ }
+ if match {
+ break
+ }
+ }
+
+ // Field value should not be in range of.
+ case "not-in":
+ match = true
+ for _, value := range gstr.SplitAndTrim(in.RulePattern, ",") {
+ if in.CaseInsensitive {
+ match = !strings.EqualFold(valueStr, strings.TrimSpace(value))
+ } else {
+ match = strings.Compare(valueStr, strings.TrimSpace(value)) != 0
+ }
+ if !match {
+ break
+ }
+ }
+
+ // Phone format validation.
+ // 1. China Mobile:
+ // 134, 135, 136, 137, 138, 139, 150, 151, 152, 157, 158, 159, 182, 183, 184, 187, 188,
+ // 178(4G), 147(Net);
+ // 172
+ //
+ // 2. China Unicom:
+ // 130, 131, 132, 155, 156, 185, 186 ,176(4G), 145(Net), 175
+ //
+ // 3. China Telecom:
+ // 133, 153, 180, 181, 189, 177(4G)
+ //
+ // 4. Satelite:
+ // 1349
+ //
+ // 5. Virtual:
+ // 170, 173
+ //
+ // 6. 2018:
+ // 16x, 19x
+ case "phone":
+ match = gregex.IsMatchString(`^13[\d]{9}$|^14[5,7]{1}\d{8}$|^15[^4]{1}\d{8}$|^16[\d]{9}$|^17[0,2,3,5,6,7,8]{1}\d{8}$|^18[\d]{9}$|^19[\d]{9}$`, valueStr)
+
+ // Loose mobile phone number verification(宽松的手机号验证)
+ // As long as the 11 digit numbers beginning with
+ // 13, 14, 15, 16, 17, 18, 19 can pass the verification (只要满足 13、14、15、16、17、18、19开头的11位数字都可以通过验证)
+ case "phone-loose":
+ match = gregex.IsMatchString(`^1(3|4|5|6|7|8|9)\d{9}$`, valueStr)
+
+ // Telephone number:
+ // "XXXX-XXXXXXX"
+ // "XXXX-XXXXXXXX"
+ // "XXX-XXXXXXX"
+ // "XXX-XXXXXXXX"
+ // "XXXXXXX"
+ // "XXXXXXXX"
+ case "telephone":
+ match = gregex.IsMatchString(`^((\d{3,4})|\d{3,4}-)?\d{7,8}$`, valueStr)
+
+ // QQ number: from 10000.
+ case "qq":
+ match = gregex.IsMatchString(`^[1-9][0-9]{4,}$`, valueStr)
+
+ // Postcode number.
+ case "postcode":
+ match = gregex.IsMatchString(`^\d{6}$`, valueStr)
+
+ // China resident id number.
+ //
+ // xxxxxx yyyy MM dd 375 0 十八位
+ // xxxxxx yy MM dd 75 0 十五位
+ //
+ // 地区: [1-9]\d{5}
+ // 年的前两位:(18|19|([23]\d)) 1800-2399
+ // 年的后两位:\d{2}
+ // 月份: ((0[1-9])|(10|11|12))
+ // 天数: (([0-2][1-9])|10|20|30|31) 闰年不能禁止29+
+ //
+ // 三位顺序码:\d{3}
+ // 两位顺序码:\d{2}
+ // 校验码: [0-9Xx]
+ //
+ // 十八位:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
+ // 十五位:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$
+ //
+ // 总:
+ // (^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)
+ case "resident-id":
+ match = v.checkResidentId(valueStr)
+
+ // Bank card number using LUHN algorithm.
+ case "bank-card":
+ match = v.checkLuHn(valueStr)
+
+ // Universal passport format rule:
+ // Starting with letter, containing only numbers or underscores, length between 6 and 18.
+ case "passport":
+ match = gregex.IsMatchString(`^[a-zA-Z]{1}\w{5,17}$`, valueStr)
+
+ // Universal password format rule1:
+ // Containing any visible chars, length between 6 and 18.
+ case "password":
+ match = gregex.IsMatchString(`^[\w\S]{6,18}$`, valueStr)
+
+ // Universal password format rule2:
+ // Must meet password rule1, must contain lower and upper letters and numbers.
+ case "password2":
+ if gregex.IsMatchString(`^[\w\S]{6,18}$`, valueStr) &&
+ gregex.IsMatchString(`[a-z]+`, valueStr) &&
+ gregex.IsMatchString(`[A-Z]+`, valueStr) &&
+ gregex.IsMatchString(`\d+`, valueStr) {
+ match = true
+ }
+
+ // Universal password format rule3:
+ // Must meet password rule1, must contain lower and upper letters, numbers and special chars.
+ case "password3":
+ if gregex.IsMatchString(`^[\w\S]{6,18}$`, valueStr) &&
+ gregex.IsMatchString(`[a-z]+`, valueStr) &&
+ gregex.IsMatchString(`[A-Z]+`, valueStr) &&
+ gregex.IsMatchString(`\d+`, valueStr) &&
+ gregex.IsMatchString(`[^a-zA-Z0-9]+`, valueStr) {
+ match = true
+ }
+
+ // Json.
+ case "json":
+ if json.Valid([]byte(valueStr)) {
+ match = true
+ }
+
+ // Integer.
+ case "integer":
+ if _, err = strconv.Atoi(valueStr); err == nil {
+ match = true
+ }
+
+ // Float.
+ case "float":
+ if _, err = strconv.ParseFloat(valueStr, 10); err == nil {
+ match = true
+ }
+
+ // Boolean(1,true,on,yes:true | 0,false,off,no,"":false).
+ case "boolean":
+ match = false
+ if _, ok := boolMap[strings.ToLower(valueStr)]; ok {
+ match = true
+ }
+
+ // Email.
+ case "email":
+ match = gregex.IsMatchString(`^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-]+(\.[a-zA-Z0-9_\-]+)+$`, valueStr)
+
+ // URL
+ case "url":
+ match = gregex.IsMatchString(`(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]`, valueStr)
+
+ // Domain
+ case "domain":
+ match = gregex.IsMatchString(`^([0-9a-zA-Z][0-9a-zA-Z\-]{0,62}\.)+([a-zA-Z]{0,62})$`, valueStr)
+
+ // IP(IPv4/IPv6).
+ case "ip":
+ match = gipv4.Validate(valueStr) || gipv6.Validate(valueStr)
+
+ // IPv4.
+ case "ipv4":
+ match = gipv4.Validate(valueStr)
+
+ // IPv6.
+ case "ipv6":
+ match = gipv6.Validate(valueStr)
+
+ // MAC.
+ case "mac":
+ match = gregex.IsMatchString(`^([0-9A-Fa-f]{2}[\-:]){5}[0-9A-Fa-f]{2}$`, valueStr)
+
+ default:
+ return match, errors.New("Invalid rule name: " + in.RuleKey)
+ }
+ return match, nil
+}
+
+type doCheckValueRecursivelyInput struct {
+ Value interface{}
+ Type reflect.Type
+ OriginKind reflect.Kind
+ ErrorMaps map[string]map[string]error
+ ResultSequenceRules *[]fieldRule
+}
+
+func (v *Validator) doCheckValueRecursively(ctx context.Context, in doCheckValueRecursivelyInput) {
+ switch in.OriginKind {
+ case reflect.Struct:
+ // Ignore data, rules and messages from parent.
+ validator := v.Clone()
+ validator.rules = nil
+ validator.messages = nil
+ if err := validator.Data(reflect.New(in.Type).Interface()).Assoc(in.Value).Run(ctx); err != nil {
+ // It merges the errors into single error map.
+ for k, m := range err.(*validationError).errors {
+ in.ErrorMaps[k] = m
+ }
+ if in.ResultSequenceRules != nil {
+ *in.ResultSequenceRules = append(*in.ResultSequenceRules, err.(*validationError).rules...)
+ }
+ }
+
+ case reflect.Map:
+ var (
+ dataMap = gconv.Map(in.Value)
+ )
+ for _, item := range dataMap {
+ originTypeAndKind := utils.OriginTypeAndKind(item)
+ v.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{
+ Value: item,
+ Type: originTypeAndKind.InputType,
+ OriginKind: originTypeAndKind.OriginKind,
+ ErrorMaps: in.ErrorMaps,
+ ResultSequenceRules: in.ResultSequenceRules,
+ })
+ // Bail feature.
+ if v.bail && len(in.ErrorMaps) > 0 {
+ break
+ }
+ }
+
+ case reflect.Slice, reflect.Array:
+ array := gconv.Interfaces(in.Value)
+ if len(array) == 0 {
+ return
+ }
+ for _, item := range array {
+ originTypeAndKind := utils.OriginTypeAndKind(item)
+ v.doCheckValueRecursively(ctx, doCheckValueRecursivelyInput{
+ Value: item,
+ Type: originTypeAndKind.InputType,
+ OriginKind: originTypeAndKind.OriginKind,
+ ErrorMaps: in.ErrorMaps,
+ ResultSequenceRules: in.ResultSequenceRules,
+ })
+ // Bail feature.
+ if v.bail && len(in.ErrorMaps) > 0 {
+ break
+ }
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_message.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_message.go
new file mode 100644
index 000000000000..30cab76d8d19
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_message.go
@@ -0,0 +1,37 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import "context"
+
+// getErrorMessageByRule retrieves and returns the error message for specified rule.
+// It firstly retrieves the message from custom message map, and then checks i18n manager,
+// it returns the default error message if it's not found in neither custom message map nor i18n manager.
+func (v *Validator) getErrorMessageByRule(ctx context.Context, ruleKey string, customMsgMap map[string]string) string {
+ content := customMsgMap[ruleKey]
+ if content != "" {
+ // I18n translation.
+ i18nContent := v.i18nManager.GetContent(ctx, content)
+ if i18nContent != "" {
+ return i18nContent
+ }
+ return content
+ }
+ // Retrieve default message according to certain rule.
+ content = v.i18nManager.GetContent(ctx, ruleMessagePrefixForI18n+ruleKey)
+ if content == "" {
+ content = defaultMessages[ruleKey]
+ }
+ // If there's no configured rule message, it uses default one.
+ if content == "" {
+ content = v.i18nManager.GetContent(ctx, ruleMessagePrefixForI18n+internalDefaultRuleName)
+ if content == "" {
+ content = defaultMessages[internalDefaultRuleName]
+ }
+ }
+ return content
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_length.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_length.go
new file mode 100644
index 000000000000..7955e5ac2cbc
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_length.go
@@ -0,0 +1,72 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "strconv"
+ "strings"
+
+ "github.com/gogf/gf/v2/util/gconv"
+)
+
+// checkLength checks `value` using length rules.
+// The length is calculated using unicode string, which means one chinese character or letter
+// both has the length of 1.
+func (v *Validator) checkLength(ctx context.Context, value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
+ var (
+ msg = ""
+ runeArray = gconv.Runes(value)
+ valueLen = len(runeArray)
+ )
+ switch ruleKey {
+ case "length":
+ var (
+ min = 0
+ max = 0
+ array = strings.Split(ruleVal, ",")
+ )
+ if len(array) > 0 {
+ if v, err := strconv.Atoi(strings.TrimSpace(array[0])); err == nil {
+ min = v
+ }
+ }
+ if len(array) > 1 {
+ if v, err := strconv.Atoi(strings.TrimSpace(array[1])); err == nil {
+ max = v
+ }
+ }
+ if valueLen < min || valueLen > max {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{min}", strconv.Itoa(min), -1)
+ msg = strings.Replace(msg, "{max}", strconv.Itoa(max), -1)
+ return msg
+ }
+
+ case "min-length":
+ min, err := strconv.Atoi(ruleVal)
+ if valueLen < min || err != nil {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{min}", strconv.Itoa(min), -1)
+ }
+
+ case "max-length":
+ max, err := strconv.Atoi(ruleVal)
+ if valueLen > max || err != nil {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{max}", strconv.Itoa(max), -1)
+ }
+
+ case "size":
+ size, err := strconv.Atoi(ruleVal)
+ if valueLen != size || err != nil {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{size}", strconv.Itoa(size), -1)
+ }
+ }
+ return msg
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_luhn.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_luhn.go
new file mode 100644
index 000000000000..9d743535d035
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_luhn.go
@@ -0,0 +1,28 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+// checkLuHn checks `value` with LUHN algorithm.
+// It's usually used for bank card number validation.
+func (v *Validator) checkLuHn(value string) bool {
+ var (
+ sum = 0
+ nDigits = len(value)
+ parity = nDigits % 2
+ )
+ for i := 0; i < nDigits; i++ {
+ var digit = int(value[i] - 48)
+ if i%2 == parity {
+ digit *= 2
+ if digit > 9 {
+ digit -= 9
+ }
+ }
+ sum += digit
+ }
+ return sum%10 == 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_range.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_range.go
new file mode 100644
index 000000000000..752d857ef03a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_range.go
@@ -0,0 +1,65 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "context"
+ "strconv"
+ "strings"
+)
+
+// checkRange checks `value` using range rules.
+func (v *Validator) checkRange(ctx context.Context, value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
+ msg := ""
+ switch ruleKey {
+ // Value range.
+ case "between":
+ array := strings.Split(ruleVal, ",")
+ min := float64(0)
+ max := float64(0)
+ if len(array) > 0 {
+ if v, err := strconv.ParseFloat(strings.TrimSpace(array[0]), 10); err == nil {
+ min = v
+ }
+ }
+ if len(array) > 1 {
+ if v, err := strconv.ParseFloat(strings.TrimSpace(array[1]), 10); err == nil {
+ max = v
+ }
+ }
+ valueF, err := strconv.ParseFloat(value, 10)
+ if valueF < min || valueF > max || err != nil {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{min}", strconv.FormatFloat(min, 'f', -1, 64), -1)
+ msg = strings.Replace(msg, "{max}", strconv.FormatFloat(max, 'f', -1, 64), -1)
+ }
+
+ // Min value.
+ case "min":
+ var (
+ min, err1 = strconv.ParseFloat(ruleVal, 10)
+ valueN, err2 = strconv.ParseFloat(value, 10)
+ )
+ if valueN < min || err1 != nil || err2 != nil {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{min}", strconv.FormatFloat(min, 'f', -1, 64), -1)
+ }
+
+ // Max value.
+ case "max":
+ var (
+ max, err1 = strconv.ParseFloat(ruleVal, 10)
+ valueN, err2 = strconv.ParseFloat(value, 10)
+ )
+ if valueN > max || err1 != nil || err2 != nil {
+ msg = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
+ msg = strings.Replace(msg, "{max}", strconv.FormatFloat(max, 'f', -1, 64), -1)
+ }
+
+ }
+ return msg
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_required.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_required.go
new file mode 100644
index 000000000000..c09dedf2416d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_required.go
@@ -0,0 +1,164 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "reflect"
+ "strings"
+
+ "github.com/gogf/gf/v2/internal/empty"
+ "github.com/gogf/gf/v2/util/gconv"
+ "github.com/gogf/gf/v2/util/gutil"
+)
+
+type checkRequiredInput struct {
+ Value interface{} // Value to be validated.
+ RuleKey string // RuleKey is like the "max" in rule "max: 6"
+ RulePattern string // RulePattern is like "6" in rule:"max:6"
+ DataMap map[string]interface{} // Parameter map.
+ CaseInsensitive bool // Case-Insensitive comparison.
+}
+
+// checkRequired checks `value` using required rules.
+// It also supports require checks for `value` of type: slice, map.
+func (v *Validator) checkRequired(in checkRequiredInput) bool {
+ required := false
+ switch in.RuleKey {
+ // Required.
+ case "required":
+ required = true
+
+ // Required unless all given field and its value are equal.
+ // Example: required-if: id,1,age,18
+ case "required-if":
+ required = false
+ var (
+ array = strings.Split(in.RulePattern, ",")
+ foundValue interface{}
+ )
+ // It supports multiple field and value pairs.
+ if len(array)%2 == 0 {
+ for i := 0; i < len(array); {
+ tk := array[i]
+ tv := array[i+1]
+ _, foundValue = gutil.MapPossibleItemByKey(in.DataMap, tk)
+ if in.CaseInsensitive {
+ required = strings.EqualFold(tv, gconv.String(foundValue))
+ } else {
+ required = strings.Compare(tv, gconv.String(foundValue)) == 0
+ }
+ if required {
+ break
+ }
+ i += 2
+ }
+ }
+
+ // Required unless all given field and its value are not equal.
+ // Example: required-unless: id,1,age,18
+ case "required-unless":
+ required = true
+ var (
+ array = strings.Split(in.RulePattern, ",")
+ foundValue interface{}
+ )
+ // It supports multiple field and value pairs.
+ if len(array)%2 == 0 {
+ for i := 0; i < len(array); {
+ tk := array[i]
+ tv := array[i+1]
+ _, foundValue = gutil.MapPossibleItemByKey(in.DataMap, tk)
+ if in.CaseInsensitive {
+ required = !strings.EqualFold(tv, gconv.String(foundValue))
+ } else {
+ required = strings.Compare(tv, gconv.String(foundValue)) != 0
+ }
+ if !required {
+ break
+ }
+ i += 2
+ }
+ }
+
+ // Required if any of given fields are not empty.
+ // Example: required-with:id,name
+ case "required-with":
+ required = false
+ var (
+ array = strings.Split(in.RulePattern, ",")
+ foundValue interface{}
+ )
+ for i := 0; i < len(array); i++ {
+ _, foundValue = gutil.MapPossibleItemByKey(in.DataMap, array[i])
+ if !empty.IsEmpty(foundValue) {
+ required = true
+ break
+ }
+ }
+
+ // Required if all given fields are not empty.
+ // Example: required-with:id,name
+ case "required-with-all":
+ required = true
+ var (
+ array = strings.Split(in.RulePattern, ",")
+ foundValue interface{}
+ )
+ for i := 0; i < len(array); i++ {
+ _, foundValue = gutil.MapPossibleItemByKey(in.DataMap, array[i])
+ if empty.IsEmpty(foundValue) {
+ required = false
+ break
+ }
+ }
+
+ // Required if any of given fields are empty.
+ // Example: required-with:id,name
+ case "required-without":
+ required = false
+ var (
+ array = strings.Split(in.RulePattern, ",")
+ foundValue interface{}
+ )
+ for i := 0; i < len(array); i++ {
+ _, foundValue = gutil.MapPossibleItemByKey(in.DataMap, array[i])
+ if empty.IsEmpty(foundValue) {
+ required = true
+ break
+ }
+ }
+
+ // Required if all given fields are empty.
+ // Example: required-with:id,name
+ case "required-without-all":
+ required = true
+ var (
+ array = strings.Split(in.RulePattern, ",")
+ foundValue interface{}
+ )
+ for i := 0; i < len(array); i++ {
+ _, foundValue = gutil.MapPossibleItemByKey(in.DataMap, array[i])
+ if !empty.IsEmpty(foundValue) {
+ required = false
+ break
+ }
+ }
+ }
+ if required {
+ reflectValue := reflect.ValueOf(in.Value)
+ for reflectValue.Kind() == reflect.Ptr {
+ reflectValue = reflectValue.Elem()
+ }
+ switch reflectValue.Kind() {
+ case reflect.String, reflect.Map, reflect.Array, reflect.Slice:
+ return reflectValue.Len() != 0
+ }
+ return gconv.String(in.Value) != ""
+ } else {
+ return true
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_resident_id.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_resident_id.go
new file mode 100644
index 000000000000..df4555924176
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/util/gvalid/gvalid_validator_rule_resident_id.go
@@ -0,0 +1,59 @@
+// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
+//
+// This Source Code Form is subject to the terms of the MIT License.
+// If a copy of the MIT was not distributed with this file,
+// You can obtain one at https://github.com/gogf/gf.
+
+package gvalid
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/gogf/gf/v2/text/gregex"
+)
+
+// checkResidentId checks whether given id a china resident id number.
+//
+// xxxxxx yyyy MM dd 375 0 十八位
+// xxxxxx yy MM dd 75 0 十五位
+//
+// 地区: [1-9]\d{5}
+// 年的前两位:(18|19|([23]\d)) 1800-2399
+// 年的后两位:\d{2}
+// 月份: ((0[1-9])|(10|11|12))
+// 天数: (([0-2][1-9])|10|20|30|31) 闰年不能禁止29+
+//
+// 三位顺序码:\d{3}
+// 两位顺序码:\d{2}
+// 校验码: [0-9Xx]
+//
+// 十八位:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
+// 十五位:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$
+//
+// 总:
+// (^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)
+func (v *Validator) checkResidentId(id string) bool {
+ id = strings.ToUpper(strings.TrimSpace(id))
+ if len(id) != 18 {
+ return false
+ }
+ var (
+ weightFactor = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
+ checkCode = []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
+ last = id[17]
+ num = 0
+ )
+ for i := 0; i < 17; i++ {
+ tmp, err := strconv.Atoi(string(id[i]))
+ if err != nil {
+ return false
+ }
+ num = num + tmp*weightFactor[i]
+ }
+ if checkCode[num%11] != last {
+ return false
+ }
+
+ return gregex.IsMatchString(`(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)`, id)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/version.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/version.go
new file mode 100644
index 000000000000..bca0c3b582e0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gogf/gf/v2/version.go
@@ -0,0 +1,4 @@
+package gf
+
+const VERSION = "v2.0.0-rc3"
+const AUTHORS = "john"
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/.gitignore
new file mode 100644
index 000000000000..09573e0169c2
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/.gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+bin
+.idea/
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/LICENSE
new file mode 100644
index 000000000000..35dbc252041e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/LICENSE
@@ -0,0 +1,9 @@
+Copyright (c) 2012 Dave Grijalva
+Copyright (c) 2021 golang-jwt maintainers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/MIGRATION_GUIDE.md b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/MIGRATION_GUIDE.md
new file mode 100644
index 000000000000..32966f59818e
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/MIGRATION_GUIDE.md
@@ -0,0 +1,22 @@
+## Migration Guide (v4.0.0)
+
+Starting from [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0), the import path will be:
+
+ "github.com/golang-jwt/jwt/v4"
+
+The `/v4` version will be backwards compatible with existing `v3.x.y` tags in this repo, as well as
+`github.com/dgrijalva/jwt-go`. For most users this should be a drop-in replacement, if you're having
+troubles migrating, please open an issue.
+
+You can replace all occurrences of `github.com/dgrijalva/jwt-go` or `github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually or by using tools such as `sed` or `gofmt`.
+
+And then you'd typically run:
+
+```
+go get github.com/golang-jwt/jwt/v4
+go mod tidy
+```
+
+## Older releases (before v3.2.0)
+
+The original migration guide for older releases can be found at https://github.com/dgrijalva/jwt-go/blob/master/MIGRATION_GUIDE.md.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/README.md b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/README.md
new file mode 100644
index 000000000000..30f2f2a6f70c
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/README.md
@@ -0,0 +1,138 @@
+# jwt-go
+
+[![build](https://github.com/golang-jwt/jwt/actions/workflows/build.yml/badge.svg)](https://github.com/golang-jwt/jwt/actions/workflows/build.yml)
+[![Go Reference](https://pkg.go.dev/badge/github.com/golang-jwt/jwt/v4.svg)](https://pkg.go.dev/github.com/golang-jwt/jwt/v4)
+
+A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](https://datatracker.ietf.org/doc/html/rfc7519).
+
+Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0) this project adds Go module support, but maintains backwards compatibility with older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`.
+See the [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information.
+
+> After the original author of the library suggested migrating the maintenance of `jwt-go`, a dedicated team of open source maintainers decided to clone the existing library into this repository. See [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a detailed discussion on this topic.
+
+
+**SECURITY NOTICE:** Some older versions of Go have a security issue in the crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue [dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more detail.
+
+**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided.
+
+### Supported Go versions
+
+Our support of Go versions is aligned with Go's [version release policy](https://golang.org/doc/devel/release#policy).
+So we will support a major version of Go until there are two newer major releases.
+We no longer support building jwt-go with unsupported Go versions, as these contain security vulnerabilities
+which will not be fixed.
+
+## What the heck is a JWT?
+
+JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
+
+In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648) encoded. The last part is the signature, encoded the same way.
+
+The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used.
+
+The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about reserved keys and the proper way to add your own.
+
+## What's in the box?
+
+This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own.
+
+## Installation Guidelines
+
+1. To install the jwt package, you first need to have [Go](https://go.dev/doc/install) installed, then you can use the command below to add `jwt-go` as a dependency in your Go program.
+
+```sh
+go get -u github.com/golang-jwt/jwt/v4
+```
+
+2. Import it in your code:
+
+```go
+import "github.com/golang-jwt/jwt/v4"
+```
+
+## Examples
+
+See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt/v4) for examples of usage:
+
+* [Simple example of parsing and validating a token](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#example-Parse-Hmac)
+* [Simple example of building and signing a token](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#example-New-Hmac)
+* [Directory of Examples](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#pkg-examples)
+
+## Extensions
+
+This library publishes all the necessary components for adding your own signing methods or key functions. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod` or provide a `jwt.Keyfunc`.
+
+A common use case would be integrating with different 3rd party signature providers, like key management services from various cloud providers or Hardware Security Modules (HSMs) or to implement additional standards.
+
+| Extension | Purpose | Repo |
+| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
+| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
+| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
+| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
+
+*Disclaimer*: Unless otherwise specified, these integrations are maintained by third parties and should not be considered as a primary offer by any of the mentioned cloud providers
+
+## Compliance
+
+This library was last reviewed to comply with [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few notable differences:
+
+* In order to protect against accidental use of [Unsecured JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
+
+## Project Status & Versioning
+
+This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
+
+This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `main`. Periodically, versions will be tagged from `main`. You can find all the releases on [the project releases page](https://github.com/golang-jwt/jwt/releases).
+
+**BREAKING CHANGES:***
+A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code.
+
+## Usage Tips
+
+### Signing vs Encryption
+
+A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data:
+
+* The author of the token was in the possession of the signing secret
+* The data has not been modified since it was signed
+
+It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. The companion project https://github.com/golang-jwt/jwe aims at a (very) experimental implementation of the JWE standard.
+
+### Choosing a Signing Method
+
+There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric.
+
+Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation.
+
+Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification.
+
+### Signing Methods and Key Types
+
+Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
+
+* The [HMAC signing method](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
+* The [RSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
+* The [ECDSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
+* The [EdDSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#SigningMethodEd25519) (`Ed25519`) expect `ed25519.PrivateKey` for signing and `ed25519.PublicKey` for validation
+
+### JWT and OAuth
+
+It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication.
+
+Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
+
+* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
+* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
+* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
+
+### Troubleshooting
+
+This library uses descriptive error messages whenever possible. If you are not getting the expected result, have a look at the errors. The most common place people get stuck is providing the correct type of key to the parser. See the above section on signing methods and key types.
+
+## More
+
+Documentation can be found [on pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt/v4).
+
+The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
+
+[golang-jwt](https://github.com/orgs/golang-jwt) incorporates a modified version of the JWT logo, which is distributed under the terms of the [MIT License](https://github.com/jsonwebtoken/jsonwebtoken.github.io/blob/master/LICENSE.txt).
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/SECURITY.md b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/SECURITY.md
new file mode 100644
index 000000000000..b08402c3427f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+## Supported Versions
+
+As of February 2022 (and until this document is updated), the latest version `v4` is supported.
+
+## Reporting a Vulnerability
+
+If you think you found a vulnerability, and even if you are not sure, please report it to jwt-go-security@googlegroups.com or one of the other [golang-jwt maintainers](https://github.com/orgs/golang-jwt/people). Please try be explicit, describe steps to reproduce the security issue with code example(s).
+
+You will receive a response within a timely manner. If the issue is confirmed, we will do our best to release a patch as soon as possible given the complexity of the problem.
+
+## Public Discussions
+
+Please avoid publicly discussing a potential security vulnerability.
+
+Let's take this offline and find a solution first, this limits the potential impact as much as possible.
+
+We appreciate your help!
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/VERSION_HISTORY.md b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/VERSION_HISTORY.md
new file mode 100644
index 000000000000..afbfc4e408d1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/VERSION_HISTORY.md
@@ -0,0 +1,135 @@
+## `jwt-go` Version History
+
+#### 4.0.0
+
+* Introduces support for Go modules. The `v4` version will be backwards compatible with `v3.x.y`.
+
+#### 3.2.2
+
+* Starting from this release, we are adopting the policy to support the most 2 recent versions of Go currently available. By the time of this release, this is Go 1.15 and 1.16 ([#28](https://github.com/golang-jwt/jwt/pull/28)).
+* Fixed a potential issue that could occur when the verification of `exp`, `iat` or `nbf` was not required and contained invalid contents, i.e. non-numeric/date. Thanks for @thaJeztah for making us aware of that and @giorgos-f3 for originally reporting it to the formtech fork ([#40](https://github.com/golang-jwt/jwt/pull/40)).
+* Added support for EdDSA / ED25519 ([#36](https://github.com/golang-jwt/jwt/pull/36)).
+* Optimized allocations ([#33](https://github.com/golang-jwt/jwt/pull/33)).
+
+#### 3.2.1
+
+* **Import Path Change**: See MIGRATION_GUIDE.md for tips on updating your code
+ * Changed the import path from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`
+* Fixed type confusing issue between `string` and `[]string` in `VerifyAudience` ([#12](https://github.com/golang-jwt/jwt/pull/12)). This fixes CVE-2020-26160
+
+#### 3.2.0
+
+* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
+* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
+* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
+* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
+
+#### 3.1.0
+
+* Improvements to `jwt` command line tool
+* Added `SkipClaimsValidation` option to `Parser`
+* Documentation updates
+
+#### 3.0.0
+
+* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
+ * Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
+ * `ParseFromRequest` has been moved to `request` subpackage and usage has changed
+ * The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims.
+* Other Additions and Changes
+ * Added `Claims` interface type to allow users to decode the claims into a custom type
+ * Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into.
+ * Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
+ * Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
+ * Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
+ * Added several new, more specific, validation errors to error type bitmask
+ * Moved examples from README to executable example files
+ * Signing method registry is now thread safe
+ * Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)
+
+#### 2.7.0
+
+This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
+
+* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
+* Error text for expired tokens includes how long it's been expired
+* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
+* Documentation updates
+
+#### 2.6.0
+
+* Exposed inner error within ValidationError
+* Fixed validation errors when using UseJSONNumber flag
+* Added several unit tests
+
+#### 2.5.0
+
+* Added support for signing method none. You shouldn't use this. The API tries to make this clear.
+* Updated/fixed some documentation
+* Added more helpful error message when trying to parse tokens that begin with `BEARER `
+
+#### 2.4.0
+
+* Added new type, Parser, to allow for configuration of various parsing parameters
+ * You can now specify a list of valid signing methods. Anything outside this set will be rejected.
+ * You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
+* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
+* Fixed some bugs with ECDSA parsing
+
+#### 2.3.0
+
+* Added support for ECDSA signing methods
+* Added support for RSA PSS signing methods (requires go v1.4)
+
+#### 2.2.0
+
+* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic.
+
+#### 2.1.0
+
+Backwards compatible API change that was missed in 2.0.0.
+
+* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
+
+#### 2.0.0
+
+There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
+
+The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
+
+It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
+
+* **Compatibility Breaking Changes**
+ * `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
+ * `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
+ * `KeyFunc` now returns `interface{}` instead of `[]byte`
+ * `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
+ * `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
+* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type.
+ * Added public package global `SigningMethodHS256`
+ * Added public package global `SigningMethodHS384`
+ * Added public package global `SigningMethodHS512`
+* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type.
+ * Added public package global `SigningMethodRS256`
+ * Added public package global `SigningMethodRS384`
+ * Added public package global `SigningMethodRS512`
+* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged.
+* Refactored the RSA implementation to be easier to read
+* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
+
+#### 1.0.2
+
+* Fixed bug in parsing public keys from certificates
+* Added more tests around the parsing of keys for RS256
+* Code refactoring in RS256 implementation. No functional changes
+
+#### 1.0.1
+
+* Fixed panic if RS256 signing method was passed an invalid key
+
+#### 1.0.0
+
+* First versioned release
+* API stabilized
+* Supports creating, signing, parsing, and validating JWT tokens
+* Supports RS256 and HS256 signing methods
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/claims.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/claims.go
new file mode 100644
index 000000000000..364cec8773cd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/claims.go
@@ -0,0 +1,269 @@
+package jwt
+
+import (
+ "crypto/subtle"
+ "fmt"
+ "time"
+)
+
+// Claims must just have a Valid method that determines
+// if the token is invalid for any supported reason
+type Claims interface {
+ Valid() error
+}
+
+// RegisteredClaims are a structured version of the JWT Claims Set,
+// restricted to Registered Claim Names, as referenced at
+// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
+//
+// This type can be used on its own, but then additional private and
+// public claims embedded in the JWT will not be parsed. The typical usecase
+// therefore is to embedded this in a user-defined claim type.
+//
+// See examples for how to use this with your own claim types.
+type RegisteredClaims struct {
+ // the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
+ Issuer string `json:"iss,omitempty"`
+
+ // the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
+ Subject string `json:"sub,omitempty"`
+
+ // the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
+ Audience ClaimStrings `json:"aud,omitempty"`
+
+ // the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
+ ExpiresAt *NumericDate `json:"exp,omitempty"`
+
+ // the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
+ NotBefore *NumericDate `json:"nbf,omitempty"`
+
+ // the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
+ IssuedAt *NumericDate `json:"iat,omitempty"`
+
+ // the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
+ ID string `json:"jti,omitempty"`
+}
+
+// Valid validates time based claims "exp, iat, nbf".
+// There is no accounting for clock skew.
+// As well, if any of the above claims are not in the token, it will still
+// be considered a valid claim.
+func (c RegisteredClaims) Valid() error {
+ vErr := new(ValidationError)
+ now := TimeFunc()
+
+ // The claims below are optional, by default, so if they are set to the
+ // default value in Go, let's not fail the verification for them.
+ if !c.VerifyExpiresAt(now, false) {
+ delta := now.Sub(c.ExpiresAt.Time)
+ vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta)
+ vErr.Errors |= ValidationErrorExpired
+ }
+
+ if !c.VerifyIssuedAt(now, false) {
+ vErr.Inner = ErrTokenUsedBeforeIssued
+ vErr.Errors |= ValidationErrorIssuedAt
+ }
+
+ if !c.VerifyNotBefore(now, false) {
+ vErr.Inner = ErrTokenNotValidYet
+ vErr.Errors |= ValidationErrorNotValidYet
+ }
+
+ if vErr.valid() {
+ return nil
+ }
+
+ return vErr
+}
+
+// VerifyAudience compares the aud claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *RegisteredClaims) VerifyAudience(cmp string, req bool) bool {
+ return verifyAud(c.Audience, cmp, req)
+}
+
+// VerifyExpiresAt compares the exp claim against cmp (cmp < exp).
+// If req is false, it will return true, if exp is unset.
+func (c *RegisteredClaims) VerifyExpiresAt(cmp time.Time, req bool) bool {
+ if c.ExpiresAt == nil {
+ return verifyExp(nil, cmp, req)
+ }
+
+ return verifyExp(&c.ExpiresAt.Time, cmp, req)
+}
+
+// VerifyIssuedAt compares the iat claim against cmp (cmp >= iat).
+// If req is false, it will return true, if iat is unset.
+func (c *RegisteredClaims) VerifyIssuedAt(cmp time.Time, req bool) bool {
+ if c.IssuedAt == nil {
+ return verifyIat(nil, cmp, req)
+ }
+
+ return verifyIat(&c.IssuedAt.Time, cmp, req)
+}
+
+// VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf).
+// If req is false, it will return true, if nbf is unset.
+func (c *RegisteredClaims) VerifyNotBefore(cmp time.Time, req bool) bool {
+ if c.NotBefore == nil {
+ return verifyNbf(nil, cmp, req)
+ }
+
+ return verifyNbf(&c.NotBefore.Time, cmp, req)
+}
+
+// VerifyIssuer compares the iss claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *RegisteredClaims) VerifyIssuer(cmp string, req bool) bool {
+ return verifyIss(c.Issuer, cmp, req)
+}
+
+// StandardClaims are a structured version of the JWT Claims Set, as referenced at
+// https://datatracker.ietf.org/doc/html/rfc7519#section-4. They do not follow the
+// specification exactly, since they were based on an earlier draft of the
+// specification and not updated. The main difference is that they only
+// support integer-based date fields and singular audiences. This might lead to
+// incompatibilities with other JWT implementations. The use of this is discouraged, instead
+// the newer RegisteredClaims struct should be used.
+//
+// Deprecated: Use RegisteredClaims instead for a forward-compatible way to access registered claims in a struct.
+type StandardClaims struct {
+ Audience string `json:"aud,omitempty"`
+ ExpiresAt int64 `json:"exp,omitempty"`
+ Id string `json:"jti,omitempty"`
+ IssuedAt int64 `json:"iat,omitempty"`
+ Issuer string `json:"iss,omitempty"`
+ NotBefore int64 `json:"nbf,omitempty"`
+ Subject string `json:"sub,omitempty"`
+}
+
+// Valid validates time based claims "exp, iat, nbf". There is no accounting for clock skew.
+// As well, if any of the above claims are not in the token, it will still
+// be considered a valid claim.
+func (c StandardClaims) Valid() error {
+ vErr := new(ValidationError)
+ now := TimeFunc().Unix()
+
+ // The claims below are optional, by default, so if they are set to the
+ // default value in Go, let's not fail the verification for them.
+ if !c.VerifyExpiresAt(now, false) {
+ delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
+ vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta)
+ vErr.Errors |= ValidationErrorExpired
+ }
+
+ if !c.VerifyIssuedAt(now, false) {
+ vErr.Inner = ErrTokenUsedBeforeIssued
+ vErr.Errors |= ValidationErrorIssuedAt
+ }
+
+ if !c.VerifyNotBefore(now, false) {
+ vErr.Inner = ErrTokenNotValidYet
+ vErr.Errors |= ValidationErrorNotValidYet
+ }
+
+ if vErr.valid() {
+ return nil
+ }
+
+ return vErr
+}
+
+// VerifyAudience compares the aud claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
+ return verifyAud([]string{c.Audience}, cmp, req)
+}
+
+// VerifyExpiresAt compares the exp claim against cmp (cmp < exp).
+// If req is false, it will return true, if exp is unset.
+func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
+ if c.ExpiresAt == 0 {
+ return verifyExp(nil, time.Unix(cmp, 0), req)
+ }
+
+ t := time.Unix(c.ExpiresAt, 0)
+ return verifyExp(&t, time.Unix(cmp, 0), req)
+}
+
+// VerifyIssuedAt compares the iat claim against cmp (cmp >= iat).
+// If req is false, it will return true, if iat is unset.
+func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
+ if c.IssuedAt == 0 {
+ return verifyIat(nil, time.Unix(cmp, 0), req)
+ }
+
+ t := time.Unix(c.IssuedAt, 0)
+ return verifyIat(&t, time.Unix(cmp, 0), req)
+}
+
+// VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf).
+// If req is false, it will return true, if nbf is unset.
+func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
+ if c.NotBefore == 0 {
+ return verifyNbf(nil, time.Unix(cmp, 0), req)
+ }
+
+ t := time.Unix(c.NotBefore, 0)
+ return verifyNbf(&t, time.Unix(cmp, 0), req)
+}
+
+// VerifyIssuer compares the iss claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
+ return verifyIss(c.Issuer, cmp, req)
+}
+
+// ----- helpers
+
+func verifyAud(aud []string, cmp string, required bool) bool {
+ if len(aud) == 0 {
+ return !required
+ }
+ // use a var here to keep constant time compare when looping over a number of claims
+ result := false
+
+ var stringClaims string
+ for _, a := range aud {
+ if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
+ result = true
+ }
+ stringClaims = stringClaims + a
+ }
+
+ // case where "" is sent in one or many aud claims
+ if len(stringClaims) == 0 {
+ return !required
+ }
+
+ return result
+}
+
+func verifyExp(exp *time.Time, now time.Time, required bool) bool {
+ if exp == nil {
+ return !required
+ }
+ return now.Before(*exp)
+}
+
+func verifyIat(iat *time.Time, now time.Time, required bool) bool {
+ if iat == nil {
+ return !required
+ }
+ return now.After(*iat) || now.Equal(*iat)
+}
+
+func verifyNbf(nbf *time.Time, now time.Time, required bool) bool {
+ if nbf == nil {
+ return !required
+ }
+ return now.After(*nbf) || now.Equal(*nbf)
+}
+
+func verifyIss(iss string, cmp string, required bool) bool {
+ if iss == "" {
+ return !required
+ }
+ return subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/doc.go
new file mode 100644
index 000000000000..a86dc1a3b348
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/doc.go
@@ -0,0 +1,4 @@
+// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html
+//
+// See README.md for more info.
+package jwt
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ecdsa.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ecdsa.go
new file mode 100644
index 000000000000..eac023fc6c84
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ecdsa.go
@@ -0,0 +1,142 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rand"
+ "errors"
+ "math/big"
+)
+
+var (
+ // Sadly this is missing from crypto/ecdsa compared to crypto/rsa
+ ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
+)
+
+// SigningMethodECDSA implements the ECDSA family of signing methods.
+// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
+type SigningMethodECDSA struct {
+ Name string
+ Hash crypto.Hash
+ KeySize int
+ CurveBits int
+}
+
+// Specific instances for EC256 and company
+var (
+ SigningMethodES256 *SigningMethodECDSA
+ SigningMethodES384 *SigningMethodECDSA
+ SigningMethodES512 *SigningMethodECDSA
+)
+
+func init() {
+ // ES256
+ SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
+ RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
+ return SigningMethodES256
+ })
+
+ // ES384
+ SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
+ RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
+ return SigningMethodES384
+ })
+
+ // ES512
+ SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
+ RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
+ return SigningMethodES512
+ })
+}
+
+func (m *SigningMethodECDSA) Alg() string {
+ return m.Name
+}
+
+// Verify implements token verification for the SigningMethod.
+// For this verify method, key must be an ecdsa.PublicKey struct
+func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
+ var err error
+
+ // Decode the signature
+ var sig []byte
+ if sig, err = DecodeSegment(signature); err != nil {
+ return err
+ }
+
+ // Get the key
+ var ecdsaKey *ecdsa.PublicKey
+ switch k := key.(type) {
+ case *ecdsa.PublicKey:
+ ecdsaKey = k
+ default:
+ return ErrInvalidKeyType
+ }
+
+ if len(sig) != 2*m.KeySize {
+ return ErrECDSAVerification
+ }
+
+ r := big.NewInt(0).SetBytes(sig[:m.KeySize])
+ s := big.NewInt(0).SetBytes(sig[m.KeySize:])
+
+ // Create hasher
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Verify the signature
+ if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus {
+ return nil
+ }
+
+ return ErrECDSAVerification
+}
+
+// Sign implements token signing for the SigningMethod.
+// For this signing method, key must be an ecdsa.PrivateKey struct
+func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
+ // Get the key
+ var ecdsaKey *ecdsa.PrivateKey
+ switch k := key.(type) {
+ case *ecdsa.PrivateKey:
+ ecdsaKey = k
+ default:
+ return "", ErrInvalidKeyType
+ }
+
+ // Create the hasher
+ if !m.Hash.Available() {
+ return "", ErrHashUnavailable
+ }
+
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Sign the string and return r, s
+ if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
+ curveBits := ecdsaKey.Curve.Params().BitSize
+
+ if m.CurveBits != curveBits {
+ return "", ErrInvalidKey
+ }
+
+ keyBytes := curveBits / 8
+ if curveBits%8 > 0 {
+ keyBytes += 1
+ }
+
+ // We serialize the outputs (r and s) into big-endian byte arrays
+ // padded with zeros on the left to make sure the sizes work out.
+ // Output must be 2*keyBytes long.
+ out := make([]byte, 2*keyBytes)
+ r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
+ s.FillBytes(out[keyBytes:]) // s is assigned to the second half of output.
+
+ return EncodeSegment(out), nil
+ } else {
+ return "", err
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ecdsa_utils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ecdsa_utils.go
new file mode 100644
index 000000000000..5700636d35b6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ecdsa_utils.go
@@ -0,0 +1,69 @@
+package jwt
+
+import (
+ "crypto/ecdsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ ErrNotECPublicKey = errors.New("key is not a valid ECDSA public key")
+ ErrNotECPrivateKey = errors.New("key is not a valid ECDSA private key")
+)
+
+// ParseECPrivateKeyFromPEM parses a PEM encoded Elliptic Curve Private Key Structure
+func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey interface{}
+ if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+ return nil, err
+ }
+ }
+
+ var pkey *ecdsa.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
+ return nil, ErrNotECPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseECPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
+func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey interface{}
+ if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+ if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
+ parsedKey = cert.PublicKey
+ } else {
+ return nil, err
+ }
+ }
+
+ var pkey *ecdsa.PublicKey
+ var ok bool
+ if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
+ return nil, ErrNotECPublicKey
+ }
+
+ return pkey, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ed25519.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ed25519.go
new file mode 100644
index 000000000000..07d3aacd631f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ed25519.go
@@ -0,0 +1,85 @@
+package jwt
+
+import (
+ "errors"
+
+ "crypto"
+ "crypto/ed25519"
+ "crypto/rand"
+)
+
+var (
+ ErrEd25519Verification = errors.New("ed25519: verification error")
+)
+
+// SigningMethodEd25519 implements the EdDSA family.
+// Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification
+type SigningMethodEd25519 struct{}
+
+// Specific instance for EdDSA
+var (
+ SigningMethodEdDSA *SigningMethodEd25519
+)
+
+func init() {
+ SigningMethodEdDSA = &SigningMethodEd25519{}
+ RegisterSigningMethod(SigningMethodEdDSA.Alg(), func() SigningMethod {
+ return SigningMethodEdDSA
+ })
+}
+
+func (m *SigningMethodEd25519) Alg() string {
+ return "EdDSA"
+}
+
+// Verify implements token verification for the SigningMethod.
+// For this verify method, key must be an ed25519.PublicKey
+func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error {
+ var err error
+ var ed25519Key ed25519.PublicKey
+ var ok bool
+
+ if ed25519Key, ok = key.(ed25519.PublicKey); !ok {
+ return ErrInvalidKeyType
+ }
+
+ if len(ed25519Key) != ed25519.PublicKeySize {
+ return ErrInvalidKey
+ }
+
+ // Decode the signature
+ var sig []byte
+ if sig, err = DecodeSegment(signature); err != nil {
+ return err
+ }
+
+ // Verify the signature
+ if !ed25519.Verify(ed25519Key, []byte(signingString), sig) {
+ return ErrEd25519Verification
+ }
+
+ return nil
+}
+
+// Sign implements token signing for the SigningMethod.
+// For this signing method, key must be an ed25519.PrivateKey
+func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) {
+ var ed25519Key crypto.Signer
+ var ok bool
+
+ if ed25519Key, ok = key.(crypto.Signer); !ok {
+ return "", ErrInvalidKeyType
+ }
+
+ if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok {
+ return "", ErrInvalidKey
+ }
+
+ // Sign the string and return the encoded result
+ // ed25519 performs a two-pass hash as part of its algorithm. Therefore, we need to pass a non-prehashed message into the Sign function, as indicated by crypto.Hash(0)
+ sig, err := ed25519Key.Sign(rand.Reader, []byte(signingString), crypto.Hash(0))
+ if err != nil {
+ return "", err
+ }
+ return EncodeSegment(sig), nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ed25519_utils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ed25519_utils.go
new file mode 100644
index 000000000000..cdb5e68e8767
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/ed25519_utils.go
@@ -0,0 +1,64 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/ed25519"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ ErrNotEdPrivateKey = errors.New("key is not a valid Ed25519 private key")
+ ErrNotEdPublicKey = errors.New("key is not a valid Ed25519 public key")
+)
+
+// ParseEdPrivateKeyFromPEM parses a PEM-encoded Edwards curve private key
+func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey interface{}
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+ return nil, err
+ }
+
+ var pkey ed25519.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(ed25519.PrivateKey); !ok {
+ return nil, ErrNotEdPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseEdPublicKeyFromPEM parses a PEM-encoded Edwards curve public key
+func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey interface{}
+ if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+ return nil, err
+ }
+
+ var pkey ed25519.PublicKey
+ var ok bool
+ if pkey, ok = parsedKey.(ed25519.PublicKey); !ok {
+ return nil, ErrNotEdPublicKey
+ }
+
+ return pkey, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/errors.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/errors.go
new file mode 100644
index 000000000000..10ac8835cc88
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/errors.go
@@ -0,0 +1,112 @@
+package jwt
+
+import (
+ "errors"
+)
+
+// Error constants
+var (
+ ErrInvalidKey = errors.New("key is invalid")
+ ErrInvalidKeyType = errors.New("key is of invalid type")
+ ErrHashUnavailable = errors.New("the requested hash function is unavailable")
+
+ ErrTokenMalformed = errors.New("token is malformed")
+ ErrTokenUnverifiable = errors.New("token is unverifiable")
+ ErrTokenSignatureInvalid = errors.New("token signature is invalid")
+
+ ErrTokenInvalidAudience = errors.New("token has invalid audience")
+ ErrTokenExpired = errors.New("token is expired")
+ ErrTokenUsedBeforeIssued = errors.New("token used before issued")
+ ErrTokenInvalidIssuer = errors.New("token has invalid issuer")
+ ErrTokenNotValidYet = errors.New("token is not valid yet")
+ ErrTokenInvalidId = errors.New("token has invalid id")
+ ErrTokenInvalidClaims = errors.New("token has invalid claims")
+)
+
+// The errors that might occur when parsing and validating a token
+const (
+ ValidationErrorMalformed uint32 = 1 << iota // Token is malformed
+ ValidationErrorUnverifiable // Token could not be verified because of signing problems
+ ValidationErrorSignatureInvalid // Signature validation failed
+
+ // Standard Claim validation errors
+ ValidationErrorAudience // AUD validation failed
+ ValidationErrorExpired // EXP validation failed
+ ValidationErrorIssuedAt // IAT validation failed
+ ValidationErrorIssuer // ISS validation failed
+ ValidationErrorNotValidYet // NBF validation failed
+ ValidationErrorId // JTI validation failed
+ ValidationErrorClaimsInvalid // Generic claims validation error
+)
+
+// NewValidationError is a helper for constructing a ValidationError with a string error message
+func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
+ return &ValidationError{
+ text: errorText,
+ Errors: errorFlags,
+ }
+}
+
+// ValidationError represents an error from Parse if token is not valid
+type ValidationError struct {
+ Inner error // stores the error returned by external dependencies, i.e.: KeyFunc
+ Errors uint32 // bitfield. see ValidationError... constants
+ text string // errors that do not have a valid error just have text
+}
+
+// Error is the implementation of the err interface.
+func (e ValidationError) Error() string {
+ if e.Inner != nil {
+ return e.Inner.Error()
+ } else if e.text != "" {
+ return e.text
+ } else {
+ return "token is invalid"
+ }
+}
+
+// Unwrap gives errors.Is and errors.As access to the inner error.
+func (e *ValidationError) Unwrap() error {
+ return e.Inner
+}
+
+// No errors
+func (e *ValidationError) valid() bool {
+ return e.Errors == 0
+}
+
+// Is checks if this ValidationError is of the supplied error. We are first checking for the exact error message
+// by comparing the inner error message. If that fails, we compare using the error flags. This way we can use
+// custom error messages (mainly for backwards compatability) and still leverage errors.Is using the global error variables.
+func (e *ValidationError) Is(err error) bool {
+ // Check, if our inner error is a direct match
+ if errors.Is(errors.Unwrap(e), err) {
+ return true
+ }
+
+ // Otherwise, we need to match using our error flags
+ switch err {
+ case ErrTokenMalformed:
+ return e.Errors&ValidationErrorMalformed != 0
+ case ErrTokenUnverifiable:
+ return e.Errors&ValidationErrorUnverifiable != 0
+ case ErrTokenSignatureInvalid:
+ return e.Errors&ValidationErrorSignatureInvalid != 0
+ case ErrTokenInvalidAudience:
+ return e.Errors&ValidationErrorAudience != 0
+ case ErrTokenExpired:
+ return e.Errors&ValidationErrorExpired != 0
+ case ErrTokenUsedBeforeIssued:
+ return e.Errors&ValidationErrorIssuedAt != 0
+ case ErrTokenInvalidIssuer:
+ return e.Errors&ValidationErrorIssuer != 0
+ case ErrTokenNotValidYet:
+ return e.Errors&ValidationErrorNotValidYet != 0
+ case ErrTokenInvalidId:
+ return e.Errors&ValidationErrorId != 0
+ case ErrTokenInvalidClaims:
+ return e.Errors&ValidationErrorClaimsInvalid != 0
+ }
+
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/hmac.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/hmac.go
new file mode 100644
index 000000000000..011f68a27440
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/hmac.go
@@ -0,0 +1,95 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/hmac"
+ "errors"
+)
+
+// SigningMethodHMAC implements the HMAC-SHA family of signing methods.
+// Expects key type of []byte for both signing and validation
+type SigningMethodHMAC struct {
+ Name string
+ Hash crypto.Hash
+}
+
+// Specific instances for HS256 and company
+var (
+ SigningMethodHS256 *SigningMethodHMAC
+ SigningMethodHS384 *SigningMethodHMAC
+ SigningMethodHS512 *SigningMethodHMAC
+ ErrSignatureInvalid = errors.New("signature is invalid")
+)
+
+func init() {
+ // HS256
+ SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
+ RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
+ return SigningMethodHS256
+ })
+
+ // HS384
+ SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
+ RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
+ return SigningMethodHS384
+ })
+
+ // HS512
+ SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
+ RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
+ return SigningMethodHS512
+ })
+}
+
+func (m *SigningMethodHMAC) Alg() string {
+ return m.Name
+}
+
+// Verify implements token verification for the SigningMethod. Returns nil if the signature is valid.
+func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
+ // Verify the key is the right type
+ keyBytes, ok := key.([]byte)
+ if !ok {
+ return ErrInvalidKeyType
+ }
+
+ // Decode signature, for comparison
+ sig, err := DecodeSegment(signature)
+ if err != nil {
+ return err
+ }
+
+ // Can we use the specified hashing method?
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+
+ // This signing method is symmetric, so we validate the signature
+ // by reproducing the signature from the signing string and key, then
+ // comparing that against the provided signature.
+ hasher := hmac.New(m.Hash.New, keyBytes)
+ hasher.Write([]byte(signingString))
+ if !hmac.Equal(sig, hasher.Sum(nil)) {
+ return ErrSignatureInvalid
+ }
+
+ // No validation errors. Signature is good.
+ return nil
+}
+
+// Sign implements token signing for the SigningMethod.
+// Key must be []byte
+func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
+ if keyBytes, ok := key.([]byte); ok {
+ if !m.Hash.Available() {
+ return "", ErrHashUnavailable
+ }
+
+ hasher := hmac.New(m.Hash.New, keyBytes)
+ hasher.Write([]byte(signingString))
+
+ return EncodeSegment(hasher.Sum(nil)), nil
+ }
+
+ return "", ErrInvalidKeyType
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/map_claims.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/map_claims.go
new file mode 100644
index 000000000000..2700d64a0d09
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/map_claims.go
@@ -0,0 +1,151 @@
+package jwt
+
+import (
+ "encoding/json"
+ "errors"
+ "time"
+ // "fmt"
+)
+
+// MapClaims is a claims type that uses the map[string]interface{} for JSON decoding.
+// This is the default claims type if you don't supply one
+type MapClaims map[string]interface{}
+
+// VerifyAudience Compares the aud claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
+ var aud []string
+ switch v := m["aud"].(type) {
+ case string:
+ aud = append(aud, v)
+ case []string:
+ aud = v
+ case []interface{}:
+ for _, a := range v {
+ vs, ok := a.(string)
+ if !ok {
+ return false
+ }
+ aud = append(aud, vs)
+ }
+ }
+ return verifyAud(aud, cmp, req)
+}
+
+// VerifyExpiresAt compares the exp claim against cmp (cmp <= exp).
+// If req is false, it will return true, if exp is unset.
+func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
+ cmpTime := time.Unix(cmp, 0)
+
+ v, ok := m["exp"]
+ if !ok {
+ return !req
+ }
+
+ switch exp := v.(type) {
+ case float64:
+ if exp == 0 {
+ return verifyExp(nil, cmpTime, req)
+ }
+
+ return verifyExp(&newNumericDateFromSeconds(exp).Time, cmpTime, req)
+ case json.Number:
+ v, _ := exp.Float64()
+
+ return verifyExp(&newNumericDateFromSeconds(v).Time, cmpTime, req)
+ }
+
+ return false
+}
+
+// VerifyIssuedAt compares the exp claim against cmp (cmp >= iat).
+// If req is false, it will return true, if iat is unset.
+func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
+ cmpTime := time.Unix(cmp, 0)
+
+ v, ok := m["iat"]
+ if !ok {
+ return !req
+ }
+
+ switch iat := v.(type) {
+ case float64:
+ if iat == 0 {
+ return verifyIat(nil, cmpTime, req)
+ }
+
+ return verifyIat(&newNumericDateFromSeconds(iat).Time, cmpTime, req)
+ case json.Number:
+ v, _ := iat.Float64()
+
+ return verifyIat(&newNumericDateFromSeconds(v).Time, cmpTime, req)
+ }
+
+ return false
+}
+
+// VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf).
+// If req is false, it will return true, if nbf is unset.
+func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
+ cmpTime := time.Unix(cmp, 0)
+
+ v, ok := m["nbf"]
+ if !ok {
+ return !req
+ }
+
+ switch nbf := v.(type) {
+ case float64:
+ if nbf == 0 {
+ return verifyNbf(nil, cmpTime, req)
+ }
+
+ return verifyNbf(&newNumericDateFromSeconds(nbf).Time, cmpTime, req)
+ case json.Number:
+ v, _ := nbf.Float64()
+
+ return verifyNbf(&newNumericDateFromSeconds(v).Time, cmpTime, req)
+ }
+
+ return false
+}
+
+// VerifyIssuer compares the iss claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
+ iss, _ := m["iss"].(string)
+ return verifyIss(iss, cmp, req)
+}
+
+// Valid validates time based claims "exp, iat, nbf".
+// There is no accounting for clock skew.
+// As well, if any of the above claims are not in the token, it will still
+// be considered a valid claim.
+func (m MapClaims) Valid() error {
+ vErr := new(ValidationError)
+ now := TimeFunc().Unix()
+
+ if !m.VerifyExpiresAt(now, false) {
+ // TODO(oxisto): this should be replaced with ErrTokenExpired
+ vErr.Inner = errors.New("Token is expired")
+ vErr.Errors |= ValidationErrorExpired
+ }
+
+ if !m.VerifyIssuedAt(now, false) {
+ // TODO(oxisto): this should be replaced with ErrTokenUsedBeforeIssued
+ vErr.Inner = errors.New("Token used before issued")
+ vErr.Errors |= ValidationErrorIssuedAt
+ }
+
+ if !m.VerifyNotBefore(now, false) {
+ // TODO(oxisto): this should be replaced with ErrTokenNotValidYet
+ vErr.Inner = errors.New("Token is not valid yet")
+ vErr.Errors |= ValidationErrorNotValidYet
+ }
+
+ if vErr.valid() {
+ return nil
+ }
+
+ return vErr
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/none.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/none.go
new file mode 100644
index 000000000000..f19835d2078b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/none.go
@@ -0,0 +1,52 @@
+package jwt
+
+// SigningMethodNone implements the none signing method. This is required by the spec
+// but you probably should never use it.
+var SigningMethodNone *signingMethodNone
+
+const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed"
+
+var NoneSignatureTypeDisallowedError error
+
+type signingMethodNone struct{}
+type unsafeNoneMagicConstant string
+
+func init() {
+ SigningMethodNone = &signingMethodNone{}
+ NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid)
+
+ RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod {
+ return SigningMethodNone
+ })
+}
+
+func (m *signingMethodNone) Alg() string {
+ return "none"
+}
+
+// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
+func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) {
+ // Key must be UnsafeAllowNoneSignatureType to prevent accidentally
+ // accepting 'none' signing method
+ if _, ok := key.(unsafeNoneMagicConstant); !ok {
+ return NoneSignatureTypeDisallowedError
+ }
+ // If signing method is none, signature must be an empty string
+ if signature != "" {
+ return NewValidationError(
+ "'none' signing method with non-empty signature",
+ ValidationErrorSignatureInvalid,
+ )
+ }
+
+ // Accept 'none' signing method.
+ return nil
+}
+
+// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
+func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) {
+ if _, ok := key.(unsafeNoneMagicConstant); ok {
+ return "", nil
+ }
+ return "", NoneSignatureTypeDisallowedError
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/parser.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/parser.go
new file mode 100644
index 000000000000..c0a6f6927917
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/parser.go
@@ -0,0 +1,177 @@
+package jwt
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "strings"
+)
+
+type Parser struct {
+ // If populated, only these methods will be considered valid.
+ //
+ // Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
+ ValidMethods []string
+
+ // Use JSON Number format in JSON decoder.
+ //
+ // Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
+ UseJSONNumber bool
+
+ // Skip claims validation during token parsing.
+ //
+ // Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
+ SkipClaimsValidation bool
+}
+
+// NewParser creates a new Parser with the specified options
+func NewParser(options ...ParserOption) *Parser {
+ p := &Parser{}
+
+ // loop through our parsing options and apply them
+ for _, option := range options {
+ option(p)
+ }
+
+ return p
+}
+
+// Parse parses, validates, verifies the signature and returns the parsed token.
+// keyFunc will receive the parsed token and should return the key for validating.
+func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
+ return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
+}
+
+// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
+// interface. This provides default values which can be overridden and allows a caller to use their own type, rather
+// than the default MapClaims implementation of Claims.
+//
+// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
+// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
+// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
+func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
+ token, parts, err := p.ParseUnverified(tokenString, claims)
+ if err != nil {
+ return token, err
+ }
+
+ // Verify signing method is in the required set
+ if p.ValidMethods != nil {
+ var signingMethodValid = false
+ var alg = token.Method.Alg()
+ for _, m := range p.ValidMethods {
+ if m == alg {
+ signingMethodValid = true
+ break
+ }
+ }
+ if !signingMethodValid {
+ // signing method is not in the listed set
+ return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
+ }
+ }
+
+ // Lookup key
+ var key interface{}
+ if keyFunc == nil {
+ // keyFunc was not provided. short circuiting validation
+ return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
+ }
+ if key, err = keyFunc(token); err != nil {
+ // keyFunc returned an error
+ if ve, ok := err.(*ValidationError); ok {
+ return token, ve
+ }
+ return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
+ }
+
+ vErr := &ValidationError{}
+
+ // Validate Claims
+ if !p.SkipClaimsValidation {
+ if err := token.Claims.Valid(); err != nil {
+
+ // If the Claims Valid returned an error, check if it is a validation error,
+ // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
+ if e, ok := err.(*ValidationError); !ok {
+ vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
+ } else {
+ vErr = e
+ }
+ }
+ }
+
+ // Perform validation
+ token.Signature = parts[2]
+ if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
+ vErr.Inner = err
+ vErr.Errors |= ValidationErrorSignatureInvalid
+ }
+
+ if vErr.valid() {
+ token.Valid = true
+ return token, nil
+ }
+
+ return token, vErr
+}
+
+// ParseUnverified parses the token but doesn't validate the signature.
+//
+// WARNING: Don't use this method unless you know what you're doing.
+//
+// It's only ever useful in cases where you know the signature is valid (because it has
+// been checked previously in the stack) and you want to extract values from it.
+func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
+ parts = strings.Split(tokenString, ".")
+ if len(parts) != 3 {
+ return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
+ }
+
+ token = &Token{Raw: tokenString}
+
+ // parse Header
+ var headerBytes []byte
+ if headerBytes, err = DecodeSegment(parts[0]); err != nil {
+ if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
+ return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
+ }
+ return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+ }
+ if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
+ return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+ }
+
+ // parse Claims
+ var claimBytes []byte
+ token.Claims = claims
+
+ if claimBytes, err = DecodeSegment(parts[1]); err != nil {
+ return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+ }
+ dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
+ if p.UseJSONNumber {
+ dec.UseNumber()
+ }
+ // JSON Decode. Special case for map type to avoid weird pointer behavior
+ if c, ok := token.Claims.(MapClaims); ok {
+ err = dec.Decode(&c)
+ } else {
+ err = dec.Decode(&claims)
+ }
+ // Handle decode error
+ if err != nil {
+ return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+ }
+
+ // Lookup signature method
+ if method, ok := token.Header["alg"].(string); ok {
+ if token.Method = GetSigningMethod(method); token.Method == nil {
+ return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
+ }
+ } else {
+ return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
+ }
+
+ return token, parts, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/parser_option.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/parser_option.go
new file mode 100644
index 000000000000..6ea6f9527de6
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/parser_option.go
@@ -0,0 +1,29 @@
+package jwt
+
+// ParserOption is used to implement functional-style options that modify the behavior of the parser. To add
+// new options, just create a function (ideally beginning with With or Without) that returns an anonymous function that
+// takes a *Parser type as input and manipulates its configuration accordingly.
+type ParserOption func(*Parser)
+
+// WithValidMethods is an option to supply algorithm methods that the parser will check. Only those methods will be considered valid.
+// It is heavily encouraged to use this option in order to prevent attacks such as https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/.
+func WithValidMethods(methods []string) ParserOption {
+ return func(p *Parser) {
+ p.ValidMethods = methods
+ }
+}
+
+// WithJSONNumber is an option to configure the underlying JSON parser with UseNumber
+func WithJSONNumber() ParserOption {
+ return func(p *Parser) {
+ p.UseJSONNumber = true
+ }
+}
+
+// WithoutClaimsValidation is an option to disable claims validation. This option should only be used if you exactly know
+// what you are doing.
+func WithoutClaimsValidation() ParserOption {
+ return func(p *Parser) {
+ p.SkipClaimsValidation = true
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa.go
new file mode 100644
index 000000000000..b910b19c0b51
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa.go
@@ -0,0 +1,101 @@
+package jwt
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+)
+
+// SigningMethodRSA implements the RSA family of signing methods.
+// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
+type SigningMethodRSA struct {
+ Name string
+ Hash crypto.Hash
+}
+
+// Specific instances for RS256 and company
+var (
+ SigningMethodRS256 *SigningMethodRSA
+ SigningMethodRS384 *SigningMethodRSA
+ SigningMethodRS512 *SigningMethodRSA
+)
+
+func init() {
+ // RS256
+ SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256}
+ RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod {
+ return SigningMethodRS256
+ })
+
+ // RS384
+ SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384}
+ RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod {
+ return SigningMethodRS384
+ })
+
+ // RS512
+ SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512}
+ RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod {
+ return SigningMethodRS512
+ })
+}
+
+func (m *SigningMethodRSA) Alg() string {
+ return m.Name
+}
+
+// Verify implements token verification for the SigningMethod
+// For this signing method, must be an *rsa.PublicKey structure.
+func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
+ var err error
+
+ // Decode the signature
+ var sig []byte
+ if sig, err = DecodeSegment(signature); err != nil {
+ return err
+ }
+
+ var rsaKey *rsa.PublicKey
+ var ok bool
+
+ if rsaKey, ok = key.(*rsa.PublicKey); !ok {
+ return ErrInvalidKeyType
+ }
+
+ // Create hasher
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Verify the signature
+ return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
+}
+
+// Sign implements token signing for the SigningMethod
+// For this signing method, must be an *rsa.PrivateKey structure.
+func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
+ var rsaKey *rsa.PrivateKey
+ var ok bool
+
+ // Validate type of key
+ if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
+ return "", ErrInvalidKey
+ }
+
+ // Create the hasher
+ if !m.Hash.Available() {
+ return "", ErrHashUnavailable
+ }
+
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Sign the string and return the encoded bytes
+ if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil {
+ return EncodeSegment(sigBytes), nil
+ } else {
+ return "", err
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa_pss.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa_pss.go
new file mode 100644
index 000000000000..4fd6f9e610b0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa_pss.go
@@ -0,0 +1,143 @@
+//go:build go1.4
+// +build go1.4
+
+package jwt
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+)
+
+// SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
+type SigningMethodRSAPSS struct {
+ *SigningMethodRSA
+ Options *rsa.PSSOptions
+ // VerifyOptions is optional. If set overrides Options for rsa.VerifyPPS.
+ // Used to accept tokens signed with rsa.PSSSaltLengthAuto, what doesn't follow
+ // https://tools.ietf.org/html/rfc7518#section-3.5 but was used previously.
+ // See https://github.com/dgrijalva/jwt-go/issues/285#issuecomment-437451244 for details.
+ VerifyOptions *rsa.PSSOptions
+}
+
+// Specific instances for RS/PS and company.
+var (
+ SigningMethodPS256 *SigningMethodRSAPSS
+ SigningMethodPS384 *SigningMethodRSAPSS
+ SigningMethodPS512 *SigningMethodRSAPSS
+)
+
+func init() {
+ // PS256
+ SigningMethodPS256 = &SigningMethodRSAPSS{
+ SigningMethodRSA: &SigningMethodRSA{
+ Name: "PS256",
+ Hash: crypto.SHA256,
+ },
+ Options: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ },
+ VerifyOptions: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ },
+ }
+ RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
+ return SigningMethodPS256
+ })
+
+ // PS384
+ SigningMethodPS384 = &SigningMethodRSAPSS{
+ SigningMethodRSA: &SigningMethodRSA{
+ Name: "PS384",
+ Hash: crypto.SHA384,
+ },
+ Options: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ },
+ VerifyOptions: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ },
+ }
+ RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
+ return SigningMethodPS384
+ })
+
+ // PS512
+ SigningMethodPS512 = &SigningMethodRSAPSS{
+ SigningMethodRSA: &SigningMethodRSA{
+ Name: "PS512",
+ Hash: crypto.SHA512,
+ },
+ Options: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ },
+ VerifyOptions: &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthAuto,
+ },
+ }
+ RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
+ return SigningMethodPS512
+ })
+}
+
+// Verify implements token verification for the SigningMethod.
+// For this verify method, key must be an rsa.PublicKey struct
+func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
+ var err error
+
+ // Decode the signature
+ var sig []byte
+ if sig, err = DecodeSegment(signature); err != nil {
+ return err
+ }
+
+ var rsaKey *rsa.PublicKey
+ switch k := key.(type) {
+ case *rsa.PublicKey:
+ rsaKey = k
+ default:
+ return ErrInvalidKey
+ }
+
+ // Create hasher
+ if !m.Hash.Available() {
+ return ErrHashUnavailable
+ }
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ opts := m.Options
+ if m.VerifyOptions != nil {
+ opts = m.VerifyOptions
+ }
+
+ return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
+}
+
+// Sign implements token signing for the SigningMethod.
+// For this signing method, key must be an rsa.PrivateKey struct
+func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
+ var rsaKey *rsa.PrivateKey
+
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ rsaKey = k
+ default:
+ return "", ErrInvalidKeyType
+ }
+
+ // Create the hasher
+ if !m.Hash.Available() {
+ return "", ErrHashUnavailable
+ }
+
+ hasher := m.Hash.New()
+ hasher.Write([]byte(signingString))
+
+ // Sign the string and return the encoded bytes
+ if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
+ return EncodeSegment(sigBytes), nil
+ } else {
+ return "", err
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa_utils.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa_utils.go
new file mode 100644
index 000000000000..1966c450bf8b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/rsa_utils.go
@@ -0,0 +1,105 @@
+package jwt
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key")
+ ErrNotRSAPrivateKey = errors.New("key is not a valid RSA private key")
+ ErrNotRSAPublicKey = errors.New("key is not a valid RSA public key")
+)
+
+// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key
+func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ var parsedKey interface{}
+ if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+ return nil, err
+ }
+ }
+
+ var pkey *rsa.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
+ return nil, ErrNotRSAPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseRSAPrivateKeyFromPEMWithPassword parses a PEM encoded PKCS1 or PKCS8 private key protected with password
+//
+// Deprecated: This function is deprecated and should not be used anymore. It uses the deprecated x509.DecryptPEMBlock
+// function, which was deprecated since RFC 1423 is regarded insecure by design. Unfortunately, there is no alternative
+// in the Go standard library for now. See https://github.com/golang/go/issues/8860.
+func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ var parsedKey interface{}
+
+ var blockDecrypted []byte
+ if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
+ return nil, err
+ }
+
+ if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
+ if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
+ return nil, err
+ }
+ }
+
+ var pkey *rsa.PrivateKey
+ var ok bool
+ if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
+ return nil, ErrNotRSAPrivateKey
+ }
+
+ return pkey, nil
+}
+
+// ParseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
+func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
+ var err error
+
+ // Parse PEM block
+ var block *pem.Block
+ if block, _ = pem.Decode(key); block == nil {
+ return nil, ErrKeyMustBePEMEncoded
+ }
+
+ // Parse the key
+ var parsedKey interface{}
+ if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+ if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
+ parsedKey = cert.PublicKey
+ } else {
+ return nil, err
+ }
+ }
+
+ var pkey *rsa.PublicKey
+ var ok bool
+ if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
+ return nil, ErrNotRSAPublicKey
+ }
+
+ return pkey, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/signing_method.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/signing_method.go
new file mode 100644
index 000000000000..241ae9c60d08
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/signing_method.go
@@ -0,0 +1,46 @@
+package jwt
+
+import (
+ "sync"
+)
+
+var signingMethods = map[string]func() SigningMethod{}
+var signingMethodLock = new(sync.RWMutex)
+
+// SigningMethod can be used add new methods for signing or verifying tokens.
+type SigningMethod interface {
+ Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid
+ Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error
+ Alg() string // returns the alg identifier for this method (example: 'HS256')
+}
+
+// RegisterSigningMethod registers the "alg" name and a factory function for signing method.
+// This is typically done during init() in the method's implementation
+func RegisterSigningMethod(alg string, f func() SigningMethod) {
+ signingMethodLock.Lock()
+ defer signingMethodLock.Unlock()
+
+ signingMethods[alg] = f
+}
+
+// GetSigningMethod retrieves a signing method from an "alg" string
+func GetSigningMethod(alg string) (method SigningMethod) {
+ signingMethodLock.RLock()
+ defer signingMethodLock.RUnlock()
+
+ if methodF, ok := signingMethods[alg]; ok {
+ method = methodF()
+ }
+ return
+}
+
+// GetAlgorithms returns a list of registered "alg" names
+func GetAlgorithms() (algs []string) {
+ signingMethodLock.RLock()
+ defer signingMethodLock.RUnlock()
+
+ for alg := range signingMethods {
+ algs = append(algs, alg)
+ }
+ return
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/staticcheck.conf b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/staticcheck.conf
new file mode 100644
index 000000000000..53745d51d7c7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/staticcheck.conf
@@ -0,0 +1 @@
+checks = ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1023"]
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go
deleted file mode 100644
index a64a6c31e323..000000000000
--- a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go
+++ /dev/null
@@ -1,336 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/golang-jwt/jwt/v4, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/golang-jwt/jwt/v4 (exports: MapClaims,RegisteredClaims,SigningMethodRSA,SigningMethodHMAC,Token; functions: NewNumericDate,NewWithClaims,New)
-
-// Package jwt is a stub of github.com/golang-jwt/jwt/v4, generated by depstubber.
-package jwt
-
-import (
- crypto "crypto"
- time "time"
-)
-
-type ClaimStrings []string
-
-func (_ ClaimStrings) MarshalJSON() ([]byte, error) {
- return nil, nil
-}
-
-func (_ *ClaimStrings) UnmarshalJSON(_ []byte) error {
- return nil
-}
-
-type Claims interface {
- Valid() error
-}
-
-type MapClaims map[string]interface{}
-
-func (_ MapClaims) Valid() error {
- return nil
-}
-
-func (_ MapClaims) VerifyAudience(_ string, _ bool) bool {
- return false
-}
-
-func (_ MapClaims) VerifyExpiresAt(_ int64, _ bool) bool {
- return false
-}
-
-func (_ MapClaims) VerifyIssuedAt(_ int64, _ bool) bool {
- return false
-}
-
-func (_ MapClaims) VerifyIssuer(_ string, _ bool) bool {
- return false
-}
-
-func (_ MapClaims) VerifyNotBefore(_ int64, _ bool) bool {
- return false
-}
-
-func New(_ SigningMethod) *Token {
- return nil
-}
-
-func NewNumericDate(_ time.Time) *NumericDate {
- return nil
-}
-
-func NewWithClaims(_ SigningMethod, _ Claims) *Token {
- return nil
-}
-
-type NumericDate struct {
- Time time.Time
-}
-
-func (_ NumericDate) Add(_ time.Duration) time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) AddDate(_ int, _ int, _ int) time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) After(_ time.Time) bool {
- return false
-}
-
-func (_ NumericDate) AppendFormat(_ []byte, _ string) []byte {
- return nil
-}
-
-func (_ NumericDate) Before(_ time.Time) bool {
- return false
-}
-
-func (_ NumericDate) Clock() (int, int, int) {
- return 0, 0, 0
-}
-
-func (_ NumericDate) Date() (int, time.Month, int) {
- return 0, 0, 0
-}
-
-func (_ NumericDate) Day() int {
- return 0
-}
-
-func (_ NumericDate) Equal(_ time.Time) bool {
- return false
-}
-
-func (_ NumericDate) Format(_ string) string {
- return ""
-}
-
-func (_ NumericDate) GoString() string {
- return ""
-}
-
-func (_ NumericDate) GobEncode() ([]byte, error) {
- return nil, nil
-}
-
-func (_ NumericDate) Hour() int {
- return 0
-}
-
-func (_ NumericDate) ISOWeek() (int, int) {
- return 0, 0
-}
-
-func (_ NumericDate) In(_ *time.Location) time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) IsDST() bool {
- return false
-}
-
-func (_ NumericDate) IsZero() bool {
- return false
-}
-
-func (_ NumericDate) Local() time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) Location() *time.Location {
- return nil
-}
-
-func (_ NumericDate) MarshalBinary() ([]byte, error) {
- return nil, nil
-}
-
-func (_ NumericDate) MarshalJSON() ([]byte, error) {
- return nil, nil
-}
-
-func (_ NumericDate) MarshalText() ([]byte, error) {
- return nil, nil
-}
-
-func (_ NumericDate) Minute() int {
- return 0
-}
-
-func (_ NumericDate) Month() time.Month {
- return 0
-}
-
-func (_ NumericDate) Nanosecond() int {
- return 0
-}
-
-func (_ NumericDate) Round(_ time.Duration) time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) Second() int {
- return 0
-}
-
-func (_ NumericDate) String() string {
- return ""
-}
-
-func (_ NumericDate) Sub(_ time.Time) time.Duration {
- return 0
-}
-
-func (_ NumericDate) Truncate(_ time.Duration) time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) UTC() time.Time {
- return time.Time{}
-}
-
-func (_ NumericDate) Unix() int64 {
- return 0
-}
-
-func (_ NumericDate) UnixMicro() int64 {
- return 0
-}
-
-func (_ NumericDate) UnixMilli() int64 {
- return 0
-}
-
-func (_ NumericDate) UnixNano() int64 {
- return 0
-}
-
-func (_ NumericDate) Weekday() time.Weekday {
- return 0
-}
-
-func (_ NumericDate) Year() int {
- return 0
-}
-
-func (_ NumericDate) YearDay() int {
- return 0
-}
-
-func (_ NumericDate) Zone() (string, int) {
- return "", 0
-}
-
-func (_ NumericDate) ZoneBounds() (time.Time, time.Time) {
- return time.Time{}, time.Time{}
-}
-
-func (_ *NumericDate) GobDecode(_ []byte) error {
- return nil
-}
-
-func (_ *NumericDate) UnmarshalBinary(_ []byte) error {
- return nil
-}
-
-func (_ *NumericDate) UnmarshalJSON(_ []byte) error {
- return nil
-}
-
-func (_ *NumericDate) UnmarshalText(_ []byte) error {
- return nil
-}
-
-type RegisteredClaims struct {
- Issuer string
- Subject string
- Audience ClaimStrings
- ExpiresAt *NumericDate
- NotBefore *NumericDate
- IssuedAt *NumericDate
- ID string
-}
-
-func (_ RegisteredClaims) Valid() error {
- return nil
-}
-
-func (_ *RegisteredClaims) VerifyAudience(_ string, _ bool) bool {
- return false
-}
-
-func (_ *RegisteredClaims) VerifyExpiresAt(_ time.Time, _ bool) bool {
- return false
-}
-
-func (_ *RegisteredClaims) VerifyIssuedAt(_ time.Time, _ bool) bool {
- return false
-}
-
-func (_ *RegisteredClaims) VerifyIssuer(_ string, _ bool) bool {
- return false
-}
-
-func (_ *RegisteredClaims) VerifyNotBefore(_ time.Time, _ bool) bool {
- return false
-}
-
-type SigningMethod interface {
- Alg() string
- Sign(_ string, _ interface{}) (string, error)
- Verify(_ string, _ string, _ interface{}) error
-}
-
-type SigningMethodHMAC struct {
- Name string
- Hash crypto.Hash
-}
-
-func (_ *SigningMethodHMAC) Alg() string {
- return ""
-}
-
-func (_ *SigningMethodHMAC) Sign(_ string, _ interface{}) (string, error) {
- return "", nil
-}
-
-func (_ *SigningMethodHMAC) Verify(_ string, _ string, _ interface{}) error {
- return nil
-}
-
-type SigningMethodRSA struct {
- Name string
- Hash crypto.Hash
-}
-
-func (_ *SigningMethodRSA) Alg() string {
- return ""
-}
-
-func (_ *SigningMethodRSA) Sign(_ string, _ interface{}) (string, error) {
- return "", nil
-}
-
-func (_ *SigningMethodRSA) Verify(_ string, _ string, _ interface{}) error {
- return nil
-}
-
-type Token struct {
- Raw string
- Method SigningMethod
- Header map[string]interface{}
- Claims Claims
- Signature string
- Valid bool
-}
-
-func (_ *Token) SignedString(_ interface{}) (string, error) {
- return "", nil
-}
-
-func (_ *Token) SigningString() (string, error) {
- return "", nil
-}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/token.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/token.go
new file mode 100644
index 000000000000..786b275ce03a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/token.go
@@ -0,0 +1,143 @@
+package jwt
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "strings"
+ "time"
+)
+
+// DecodePaddingAllowed will switch the codec used for decoding JWTs respectively. Note that the JWS RFC7515
+// states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations
+// of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global
+// variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe.
+// To use the non-recommended decoding, set this boolean to `true` prior to using this package.
+var DecodePaddingAllowed bool
+
+// DecodeStrict will switch the codec used for decoding JWTs into strict mode.
+// In this mode, the decoder requires that trailing padding bits are zero, as described in RFC 4648 section 3.5.
+// Note that this is a global variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe.
+// To use strict decoding, set this boolean to `true` prior to using this package.
+var DecodeStrict bool
+
+// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
+// You can override it to use another time value. This is useful for testing or if your
+// server uses a different time zone than your tokens.
+var TimeFunc = time.Now
+
+// Keyfunc will be used by the Parse methods as a callback function to supply
+// the key for verification. The function receives the parsed,
+// but unverified Token. This allows you to use properties in the
+// Header of the token (such as `kid`) to identify which key to use.
+type Keyfunc func(*Token) (interface{}, error)
+
+// Token represents a JWT Token. Different fields will be used depending on whether you're
+// creating or parsing/verifying a token.
+type Token struct {
+ Raw string // The raw token. Populated when you Parse a token
+ Method SigningMethod // The signing method used or to be used
+ Header map[string]interface{} // The first segment of the token
+ Claims Claims // The second segment of the token
+ Signature string // The third segment of the token. Populated when you Parse a token
+ Valid bool // Is the token valid? Populated when you Parse/Verify a token
+}
+
+// New creates a new Token with the specified signing method and an empty map of claims.
+func New(method SigningMethod) *Token {
+ return NewWithClaims(method, MapClaims{})
+}
+
+// NewWithClaims creates a new Token with the specified signing method and claims.
+func NewWithClaims(method SigningMethod, claims Claims) *Token {
+ return &Token{
+ Header: map[string]interface{}{
+ "typ": "JWT",
+ "alg": method.Alg(),
+ },
+ Claims: claims,
+ Method: method,
+ }
+}
+
+// SignedString creates and returns a complete, signed JWT.
+// The token is signed using the SigningMethod specified in the token.
+func (t *Token) SignedString(key interface{}) (string, error) {
+ var sig, sstr string
+ var err error
+ if sstr, err = t.SigningString(); err != nil {
+ return "", err
+ }
+ if sig, err = t.Method.Sign(sstr, key); err != nil {
+ return "", err
+ }
+ return strings.Join([]string{sstr, sig}, "."), nil
+}
+
+// SigningString generates the signing string. This is the
+// most expensive part of the whole deal. Unless you
+// need this for something special, just go straight for
+// the SignedString.
+func (t *Token) SigningString() (string, error) {
+ var err error
+ var jsonValue []byte
+
+ if jsonValue, err = json.Marshal(t.Header); err != nil {
+ return "", err
+ }
+ header := EncodeSegment(jsonValue)
+
+ if jsonValue, err = json.Marshal(t.Claims); err != nil {
+ return "", err
+ }
+ claim := EncodeSegment(jsonValue)
+
+ return strings.Join([]string{header, claim}, "."), nil
+}
+
+// Parse parses, validates, verifies the signature and returns the parsed token.
+// keyFunc will receive the parsed token and should return the cryptographic key
+// for verifying the signature.
+// The caller is strongly encouraged to set the WithValidMethods option to
+// validate the 'alg' claim in the token matches the expected algorithm.
+// For more details about the importance of validating the 'alg' claim,
+// see https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
+func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
+ return NewParser(options...).Parse(tokenString, keyFunc)
+}
+
+// ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
+//
+// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
+// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
+// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
+func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
+ return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
+}
+
+// EncodeSegment encodes a JWT specific base64url encoding with padding stripped
+//
+// Deprecated: In a future release, we will demote this function to a non-exported function, since it
+// should only be used internally
+func EncodeSegment(seg []byte) string {
+ return base64.RawURLEncoding.EncodeToString(seg)
+}
+
+// DecodeSegment decodes a JWT specific base64url encoding with padding stripped
+//
+// Deprecated: In a future release, we will demote this function to a non-exported function, since it
+// should only be used internally
+func DecodeSegment(seg string) ([]byte, error) {
+ encoding := base64.RawURLEncoding
+
+ if DecodePaddingAllowed {
+ if l := len(seg) % 4; l > 0 {
+ seg += strings.Repeat("=", 4-l)
+ }
+ encoding = base64.URLEncoding
+ }
+
+ if DecodeStrict {
+ encoding = encoding.Strict()
+ }
+ return encoding.DecodeString(seg)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/types.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/types.go
new file mode 100644
index 000000000000..ac8e140eb119
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/types.go
@@ -0,0 +1,145 @@
+package jwt
+
+import (
+ "encoding/json"
+ "fmt"
+ "math"
+ "reflect"
+ "strconv"
+ "time"
+)
+
+// TimePrecision sets the precision of times and dates within this library.
+// This has an influence on the precision of times when comparing expiry or
+// other related time fields. Furthermore, it is also the precision of times
+// when serializing.
+//
+// For backwards compatibility the default precision is set to seconds, so that
+// no fractional timestamps are generated.
+var TimePrecision = time.Second
+
+// MarshalSingleStringAsArray modifies the behaviour of the ClaimStrings type, especially
+// its MarshalJSON function.
+//
+// If it is set to true (the default), it will always serialize the type as an
+// array of strings, even if it just contains one element, defaulting to the behaviour
+// of the underlying []string. If it is set to false, it will serialize to a single
+// string, if it contains one element. Otherwise, it will serialize to an array of strings.
+var MarshalSingleStringAsArray = true
+
+// NumericDate represents a JSON numeric date value, as referenced at
+// https://datatracker.ietf.org/doc/html/rfc7519#section-2.
+type NumericDate struct {
+ time.Time
+}
+
+// NewNumericDate constructs a new *NumericDate from a standard library time.Time struct.
+// It will truncate the timestamp according to the precision specified in TimePrecision.
+func NewNumericDate(t time.Time) *NumericDate {
+ return &NumericDate{t.Truncate(TimePrecision)}
+}
+
+// newNumericDateFromSeconds creates a new *NumericDate out of a float64 representing a
+// UNIX epoch with the float fraction representing non-integer seconds.
+func newNumericDateFromSeconds(f float64) *NumericDate {
+ round, frac := math.Modf(f)
+ return NewNumericDate(time.Unix(int64(round), int64(frac*1e9)))
+}
+
+// MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch
+// represented in NumericDate to a byte array, using the precision specified in TimePrecision.
+func (date NumericDate) MarshalJSON() (b []byte, err error) {
+ var prec int
+ if TimePrecision < time.Second {
+ prec = int(math.Log10(float64(time.Second) / float64(TimePrecision)))
+ }
+ truncatedDate := date.Truncate(TimePrecision)
+
+ // For very large timestamps, UnixNano would overflow an int64, but this
+ // function requires nanosecond level precision, so we have to use the
+ // following technique to get round the issue:
+ // 1. Take the normal unix timestamp to form the whole number part of the
+ // output,
+ // 2. Take the result of the Nanosecond function, which retuns the offset
+ // within the second of the particular unix time instance, to form the
+ // decimal part of the output
+ // 3. Concatenate them to produce the final result
+ seconds := strconv.FormatInt(truncatedDate.Unix(), 10)
+ nanosecondsOffset := strconv.FormatFloat(float64(truncatedDate.Nanosecond())/float64(time.Second), 'f', prec, 64)
+
+ output := append([]byte(seconds), []byte(nanosecondsOffset)[1:]...)
+
+ return output, nil
+}
+
+// UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a
+// NumericDate from a JSON representation, i.e. a json.Number. This number represents an UNIX epoch
+// with either integer or non-integer seconds.
+func (date *NumericDate) UnmarshalJSON(b []byte) (err error) {
+ var (
+ number json.Number
+ f float64
+ )
+
+ if err = json.Unmarshal(b, &number); err != nil {
+ return fmt.Errorf("could not parse NumericData: %w", err)
+ }
+
+ if f, err = number.Float64(); err != nil {
+ return fmt.Errorf("could not convert json number value to float: %w", err)
+ }
+
+ n := newNumericDateFromSeconds(f)
+ *date = *n
+
+ return nil
+}
+
+// ClaimStrings is basically just a slice of strings, but it can be either serialized from a string array or just a string.
+// This type is necessary, since the "aud" claim can either be a single string or an array.
+type ClaimStrings []string
+
+func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
+ var value interface{}
+
+ if err = json.Unmarshal(data, &value); err != nil {
+ return err
+ }
+
+ var aud []string
+
+ switch v := value.(type) {
+ case string:
+ aud = append(aud, v)
+ case []string:
+ aud = ClaimStrings(v)
+ case []interface{}:
+ for _, vv := range v {
+ vs, ok := vv.(string)
+ if !ok {
+ return &json.UnsupportedTypeError{Type: reflect.TypeOf(vv)}
+ }
+ aud = append(aud, vs)
+ }
+ case nil:
+ return nil
+ default:
+ return &json.UnsupportedTypeError{Type: reflect.TypeOf(v)}
+ }
+
+ *s = aud
+
+ return
+}
+
+func (s ClaimStrings) MarshalJSON() (b []byte, err error) {
+ // This handles a special case in the JWT RFC. If the string array, e.g. used by the "aud" field,
+ // only contains one element, it MAY be serialized as a single string. This may or may not be
+ // desired based on the ecosystem of other JWT library used, so we make it configurable by the
+ // variable MarshalSingleStringAsArray.
+ if len(s) == 1 && !MarshalSingleStringAsArray {
+ return json.Marshal(s[0])
+ }
+
+ return json.Marshal([]string(s))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/AUTHORS b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/AUTHORS
new file mode 100644
index 000000000000..15167cd746c5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/CONTRIBUTORS b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/CONTRIBUTORS
new file mode 100644
index 000000000000..1c4577e96806
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/LICENSE
new file mode 100644
index 000000000000..0f646931a462
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2010 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/decode.go
new file mode 100644
index 000000000000..6c16c255ffba
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/decode.go
@@ -0,0 +1,530 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonpb
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+ "google.golang.org/protobuf/encoding/protojson"
+ protoV2 "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+)
+
+const wrapJSONUnmarshalV2 = false
+
+// UnmarshalNext unmarshals the next JSON object from d into m.
+func UnmarshalNext(d *json.Decoder, m proto.Message) error {
+ return new(Unmarshaler).UnmarshalNext(d, m)
+}
+
+// Unmarshal unmarshals a JSON object from r into m.
+func Unmarshal(r io.Reader, m proto.Message) error {
+ return new(Unmarshaler).Unmarshal(r, m)
+}
+
+// UnmarshalString unmarshals a JSON object from s into m.
+func UnmarshalString(s string, m proto.Message) error {
+ return new(Unmarshaler).Unmarshal(strings.NewReader(s), m)
+}
+
+// Unmarshaler is a configurable object for converting from a JSON
+// representation to a protocol buffer object.
+type Unmarshaler struct {
+ // AllowUnknownFields specifies whether to allow messages to contain
+ // unknown JSON fields, as opposed to failing to unmarshal.
+ AllowUnknownFields bool
+
+ // AnyResolver is used to resolve the google.protobuf.Any well-known type.
+ // If unset, the global registry is used by default.
+ AnyResolver AnyResolver
+}
+
+// JSONPBUnmarshaler is implemented by protobuf messages that customize the way
+// they are unmarshaled from JSON. Messages that implement this should also
+// implement JSONPBMarshaler so that the custom format can be produced.
+//
+// The JSON unmarshaling must follow the JSON to proto specification:
+// https://developers.google.com/protocol-buffers/docs/proto3#json
+//
+// Deprecated: Custom types should implement protobuf reflection instead.
+type JSONPBUnmarshaler interface {
+ UnmarshalJSONPB(*Unmarshaler, []byte) error
+}
+
+// Unmarshal unmarshals a JSON object from r into m.
+func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error {
+ return u.UnmarshalNext(json.NewDecoder(r), m)
+}
+
+// UnmarshalNext unmarshals the next JSON object from d into m.
+func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error {
+ if m == nil {
+ return errors.New("invalid nil message")
+ }
+
+ // Parse the next JSON object from the stream.
+ raw := json.RawMessage{}
+ if err := d.Decode(&raw); err != nil {
+ return err
+ }
+
+ // Check for custom unmarshalers first since they may not properly
+ // implement protobuf reflection that the logic below relies on.
+ if jsu, ok := m.(JSONPBUnmarshaler); ok {
+ return jsu.UnmarshalJSONPB(u, raw)
+ }
+
+ mr := proto.MessageReflect(m)
+
+ // NOTE: For historical reasons, a top-level null is treated as a noop.
+ // This is incorrect, but kept for compatibility.
+ if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" {
+ return nil
+ }
+
+ if wrapJSONUnmarshalV2 {
+ // NOTE: If input message is non-empty, we need to preserve merge semantics
+ // of the old jsonpb implementation. These semantics are not supported by
+ // the protobuf JSON specification.
+ isEmpty := true
+ mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool {
+ isEmpty = false // at least one iteration implies non-empty
+ return false
+ })
+ if !isEmpty {
+ // Perform unmarshaling into a newly allocated, empty message.
+ mr = mr.New()
+
+ // Use a defer to copy all unmarshaled fields into the original message.
+ dst := proto.MessageReflect(m)
+ defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ dst.Set(fd, v)
+ return true
+ })
+ }
+
+ // Unmarshal using the v2 JSON unmarshaler.
+ opts := protojson.UnmarshalOptions{
+ DiscardUnknown: u.AllowUnknownFields,
+ }
+ if u.AnyResolver != nil {
+ opts.Resolver = anyResolver{u.AnyResolver}
+ }
+ return opts.Unmarshal(raw, mr.Interface())
+ } else {
+ if err := u.unmarshalMessage(mr, raw); err != nil {
+ return err
+ }
+ return protoV2.CheckInitialized(mr.Interface())
+ }
+}
+
+func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error {
+ md := m.Descriptor()
+ fds := md.Fields()
+
+ if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok {
+ return jsu.UnmarshalJSONPB(u, in)
+ }
+
+ if string(in) == "null" && md.FullName() != "google.protobuf.Value" {
+ return nil
+ }
+
+ switch wellKnownType(md.FullName()) {
+ case "Any":
+ var jsonObject map[string]json.RawMessage
+ if err := json.Unmarshal(in, &jsonObject); err != nil {
+ return err
+ }
+
+ rawTypeURL, ok := jsonObject["@type"]
+ if !ok {
+ return errors.New("Any JSON doesn't have '@type'")
+ }
+ typeURL, err := unquoteString(string(rawTypeURL))
+ if err != nil {
+ return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL)
+ }
+ m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL))
+
+ var m2 protoreflect.Message
+ if u.AnyResolver != nil {
+ mi, err := u.AnyResolver.Resolve(typeURL)
+ if err != nil {
+ return err
+ }
+ m2 = proto.MessageReflect(mi)
+ } else {
+ mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
+ if err != nil {
+ if err == protoregistry.NotFound {
+ return fmt.Errorf("could not resolve Any message type: %v", typeURL)
+ }
+ return err
+ }
+ m2 = mt.New()
+ }
+
+ if wellKnownType(m2.Descriptor().FullName()) != "" {
+ rawValue, ok := jsonObject["value"]
+ if !ok {
+ return errors.New("Any JSON doesn't have 'value'")
+ }
+ if err := u.unmarshalMessage(m2, rawValue); err != nil {
+ return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
+ }
+ } else {
+ delete(jsonObject, "@type")
+ rawJSON, err := json.Marshal(jsonObject)
+ if err != nil {
+ return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err)
+ }
+ if err = u.unmarshalMessage(m2, rawJSON); err != nil {
+ return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
+ }
+ }
+
+ rawWire, err := protoV2.Marshal(m2.Interface())
+ if err != nil {
+ return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err)
+ }
+ m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire))
+ return nil
+ case "BoolValue", "BytesValue", "StringValue",
+ "Int32Value", "UInt32Value", "FloatValue",
+ "Int64Value", "UInt64Value", "DoubleValue":
+ fd := fds.ByNumber(1)
+ v, err := u.unmarshalValue(m.NewField(fd), in, fd)
+ if err != nil {
+ return err
+ }
+ m.Set(fd, v)
+ return nil
+ case "Duration":
+ v, err := unquoteString(string(in))
+ if err != nil {
+ return err
+ }
+ d, err := time.ParseDuration(v)
+ if err != nil {
+ return fmt.Errorf("bad Duration: %v", err)
+ }
+
+ sec := d.Nanoseconds() / 1e9
+ nsec := d.Nanoseconds() % 1e9
+ m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
+ m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
+ return nil
+ case "Timestamp":
+ v, err := unquoteString(string(in))
+ if err != nil {
+ return err
+ }
+ t, err := time.Parse(time.RFC3339Nano, v)
+ if err != nil {
+ return fmt.Errorf("bad Timestamp: %v", err)
+ }
+
+ sec := t.Unix()
+ nsec := t.Nanosecond()
+ m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
+ m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
+ return nil
+ case "Value":
+ switch {
+ case string(in) == "null":
+ m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0))
+ case string(in) == "true":
+ m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true))
+ case string(in) == "false":
+ m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false))
+ case hasPrefixAndSuffix('"', in, '"'):
+ s, err := unquoteString(string(in))
+ if err != nil {
+ return fmt.Errorf("unrecognized type for Value %q", in)
+ }
+ m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s))
+ case hasPrefixAndSuffix('[', in, ']'):
+ v := m.Mutable(fds.ByNumber(6))
+ return u.unmarshalMessage(v.Message(), in)
+ case hasPrefixAndSuffix('{', in, '}'):
+ v := m.Mutable(fds.ByNumber(5))
+ return u.unmarshalMessage(v.Message(), in)
+ default:
+ f, err := strconv.ParseFloat(string(in), 0)
+ if err != nil {
+ return fmt.Errorf("unrecognized type for Value %q", in)
+ }
+ m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f))
+ }
+ return nil
+ case "ListValue":
+ var jsonArray []json.RawMessage
+ if err := json.Unmarshal(in, &jsonArray); err != nil {
+ return fmt.Errorf("bad ListValue: %v", err)
+ }
+
+ lv := m.Mutable(fds.ByNumber(1)).List()
+ for _, raw := range jsonArray {
+ ve := lv.NewElement()
+ if err := u.unmarshalMessage(ve.Message(), raw); err != nil {
+ return err
+ }
+ lv.Append(ve)
+ }
+ return nil
+ case "Struct":
+ var jsonObject map[string]json.RawMessage
+ if err := json.Unmarshal(in, &jsonObject); err != nil {
+ return fmt.Errorf("bad StructValue: %v", err)
+ }
+
+ mv := m.Mutable(fds.ByNumber(1)).Map()
+ for key, raw := range jsonObject {
+ kv := protoreflect.ValueOf(key).MapKey()
+ vv := mv.NewValue()
+ if err := u.unmarshalMessage(vv.Message(), raw); err != nil {
+ return fmt.Errorf("bad value in StructValue for key %q: %v", key, err)
+ }
+ mv.Set(kv, vv)
+ }
+ return nil
+ }
+
+ var jsonObject map[string]json.RawMessage
+ if err := json.Unmarshal(in, &jsonObject); err != nil {
+ return err
+ }
+
+ // Handle known fields.
+ for i := 0; i < fds.Len(); i++ {
+ fd := fds.Get(i)
+ if fd.IsWeak() && fd.Message().IsPlaceholder() {
+ continue // weak reference is not linked in
+ }
+
+ // Search for any raw JSON value associated with this field.
+ var raw json.RawMessage
+ name := string(fd.Name())
+ if fd.Kind() == protoreflect.GroupKind {
+ name = string(fd.Message().Name())
+ }
+ if v, ok := jsonObject[name]; ok {
+ delete(jsonObject, name)
+ raw = v
+ }
+ name = string(fd.JSONName())
+ if v, ok := jsonObject[name]; ok {
+ delete(jsonObject, name)
+ raw = v
+ }
+
+ field := m.NewField(fd)
+ // Unmarshal the field value.
+ if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) {
+ continue
+ }
+ v, err := u.unmarshalValue(field, raw, fd)
+ if err != nil {
+ return err
+ }
+ m.Set(fd, v)
+ }
+
+ // Handle extension fields.
+ for name, raw := range jsonObject {
+ if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") {
+ continue
+ }
+
+ // Resolve the extension field by name.
+ xname := protoreflect.FullName(name[len("[") : len(name)-len("]")])
+ xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
+ if xt == nil && isMessageSet(md) {
+ xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
+ }
+ if xt == nil {
+ continue
+ }
+ delete(jsonObject, name)
+ fd := xt.TypeDescriptor()
+ if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
+ return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName())
+ }
+
+ field := m.NewField(fd)
+ // Unmarshal the field value.
+ if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) {
+ continue
+ }
+ v, err := u.unmarshalValue(field, raw, fd)
+ if err != nil {
+ return err
+ }
+ m.Set(fd, v)
+ }
+
+ if !u.AllowUnknownFields && len(jsonObject) > 0 {
+ for name := range jsonObject {
+ return fmt.Errorf("unknown field %q in %v", name, md.FullName())
+ }
+ }
+ return nil
+}
+
+func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool {
+ if fd.Cardinality() == protoreflect.Repeated {
+ return false
+ }
+ if md := fd.Message(); md != nil {
+ return md.FullName() == "google.protobuf.Value"
+ }
+ if ed := fd.Enum(); ed != nil {
+ return ed.FullName() == "google.protobuf.NullValue"
+ }
+ return false
+}
+
+func isSingularJSONPBUnmarshaler(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool {
+ if fd.Message() != nil && fd.Cardinality() != protoreflect.Repeated {
+ _, ok := proto.MessageV1(v.Interface()).(JSONPBUnmarshaler)
+ return ok
+ }
+ return false
+}
+
+func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
+ switch {
+ case fd.IsList():
+ var jsonArray []json.RawMessage
+ if err := json.Unmarshal(in, &jsonArray); err != nil {
+ return v, err
+ }
+ lv := v.List()
+ for _, raw := range jsonArray {
+ ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd)
+ if err != nil {
+ return v, err
+ }
+ lv.Append(ve)
+ }
+ return v, nil
+ case fd.IsMap():
+ var jsonObject map[string]json.RawMessage
+ if err := json.Unmarshal(in, &jsonObject); err != nil {
+ return v, err
+ }
+ kfd := fd.MapKey()
+ vfd := fd.MapValue()
+ mv := v.Map()
+ for key, raw := range jsonObject {
+ var kv protoreflect.MapKey
+ if kfd.Kind() == protoreflect.StringKind {
+ kv = protoreflect.ValueOf(key).MapKey()
+ } else {
+ v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd)
+ if err != nil {
+ return v, err
+ }
+ kv = v.MapKey()
+ }
+
+ vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd)
+ if err != nil {
+ return v, err
+ }
+ mv.Set(kv, vv)
+ }
+ return v, nil
+ default:
+ return u.unmarshalSingularValue(v, in, fd)
+ }
+}
+
+var nonFinite = map[string]float64{
+ `"NaN"`: math.NaN(),
+ `"Infinity"`: math.Inf(+1),
+ `"-Infinity"`: math.Inf(-1),
+}
+
+func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
+ switch fd.Kind() {
+ case protoreflect.BoolKind:
+ return unmarshalValue(in, new(bool))
+ case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
+ return unmarshalValue(trimQuote(in), new(int32))
+ case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
+ return unmarshalValue(trimQuote(in), new(int64))
+ case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
+ return unmarshalValue(trimQuote(in), new(uint32))
+ case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
+ return unmarshalValue(trimQuote(in), new(uint64))
+ case protoreflect.FloatKind:
+ if f, ok := nonFinite[string(in)]; ok {
+ return protoreflect.ValueOfFloat32(float32(f)), nil
+ }
+ return unmarshalValue(trimQuote(in), new(float32))
+ case protoreflect.DoubleKind:
+ if f, ok := nonFinite[string(in)]; ok {
+ return protoreflect.ValueOfFloat64(float64(f)), nil
+ }
+ return unmarshalValue(trimQuote(in), new(float64))
+ case protoreflect.StringKind:
+ return unmarshalValue(in, new(string))
+ case protoreflect.BytesKind:
+ return unmarshalValue(in, new([]byte))
+ case protoreflect.EnumKind:
+ if hasPrefixAndSuffix('"', in, '"') {
+ vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in)))
+ if vd == nil {
+ return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName())
+ }
+ return protoreflect.ValueOfEnum(vd.Number()), nil
+ }
+ return unmarshalValue(in, new(protoreflect.EnumNumber))
+ case protoreflect.MessageKind, protoreflect.GroupKind:
+ err := u.unmarshalMessage(v.Message(), in)
+ return v, err
+ default:
+ panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
+ }
+}
+
+func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) {
+ err := json.Unmarshal(in, v)
+ return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err
+}
+
+func unquoteString(in string) (out string, err error) {
+ err = json.Unmarshal([]byte(in), &out)
+ return out, err
+}
+
+func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool {
+ if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix {
+ return true
+ }
+ return false
+}
+
+// trimQuote is like unquoteString but simply strips surrounding quotes.
+// This is incorrect, but is behavior done by the legacy implementation.
+func trimQuote(in []byte) []byte {
+ if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' {
+ in = in[1 : len(in)-1]
+ }
+ return in
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/encode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/encode.go
new file mode 100644
index 000000000000..685c80a62bc9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/encode.go
@@ -0,0 +1,559 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonpb
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+ "google.golang.org/protobuf/encoding/protojson"
+ protoV2 "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+)
+
+const wrapJSONMarshalV2 = false
+
+// Marshaler is a configurable object for marshaling protocol buffer messages
+// to the specified JSON representation.
+type Marshaler struct {
+ // OrigName specifies whether to use the original protobuf name for fields.
+ OrigName bool
+
+ // EnumsAsInts specifies whether to render enum values as integers,
+ // as opposed to string values.
+ EnumsAsInts bool
+
+ // EmitDefaults specifies whether to render fields with zero values.
+ EmitDefaults bool
+
+ // Indent controls whether the output is compact or not.
+ // If empty, the output is compact JSON. Otherwise, every JSON object
+ // entry and JSON array value will be on its own line.
+ // Each line will be preceded by repeated copies of Indent, where the
+ // number of copies is the current indentation depth.
+ Indent string
+
+ // AnyResolver is used to resolve the google.protobuf.Any well-known type.
+ // If unset, the global registry is used by default.
+ AnyResolver AnyResolver
+}
+
+// JSONPBMarshaler is implemented by protobuf messages that customize the
+// way they are marshaled to JSON. Messages that implement this should also
+// implement JSONPBUnmarshaler so that the custom format can be parsed.
+//
+// The JSON marshaling must follow the proto to JSON specification:
+// https://developers.google.com/protocol-buffers/docs/proto3#json
+//
+// Deprecated: Custom types should implement protobuf reflection instead.
+type JSONPBMarshaler interface {
+ MarshalJSONPB(*Marshaler) ([]byte, error)
+}
+
+// Marshal serializes a protobuf message as JSON into w.
+func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error {
+ b, err := jm.marshal(m)
+ if len(b) > 0 {
+ if _, err := w.Write(b); err != nil {
+ return err
+ }
+ }
+ return err
+}
+
+// MarshalToString serializes a protobuf message as JSON in string form.
+func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) {
+ b, err := jm.marshal(m)
+ if err != nil {
+ return "", err
+ }
+ return string(b), nil
+}
+
+func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) {
+ v := reflect.ValueOf(m)
+ if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) {
+ return nil, errors.New("Marshal called with nil")
+ }
+
+ // Check for custom marshalers first since they may not properly
+ // implement protobuf reflection that the logic below relies on.
+ if jsm, ok := m.(JSONPBMarshaler); ok {
+ return jsm.MarshalJSONPB(jm)
+ }
+
+ if wrapJSONMarshalV2 {
+ opts := protojson.MarshalOptions{
+ UseProtoNames: jm.OrigName,
+ UseEnumNumbers: jm.EnumsAsInts,
+ EmitUnpopulated: jm.EmitDefaults,
+ Indent: jm.Indent,
+ }
+ if jm.AnyResolver != nil {
+ opts.Resolver = anyResolver{jm.AnyResolver}
+ }
+ return opts.Marshal(proto.MessageReflect(m).Interface())
+ } else {
+ // Check for unpopulated required fields first.
+ m2 := proto.MessageReflect(m)
+ if err := protoV2.CheckInitialized(m2.Interface()); err != nil {
+ return nil, err
+ }
+
+ w := jsonWriter{Marshaler: jm}
+ err := w.marshalMessage(m2, "", "")
+ return w.buf, err
+ }
+}
+
+type jsonWriter struct {
+ *Marshaler
+ buf []byte
+}
+
+func (w *jsonWriter) write(s string) {
+ w.buf = append(w.buf, s...)
+}
+
+func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error {
+ if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok {
+ b, err := jsm.MarshalJSONPB(w.Marshaler)
+ if err != nil {
+ return err
+ }
+ if typeURL != "" {
+ // we are marshaling this object to an Any type
+ var js map[string]*json.RawMessage
+ if err = json.Unmarshal(b, &js); err != nil {
+ return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err)
+ }
+ turl, err := json.Marshal(typeURL)
+ if err != nil {
+ return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
+ }
+ js["@type"] = (*json.RawMessage)(&turl)
+ if b, err = json.Marshal(js); err != nil {
+ return err
+ }
+ }
+ w.write(string(b))
+ return nil
+ }
+
+ md := m.Descriptor()
+ fds := md.Fields()
+
+ // Handle well-known types.
+ const secondInNanos = int64(time.Second / time.Nanosecond)
+ switch wellKnownType(md.FullName()) {
+ case "Any":
+ return w.marshalAny(m, indent)
+ case "BoolValue", "BytesValue", "StringValue",
+ "Int32Value", "UInt32Value", "FloatValue",
+ "Int64Value", "UInt64Value", "DoubleValue":
+ fd := fds.ByNumber(1)
+ return w.marshalValue(fd, m.Get(fd), indent)
+ case "Duration":
+ const maxSecondsInDuration = 315576000000
+ // "Generated output always contains 0, 3, 6, or 9 fractional digits,
+ // depending on required precision."
+ s := m.Get(fds.ByNumber(1)).Int()
+ ns := m.Get(fds.ByNumber(2)).Int()
+ if s < -maxSecondsInDuration || s > maxSecondsInDuration {
+ return fmt.Errorf("seconds out of range %v", s)
+ }
+ if ns <= -secondInNanos || ns >= secondInNanos {
+ return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
+ }
+ if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
+ return errors.New("signs of seconds and nanos do not match")
+ }
+ var sign string
+ if s < 0 || ns < 0 {
+ sign, s, ns = "-", -1*s, -1*ns
+ }
+ x := fmt.Sprintf("%s%d.%09d", sign, s, ns)
+ x = strings.TrimSuffix(x, "000")
+ x = strings.TrimSuffix(x, "000")
+ x = strings.TrimSuffix(x, ".000")
+ w.write(fmt.Sprintf(`"%vs"`, x))
+ return nil
+ case "Timestamp":
+ // "RFC 3339, where generated output will always be Z-normalized
+ // and uses 0, 3, 6 or 9 fractional digits."
+ s := m.Get(fds.ByNumber(1)).Int()
+ ns := m.Get(fds.ByNumber(2)).Int()
+ if ns < 0 || ns >= secondInNanos {
+ return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
+ }
+ t := time.Unix(s, ns).UTC()
+ // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
+ x := t.Format("2006-01-02T15:04:05.000000000")
+ x = strings.TrimSuffix(x, "000")
+ x = strings.TrimSuffix(x, "000")
+ x = strings.TrimSuffix(x, ".000")
+ w.write(fmt.Sprintf(`"%vZ"`, x))
+ return nil
+ case "Value":
+ // JSON value; which is a null, number, string, bool, object, or array.
+ od := md.Oneofs().Get(0)
+ fd := m.WhichOneof(od)
+ if fd == nil {
+ return errors.New("nil Value")
+ }
+ return w.marshalValue(fd, m.Get(fd), indent)
+ case "Struct", "ListValue":
+ // JSON object or array.
+ fd := fds.ByNumber(1)
+ return w.marshalValue(fd, m.Get(fd), indent)
+ }
+
+ w.write("{")
+ if w.Indent != "" {
+ w.write("\n")
+ }
+
+ firstField := true
+ if typeURL != "" {
+ if err := w.marshalTypeURL(indent, typeURL); err != nil {
+ return err
+ }
+ firstField = false
+ }
+
+ for i := 0; i < fds.Len(); {
+ fd := fds.Get(i)
+ if od := fd.ContainingOneof(); od != nil {
+ fd = m.WhichOneof(od)
+ i += od.Fields().Len()
+ if fd == nil {
+ continue
+ }
+ } else {
+ i++
+ }
+
+ v := m.Get(fd)
+
+ if !m.Has(fd) {
+ if !w.EmitDefaults || fd.ContainingOneof() != nil {
+ continue
+ }
+ if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) {
+ v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
+ }
+ }
+
+ if !firstField {
+ w.writeComma()
+ }
+ if err := w.marshalField(fd, v, indent); err != nil {
+ return err
+ }
+ firstField = false
+ }
+
+ // Handle proto2 extensions.
+ if md.ExtensionRanges().Len() > 0 {
+ // Collect a sorted list of all extension descriptor and values.
+ type ext struct {
+ desc protoreflect.FieldDescriptor
+ val protoreflect.Value
+ }
+ var exts []ext
+ m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ if fd.IsExtension() {
+ exts = append(exts, ext{fd, v})
+ }
+ return true
+ })
+ sort.Slice(exts, func(i, j int) bool {
+ return exts[i].desc.Number() < exts[j].desc.Number()
+ })
+
+ for _, ext := range exts {
+ if !firstField {
+ w.writeComma()
+ }
+ if err := w.marshalField(ext.desc, ext.val, indent); err != nil {
+ return err
+ }
+ firstField = false
+ }
+ }
+
+ if w.Indent != "" {
+ w.write("\n")
+ w.write(indent)
+ }
+ w.write("}")
+ return nil
+}
+
+func (w *jsonWriter) writeComma() {
+ if w.Indent != "" {
+ w.write(",\n")
+ } else {
+ w.write(",")
+ }
+}
+
+func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error {
+ // "If the Any contains a value that has a special JSON mapping,
+ // it will be converted as follows: {"@type": xxx, "value": yyy}.
+ // Otherwise, the value will be converted into a JSON object,
+ // and the "@type" field will be inserted to indicate the actual data type."
+ md := m.Descriptor()
+ typeURL := m.Get(md.Fields().ByNumber(1)).String()
+ rawVal := m.Get(md.Fields().ByNumber(2)).Bytes()
+
+ var m2 protoreflect.Message
+ if w.AnyResolver != nil {
+ mi, err := w.AnyResolver.Resolve(typeURL)
+ if err != nil {
+ return err
+ }
+ m2 = proto.MessageReflect(mi)
+ } else {
+ mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
+ if err != nil {
+ return err
+ }
+ m2 = mt.New()
+ }
+
+ if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil {
+ return err
+ }
+
+ if wellKnownType(m2.Descriptor().FullName()) == "" {
+ return w.marshalMessage(m2, indent, typeURL)
+ }
+
+ w.write("{")
+ if w.Indent != "" {
+ w.write("\n")
+ }
+ if err := w.marshalTypeURL(indent, typeURL); err != nil {
+ return err
+ }
+ w.writeComma()
+ if w.Indent != "" {
+ w.write(indent)
+ w.write(w.Indent)
+ w.write(`"value": `)
+ } else {
+ w.write(`"value":`)
+ }
+ if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil {
+ return err
+ }
+ if w.Indent != "" {
+ w.write("\n")
+ w.write(indent)
+ }
+ w.write("}")
+ return nil
+}
+
+func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error {
+ if w.Indent != "" {
+ w.write(indent)
+ w.write(w.Indent)
+ }
+ w.write(`"@type":`)
+ if w.Indent != "" {
+ w.write(" ")
+ }
+ b, err := json.Marshal(typeURL)
+ if err != nil {
+ return err
+ }
+ w.write(string(b))
+ return nil
+}
+
+// marshalField writes field description and value to the Writer.
+func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
+ if w.Indent != "" {
+ w.write(indent)
+ w.write(w.Indent)
+ }
+ w.write(`"`)
+ switch {
+ case fd.IsExtension():
+ // For message set, use the fname of the message as the extension name.
+ name := string(fd.FullName())
+ if isMessageSet(fd.ContainingMessage()) {
+ name = strings.TrimSuffix(name, ".message_set_extension")
+ }
+
+ w.write("[" + name + "]")
+ case w.OrigName:
+ name := string(fd.Name())
+ if fd.Kind() == protoreflect.GroupKind {
+ name = string(fd.Message().Name())
+ }
+ w.write(name)
+ default:
+ w.write(string(fd.JSONName()))
+ }
+ w.write(`":`)
+ if w.Indent != "" {
+ w.write(" ")
+ }
+ return w.marshalValue(fd, v, indent)
+}
+
+func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
+ switch {
+ case fd.IsList():
+ w.write("[")
+ comma := ""
+ lv := v.List()
+ for i := 0; i < lv.Len(); i++ {
+ w.write(comma)
+ if w.Indent != "" {
+ w.write("\n")
+ w.write(indent)
+ w.write(w.Indent)
+ w.write(w.Indent)
+ }
+ if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil {
+ return err
+ }
+ comma = ","
+ }
+ if w.Indent != "" {
+ w.write("\n")
+ w.write(indent)
+ w.write(w.Indent)
+ }
+ w.write("]")
+ return nil
+ case fd.IsMap():
+ kfd := fd.MapKey()
+ vfd := fd.MapValue()
+ mv := v.Map()
+
+ // Collect a sorted list of all map keys and values.
+ type entry struct{ key, val protoreflect.Value }
+ var entries []entry
+ mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
+ entries = append(entries, entry{k.Value(), v})
+ return true
+ })
+ sort.Slice(entries, func(i, j int) bool {
+ switch kfd.Kind() {
+ case protoreflect.BoolKind:
+ return !entries[i].key.Bool() && entries[j].key.Bool()
+ case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
+ return entries[i].key.Int() < entries[j].key.Int()
+ case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
+ return entries[i].key.Uint() < entries[j].key.Uint()
+ case protoreflect.StringKind:
+ return entries[i].key.String() < entries[j].key.String()
+ default:
+ panic("invalid kind")
+ }
+ })
+
+ w.write(`{`)
+ comma := ""
+ for _, entry := range entries {
+ w.write(comma)
+ if w.Indent != "" {
+ w.write("\n")
+ w.write(indent)
+ w.write(w.Indent)
+ w.write(w.Indent)
+ }
+
+ s := fmt.Sprint(entry.key.Interface())
+ b, err := json.Marshal(s)
+ if err != nil {
+ return err
+ }
+ w.write(string(b))
+
+ w.write(`:`)
+ if w.Indent != "" {
+ w.write(` `)
+ }
+
+ if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil {
+ return err
+ }
+ comma = ","
+ }
+ if w.Indent != "" {
+ w.write("\n")
+ w.write(indent)
+ w.write(w.Indent)
+ }
+ w.write(`}`)
+ return nil
+ default:
+ return w.marshalSingularValue(fd, v, indent)
+ }
+}
+
+func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
+ switch {
+ case !v.IsValid():
+ w.write("null")
+ return nil
+ case fd.Message() != nil:
+ return w.marshalMessage(v.Message(), indent+w.Indent, "")
+ case fd.Enum() != nil:
+ if fd.Enum().FullName() == "google.protobuf.NullValue" {
+ w.write("null")
+ return nil
+ }
+
+ vd := fd.Enum().Values().ByNumber(v.Enum())
+ if vd == nil || w.EnumsAsInts {
+ w.write(strconv.Itoa(int(v.Enum())))
+ } else {
+ w.write(`"` + string(vd.Name()) + `"`)
+ }
+ return nil
+ default:
+ switch v.Interface().(type) {
+ case float32, float64:
+ switch {
+ case math.IsInf(v.Float(), +1):
+ w.write(`"Infinity"`)
+ return nil
+ case math.IsInf(v.Float(), -1):
+ w.write(`"-Infinity"`)
+ return nil
+ case math.IsNaN(v.Float()):
+ w.write(`"NaN"`)
+ return nil
+ }
+ case int64, uint64:
+ w.write(fmt.Sprintf(`"%d"`, v.Interface()))
+ return nil
+ }
+
+ b, err := json.Marshal(v.Interface())
+ if err != nil {
+ return err
+ }
+ w.write(string(b))
+ return nil
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/json.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/json.go
new file mode 100644
index 000000000000..480e2448de66
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/jsonpb/json.go
@@ -0,0 +1,69 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package jsonpb provides functionality to marshal and unmarshal between a
+// protocol buffer message and JSON. It follows the specification at
+// https://developers.google.com/protocol-buffers/docs/proto3#json.
+//
+// Do not rely on the default behavior of the standard encoding/json package
+// when called on generated message types as it does not operate correctly.
+//
+// Deprecated: Use the "google.golang.org/protobuf/encoding/protojson"
+// package instead.
+package jsonpb
+
+import (
+ "github.com/golang/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+ "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+// AnyResolver takes a type URL, present in an Any message,
+// and resolves it into an instance of the associated message.
+type AnyResolver interface {
+ Resolve(typeURL string) (proto.Message, error)
+}
+
+type anyResolver struct{ AnyResolver }
+
+func (r anyResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {
+ return r.FindMessageByURL(string(message))
+}
+
+func (r anyResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {
+ m, err := r.Resolve(url)
+ if err != nil {
+ return nil, err
+ }
+ return protoimpl.X.MessageTypeOf(m), nil
+}
+
+func (r anyResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
+ return protoregistry.GlobalTypes.FindExtensionByName(field)
+}
+
+func (r anyResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
+ return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
+}
+
+func wellKnownType(s protoreflect.FullName) string {
+ if s.Parent() == "google.protobuf" {
+ switch s.Name() {
+ case "Empty", "Any",
+ "BoolValue", "BytesValue", "StringValue",
+ "Int32Value", "UInt32Value", "FloatValue",
+ "Int64Value", "UInt64Value", "DoubleValue",
+ "Duration", "Timestamp",
+ "NullValue", "Struct", "Value", "ListValue":
+ return string(s.Name())
+ }
+ }
+ return ""
+}
+
+func isMessageSet(md protoreflect.MessageDescriptor) bool {
+ ms, ok := md.(interface{ IsMessageSet() bool })
+ return ok && ms.IsMessageSet()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/buffer.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/buffer.go
new file mode 100644
index 000000000000..e810e6fea129
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/buffer.go
@@ -0,0 +1,324 @@
+// 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 proto
+
+import (
+ "errors"
+ "fmt"
+
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/encoding/protowire"
+ "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+ WireVarint = 0
+ WireFixed32 = 5
+ WireFixed64 = 1
+ WireBytes = 2
+ WireStartGroup = 3
+ WireEndGroup = 4
+)
+
+// EncodeVarint returns the varint encoded bytes of v.
+func EncodeVarint(v uint64) []byte {
+ return protowire.AppendVarint(nil, v)
+}
+
+// SizeVarint returns the length of the varint encoded bytes of v.
+// This is equal to len(EncodeVarint(v)).
+func SizeVarint(v uint64) int {
+ return protowire.SizeVarint(v)
+}
+
+// DecodeVarint parses a varint encoded integer from b,
+// returning the integer value and the length of the varint.
+// It returns (0, 0) if there is a parse error.
+func DecodeVarint(b []byte) (uint64, int) {
+ v, n := protowire.ConsumeVarint(b)
+ if n < 0 {
+ return 0, 0
+ }
+ return v, n
+}
+
+// Buffer is a buffer for encoding and decoding the protobuf wire format.
+// It may be reused between invocations to reduce memory usage.
+type Buffer struct {
+ buf []byte
+ idx int
+ deterministic bool
+}
+
+// NewBuffer allocates a new Buffer initialized with buf,
+// where the contents of buf are considered the unread portion of the buffer.
+func NewBuffer(buf []byte) *Buffer {
+ return &Buffer{buf: buf}
+}
+
+// SetDeterministic specifies whether to use deterministic serialization.
+//
+// Deterministic serialization guarantees that for a given binary, equal
+// messages will always be serialized to the same bytes. This implies:
+//
+// - Repeated serialization of a message will return the same bytes.
+// - Different processes of the same binary (which may be executing on
+// different machines) will serialize equal messages to the same bytes.
+//
+// Note that the deterministic serialization is NOT canonical across
+// languages. It is not guaranteed to remain stable over time. It is unstable
+// across different builds with schema changes due to unknown fields.
+// Users who need canonical serialization (e.g., persistent storage in a
+// canonical form, fingerprinting, etc.) should define their own
+// canonicalization specification and implement their own serializer rather
+// than relying on this API.
+//
+// If deterministic serialization is requested, map entries will be sorted
+// by keys in lexographical order. This is an implementation detail and
+// subject to change.
+func (b *Buffer) SetDeterministic(deterministic bool) {
+ b.deterministic = deterministic
+}
+
+// SetBuf sets buf as the internal buffer,
+// where the contents of buf are considered the unread portion of the buffer.
+func (b *Buffer) SetBuf(buf []byte) {
+ b.buf = buf
+ b.idx = 0
+}
+
+// Reset clears the internal buffer of all written and unread data.
+func (b *Buffer) Reset() {
+ b.buf = b.buf[:0]
+ b.idx = 0
+}
+
+// Bytes returns the internal buffer.
+func (b *Buffer) Bytes() []byte {
+ return b.buf
+}
+
+// Unread returns the unread portion of the buffer.
+func (b *Buffer) Unread() []byte {
+ return b.buf[b.idx:]
+}
+
+// Marshal appends the wire-format encoding of m to the buffer.
+func (b *Buffer) Marshal(m Message) error {
+ var err error
+ b.buf, err = marshalAppend(b.buf, m, b.deterministic)
+ return err
+}
+
+// Unmarshal parses the wire-format message in the buffer and
+// places the decoded results in m.
+// It does not reset m before unmarshaling.
+func (b *Buffer) Unmarshal(m Message) error {
+ err := UnmarshalMerge(b.Unread(), m)
+ b.idx = len(b.buf)
+ return err
+}
+
+type unknownFields struct{ XXX_unrecognized protoimpl.UnknownFields }
+
+func (m *unknownFields) String() string { panic("not implemented") }
+func (m *unknownFields) Reset() { panic("not implemented") }
+func (m *unknownFields) ProtoMessage() { panic("not implemented") }
+
+// DebugPrint dumps the encoded bytes of b with a header and footer including s
+// to stdout. This is only intended for debugging.
+func (*Buffer) DebugPrint(s string, b []byte) {
+ m := MessageReflect(new(unknownFields))
+ m.SetUnknown(b)
+ b, _ = prototext.MarshalOptions{AllowPartial: true, Indent: "\t"}.Marshal(m.Interface())
+ fmt.Printf("==== %s ====\n%s==== %s ====\n", s, b, s)
+}
+
+// EncodeVarint appends an unsigned varint encoding to the buffer.
+func (b *Buffer) EncodeVarint(v uint64) error {
+ b.buf = protowire.AppendVarint(b.buf, v)
+ return nil
+}
+
+// EncodeZigzag32 appends a 32-bit zig-zag varint encoding to the buffer.
+func (b *Buffer) EncodeZigzag32(v uint64) error {
+ return b.EncodeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
+}
+
+// EncodeZigzag64 appends a 64-bit zig-zag varint encoding to the buffer.
+func (b *Buffer) EncodeZigzag64(v uint64) error {
+ return b.EncodeVarint(uint64((uint64(v) << 1) ^ uint64((int64(v) >> 63))))
+}
+
+// EncodeFixed32 appends a 32-bit little-endian integer to the buffer.
+func (b *Buffer) EncodeFixed32(v uint64) error {
+ b.buf = protowire.AppendFixed32(b.buf, uint32(v))
+ return nil
+}
+
+// EncodeFixed64 appends a 64-bit little-endian integer to the buffer.
+func (b *Buffer) EncodeFixed64(v uint64) error {
+ b.buf = protowire.AppendFixed64(b.buf, uint64(v))
+ return nil
+}
+
+// EncodeRawBytes appends a length-prefixed raw bytes to the buffer.
+func (b *Buffer) EncodeRawBytes(v []byte) error {
+ b.buf = protowire.AppendBytes(b.buf, v)
+ return nil
+}
+
+// EncodeStringBytes appends a length-prefixed raw bytes to the buffer.
+// It does not validate whether v contains valid UTF-8.
+func (b *Buffer) EncodeStringBytes(v string) error {
+ b.buf = protowire.AppendString(b.buf, v)
+ return nil
+}
+
+// EncodeMessage appends a length-prefixed encoded message to the buffer.
+func (b *Buffer) EncodeMessage(m Message) error {
+ var err error
+ b.buf = protowire.AppendVarint(b.buf, uint64(Size(m)))
+ b.buf, err = marshalAppend(b.buf, m, b.deterministic)
+ return err
+}
+
+// DecodeVarint consumes an encoded unsigned varint from the buffer.
+func (b *Buffer) DecodeVarint() (uint64, error) {
+ v, n := protowire.ConsumeVarint(b.buf[b.idx:])
+ if n < 0 {
+ return 0, protowire.ParseError(n)
+ }
+ b.idx += n
+ return uint64(v), nil
+}
+
+// DecodeZigzag32 consumes an encoded 32-bit zig-zag varint from the buffer.
+func (b *Buffer) DecodeZigzag32() (uint64, error) {
+ v, err := b.DecodeVarint()
+ if err != nil {
+ return 0, err
+ }
+ return uint64((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31)), nil
+}
+
+// DecodeZigzag64 consumes an encoded 64-bit zig-zag varint from the buffer.
+func (b *Buffer) DecodeZigzag64() (uint64, error) {
+ v, err := b.DecodeVarint()
+ if err != nil {
+ return 0, err
+ }
+ return uint64((uint64(v) >> 1) ^ uint64((int64(v&1)<<63)>>63)), nil
+}
+
+// DecodeFixed32 consumes a 32-bit little-endian integer from the buffer.
+func (b *Buffer) DecodeFixed32() (uint64, error) {
+ v, n := protowire.ConsumeFixed32(b.buf[b.idx:])
+ if n < 0 {
+ return 0, protowire.ParseError(n)
+ }
+ b.idx += n
+ return uint64(v), nil
+}
+
+// DecodeFixed64 consumes a 64-bit little-endian integer from the buffer.
+func (b *Buffer) DecodeFixed64() (uint64, error) {
+ v, n := protowire.ConsumeFixed64(b.buf[b.idx:])
+ if n < 0 {
+ return 0, protowire.ParseError(n)
+ }
+ b.idx += n
+ return uint64(v), nil
+}
+
+// DecodeRawBytes consumes a length-prefixed raw bytes from the buffer.
+// If alloc is specified, it returns a copy the raw bytes
+// rather than a sub-slice of the buffer.
+func (b *Buffer) DecodeRawBytes(alloc bool) ([]byte, error) {
+ v, n := protowire.ConsumeBytes(b.buf[b.idx:])
+ if n < 0 {
+ return nil, protowire.ParseError(n)
+ }
+ b.idx += n
+ if alloc {
+ v = append([]byte(nil), v...)
+ }
+ return v, nil
+}
+
+// DecodeStringBytes consumes a length-prefixed raw bytes from the buffer.
+// It does not validate whether the raw bytes contain valid UTF-8.
+func (b *Buffer) DecodeStringBytes() (string, error) {
+ v, n := protowire.ConsumeString(b.buf[b.idx:])
+ if n < 0 {
+ return "", protowire.ParseError(n)
+ }
+ b.idx += n
+ return v, nil
+}
+
+// DecodeMessage consumes a length-prefixed message from the buffer.
+// It does not reset m before unmarshaling.
+func (b *Buffer) DecodeMessage(m Message) error {
+ v, err := b.DecodeRawBytes(false)
+ if err != nil {
+ return err
+ }
+ return UnmarshalMerge(v, m)
+}
+
+// DecodeGroup consumes a message group from the buffer.
+// It assumes that the start group marker has already been consumed and
+// consumes all bytes until (and including the end group marker).
+// It does not reset m before unmarshaling.
+func (b *Buffer) DecodeGroup(m Message) error {
+ v, n, err := consumeGroup(b.buf[b.idx:])
+ if err != nil {
+ return err
+ }
+ b.idx += n
+ return UnmarshalMerge(v, m)
+}
+
+// consumeGroup parses b until it finds an end group marker, returning
+// the raw bytes of the message (excluding the end group marker) and the
+// the total length of the message (including the end group marker).
+func consumeGroup(b []byte) ([]byte, int, error) {
+ b0 := b
+ depth := 1 // assume this follows a start group marker
+ for {
+ _, wtyp, tagLen := protowire.ConsumeTag(b)
+ if tagLen < 0 {
+ return nil, 0, protowire.ParseError(tagLen)
+ }
+ b = b[tagLen:]
+
+ var valLen int
+ switch wtyp {
+ case protowire.VarintType:
+ _, valLen = protowire.ConsumeVarint(b)
+ case protowire.Fixed32Type:
+ _, valLen = protowire.ConsumeFixed32(b)
+ case protowire.Fixed64Type:
+ _, valLen = protowire.ConsumeFixed64(b)
+ case protowire.BytesType:
+ _, valLen = protowire.ConsumeBytes(b)
+ case protowire.StartGroupType:
+ depth++
+ case protowire.EndGroupType:
+ depth--
+ default:
+ return nil, 0, errors.New("proto: cannot parse reserved wire type")
+ }
+ if valLen < 0 {
+ return nil, 0, protowire.ParseError(valLen)
+ }
+ b = b[valLen:]
+
+ if depth == 0 {
+ return b0[:len(b0)-len(b)-tagLen], len(b0) - len(b), nil
+ }
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/defaults.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/defaults.go
new file mode 100644
index 000000000000..d399bf069c3d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/defaults.go
@@ -0,0 +1,63 @@
+// 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 proto
+
+import (
+ "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// SetDefaults sets unpopulated scalar fields to their default values.
+// Fields within a oneof are not set even if they have a default value.
+// SetDefaults is recursively called upon any populated message fields.
+func SetDefaults(m Message) {
+ if m != nil {
+ setDefaults(MessageReflect(m))
+ }
+}
+
+func setDefaults(m protoreflect.Message) {
+ fds := m.Descriptor().Fields()
+ for i := 0; i < fds.Len(); i++ {
+ fd := fds.Get(i)
+ if !m.Has(fd) {
+ if fd.HasDefault() && fd.ContainingOneof() == nil {
+ v := fd.Default()
+ if fd.Kind() == protoreflect.BytesKind {
+ v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes
+ }
+ m.Set(fd, v)
+ }
+ continue
+ }
+ }
+
+ m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ switch {
+ // Handle singular message.
+ case fd.Cardinality() != protoreflect.Repeated:
+ if fd.Message() != nil {
+ setDefaults(m.Get(fd).Message())
+ }
+ // Handle list of messages.
+ case fd.IsList():
+ if fd.Message() != nil {
+ ls := m.Get(fd).List()
+ for i := 0; i < ls.Len(); i++ {
+ setDefaults(ls.Get(i).Message())
+ }
+ }
+ // Handle map of messages.
+ case fd.IsMap():
+ if fd.MapValue().Message() != nil {
+ ms := m.Get(fd).Map()
+ ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
+ setDefaults(v.Message())
+ return true
+ })
+ }
+ }
+ return true
+ })
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/deprecated.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/deprecated.go
new file mode 100644
index 000000000000..e8db57e097a1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/deprecated.go
@@ -0,0 +1,113 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "strconv"
+
+ protoV2 "google.golang.org/protobuf/proto"
+)
+
+var (
+ // Deprecated: No longer returned.
+ ErrNil = errors.New("proto: Marshal called with nil")
+
+ // Deprecated: No longer returned.
+ ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
+
+ // Deprecated: No longer returned.
+ ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
+)
+
+// Deprecated: Do not use.
+type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
+
+// Deprecated: Do not use.
+func GetStats() Stats { return Stats{} }
+
+// Deprecated: Do not use.
+func MarshalMessageSet(interface{}) ([]byte, error) {
+ return nil, errors.New("proto: not implemented")
+}
+
+// Deprecated: Do not use.
+func UnmarshalMessageSet([]byte, interface{}) error {
+ return errors.New("proto: not implemented")
+}
+
+// Deprecated: Do not use.
+func MarshalMessageSetJSON(interface{}) ([]byte, error) {
+ return nil, errors.New("proto: not implemented")
+}
+
+// Deprecated: Do not use.
+func UnmarshalMessageSetJSON([]byte, interface{}) error {
+ return errors.New("proto: not implemented")
+}
+
+// Deprecated: Do not use.
+func RegisterMessageSetType(Message, int32, string) {}
+
+// Deprecated: Do not use.
+func EnumName(m map[int32]string, v int32) string {
+ s, ok := m[v]
+ if ok {
+ return s
+ }
+ return strconv.Itoa(int(v))
+}
+
+// Deprecated: Do not use.
+func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
+ if data[0] == '"' {
+ // New style: enums are strings.
+ var repr string
+ if err := json.Unmarshal(data, &repr); err != nil {
+ return -1, err
+ }
+ val, ok := m[repr]
+ if !ok {
+ return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
+ }
+ return val, nil
+ }
+ // Old style: enums are ints.
+ var val int32
+ if err := json.Unmarshal(data, &val); err != nil {
+ return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
+ }
+ return val, nil
+}
+
+// Deprecated: Do not use; this type existed for intenal-use only.
+type InternalMessageInfo struct{}
+
+// Deprecated: Do not use; this method existed for intenal-use only.
+func (*InternalMessageInfo) DiscardUnknown(m Message) {
+ DiscardUnknown(m)
+}
+
+// Deprecated: Do not use; this method existed for intenal-use only.
+func (*InternalMessageInfo) Marshal(b []byte, m Message, deterministic bool) ([]byte, error) {
+ return protoV2.MarshalOptions{Deterministic: deterministic}.MarshalAppend(b, MessageV2(m))
+}
+
+// Deprecated: Do not use; this method existed for intenal-use only.
+func (*InternalMessageInfo) Merge(dst, src Message) {
+ protoV2.Merge(MessageV2(dst), MessageV2(src))
+}
+
+// Deprecated: Do not use; this method existed for intenal-use only.
+func (*InternalMessageInfo) Size(m Message) int {
+ return protoV2.Size(MessageV2(m))
+}
+
+// Deprecated: Do not use; this method existed for intenal-use only.
+func (*InternalMessageInfo) Unmarshal(m Message, b []byte) error {
+ return protoV2.UnmarshalOptions{Merge: true}.Unmarshal(b, MessageV2(m))
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/discard.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/discard.go
new file mode 100644
index 000000000000..2187e877fa4a
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/discard.go
@@ -0,0 +1,58 @@
+// 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 proto
+
+import (
+ "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// DiscardUnknown recursively discards all unknown fields from this message
+// and all embedded messages.
+//
+// When unmarshaling a message with unrecognized fields, the tags and values
+// of such fields are preserved in the Message. This allows a later call to
+// marshal to be able to produce a message that continues to have those
+// unrecognized fields. To avoid this, DiscardUnknown is used to
+// explicitly clear the unknown fields after unmarshaling.
+func DiscardUnknown(m Message) {
+ if m != nil {
+ discardUnknown(MessageReflect(m))
+ }
+}
+
+func discardUnknown(m protoreflect.Message) {
+ m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
+ switch {
+ // Handle singular message.
+ case fd.Cardinality() != protoreflect.Repeated:
+ if fd.Message() != nil {
+ discardUnknown(m.Get(fd).Message())
+ }
+ // Handle list of messages.
+ case fd.IsList():
+ if fd.Message() != nil {
+ ls := m.Get(fd).List()
+ for i := 0; i < ls.Len(); i++ {
+ discardUnknown(ls.Get(i).Message())
+ }
+ }
+ // Handle map of messages.
+ case fd.IsMap():
+ if fd.MapValue().Message() != nil {
+ ms := m.Get(fd).Map()
+ ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
+ discardUnknown(v.Message())
+ return true
+ })
+ }
+ }
+ return true
+ })
+
+ // Discard unknown fields.
+ if len(m.GetUnknown()) > 0 {
+ m.SetUnknown(nil)
+ }
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/extensions.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/extensions.go
new file mode 100644
index 000000000000..42fc120c972b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/extensions.go
@@ -0,0 +1,356 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+
+ "google.golang.org/protobuf/encoding/protowire"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+ "google.golang.org/protobuf/runtime/protoiface"
+ "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+type (
+ // ExtensionDesc represents an extension descriptor and
+ // is used to interact with an extension field in a message.
+ //
+ // Variables of this type are generated in code by protoc-gen-go.
+ ExtensionDesc = protoimpl.ExtensionInfo
+
+ // ExtensionRange represents a range of message extensions.
+ // Used in code generated by protoc-gen-go.
+ ExtensionRange = protoiface.ExtensionRangeV1
+
+ // Deprecated: Do not use; this is an internal type.
+ Extension = protoimpl.ExtensionFieldV1
+
+ // Deprecated: Do not use; this is an internal type.
+ XXX_InternalExtensions = protoimpl.ExtensionFields
+)
+
+// ErrMissingExtension reports whether the extension was not present.
+var ErrMissingExtension = errors.New("proto: missing extension")
+
+var errNotExtendable = errors.New("proto: not an extendable proto.Message")
+
+// HasExtension reports whether the extension field is present in m
+// either as an explicitly populated field or as an unknown field.
+func HasExtension(m Message, xt *ExtensionDesc) (has bool) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() {
+ return false
+ }
+
+ // Check whether any populated known field matches the field number.
+ xtd := xt.TypeDescriptor()
+ if isValidExtension(mr.Descriptor(), xtd) {
+ has = mr.Has(xtd)
+ } else {
+ mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
+ has = int32(fd.Number()) == xt.Field
+ return !has
+ })
+ }
+
+ // Check whether any unknown field matches the field number.
+ for b := mr.GetUnknown(); !has && len(b) > 0; {
+ num, _, n := protowire.ConsumeField(b)
+ has = int32(num) == xt.Field
+ b = b[n:]
+ }
+ return has
+}
+
+// ClearExtension removes the extension field from m
+// either as an explicitly populated field or as an unknown field.
+func ClearExtension(m Message, xt *ExtensionDesc) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() {
+ return
+ }
+
+ xtd := xt.TypeDescriptor()
+ if isValidExtension(mr.Descriptor(), xtd) {
+ mr.Clear(xtd)
+ } else {
+ mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
+ if int32(fd.Number()) == xt.Field {
+ mr.Clear(fd)
+ return false
+ }
+ return true
+ })
+ }
+ clearUnknown(mr, fieldNum(xt.Field))
+}
+
+// ClearAllExtensions clears all extensions from m.
+// This includes populated fields and unknown fields in the extension range.
+func ClearAllExtensions(m Message) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() {
+ return
+ }
+
+ mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
+ if fd.IsExtension() {
+ mr.Clear(fd)
+ }
+ return true
+ })
+ clearUnknown(mr, mr.Descriptor().ExtensionRanges())
+}
+
+// GetExtension retrieves a proto2 extended field from m.
+//
+// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
+// then GetExtension parses the encoded field and returns a Go value of the specified type.
+// If the field is not present, then the default value is returned (if one is specified),
+// otherwise ErrMissingExtension is reported.
+//
+// If the descriptor is type incomplete (i.e., ExtensionDesc.ExtensionType is nil),
+// then GetExtension returns the raw encoded bytes for the extension field.
+func GetExtension(m Message, xt *ExtensionDesc) (interface{}, error) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
+ return nil, errNotExtendable
+ }
+
+ // Retrieve the unknown fields for this extension field.
+ var bo protoreflect.RawFields
+ for bi := mr.GetUnknown(); len(bi) > 0; {
+ num, _, n := protowire.ConsumeField(bi)
+ if int32(num) == xt.Field {
+ bo = append(bo, bi[:n]...)
+ }
+ bi = bi[n:]
+ }
+
+ // For type incomplete descriptors, only retrieve the unknown fields.
+ if xt.ExtensionType == nil {
+ return []byte(bo), nil
+ }
+
+ // If the extension field only exists as unknown fields, unmarshal it.
+ // This is rarely done since proto.Unmarshal eagerly unmarshals extensions.
+ xtd := xt.TypeDescriptor()
+ if !isValidExtension(mr.Descriptor(), xtd) {
+ return nil, fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
+ }
+ if !mr.Has(xtd) && len(bo) > 0 {
+ m2 := mr.New()
+ if err := (proto.UnmarshalOptions{
+ Resolver: extensionResolver{xt},
+ }.Unmarshal(bo, m2.Interface())); err != nil {
+ return nil, err
+ }
+ if m2.Has(xtd) {
+ mr.Set(xtd, m2.Get(xtd))
+ clearUnknown(mr, fieldNum(xt.Field))
+ }
+ }
+
+ // Check whether the message has the extension field set or a default.
+ var pv protoreflect.Value
+ switch {
+ case mr.Has(xtd):
+ pv = mr.Get(xtd)
+ case xtd.HasDefault():
+ pv = xtd.Default()
+ default:
+ return nil, ErrMissingExtension
+ }
+
+ v := xt.InterfaceOf(pv)
+ rv := reflect.ValueOf(v)
+ if isScalarKind(rv.Kind()) {
+ rv2 := reflect.New(rv.Type())
+ rv2.Elem().Set(rv)
+ v = rv2.Interface()
+ }
+ return v, nil
+}
+
+// extensionResolver is a custom extension resolver that stores a single
+// extension type that takes precedence over the global registry.
+type extensionResolver struct{ xt protoreflect.ExtensionType }
+
+func (r extensionResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
+ if xtd := r.xt.TypeDescriptor(); xtd.FullName() == field {
+ return r.xt, nil
+ }
+ return protoregistry.GlobalTypes.FindExtensionByName(field)
+}
+
+func (r extensionResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
+ if xtd := r.xt.TypeDescriptor(); xtd.ContainingMessage().FullName() == message && xtd.Number() == field {
+ return r.xt, nil
+ }
+ return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
+}
+
+// GetExtensions returns a list of the extensions values present in m,
+// corresponding with the provided list of extension descriptors, xts.
+// If an extension is missing in m, the corresponding value is nil.
+func GetExtensions(m Message, xts []*ExtensionDesc) ([]interface{}, error) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() {
+ return nil, errNotExtendable
+ }
+
+ vs := make([]interface{}, len(xts))
+ for i, xt := range xts {
+ v, err := GetExtension(m, xt)
+ if err != nil {
+ if err == ErrMissingExtension {
+ continue
+ }
+ return vs, err
+ }
+ vs[i] = v
+ }
+ return vs, nil
+}
+
+// SetExtension sets an extension field in m to the provided value.
+func SetExtension(m Message, xt *ExtensionDesc, v interface{}) error {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
+ return errNotExtendable
+ }
+
+ rv := reflect.ValueOf(v)
+ if reflect.TypeOf(v) != reflect.TypeOf(xt.ExtensionType) {
+ return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", v, xt.ExtensionType)
+ }
+ if rv.Kind() == reflect.Ptr {
+ if rv.IsNil() {
+ return fmt.Errorf("proto: SetExtension called with nil value of type %T", v)
+ }
+ if isScalarKind(rv.Elem().Kind()) {
+ v = rv.Elem().Interface()
+ }
+ }
+
+ xtd := xt.TypeDescriptor()
+ if !isValidExtension(mr.Descriptor(), xtd) {
+ return fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
+ }
+ mr.Set(xtd, xt.ValueOf(v))
+ clearUnknown(mr, fieldNum(xt.Field))
+ return nil
+}
+
+// SetRawExtension inserts b into the unknown fields of m.
+//
+// Deprecated: Use Message.ProtoReflect.SetUnknown instead.
+func SetRawExtension(m Message, fnum int32, b []byte) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() {
+ return
+ }
+
+ // Verify that the raw field is valid.
+ for b0 := b; len(b0) > 0; {
+ num, _, n := protowire.ConsumeField(b0)
+ if int32(num) != fnum {
+ panic(fmt.Sprintf("mismatching field number: got %d, want %d", num, fnum))
+ }
+ b0 = b0[n:]
+ }
+
+ ClearExtension(m, &ExtensionDesc{Field: fnum})
+ mr.SetUnknown(append(mr.GetUnknown(), b...))
+}
+
+// ExtensionDescs returns a list of extension descriptors found in m,
+// containing descriptors for both populated extension fields in m and
+// also unknown fields of m that are in the extension range.
+// For the later case, an type incomplete descriptor is provided where only
+// the ExtensionDesc.Field field is populated.
+// The order of the extension descriptors is undefined.
+func ExtensionDescs(m Message) ([]*ExtensionDesc, error) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
+ return nil, errNotExtendable
+ }
+
+ // Collect a set of known extension descriptors.
+ extDescs := make(map[protoreflect.FieldNumber]*ExtensionDesc)
+ mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ if fd.IsExtension() {
+ xt := fd.(protoreflect.ExtensionTypeDescriptor)
+ if xd, ok := xt.Type().(*ExtensionDesc); ok {
+ extDescs[fd.Number()] = xd
+ }
+ }
+ return true
+ })
+
+ // Collect a set of unknown extension descriptors.
+ extRanges := mr.Descriptor().ExtensionRanges()
+ for b := mr.GetUnknown(); len(b) > 0; {
+ num, _, n := protowire.ConsumeField(b)
+ if extRanges.Has(num) && extDescs[num] == nil {
+ extDescs[num] = nil
+ }
+ b = b[n:]
+ }
+
+ // Transpose the set of descriptors into a list.
+ var xts []*ExtensionDesc
+ for num, xt := range extDescs {
+ if xt == nil {
+ xt = &ExtensionDesc{Field: int32(num)}
+ }
+ xts = append(xts, xt)
+ }
+ return xts, nil
+}
+
+// isValidExtension reports whether xtd is a valid extension descriptor for md.
+func isValidExtension(md protoreflect.MessageDescriptor, xtd protoreflect.ExtensionTypeDescriptor) bool {
+ return xtd.ContainingMessage() == md && md.ExtensionRanges().Has(xtd.Number())
+}
+
+// isScalarKind reports whether k is a protobuf scalar kind (except bytes).
+// This function exists for historical reasons since the representation of
+// scalars differs between v1 and v2, where v1 uses *T and v2 uses T.
+func isScalarKind(k reflect.Kind) bool {
+ switch k {
+ case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
+ return true
+ default:
+ return false
+ }
+}
+
+// clearUnknown removes unknown fields from m where remover.Has reports true.
+func clearUnknown(m protoreflect.Message, remover interface {
+ Has(protoreflect.FieldNumber) bool
+}) {
+ var bo protoreflect.RawFields
+ for bi := m.GetUnknown(); len(bi) > 0; {
+ num, _, n := protowire.ConsumeField(bi)
+ if !remover.Has(num) {
+ bo = append(bo, bi[:n]...)
+ }
+ bi = bi[n:]
+ }
+ if bi := m.GetUnknown(); len(bi) != len(bo) {
+ m.SetUnknown(bo)
+ }
+}
+
+type fieldNum protoreflect.FieldNumber
+
+func (n1 fieldNum) Has(n2 protoreflect.FieldNumber) bool {
+ return protoreflect.FieldNumber(n1) == n2
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/properties.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/properties.go
new file mode 100644
index 000000000000..dcdc2202fada
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/properties.go
@@ -0,0 +1,306 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+// StructProperties represents protocol buffer type information for a
+// generated protobuf message in the open-struct API.
+//
+// Deprecated: Do not use.
+type StructProperties struct {
+ // Prop are the properties for each field.
+ //
+ // Fields belonging to a oneof are stored in OneofTypes instead, with a
+ // single Properties representing the parent oneof held here.
+ //
+ // The order of Prop matches the order of fields in the Go struct.
+ // Struct fields that are not related to protobufs have a "XXX_" prefix
+ // in the Properties.Name and must be ignored by the user.
+ Prop []*Properties
+
+ // OneofTypes contains information about the oneof fields in this message.
+ // It is keyed by the protobuf field name.
+ OneofTypes map[string]*OneofProperties
+}
+
+// Properties represents the type information for a protobuf message field.
+//
+// Deprecated: Do not use.
+type Properties struct {
+ // Name is a placeholder name with little meaningful semantic value.
+ // If the name has an "XXX_" prefix, the entire Properties must be ignored.
+ Name string
+ // OrigName is the protobuf field name or oneof name.
+ OrigName string
+ // JSONName is the JSON name for the protobuf field.
+ JSONName string
+ // Enum is a placeholder name for enums.
+ // For historical reasons, this is neither the Go name for the enum,
+ // nor the protobuf name for the enum.
+ Enum string // Deprecated: Do not use.
+ // Weak contains the full name of the weakly referenced message.
+ Weak string
+ // Wire is a string representation of the wire type.
+ Wire string
+ // WireType is the protobuf wire type for the field.
+ WireType int
+ // Tag is the protobuf field number.
+ Tag int
+ // Required reports whether this is a required field.
+ Required bool
+ // Optional reports whether this is a optional field.
+ Optional bool
+ // Repeated reports whether this is a repeated field.
+ Repeated bool
+ // Packed reports whether this is a packed repeated field of scalars.
+ Packed bool
+ // Proto3 reports whether this field operates under the proto3 syntax.
+ Proto3 bool
+ // Oneof reports whether this field belongs within a oneof.
+ Oneof bool
+
+ // Default is the default value in string form.
+ Default string
+ // HasDefault reports whether the field has a default value.
+ HasDefault bool
+
+ // MapKeyProp is the properties for the key field for a map field.
+ MapKeyProp *Properties
+ // MapValProp is the properties for the value field for a map field.
+ MapValProp *Properties
+}
+
+// OneofProperties represents the type information for a protobuf oneof.
+//
+// Deprecated: Do not use.
+type OneofProperties struct {
+ // Type is a pointer to the generated wrapper type for the field value.
+ // This is nil for messages that are not in the open-struct API.
+ Type reflect.Type
+ // Field is the index into StructProperties.Prop for the containing oneof.
+ Field int
+ // Prop is the properties for the field.
+ Prop *Properties
+}
+
+// String formats the properties in the protobuf struct field tag style.
+func (p *Properties) String() string {
+ s := p.Wire
+ s += "," + strconv.Itoa(p.Tag)
+ if p.Required {
+ s += ",req"
+ }
+ if p.Optional {
+ s += ",opt"
+ }
+ if p.Repeated {
+ s += ",rep"
+ }
+ if p.Packed {
+ s += ",packed"
+ }
+ s += ",name=" + p.OrigName
+ if p.JSONName != "" {
+ s += ",json=" + p.JSONName
+ }
+ if len(p.Enum) > 0 {
+ s += ",enum=" + p.Enum
+ }
+ if len(p.Weak) > 0 {
+ s += ",weak=" + p.Weak
+ }
+ if p.Proto3 {
+ s += ",proto3"
+ }
+ if p.Oneof {
+ s += ",oneof"
+ }
+ if p.HasDefault {
+ s += ",def=" + p.Default
+ }
+ return s
+}
+
+// Parse populates p by parsing a string in the protobuf struct field tag style.
+func (p *Properties) Parse(tag string) {
+ // For example: "bytes,49,opt,name=foo,def=hello!"
+ for len(tag) > 0 {
+ i := strings.IndexByte(tag, ',')
+ if i < 0 {
+ i = len(tag)
+ }
+ switch s := tag[:i]; {
+ case strings.HasPrefix(s, "name="):
+ p.OrigName = s[len("name="):]
+ case strings.HasPrefix(s, "json="):
+ p.JSONName = s[len("json="):]
+ case strings.HasPrefix(s, "enum="):
+ p.Enum = s[len("enum="):]
+ case strings.HasPrefix(s, "weak="):
+ p.Weak = s[len("weak="):]
+ case strings.Trim(s, "0123456789") == "":
+ n, _ := strconv.ParseUint(s, 10, 32)
+ p.Tag = int(n)
+ case s == "opt":
+ p.Optional = true
+ case s == "req":
+ p.Required = true
+ case s == "rep":
+ p.Repeated = true
+ case s == "varint" || s == "zigzag32" || s == "zigzag64":
+ p.Wire = s
+ p.WireType = WireVarint
+ case s == "fixed32":
+ p.Wire = s
+ p.WireType = WireFixed32
+ case s == "fixed64":
+ p.Wire = s
+ p.WireType = WireFixed64
+ case s == "bytes":
+ p.Wire = s
+ p.WireType = WireBytes
+ case s == "group":
+ p.Wire = s
+ p.WireType = WireStartGroup
+ case s == "packed":
+ p.Packed = true
+ case s == "proto3":
+ p.Proto3 = true
+ case s == "oneof":
+ p.Oneof = true
+ case strings.HasPrefix(s, "def="):
+ // The default tag is special in that everything afterwards is the
+ // default regardless of the presence of commas.
+ p.HasDefault = true
+ p.Default, i = tag[len("def="):], len(tag)
+ }
+ tag = strings.TrimPrefix(tag[i:], ",")
+ }
+}
+
+// Init populates the properties from a protocol buffer struct tag.
+//
+// Deprecated: Do not use.
+func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
+ p.Name = name
+ p.OrigName = name
+ if tag == "" {
+ return
+ }
+ p.Parse(tag)
+
+ if typ != nil && typ.Kind() == reflect.Map {
+ p.MapKeyProp = new(Properties)
+ p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
+ p.MapValProp = new(Properties)
+ p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
+ }
+}
+
+var propertiesCache sync.Map // map[reflect.Type]*StructProperties
+
+// GetProperties returns the list of properties for the type represented by t,
+// which must be a generated protocol buffer message in the open-struct API,
+// where protobuf message fields are represented by exported Go struct fields.
+//
+// Deprecated: Use protobuf reflection instead.
+func GetProperties(t reflect.Type) *StructProperties {
+ if p, ok := propertiesCache.Load(t); ok {
+ return p.(*StructProperties)
+ }
+ p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
+ return p.(*StructProperties)
+}
+
+func newProperties(t reflect.Type) *StructProperties {
+ if t.Kind() != reflect.Struct {
+ panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
+ }
+
+ var hasOneof bool
+ prop := new(StructProperties)
+
+ // Construct a list of properties for each field in the struct.
+ for i := 0; i < t.NumField(); i++ {
+ p := new(Properties)
+ f := t.Field(i)
+ tagField := f.Tag.Get("protobuf")
+ p.Init(f.Type, f.Name, tagField, &f)
+
+ tagOneof := f.Tag.Get("protobuf_oneof")
+ if tagOneof != "" {
+ hasOneof = true
+ p.OrigName = tagOneof
+ }
+
+ // Rename unrelated struct fields with the "XXX_" prefix since so much
+ // user code simply checks for this to exclude special fields.
+ if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
+ p.Name = "XXX_" + p.Name
+ p.OrigName = "XXX_" + p.OrigName
+ } else if p.Weak != "" {
+ p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
+ }
+
+ prop.Prop = append(prop.Prop, p)
+ }
+
+ // Construct a mapping of oneof field names to properties.
+ if hasOneof {
+ var oneofWrappers []interface{}
+ if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
+ oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
+ }
+ if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
+ oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
+ }
+ if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
+ if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
+ oneofWrappers = m.ProtoMessageInfo().OneofWrappers
+ }
+ }
+
+ prop.OneofTypes = make(map[string]*OneofProperties)
+ for _, wrapper := range oneofWrappers {
+ p := &OneofProperties{
+ Type: reflect.ValueOf(wrapper).Type(), // *T
+ Prop: new(Properties),
+ }
+ f := p.Type.Elem().Field(0)
+ p.Prop.Name = f.Name
+ p.Prop.Parse(f.Tag.Get("protobuf"))
+
+ // Determine the struct field that contains this oneof.
+ // Each wrapper is assignable to exactly one parent field.
+ var foundOneof bool
+ for i := 0; i < t.NumField() && !foundOneof; i++ {
+ if p.Type.AssignableTo(t.Field(i).Type) {
+ p.Field = i
+ foundOneof = true
+ }
+ }
+ if !foundOneof {
+ panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
+ }
+ prop.OneofTypes[p.Prop.OrigName] = p
+ }
+ }
+
+ return prop
+}
+
+func (sp *StructProperties) Len() int { return len(sp.Prop) }
+func (sp *StructProperties) Less(i, j int) bool { return false }
+func (sp *StructProperties) Swap(i, j int) { return }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/proto.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/proto.go
new file mode 100644
index 000000000000..5aee89c323e0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/proto.go
@@ -0,0 +1,167 @@
+// 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 proto provides functionality for handling protocol buffer messages.
+// In particular, it provides marshaling and unmarshaling between a protobuf
+// message and the binary wire format.
+//
+// See https://developers.google.com/protocol-buffers/docs/gotutorial for
+// more information.
+//
+// Deprecated: Use the "google.golang.org/protobuf/proto" package instead.
+package proto
+
+import (
+ protoV2 "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/runtime/protoiface"
+ "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+ ProtoPackageIsVersion1 = true
+ ProtoPackageIsVersion2 = true
+ ProtoPackageIsVersion3 = true
+ ProtoPackageIsVersion4 = true
+)
+
+// GeneratedEnum is any enum type generated by protoc-gen-go
+// which is a named int32 kind.
+// This type exists for documentation purposes.
+type GeneratedEnum interface{}
+
+// GeneratedMessage is any message type generated by protoc-gen-go
+// which is a pointer to a named struct kind.
+// This type exists for documentation purposes.
+type GeneratedMessage interface{}
+
+// Message is a protocol buffer message.
+//
+// This is the v1 version of the message interface and is marginally better
+// than an empty interface as it lacks any method to programatically interact
+// with the contents of the message.
+//
+// A v2 message is declared in "google.golang.org/protobuf/proto".Message and
+// exposes protobuf reflection as a first-class feature of the interface.
+//
+// To convert a v1 message to a v2 message, use the MessageV2 function.
+// To convert a v2 message to a v1 message, use the MessageV1 function.
+type Message = protoiface.MessageV1
+
+// MessageV1 converts either a v1 or v2 message to a v1 message.
+// It returns nil if m is nil.
+func MessageV1(m GeneratedMessage) protoiface.MessageV1 {
+ return protoimpl.X.ProtoMessageV1Of(m)
+}
+
+// MessageV2 converts either a v1 or v2 message to a v2 message.
+// It returns nil if m is nil.
+func MessageV2(m GeneratedMessage) protoV2.Message {
+ return protoimpl.X.ProtoMessageV2Of(m)
+}
+
+// MessageReflect returns a reflective view for a message.
+// It returns nil if m is nil.
+func MessageReflect(m Message) protoreflect.Message {
+ return protoimpl.X.MessageOf(m)
+}
+
+// Marshaler is implemented by messages that can marshal themselves.
+// This interface is used by the following functions: Size, Marshal,
+// Buffer.Marshal, and Buffer.EncodeMessage.
+//
+// Deprecated: Do not implement.
+type Marshaler interface {
+ // Marshal formats the encoded bytes of the message.
+ // It should be deterministic and emit valid protobuf wire data.
+ // The caller takes ownership of the returned buffer.
+ Marshal() ([]byte, error)
+}
+
+// Unmarshaler is implemented by messages that can unmarshal themselves.
+// This interface is used by the following functions: Unmarshal, UnmarshalMerge,
+// Buffer.Unmarshal, Buffer.DecodeMessage, and Buffer.DecodeGroup.
+//
+// Deprecated: Do not implement.
+type Unmarshaler interface {
+ // Unmarshal parses the encoded bytes of the protobuf wire input.
+ // The provided buffer is only valid for during method call.
+ // It should not reset the receiver message.
+ Unmarshal([]byte) error
+}
+
+// Merger is implemented by messages that can merge themselves.
+// This interface is used by the following functions: Clone and Merge.
+//
+// Deprecated: Do not implement.
+type Merger interface {
+ // Merge merges the contents of src into the receiver message.
+ // It clones all data structures in src such that it aliases no mutable
+ // memory referenced by src.
+ Merge(src Message)
+}
+
+// RequiredNotSetError is an error type returned when
+// marshaling or unmarshaling a message with missing required fields.
+type RequiredNotSetError struct {
+ err error
+}
+
+func (e *RequiredNotSetError) Error() string {
+ if e.err != nil {
+ return e.err.Error()
+ }
+ return "proto: required field not set"
+}
+func (e *RequiredNotSetError) RequiredNotSet() bool {
+ return true
+}
+
+func checkRequiredNotSet(m protoV2.Message) error {
+ if err := protoV2.CheckInitialized(m); err != nil {
+ return &RequiredNotSetError{err: err}
+ }
+ return nil
+}
+
+// Clone returns a deep copy of src.
+func Clone(src Message) Message {
+ return MessageV1(protoV2.Clone(MessageV2(src)))
+}
+
+// Merge merges src into dst, which must be messages of the same type.
+//
+// Populated scalar fields in src are copied to dst, while populated
+// singular messages in src are merged into dst by recursively calling Merge.
+// The elements of every list field in src is appended to the corresponded
+// list fields in dst. The entries of every map field in src is copied into
+// the corresponding map field in dst, possibly replacing existing entries.
+// The unknown fields of src are appended to the unknown fields of dst.
+func Merge(dst, src Message) {
+ protoV2.Merge(MessageV2(dst), MessageV2(src))
+}
+
+// Equal reports whether two messages are equal.
+// If two messages marshal to the same bytes under deterministic serialization,
+// then Equal is guaranteed to report true.
+//
+// Two messages are equal if they are the same protobuf message type,
+// have the same set of populated known and extension field values,
+// and the same set of unknown fields values.
+//
+// Scalar values are compared with the equivalent of the == operator in Go,
+// except bytes values which are compared using bytes.Equal and
+// floating point values which specially treat NaNs as equal.
+// Message values are compared by recursively calling Equal.
+// Lists are equal if each element value is also equal.
+// Maps are equal if they have the same set of keys, where the pair of values
+// for each key is also equal.
+func Equal(x, y Message) bool {
+ return protoV2.Equal(MessageV2(x), MessageV2(y))
+}
+
+func isMessageSet(md protoreflect.MessageDescriptor) bool {
+ ms, ok := md.(interface{ IsMessageSet() bool })
+ return ok && ms.IsMessageSet()
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/registry.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/registry.go
new file mode 100644
index 000000000000..066b4323b499
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/registry.go
@@ -0,0 +1,317 @@
+// 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 proto
+
+import (
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "io/ioutil"
+ "reflect"
+ "strings"
+ "sync"
+
+ "google.golang.org/protobuf/reflect/protodesc"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+ "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+// filePath is the path to the proto source file.
+type filePath = string // e.g., "google/protobuf/descriptor.proto"
+
+// fileDescGZIP is the compressed contents of the encoded FileDescriptorProto.
+type fileDescGZIP = []byte
+
+var fileCache sync.Map // map[filePath]fileDescGZIP
+
+// RegisterFile is called from generated code to register the compressed
+// FileDescriptorProto with the file path for a proto source file.
+//
+// Deprecated: Use protoregistry.GlobalFiles.RegisterFile instead.
+func RegisterFile(s filePath, d fileDescGZIP) {
+ // Decompress the descriptor.
+ zr, err := gzip.NewReader(bytes.NewReader(d))
+ if err != nil {
+ panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
+ }
+ b, err := ioutil.ReadAll(zr)
+ if err != nil {
+ panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
+ }
+
+ // Construct a protoreflect.FileDescriptor from the raw descriptor.
+ // Note that DescBuilder.Build automatically registers the constructed
+ // file descriptor with the v2 registry.
+ protoimpl.DescBuilder{RawDescriptor: b}.Build()
+
+ // Locally cache the raw descriptor form for the file.
+ fileCache.Store(s, d)
+}
+
+// FileDescriptor returns the compressed FileDescriptorProto given the file path
+// for a proto source file. It returns nil if not found.
+//
+// Deprecated: Use protoregistry.GlobalFiles.FindFileByPath instead.
+func FileDescriptor(s filePath) fileDescGZIP {
+ if v, ok := fileCache.Load(s); ok {
+ return v.(fileDescGZIP)
+ }
+
+ // Find the descriptor in the v2 registry.
+ var b []byte
+ if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil {
+ b, _ = Marshal(protodesc.ToFileDescriptorProto(fd))
+ }
+
+ // Locally cache the raw descriptor form for the file.
+ if len(b) > 0 {
+ v, _ := fileCache.LoadOrStore(s, protoimpl.X.CompressGZIP(b))
+ return v.(fileDescGZIP)
+ }
+ return nil
+}
+
+// enumName is the name of an enum. For historical reasons, the enum name is
+// neither the full Go name nor the full protobuf name of the enum.
+// The name is the dot-separated combination of just the proto package that the
+// enum is declared within followed by the Go type name of the generated enum.
+type enumName = string // e.g., "my.proto.package.GoMessage_GoEnum"
+
+// enumsByName maps enum values by name to their numeric counterpart.
+type enumsByName = map[string]int32
+
+// enumsByNumber maps enum values by number to their name counterpart.
+type enumsByNumber = map[int32]string
+
+var enumCache sync.Map // map[enumName]enumsByName
+var numFilesCache sync.Map // map[protoreflect.FullName]int
+
+// RegisterEnum is called from the generated code to register the mapping of
+// enum value names to enum numbers for the enum identified by s.
+//
+// Deprecated: Use protoregistry.GlobalTypes.RegisterEnum instead.
+func RegisterEnum(s enumName, _ enumsByNumber, m enumsByName) {
+ if _, ok := enumCache.Load(s); ok {
+ panic("proto: duplicate enum registered: " + s)
+ }
+ enumCache.Store(s, m)
+
+ // This does not forward registration to the v2 registry since this API
+ // lacks sufficient information to construct a complete v2 enum descriptor.
+}
+
+// EnumValueMap returns the mapping from enum value names to enum numbers for
+// the enum of the given name. It returns nil if not found.
+//
+// Deprecated: Use protoregistry.GlobalTypes.FindEnumByName instead.
+func EnumValueMap(s enumName) enumsByName {
+ if v, ok := enumCache.Load(s); ok {
+ return v.(enumsByName)
+ }
+
+ // Check whether the cache is stale. If the number of files in the current
+ // package differs, then it means that some enums may have been recently
+ // registered upstream that we do not know about.
+ var protoPkg protoreflect.FullName
+ if i := strings.LastIndexByte(s, '.'); i >= 0 {
+ protoPkg = protoreflect.FullName(s[:i])
+ }
+ v, _ := numFilesCache.Load(protoPkg)
+ numFiles, _ := v.(int)
+ if protoregistry.GlobalFiles.NumFilesByPackage(protoPkg) == numFiles {
+ return nil // cache is up-to-date; was not found earlier
+ }
+
+ // Update the enum cache for all enums declared in the given proto package.
+ numFiles = 0
+ protoregistry.GlobalFiles.RangeFilesByPackage(protoPkg, func(fd protoreflect.FileDescriptor) bool {
+ walkEnums(fd, func(ed protoreflect.EnumDescriptor) {
+ name := protoimpl.X.LegacyEnumName(ed)
+ if _, ok := enumCache.Load(name); !ok {
+ m := make(enumsByName)
+ evs := ed.Values()
+ for i := evs.Len() - 1; i >= 0; i-- {
+ ev := evs.Get(i)
+ m[string(ev.Name())] = int32(ev.Number())
+ }
+ enumCache.LoadOrStore(name, m)
+ }
+ })
+ numFiles++
+ return true
+ })
+ numFilesCache.Store(protoPkg, numFiles)
+
+ // Check cache again for enum map.
+ if v, ok := enumCache.Load(s); ok {
+ return v.(enumsByName)
+ }
+ return nil
+}
+
+// walkEnums recursively walks all enums declared in d.
+func walkEnums(d interface {
+ Enums() protoreflect.EnumDescriptors
+ Messages() protoreflect.MessageDescriptors
+}, f func(protoreflect.EnumDescriptor)) {
+ eds := d.Enums()
+ for i := eds.Len() - 1; i >= 0; i-- {
+ f(eds.Get(i))
+ }
+ mds := d.Messages()
+ for i := mds.Len() - 1; i >= 0; i-- {
+ walkEnums(mds.Get(i), f)
+ }
+}
+
+// messageName is the full name of protobuf message.
+type messageName = string
+
+var messageTypeCache sync.Map // map[messageName]reflect.Type
+
+// RegisterType is called from generated code to register the message Go type
+// for a message of the given name.
+//
+// Deprecated: Use protoregistry.GlobalTypes.RegisterMessage instead.
+func RegisterType(m Message, s messageName) {
+ mt := protoimpl.X.LegacyMessageTypeOf(m, protoreflect.FullName(s))
+ if err := protoregistry.GlobalTypes.RegisterMessage(mt); err != nil {
+ panic(err)
+ }
+ messageTypeCache.Store(s, reflect.TypeOf(m))
+}
+
+// RegisterMapType is called from generated code to register the Go map type
+// for a protobuf message representing a map entry.
+//
+// Deprecated: Do not use.
+func RegisterMapType(m interface{}, s messageName) {
+ t := reflect.TypeOf(m)
+ if t.Kind() != reflect.Map {
+ panic(fmt.Sprintf("invalid map kind: %v", t))
+ }
+ if _, ok := messageTypeCache.Load(s); ok {
+ panic(fmt.Errorf("proto: duplicate proto message registered: %s", s))
+ }
+ messageTypeCache.Store(s, t)
+}
+
+// MessageType returns the message type for a named message.
+// It returns nil if not found.
+//
+// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead.
+func MessageType(s messageName) reflect.Type {
+ if v, ok := messageTypeCache.Load(s); ok {
+ return v.(reflect.Type)
+ }
+
+ // Derive the message type from the v2 registry.
+ var t reflect.Type
+ if mt, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(s)); mt != nil {
+ t = messageGoType(mt)
+ }
+
+ // If we could not get a concrete type, it is possible that it is a
+ // pseudo-message for a map entry.
+ if t == nil {
+ d, _ := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(s))
+ if md, _ := d.(protoreflect.MessageDescriptor); md != nil && md.IsMapEntry() {
+ kt := goTypeForField(md.Fields().ByNumber(1))
+ vt := goTypeForField(md.Fields().ByNumber(2))
+ t = reflect.MapOf(kt, vt)
+ }
+ }
+
+ // Locally cache the message type for the given name.
+ if t != nil {
+ v, _ := messageTypeCache.LoadOrStore(s, t)
+ return v.(reflect.Type)
+ }
+ return nil
+}
+
+func goTypeForField(fd protoreflect.FieldDescriptor) reflect.Type {
+ switch k := fd.Kind(); k {
+ case protoreflect.EnumKind:
+ if et, _ := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()); et != nil {
+ return enumGoType(et)
+ }
+ return reflect.TypeOf(protoreflect.EnumNumber(0))
+ case protoreflect.MessageKind, protoreflect.GroupKind:
+ if mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()); mt != nil {
+ return messageGoType(mt)
+ }
+ return reflect.TypeOf((*protoreflect.Message)(nil)).Elem()
+ default:
+ return reflect.TypeOf(fd.Default().Interface())
+ }
+}
+
+func enumGoType(et protoreflect.EnumType) reflect.Type {
+ return reflect.TypeOf(et.New(0))
+}
+
+func messageGoType(mt protoreflect.MessageType) reflect.Type {
+ return reflect.TypeOf(MessageV1(mt.Zero().Interface()))
+}
+
+// MessageName returns the full protobuf name for the given message type.
+//
+// Deprecated: Use protoreflect.MessageDescriptor.FullName instead.
+func MessageName(m Message) messageName {
+ if m == nil {
+ return ""
+ }
+ if m, ok := m.(interface{ XXX_MessageName() messageName }); ok {
+ return m.XXX_MessageName()
+ }
+ return messageName(protoimpl.X.MessageDescriptorOf(m).FullName())
+}
+
+// RegisterExtension is called from the generated code to register
+// the extension descriptor.
+//
+// Deprecated: Use protoregistry.GlobalTypes.RegisterExtension instead.
+func RegisterExtension(d *ExtensionDesc) {
+ if err := protoregistry.GlobalTypes.RegisterExtension(d); err != nil {
+ panic(err)
+ }
+}
+
+type extensionsByNumber = map[int32]*ExtensionDesc
+
+var extensionCache sync.Map // map[messageName]extensionsByNumber
+
+// RegisteredExtensions returns a map of the registered extensions for the
+// provided protobuf message, indexed by the extension field number.
+//
+// Deprecated: Use protoregistry.GlobalTypes.RangeExtensionsByMessage instead.
+func RegisteredExtensions(m Message) extensionsByNumber {
+ // Check whether the cache is stale. If the number of extensions for
+ // the given message differs, then it means that some extensions were
+ // recently registered upstream that we do not know about.
+ s := MessageName(m)
+ v, _ := extensionCache.Load(s)
+ xs, _ := v.(extensionsByNumber)
+ if protoregistry.GlobalTypes.NumExtensionsByMessage(protoreflect.FullName(s)) == len(xs) {
+ return xs // cache is up-to-date
+ }
+
+ // Cache is stale, re-compute the extensions map.
+ xs = make(extensionsByNumber)
+ protoregistry.GlobalTypes.RangeExtensionsByMessage(protoreflect.FullName(s), func(xt protoreflect.ExtensionType) bool {
+ if xd, ok := xt.(*ExtensionDesc); ok {
+ xs[int32(xt.TypeDescriptor().Number())] = xd
+ } else {
+ // TODO: This implies that the protoreflect.ExtensionType is a
+ // custom type not generated by protoc-gen-go. We could try and
+ // convert the type to an ExtensionDesc.
+ }
+ return true
+ })
+ extensionCache.Store(s, xs)
+ return xs
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/text_decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/text_decode.go
new file mode 100644
index 000000000000..47eb3e44501d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/text_decode.go
@@ -0,0 +1,801 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import (
+ "encoding"
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+
+ "google.golang.org/protobuf/encoding/prototext"
+ protoV2 "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+)
+
+const wrapTextUnmarshalV2 = false
+
+// ParseError is returned by UnmarshalText.
+type ParseError struct {
+ Message string
+
+ // Deprecated: Do not use.
+ Line, Offset int
+}
+
+func (e *ParseError) Error() string {
+ if wrapTextUnmarshalV2 {
+ return e.Message
+ }
+ if e.Line == 1 {
+ return fmt.Sprintf("line 1.%d: %v", e.Offset, e.Message)
+ }
+ return fmt.Sprintf("line %d: %v", e.Line, e.Message)
+}
+
+// UnmarshalText parses a proto text formatted string into m.
+func UnmarshalText(s string, m Message) error {
+ if u, ok := m.(encoding.TextUnmarshaler); ok {
+ return u.UnmarshalText([]byte(s))
+ }
+
+ m.Reset()
+ mi := MessageV2(m)
+
+ if wrapTextUnmarshalV2 {
+ err := prototext.UnmarshalOptions{
+ AllowPartial: true,
+ }.Unmarshal([]byte(s), mi)
+ if err != nil {
+ return &ParseError{Message: err.Error()}
+ }
+ return checkRequiredNotSet(mi)
+ } else {
+ if err := newTextParser(s).unmarshalMessage(mi.ProtoReflect(), ""); err != nil {
+ return err
+ }
+ return checkRequiredNotSet(mi)
+ }
+}
+
+type textParser struct {
+ s string // remaining input
+ done bool // whether the parsing is finished (success or error)
+ backed bool // whether back() was called
+ offset, line int
+ cur token
+}
+
+type token struct {
+ value string
+ err *ParseError
+ line int // line number
+ offset int // byte number from start of input, not start of line
+ unquoted string // the unquoted version of value, if it was a quoted string
+}
+
+func newTextParser(s string) *textParser {
+ p := new(textParser)
+ p.s = s
+ p.line = 1
+ p.cur.line = 1
+ return p
+}
+
+func (p *textParser) unmarshalMessage(m protoreflect.Message, terminator string) (err error) {
+ md := m.Descriptor()
+ fds := md.Fields()
+
+ // A struct is a sequence of "name: value", terminated by one of
+ // '>' or '}', or the end of the input. A name may also be
+ // "[extension]" or "[type/url]".
+ //
+ // The whole struct can also be an expanded Any message, like:
+ // [type/url] < ... struct contents ... >
+ seen := make(map[protoreflect.FieldNumber]bool)
+ for {
+ tok := p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ if tok.value == terminator {
+ break
+ }
+ if tok.value == "[" {
+ if err := p.unmarshalExtensionOrAny(m, seen); err != nil {
+ return err
+ }
+ continue
+ }
+
+ // This is a normal, non-extension field.
+ name := protoreflect.Name(tok.value)
+ fd := fds.ByName(name)
+ switch {
+ case fd == nil:
+ gd := fds.ByName(protoreflect.Name(strings.ToLower(string(name))))
+ if gd != nil && gd.Kind() == protoreflect.GroupKind && gd.Message().Name() == name {
+ fd = gd
+ }
+ case fd.Kind() == protoreflect.GroupKind && fd.Message().Name() != name:
+ fd = nil
+ case fd.IsWeak() && fd.Message().IsPlaceholder():
+ fd = nil
+ }
+ if fd == nil {
+ typeName := string(md.FullName())
+ if m, ok := m.Interface().(Message); ok {
+ t := reflect.TypeOf(m)
+ if t.Kind() == reflect.Ptr {
+ typeName = t.Elem().String()
+ }
+ }
+ return p.errorf("unknown field name %q in %v", name, typeName)
+ }
+ if od := fd.ContainingOneof(); od != nil && m.WhichOneof(od) != nil {
+ return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, od.Name())
+ }
+ if fd.Cardinality() != protoreflect.Repeated && seen[fd.Number()] {
+ return p.errorf("non-repeated field %q was repeated", fd.Name())
+ }
+ seen[fd.Number()] = true
+
+ // Consume any colon.
+ if err := p.checkForColon(fd); err != nil {
+ return err
+ }
+
+ // Parse into the field.
+ v := m.Get(fd)
+ if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
+ v = m.Mutable(fd)
+ }
+ if v, err = p.unmarshalValue(v, fd); err != nil {
+ return err
+ }
+ m.Set(fd, v)
+
+ if err := p.consumeOptionalSeparator(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *textParser) unmarshalExtensionOrAny(m protoreflect.Message, seen map[protoreflect.FieldNumber]bool) error {
+ name, err := p.consumeExtensionOrAnyName()
+ if err != nil {
+ return err
+ }
+
+ // If it contains a slash, it's an Any type URL.
+ if slashIdx := strings.LastIndex(name, "/"); slashIdx >= 0 {
+ tok := p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ // consume an optional colon
+ if tok.value == ":" {
+ tok = p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ }
+
+ var terminator string
+ switch tok.value {
+ case "<":
+ terminator = ">"
+ case "{":
+ terminator = "}"
+ default:
+ return p.errorf("expected '{' or '<', found %q", tok.value)
+ }
+
+ mt, err := protoregistry.GlobalTypes.FindMessageByURL(name)
+ if err != nil {
+ return p.errorf("unrecognized message %q in google.protobuf.Any", name[slashIdx+len("/"):])
+ }
+ m2 := mt.New()
+ if err := p.unmarshalMessage(m2, terminator); err != nil {
+ return err
+ }
+ b, err := protoV2.Marshal(m2.Interface())
+ if err != nil {
+ return p.errorf("failed to marshal message of type %q: %v", name[slashIdx+len("/"):], err)
+ }
+
+ urlFD := m.Descriptor().Fields().ByName("type_url")
+ valFD := m.Descriptor().Fields().ByName("value")
+ if seen[urlFD.Number()] {
+ return p.errorf("Any message unpacked multiple times, or %q already set", urlFD.Name())
+ }
+ if seen[valFD.Number()] {
+ return p.errorf("Any message unpacked multiple times, or %q already set", valFD.Name())
+ }
+ m.Set(urlFD, protoreflect.ValueOfString(name))
+ m.Set(valFD, protoreflect.ValueOfBytes(b))
+ seen[urlFD.Number()] = true
+ seen[valFD.Number()] = true
+ return nil
+ }
+
+ xname := protoreflect.FullName(name)
+ xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
+ if xt == nil && isMessageSet(m.Descriptor()) {
+ xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
+ }
+ if xt == nil {
+ return p.errorf("unrecognized extension %q", name)
+ }
+ fd := xt.TypeDescriptor()
+ if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
+ return p.errorf("extension field %q does not extend message %q", name, m.Descriptor().FullName())
+ }
+
+ if err := p.checkForColon(fd); err != nil {
+ return err
+ }
+
+ v := m.Get(fd)
+ if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
+ v = m.Mutable(fd)
+ }
+ v, err = p.unmarshalValue(v, fd)
+ if err != nil {
+ return err
+ }
+ m.Set(fd, v)
+ return p.consumeOptionalSeparator()
+}
+
+func (p *textParser) unmarshalValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
+ tok := p.next()
+ if tok.err != nil {
+ return v, tok.err
+ }
+ if tok.value == "" {
+ return v, p.errorf("unexpected EOF")
+ }
+
+ switch {
+ case fd.IsList():
+ lv := v.List()
+ var err error
+ if tok.value == "[" {
+ // Repeated field with list notation, like [1,2,3].
+ for {
+ vv := lv.NewElement()
+ vv, err = p.unmarshalSingularValue(vv, fd)
+ if err != nil {
+ return v, err
+ }
+ lv.Append(vv)
+
+ tok := p.next()
+ if tok.err != nil {
+ return v, tok.err
+ }
+ if tok.value == "]" {
+ break
+ }
+ if tok.value != "," {
+ return v, p.errorf("Expected ']' or ',' found %q", tok.value)
+ }
+ }
+ return v, nil
+ }
+
+ // One value of the repeated field.
+ p.back()
+ vv := lv.NewElement()
+ vv, err = p.unmarshalSingularValue(vv, fd)
+ if err != nil {
+ return v, err
+ }
+ lv.Append(vv)
+ return v, nil
+ case fd.IsMap():
+ // The map entry should be this sequence of tokens:
+ // < key : KEY value : VALUE >
+ // However, implementations may omit key or value, and technically
+ // we should support them in any order.
+ var terminator string
+ switch tok.value {
+ case "<":
+ terminator = ">"
+ case "{":
+ terminator = "}"
+ default:
+ return v, p.errorf("expected '{' or '<', found %q", tok.value)
+ }
+
+ keyFD := fd.MapKey()
+ valFD := fd.MapValue()
+
+ mv := v.Map()
+ kv := keyFD.Default()
+ vv := mv.NewValue()
+ for {
+ tok := p.next()
+ if tok.err != nil {
+ return v, tok.err
+ }
+ if tok.value == terminator {
+ break
+ }
+ var err error
+ switch tok.value {
+ case "key":
+ if err := p.consumeToken(":"); err != nil {
+ return v, err
+ }
+ if kv, err = p.unmarshalSingularValue(kv, keyFD); err != nil {
+ return v, err
+ }
+ if err := p.consumeOptionalSeparator(); err != nil {
+ return v, err
+ }
+ case "value":
+ if err := p.checkForColon(valFD); err != nil {
+ return v, err
+ }
+ if vv, err = p.unmarshalSingularValue(vv, valFD); err != nil {
+ return v, err
+ }
+ if err := p.consumeOptionalSeparator(); err != nil {
+ return v, err
+ }
+ default:
+ p.back()
+ return v, p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
+ }
+ }
+ mv.Set(kv.MapKey(), vv)
+ return v, nil
+ default:
+ p.back()
+ return p.unmarshalSingularValue(v, fd)
+ }
+}
+
+func (p *textParser) unmarshalSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
+ tok := p.next()
+ if tok.err != nil {
+ return v, tok.err
+ }
+ if tok.value == "" {
+ return v, p.errorf("unexpected EOF")
+ }
+
+ switch fd.Kind() {
+ case protoreflect.BoolKind:
+ switch tok.value {
+ case "true", "1", "t", "True":
+ return protoreflect.ValueOfBool(true), nil
+ case "false", "0", "f", "False":
+ return protoreflect.ValueOfBool(false), nil
+ }
+ case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
+ if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
+ return protoreflect.ValueOfInt32(int32(x)), nil
+ }
+
+ // The C++ parser accepts large positive hex numbers that uses
+ // two's complement arithmetic to represent negative numbers.
+ // This feature is here for backwards compatibility with C++.
+ if strings.HasPrefix(tok.value, "0x") {
+ if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
+ return protoreflect.ValueOfInt32(int32(-(int64(^x) + 1))), nil
+ }
+ }
+ case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
+ if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
+ return protoreflect.ValueOfInt64(int64(x)), nil
+ }
+
+ // The C++ parser accepts large positive hex numbers that uses
+ // two's complement arithmetic to represent negative numbers.
+ // This feature is here for backwards compatibility with C++.
+ if strings.HasPrefix(tok.value, "0x") {
+ if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
+ return protoreflect.ValueOfInt64(int64(-(int64(^x) + 1))), nil
+ }
+ }
+ case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
+ if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
+ return protoreflect.ValueOfUint32(uint32(x)), nil
+ }
+ case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
+ if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
+ return protoreflect.ValueOfUint64(uint64(x)), nil
+ }
+ case protoreflect.FloatKind:
+ // Ignore 'f' for compatibility with output generated by C++,
+ // but don't remove 'f' when the value is "-inf" or "inf".
+ v := tok.value
+ if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
+ v = v[:len(v)-len("f")]
+ }
+ if x, err := strconv.ParseFloat(v, 32); err == nil {
+ return protoreflect.ValueOfFloat32(float32(x)), nil
+ }
+ case protoreflect.DoubleKind:
+ // Ignore 'f' for compatibility with output generated by C++,
+ // but don't remove 'f' when the value is "-inf" or "inf".
+ v := tok.value
+ if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
+ v = v[:len(v)-len("f")]
+ }
+ if x, err := strconv.ParseFloat(v, 64); err == nil {
+ return protoreflect.ValueOfFloat64(float64(x)), nil
+ }
+ case protoreflect.StringKind:
+ if isQuote(tok.value[0]) {
+ return protoreflect.ValueOfString(tok.unquoted), nil
+ }
+ case protoreflect.BytesKind:
+ if isQuote(tok.value[0]) {
+ return protoreflect.ValueOfBytes([]byte(tok.unquoted)), nil
+ }
+ case protoreflect.EnumKind:
+ if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
+ return protoreflect.ValueOfEnum(protoreflect.EnumNumber(x)), nil
+ }
+ vd := fd.Enum().Values().ByName(protoreflect.Name(tok.value))
+ if vd != nil {
+ return protoreflect.ValueOfEnum(vd.Number()), nil
+ }
+ case protoreflect.MessageKind, protoreflect.GroupKind:
+ var terminator string
+ switch tok.value {
+ case "{":
+ terminator = "}"
+ case "<":
+ terminator = ">"
+ default:
+ return v, p.errorf("expected '{' or '<', found %q", tok.value)
+ }
+ err := p.unmarshalMessage(v.Message(), terminator)
+ return v, err
+ default:
+ panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
+ }
+ return v, p.errorf("invalid %v: %v", fd.Kind(), tok.value)
+}
+
+// Consume a ':' from the input stream (if the next token is a colon),
+// returning an error if a colon is needed but not present.
+func (p *textParser) checkForColon(fd protoreflect.FieldDescriptor) *ParseError {
+ tok := p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ if tok.value != ":" {
+ if fd.Message() == nil {
+ return p.errorf("expected ':', found %q", tok.value)
+ }
+ p.back()
+ }
+ return nil
+}
+
+// consumeExtensionOrAnyName consumes an extension name or an Any type URL and
+// the following ']'. It returns the name or URL consumed.
+func (p *textParser) consumeExtensionOrAnyName() (string, error) {
+ tok := p.next()
+ if tok.err != nil {
+ return "", tok.err
+ }
+
+ // If extension name or type url is quoted, it's a single token.
+ if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
+ name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
+ if err != nil {
+ return "", err
+ }
+ return name, p.consumeToken("]")
+ }
+
+ // Consume everything up to "]"
+ var parts []string
+ for tok.value != "]" {
+ parts = append(parts, tok.value)
+ tok = p.next()
+ if tok.err != nil {
+ return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
+ }
+ if p.done && tok.value != "]" {
+ return "", p.errorf("unclosed type_url or extension name")
+ }
+ }
+ return strings.Join(parts, ""), nil
+}
+
+// consumeOptionalSeparator consumes an optional semicolon or comma.
+// It is used in unmarshalMessage to provide backward compatibility.
+func (p *textParser) consumeOptionalSeparator() error {
+ tok := p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ if tok.value != ";" && tok.value != "," {
+ p.back()
+ }
+ return nil
+}
+
+func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
+ pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
+ p.cur.err = pe
+ p.done = true
+ return pe
+}
+
+func (p *textParser) skipWhitespace() {
+ i := 0
+ for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
+ if p.s[i] == '#' {
+ // comment; skip to end of line or input
+ for i < len(p.s) && p.s[i] != '\n' {
+ i++
+ }
+ if i == len(p.s) {
+ break
+ }
+ }
+ if p.s[i] == '\n' {
+ p.line++
+ }
+ i++
+ }
+ p.offset += i
+ p.s = p.s[i:len(p.s)]
+ if len(p.s) == 0 {
+ p.done = true
+ }
+}
+
+func (p *textParser) advance() {
+ // Skip whitespace
+ p.skipWhitespace()
+ if p.done {
+ return
+ }
+
+ // Start of non-whitespace
+ p.cur.err = nil
+ p.cur.offset, p.cur.line = p.offset, p.line
+ p.cur.unquoted = ""
+ switch p.s[0] {
+ case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
+ // Single symbol
+ p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
+ case '"', '\'':
+ // Quoted string
+ i := 1
+ for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
+ if p.s[i] == '\\' && i+1 < len(p.s) {
+ // skip escaped char
+ i++
+ }
+ i++
+ }
+ if i >= len(p.s) || p.s[i] != p.s[0] {
+ p.errorf("unmatched quote")
+ return
+ }
+ unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
+ if err != nil {
+ p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err)
+ return
+ }
+ p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
+ p.cur.unquoted = unq
+ default:
+ i := 0
+ for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
+ i++
+ }
+ if i == 0 {
+ p.errorf("unexpected byte %#x", p.s[0])
+ return
+ }
+ p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
+ }
+ p.offset += len(p.cur.value)
+}
+
+// Back off the parser by one token. Can only be done between calls to next().
+// It makes the next advance() a no-op.
+func (p *textParser) back() { p.backed = true }
+
+// Advances the parser and returns the new current token.
+func (p *textParser) next() *token {
+ if p.backed || p.done {
+ p.backed = false
+ return &p.cur
+ }
+ p.advance()
+ if p.done {
+ p.cur.value = ""
+ } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
+ // Look for multiple quoted strings separated by whitespace,
+ // and concatenate them.
+ cat := p.cur
+ for {
+ p.skipWhitespace()
+ if p.done || !isQuote(p.s[0]) {
+ break
+ }
+ p.advance()
+ if p.cur.err != nil {
+ return &p.cur
+ }
+ cat.value += " " + p.cur.value
+ cat.unquoted += p.cur.unquoted
+ }
+ p.done = false // parser may have seen EOF, but we want to return cat
+ p.cur = cat
+ }
+ return &p.cur
+}
+
+func (p *textParser) consumeToken(s string) error {
+ tok := p.next()
+ if tok.err != nil {
+ return tok.err
+ }
+ if tok.value != s {
+ p.back()
+ return p.errorf("expected %q, found %q", s, tok.value)
+ }
+ return nil
+}
+
+var errBadUTF8 = errors.New("proto: bad UTF-8")
+
+func unquoteC(s string, quote rune) (string, error) {
+ // This is based on C++'s tokenizer.cc.
+ // Despite its name, this is *not* parsing C syntax.
+ // For instance, "\0" is an invalid quoted string.
+
+ // Avoid allocation in trivial cases.
+ simple := true
+ for _, r := range s {
+ if r == '\\' || r == quote {
+ simple = false
+ break
+ }
+ }
+ if simple {
+ return s, nil
+ }
+
+ buf := make([]byte, 0, 3*len(s)/2)
+ for len(s) > 0 {
+ r, n := utf8.DecodeRuneInString(s)
+ if r == utf8.RuneError && n == 1 {
+ return "", errBadUTF8
+ }
+ s = s[n:]
+ if r != '\\' {
+ if r < utf8.RuneSelf {
+ buf = append(buf, byte(r))
+ } else {
+ buf = append(buf, string(r)...)
+ }
+ continue
+ }
+
+ ch, tail, err := unescape(s)
+ if err != nil {
+ return "", err
+ }
+ buf = append(buf, ch...)
+ s = tail
+ }
+ return string(buf), nil
+}
+
+func unescape(s string) (ch string, tail string, err error) {
+ r, n := utf8.DecodeRuneInString(s)
+ if r == utf8.RuneError && n == 1 {
+ return "", "", errBadUTF8
+ }
+ s = s[n:]
+ switch r {
+ case 'a':
+ return "\a", s, nil
+ case 'b':
+ return "\b", s, nil
+ case 'f':
+ return "\f", s, nil
+ case 'n':
+ return "\n", s, nil
+ case 'r':
+ return "\r", s, nil
+ case 't':
+ return "\t", s, nil
+ case 'v':
+ return "\v", s, nil
+ case '?':
+ return "?", s, nil // trigraph workaround
+ case '\'', '"', '\\':
+ return string(r), s, nil
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ if len(s) < 2 {
+ return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
+ }
+ ss := string(r) + s[:2]
+ s = s[2:]
+ i, err := strconv.ParseUint(ss, 8, 8)
+ if err != nil {
+ return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
+ }
+ return string([]byte{byte(i)}), s, nil
+ case 'x', 'X', 'u', 'U':
+ var n int
+ switch r {
+ case 'x', 'X':
+ n = 2
+ case 'u':
+ n = 4
+ case 'U':
+ n = 8
+ }
+ if len(s) < n {
+ return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
+ }
+ ss := s[:n]
+ s = s[n:]
+ i, err := strconv.ParseUint(ss, 16, 64)
+ if err != nil {
+ return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
+ }
+ if r == 'x' || r == 'X' {
+ return string([]byte{byte(i)}), s, nil
+ }
+ if i > utf8.MaxRune {
+ return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
+ }
+ return string(rune(i)), s, nil
+ }
+ return "", "", fmt.Errorf(`unknown escape \%c`, r)
+}
+
+func isIdentOrNumberChar(c byte) bool {
+ switch {
+ case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
+ return true
+ case '0' <= c && c <= '9':
+ return true
+ }
+ switch c {
+ case '-', '+', '.', '_':
+ return true
+ }
+ return false
+}
+
+func isWhitespace(c byte) bool {
+ switch c {
+ case ' ', '\t', '\n', '\r':
+ return true
+ }
+ return false
+}
+
+func isQuote(c byte) bool {
+ switch c {
+ case '"', '\'':
+ return true
+ }
+ return false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/text_encode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/text_encode.go
new file mode 100644
index 000000000000..a31134eeb3b7
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/text_encode.go
@@ -0,0 +1,560 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import (
+ "bytes"
+ "encoding"
+ "fmt"
+ "io"
+ "math"
+ "sort"
+ "strings"
+
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/encoding/protowire"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+)
+
+const wrapTextMarshalV2 = false
+
+// TextMarshaler is a configurable text format marshaler.
+type TextMarshaler struct {
+ Compact bool // use compact text format (one line)
+ ExpandAny bool // expand google.protobuf.Any messages of known types
+}
+
+// Marshal writes the proto text format of m to w.
+func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error {
+ b, err := tm.marshal(m)
+ if len(b) > 0 {
+ if _, err := w.Write(b); err != nil {
+ return err
+ }
+ }
+ return err
+}
+
+// Text returns a proto text formatted string of m.
+func (tm *TextMarshaler) Text(m Message) string {
+ b, _ := tm.marshal(m)
+ return string(b)
+}
+
+func (tm *TextMarshaler) marshal(m Message) ([]byte, error) {
+ mr := MessageReflect(m)
+ if mr == nil || !mr.IsValid() {
+ return []byte(""), nil
+ }
+
+ if wrapTextMarshalV2 {
+ if m, ok := m.(encoding.TextMarshaler); ok {
+ return m.MarshalText()
+ }
+
+ opts := prototext.MarshalOptions{
+ AllowPartial: true,
+ EmitUnknown: true,
+ }
+ if !tm.Compact {
+ opts.Indent = " "
+ }
+ if !tm.ExpandAny {
+ opts.Resolver = (*protoregistry.Types)(nil)
+ }
+ return opts.Marshal(mr.Interface())
+ } else {
+ w := &textWriter{
+ compact: tm.Compact,
+ expandAny: tm.ExpandAny,
+ complete: true,
+ }
+
+ if m, ok := m.(encoding.TextMarshaler); ok {
+ b, err := m.MarshalText()
+ if err != nil {
+ return nil, err
+ }
+ w.Write(b)
+ return w.buf, nil
+ }
+
+ err := w.writeMessage(mr)
+ return w.buf, err
+ }
+}
+
+var (
+ defaultTextMarshaler = TextMarshaler{}
+ compactTextMarshaler = TextMarshaler{Compact: true}
+)
+
+// MarshalText writes the proto text format of m to w.
+func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) }
+
+// MarshalTextString returns a proto text formatted string of m.
+func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) }
+
+// CompactText writes the compact proto text format of m to w.
+func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) }
+
+// CompactTextString returns a compact proto text formatted string of m.
+func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) }
+
+var (
+ newline = []byte("\n")
+ endBraceNewline = []byte("}\n")
+ posInf = []byte("inf")
+ negInf = []byte("-inf")
+ nan = []byte("nan")
+)
+
+// textWriter is an io.Writer that tracks its indentation level.
+type textWriter struct {
+ compact bool // same as TextMarshaler.Compact
+ expandAny bool // same as TextMarshaler.ExpandAny
+ complete bool // whether the current position is a complete line
+ indent int // indentation level; never negative
+ buf []byte
+}
+
+func (w *textWriter) Write(p []byte) (n int, _ error) {
+ newlines := bytes.Count(p, newline)
+ if newlines == 0 {
+ if !w.compact && w.complete {
+ w.writeIndent()
+ }
+ w.buf = append(w.buf, p...)
+ w.complete = false
+ return len(p), nil
+ }
+
+ frags := bytes.SplitN(p, newline, newlines+1)
+ if w.compact {
+ for i, frag := range frags {
+ if i > 0 {
+ w.buf = append(w.buf, ' ')
+ n++
+ }
+ w.buf = append(w.buf, frag...)
+ n += len(frag)
+ }
+ return n, nil
+ }
+
+ for i, frag := range frags {
+ if w.complete {
+ w.writeIndent()
+ }
+ w.buf = append(w.buf, frag...)
+ n += len(frag)
+ if i+1 < len(frags) {
+ w.buf = append(w.buf, '\n')
+ n++
+ }
+ }
+ w.complete = len(frags[len(frags)-1]) == 0
+ return n, nil
+}
+
+func (w *textWriter) WriteByte(c byte) error {
+ if w.compact && c == '\n' {
+ c = ' '
+ }
+ if !w.compact && w.complete {
+ w.writeIndent()
+ }
+ w.buf = append(w.buf, c)
+ w.complete = c == '\n'
+ return nil
+}
+
+func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) {
+ if !w.compact && w.complete {
+ w.writeIndent()
+ }
+ w.complete = false
+
+ if fd.Kind() != protoreflect.GroupKind {
+ w.buf = append(w.buf, fd.Name()...)
+ w.WriteByte(':')
+ } else {
+ // Use message type name for group field name.
+ w.buf = append(w.buf, fd.Message().Name()...)
+ }
+
+ if !w.compact {
+ w.WriteByte(' ')
+ }
+}
+
+func requiresQuotes(u string) bool {
+ // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
+ for _, ch := range u {
+ switch {
+ case ch == '.' || ch == '/' || ch == '_':
+ continue
+ case '0' <= ch && ch <= '9':
+ continue
+ case 'A' <= ch && ch <= 'Z':
+ continue
+ case 'a' <= ch && ch <= 'z':
+ continue
+ default:
+ return true
+ }
+ }
+ return false
+}
+
+// writeProto3Any writes an expanded google.protobuf.Any message.
+//
+// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
+// required messages are not linked in).
+//
+// It returns (true, error) when sv was written in expanded format or an error
+// was encountered.
+func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) {
+ md := m.Descriptor()
+ fdURL := md.Fields().ByName("type_url")
+ fdVal := md.Fields().ByName("value")
+
+ url := m.Get(fdURL).String()
+ mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
+ if err != nil {
+ return false, nil
+ }
+
+ b := m.Get(fdVal).Bytes()
+ m2 := mt.New()
+ if err := proto.Unmarshal(b, m2.Interface()); err != nil {
+ return false, nil
+ }
+ w.Write([]byte("["))
+ if requiresQuotes(url) {
+ w.writeQuotedString(url)
+ } else {
+ w.Write([]byte(url))
+ }
+ if w.compact {
+ w.Write([]byte("]:<"))
+ } else {
+ w.Write([]byte("]: <\n"))
+ w.indent++
+ }
+ if err := w.writeMessage(m2); err != nil {
+ return true, err
+ }
+ if w.compact {
+ w.Write([]byte("> "))
+ } else {
+ w.indent--
+ w.Write([]byte(">\n"))
+ }
+ return true, nil
+}
+
+func (w *textWriter) writeMessage(m protoreflect.Message) error {
+ md := m.Descriptor()
+ if w.expandAny && md.FullName() == "google.protobuf.Any" {
+ if canExpand, err := w.writeProto3Any(m); canExpand {
+ return err
+ }
+ }
+
+ fds := md.Fields()
+ for i := 0; i < fds.Len(); {
+ fd := fds.Get(i)
+ if od := fd.ContainingOneof(); od != nil {
+ fd = m.WhichOneof(od)
+ i += od.Fields().Len()
+ } else {
+ i++
+ }
+ if fd == nil || !m.Has(fd) {
+ continue
+ }
+
+ switch {
+ case fd.IsList():
+ lv := m.Get(fd).List()
+ for j := 0; j < lv.Len(); j++ {
+ w.writeName(fd)
+ v := lv.Get(j)
+ if err := w.writeSingularValue(v, fd); err != nil {
+ return err
+ }
+ w.WriteByte('\n')
+ }
+ case fd.IsMap():
+ kfd := fd.MapKey()
+ vfd := fd.MapValue()
+ mv := m.Get(fd).Map()
+
+ type entry struct{ key, val protoreflect.Value }
+ var entries []entry
+ mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
+ entries = append(entries, entry{k.Value(), v})
+ return true
+ })
+ sort.Slice(entries, func(i, j int) bool {
+ switch kfd.Kind() {
+ case protoreflect.BoolKind:
+ return !entries[i].key.Bool() && entries[j].key.Bool()
+ case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
+ return entries[i].key.Int() < entries[j].key.Int()
+ case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
+ return entries[i].key.Uint() < entries[j].key.Uint()
+ case protoreflect.StringKind:
+ return entries[i].key.String() < entries[j].key.String()
+ default:
+ panic("invalid kind")
+ }
+ })
+ for _, entry := range entries {
+ w.writeName(fd)
+ w.WriteByte('<')
+ if !w.compact {
+ w.WriteByte('\n')
+ }
+ w.indent++
+ w.writeName(kfd)
+ if err := w.writeSingularValue(entry.key, kfd); err != nil {
+ return err
+ }
+ w.WriteByte('\n')
+ w.writeName(vfd)
+ if err := w.writeSingularValue(entry.val, vfd); err != nil {
+ return err
+ }
+ w.WriteByte('\n')
+ w.indent--
+ w.WriteByte('>')
+ w.WriteByte('\n')
+ }
+ default:
+ w.writeName(fd)
+ if err := w.writeSingularValue(m.Get(fd), fd); err != nil {
+ return err
+ }
+ w.WriteByte('\n')
+ }
+ }
+
+ if b := m.GetUnknown(); len(b) > 0 {
+ w.writeUnknownFields(b)
+ }
+ return w.writeExtensions(m)
+}
+
+func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
+ switch fd.Kind() {
+ case protoreflect.FloatKind, protoreflect.DoubleKind:
+ switch vf := v.Float(); {
+ case math.IsInf(vf, +1):
+ w.Write(posInf)
+ case math.IsInf(vf, -1):
+ w.Write(negInf)
+ case math.IsNaN(vf):
+ w.Write(nan)
+ default:
+ fmt.Fprint(w, v.Interface())
+ }
+ case protoreflect.StringKind:
+ // NOTE: This does not validate UTF-8 for historical reasons.
+ w.writeQuotedString(string(v.String()))
+ case protoreflect.BytesKind:
+ w.writeQuotedString(string(v.Bytes()))
+ case protoreflect.MessageKind, protoreflect.GroupKind:
+ var bra, ket byte = '<', '>'
+ if fd.Kind() == protoreflect.GroupKind {
+ bra, ket = '{', '}'
+ }
+ w.WriteByte(bra)
+ if !w.compact {
+ w.WriteByte('\n')
+ }
+ w.indent++
+ m := v.Message()
+ if m2, ok := m.Interface().(encoding.TextMarshaler); ok {
+ b, err := m2.MarshalText()
+ if err != nil {
+ return err
+ }
+ w.Write(b)
+ } else {
+ w.writeMessage(m)
+ }
+ w.indent--
+ w.WriteByte(ket)
+ case protoreflect.EnumKind:
+ if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil {
+ fmt.Fprint(w, ev.Name())
+ } else {
+ fmt.Fprint(w, v.Enum())
+ }
+ default:
+ fmt.Fprint(w, v.Interface())
+ }
+ return nil
+}
+
+// writeQuotedString writes a quoted string in the protocol buffer text format.
+func (w *textWriter) writeQuotedString(s string) {
+ w.WriteByte('"')
+ for i := 0; i < len(s); i++ {
+ switch c := s[i]; c {
+ case '\n':
+ w.buf = append(w.buf, `\n`...)
+ case '\r':
+ w.buf = append(w.buf, `\r`...)
+ case '\t':
+ w.buf = append(w.buf, `\t`...)
+ case '"':
+ w.buf = append(w.buf, `\"`...)
+ case '\\':
+ w.buf = append(w.buf, `\\`...)
+ default:
+ if isPrint := c >= 0x20 && c < 0x7f; isPrint {
+ w.buf = append(w.buf, c)
+ } else {
+ w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...)
+ }
+ }
+ }
+ w.WriteByte('"')
+}
+
+func (w *textWriter) writeUnknownFields(b []byte) {
+ if !w.compact {
+ fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b))
+ }
+
+ for len(b) > 0 {
+ num, wtyp, n := protowire.ConsumeTag(b)
+ if n < 0 {
+ return
+ }
+ b = b[n:]
+
+ if wtyp == protowire.EndGroupType {
+ w.indent--
+ w.Write(endBraceNewline)
+ continue
+ }
+ fmt.Fprint(w, num)
+ if wtyp != protowire.StartGroupType {
+ w.WriteByte(':')
+ }
+ if !w.compact || wtyp == protowire.StartGroupType {
+ w.WriteByte(' ')
+ }
+ switch wtyp {
+ case protowire.VarintType:
+ v, n := protowire.ConsumeVarint(b)
+ if n < 0 {
+ return
+ }
+ b = b[n:]
+ fmt.Fprint(w, v)
+ case protowire.Fixed32Type:
+ v, n := protowire.ConsumeFixed32(b)
+ if n < 0 {
+ return
+ }
+ b = b[n:]
+ fmt.Fprint(w, v)
+ case protowire.Fixed64Type:
+ v, n := protowire.ConsumeFixed64(b)
+ if n < 0 {
+ return
+ }
+ b = b[n:]
+ fmt.Fprint(w, v)
+ case protowire.BytesType:
+ v, n := protowire.ConsumeBytes(b)
+ if n < 0 {
+ return
+ }
+ b = b[n:]
+ fmt.Fprintf(w, "%q", v)
+ case protowire.StartGroupType:
+ w.WriteByte('{')
+ w.indent++
+ default:
+ fmt.Fprintf(w, "/* unknown wire type %d */", wtyp)
+ }
+ w.WriteByte('\n')
+ }
+}
+
+// writeExtensions writes all the extensions in m.
+func (w *textWriter) writeExtensions(m protoreflect.Message) error {
+ md := m.Descriptor()
+ if md.ExtensionRanges().Len() == 0 {
+ return nil
+ }
+
+ type ext struct {
+ desc protoreflect.FieldDescriptor
+ val protoreflect.Value
+ }
+ var exts []ext
+ m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ if fd.IsExtension() {
+ exts = append(exts, ext{fd, v})
+ }
+ return true
+ })
+ sort.Slice(exts, func(i, j int) bool {
+ return exts[i].desc.Number() < exts[j].desc.Number()
+ })
+
+ for _, ext := range exts {
+ // For message set, use the name of the message as the extension name.
+ name := string(ext.desc.FullName())
+ if isMessageSet(ext.desc.ContainingMessage()) {
+ name = strings.TrimSuffix(name, ".message_set_extension")
+ }
+
+ if !ext.desc.IsList() {
+ if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil {
+ return err
+ }
+ } else {
+ lv := ext.val.List()
+ for i := 0; i < lv.Len(); i++ {
+ if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
+ fmt.Fprintf(w, "[%s]:", name)
+ if !w.compact {
+ w.WriteByte(' ')
+ }
+ if err := w.writeSingularValue(v, fd); err != nil {
+ return err
+ }
+ w.WriteByte('\n')
+ return nil
+}
+
+func (w *textWriter) writeIndent() {
+ if !w.complete {
+ return
+ }
+ for i := 0; i < w.indent*2; i++ {
+ w.buf = append(w.buf, ' ')
+ }
+ w.complete = false
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/wire.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/wire.go
new file mode 100644
index 000000000000..d7c28da5a758
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/wire.go
@@ -0,0 +1,78 @@
+// 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 proto
+
+import (
+ protoV2 "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/runtime/protoiface"
+)
+
+// Size returns the size in bytes of the wire-format encoding of m.
+func Size(m Message) int {
+ if m == nil {
+ return 0
+ }
+ mi := MessageV2(m)
+ return protoV2.Size(mi)
+}
+
+// Marshal returns the wire-format encoding of m.
+func Marshal(m Message) ([]byte, error) {
+ b, err := marshalAppend(nil, m, false)
+ if b == nil {
+ b = zeroBytes
+ }
+ return b, err
+}
+
+var zeroBytes = make([]byte, 0, 0)
+
+func marshalAppend(buf []byte, m Message, deterministic bool) ([]byte, error) {
+ if m == nil {
+ return nil, ErrNil
+ }
+ mi := MessageV2(m)
+ nbuf, err := protoV2.MarshalOptions{
+ Deterministic: deterministic,
+ AllowPartial: true,
+ }.MarshalAppend(buf, mi)
+ if err != nil {
+ return buf, err
+ }
+ if len(buf) == len(nbuf) {
+ if !mi.ProtoReflect().IsValid() {
+ return buf, ErrNil
+ }
+ }
+ return nbuf, checkRequiredNotSet(mi)
+}
+
+// Unmarshal parses a wire-format message in b and places the decoded results in m.
+//
+// Unmarshal resets m before starting to unmarshal, so any existing data in m is always
+// removed. Use UnmarshalMerge to preserve and append to existing data.
+func Unmarshal(b []byte, m Message) error {
+ m.Reset()
+ return UnmarshalMerge(b, m)
+}
+
+// UnmarshalMerge parses a wire-format message in b and places the decoded results in m.
+func UnmarshalMerge(b []byte, m Message) error {
+ mi := MessageV2(m)
+ out, err := protoV2.UnmarshalOptions{
+ AllowPartial: true,
+ Merge: true,
+ }.UnmarshalState(protoiface.UnmarshalInput{
+ Buf: b,
+ Message: mi.ProtoReflect(),
+ })
+ if err != nil {
+ return err
+ }
+ if out.Flags&protoiface.UnmarshalInitialized > 0 {
+ return nil
+ }
+ return checkRequiredNotSet(mi)
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/wrappers.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/wrappers.go
new file mode 100644
index 000000000000..398e348599bd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/proto/wrappers.go
@@ -0,0 +1,34 @@
+// 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 proto
+
+// Bool stores v in a new bool value and returns a pointer to it.
+func Bool(v bool) *bool { return &v }
+
+// Int stores v in a new int32 value and returns a pointer to it.
+//
+// Deprecated: Use Int32 instead.
+func Int(v int) *int32 { return Int32(int32(v)) }
+
+// Int32 stores v in a new int32 value and returns a pointer to it.
+func Int32(v int32) *int32 { return &v }
+
+// Int64 stores v in a new int64 value and returns a pointer to it.
+func Int64(v int64) *int64 { return &v }
+
+// Uint32 stores v in a new uint32 value and returns a pointer to it.
+func Uint32(v uint32) *uint32 { return &v }
+
+// Uint64 stores v in a new uint64 value and returns a pointer to it.
+func Uint64(v uint64) *uint64 { return &v }
+
+// Float32 stores v in a new float32 value and returns a pointer to it.
+func Float32(v float32) *float32 { return &v }
+
+// Float64 stores v in a new float64 value and returns a pointer to it.
+func Float64(v float64) *float64 { return &v }
+
+// String stores v in a new string value and returns a pointer to it.
+func String(v string) *string { return &v }
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/any.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/any.go
new file mode 100644
index 000000000000..85f9f57365fd
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/any.go
@@ -0,0 +1,179 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ptypes
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/golang/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoregistry"
+
+ anypb "github.com/golang/protobuf/ptypes/any"
+)
+
+const urlPrefix = "type.googleapis.com/"
+
+// AnyMessageName returns the message name contained in an anypb.Any message.
+// Most type assertions should use the Is function instead.
+//
+// Deprecated: Call the any.MessageName method instead.
+func AnyMessageName(any *anypb.Any) (string, error) {
+ name, err := anyMessageName(any)
+ return string(name), err
+}
+func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) {
+ if any == nil {
+ return "", fmt.Errorf("message is nil")
+ }
+ name := protoreflect.FullName(any.TypeUrl)
+ if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 {
+ name = name[i+len("/"):]
+ }
+ if !name.IsValid() {
+ return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
+ }
+ return name, nil
+}
+
+// MarshalAny marshals the given message m into an anypb.Any message.
+//
+// Deprecated: Call the anypb.New function instead.
+func MarshalAny(m proto.Message) (*anypb.Any, error) {
+ switch dm := m.(type) {
+ case DynamicAny:
+ m = dm.Message
+ case *DynamicAny:
+ if dm == nil {
+ return nil, proto.ErrNil
+ }
+ m = dm.Message
+ }
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return nil, err
+ }
+ return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil
+}
+
+// Empty returns a new message of the type specified in an anypb.Any message.
+// It returns protoregistry.NotFound if the corresponding message type could not
+// be resolved in the global registry.
+//
+// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead
+// to resolve the message name and create a new instance of it.
+func Empty(any *anypb.Any) (proto.Message, error) {
+ name, err := anyMessageName(any)
+ if err != nil {
+ return nil, err
+ }
+ mt, err := protoregistry.GlobalTypes.FindMessageByName(name)
+ if err != nil {
+ return nil, err
+ }
+ return proto.MessageV1(mt.New().Interface()), nil
+}
+
+// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message
+// into the provided message m. It returns an error if the target message
+// does not match the type in the Any message or if an unmarshal error occurs.
+//
+// The target message m may be a *DynamicAny message. If the underlying message
+// type could not be resolved, then this returns protoregistry.NotFound.
+//
+// Deprecated: Call the any.UnmarshalTo method instead.
+func UnmarshalAny(any *anypb.Any, m proto.Message) error {
+ if dm, ok := m.(*DynamicAny); ok {
+ if dm.Message == nil {
+ var err error
+ dm.Message, err = Empty(any)
+ if err != nil {
+ return err
+ }
+ }
+ m = dm.Message
+ }
+
+ anyName, err := AnyMessageName(any)
+ if err != nil {
+ return err
+ }
+ msgName := proto.MessageName(m)
+ if anyName != msgName {
+ return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName)
+ }
+ return proto.Unmarshal(any.Value, m)
+}
+
+// Is reports whether the Any message contains a message of the specified type.
+//
+// Deprecated: Call the any.MessageIs method instead.
+func Is(any *anypb.Any, m proto.Message) bool {
+ if any == nil || m == nil {
+ return false
+ }
+ name := proto.MessageName(m)
+ if !strings.HasSuffix(any.TypeUrl, name) {
+ return false
+ }
+ return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/'
+}
+
+// DynamicAny is a value that can be passed to UnmarshalAny to automatically
+// allocate a proto.Message for the type specified in an anypb.Any message.
+// The allocated message is stored in the embedded proto.Message.
+//
+// Example:
+// var x ptypes.DynamicAny
+// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
+// fmt.Printf("unmarshaled message: %v", x.Message)
+//
+// Deprecated: Use the any.UnmarshalNew method instead to unmarshal
+// the any message contents into a new instance of the underlying message.
+type DynamicAny struct{ proto.Message }
+
+func (m DynamicAny) String() string {
+ if m.Message == nil {
+ return ""
+ }
+ return m.Message.String()
+}
+func (m DynamicAny) Reset() {
+ if m.Message == nil {
+ return
+ }
+ m.Message.Reset()
+}
+func (m DynamicAny) ProtoMessage() {
+ return
+}
+func (m DynamicAny) ProtoReflect() protoreflect.Message {
+ if m.Message == nil {
+ return nil
+ }
+ return dynamicAny{proto.MessageReflect(m.Message)}
+}
+
+type dynamicAny struct{ protoreflect.Message }
+
+func (m dynamicAny) Type() protoreflect.MessageType {
+ return dynamicAnyType{m.Message.Type()}
+}
+func (m dynamicAny) New() protoreflect.Message {
+ return dynamicAnyType{m.Message.Type()}.New()
+}
+func (m dynamicAny) Interface() protoreflect.ProtoMessage {
+ return DynamicAny{proto.MessageV1(m.Message.Interface())}
+}
+
+type dynamicAnyType struct{ protoreflect.MessageType }
+
+func (t dynamicAnyType) New() protoreflect.Message {
+ return dynamicAny{t.MessageType.New()}
+}
+func (t dynamicAnyType) Zero() protoreflect.Message {
+ return dynamicAny{t.MessageType.Zero()}
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
new file mode 100644
index 000000000000..0ef27d33deb9
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
@@ -0,0 +1,62 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: github.com/golang/protobuf/ptypes/any/any.proto
+
+package any
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ anypb "google.golang.org/protobuf/types/known/anypb"
+ reflect "reflect"
+)
+
+// Symbols defined in public import of google/protobuf/any.proto.
+
+type Any = anypb.Any
+
+var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor
+
+var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{
+ 0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
+ 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
+ 0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
+ 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65,
+ 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
+}
+
+var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{}
+var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() }
+func file_github_com_golang_protobuf_ptypes_any_any_proto_init() {
+ if File_github_com_golang_protobuf_ptypes_any_any_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 0,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes,
+ DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs,
+ }.Build()
+ File_github_com_golang_protobuf_ptypes_any_any_proto = out.File
+ file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil
+ file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil
+ file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/doc.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/doc.go
new file mode 100644
index 000000000000..d3c33259d28d
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/doc.go
@@ -0,0 +1,10 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ptypes provides functionality for interacting with well-known types.
+//
+// Deprecated: Well-known types have specialized functionality directly
+// injected into the generated packages for each message type.
+// See the deprecation notice for each function for the suggested alternative.
+package ptypes
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/duration.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/duration.go
new file mode 100644
index 000000000000..b2b55dd851f5
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/duration.go
@@ -0,0 +1,76 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ptypes
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ durationpb "github.com/golang/protobuf/ptypes/duration"
+)
+
+// Range of google.protobuf.Duration as specified in duration.proto.
+// This is about 10,000 years in seconds.
+const (
+ maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
+ minSeconds = -maxSeconds
+)
+
+// Duration converts a durationpb.Duration to a time.Duration.
+// Duration returns an error if dur is invalid or overflows a time.Duration.
+//
+// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead.
+func Duration(dur *durationpb.Duration) (time.Duration, error) {
+ if err := validateDuration(dur); err != nil {
+ return 0, err
+ }
+ d := time.Duration(dur.Seconds) * time.Second
+ if int64(d/time.Second) != dur.Seconds {
+ return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
+ }
+ if dur.Nanos != 0 {
+ d += time.Duration(dur.Nanos) * time.Nanosecond
+ if (d < 0) != (dur.Nanos < 0) {
+ return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
+ }
+ }
+ return d, nil
+}
+
+// DurationProto converts a time.Duration to a durationpb.Duration.
+//
+// Deprecated: Call the durationpb.New function instead.
+func DurationProto(d time.Duration) *durationpb.Duration {
+ nanos := d.Nanoseconds()
+ secs := nanos / 1e9
+ nanos -= secs * 1e9
+ return &durationpb.Duration{
+ Seconds: int64(secs),
+ Nanos: int32(nanos),
+ }
+}
+
+// validateDuration determines whether the durationpb.Duration is valid
+// according to the definition in google/protobuf/duration.proto.
+// A valid durpb.Duration may still be too large to fit into a time.Duration
+// Note that the range of durationpb.Duration is about 10,000 years,
+// while the range of time.Duration is about 290 years.
+func validateDuration(dur *durationpb.Duration) error {
+ if dur == nil {
+ return errors.New("duration: nil Duration")
+ }
+ if dur.Seconds < minSeconds || dur.Seconds > maxSeconds {
+ return fmt.Errorf("duration: %v: seconds out of range", dur)
+ }
+ if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 {
+ return fmt.Errorf("duration: %v: nanos out of range", dur)
+ }
+ // Seconds and Nanos must have the same sign, unless d.Nanos is zero.
+ if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) {
+ return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
new file mode 100644
index 000000000000..d0079ee3ef37
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
@@ -0,0 +1,63 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: github.com/golang/protobuf/ptypes/duration/duration.proto
+
+package duration
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+ reflect "reflect"
+)
+
+// Symbols defined in public import of google/protobuf/duration.proto.
+
+type Duration = durationpb.Duration
+
+var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor
+
+var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{
+ 0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
+ 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
+ 0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
+ 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
+ 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{}
+var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() }
+func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() {
+ if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 0,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes,
+ DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs,
+ }.Build()
+ File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File
+ file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil
+ file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil
+ file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/timestamp.go
new file mode 100644
index 000000000000..8368a3f70d38
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/timestamp.go
@@ -0,0 +1,112 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ptypes
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ timestamppb "github.com/golang/protobuf/ptypes/timestamp"
+)
+
+// Range of google.protobuf.Duration as specified in timestamp.proto.
+const (
+ // Seconds field of the earliest valid Timestamp.
+ // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
+ minValidSeconds = -62135596800
+ // Seconds field just after the latest valid Timestamp.
+ // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
+ maxValidSeconds = 253402300800
+)
+
+// Timestamp converts a timestamppb.Timestamp to a time.Time.
+// It returns an error if the argument is invalid.
+//
+// Unlike most Go functions, if Timestamp returns an error, the first return
+// value is not the zero time.Time. Instead, it is the value obtained from the
+// time.Unix function when passed the contents of the Timestamp, in the UTC
+// locale. This may or may not be a meaningful time; many invalid Timestamps
+// do map to valid time.Times.
+//
+// A nil Timestamp returns an error. The first return value in that case is
+// undefined.
+//
+// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead.
+func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) {
+ // Don't return the zero value on error, because corresponds to a valid
+ // timestamp. Instead return whatever time.Unix gives us.
+ var t time.Time
+ if ts == nil {
+ t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
+ } else {
+ t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
+ }
+ return t, validateTimestamp(ts)
+}
+
+// TimestampNow returns a google.protobuf.Timestamp for the current time.
+//
+// Deprecated: Call the timestamppb.Now function instead.
+func TimestampNow() *timestamppb.Timestamp {
+ ts, err := TimestampProto(time.Now())
+ if err != nil {
+ panic("ptypes: time.Now() out of Timestamp range")
+ }
+ return ts
+}
+
+// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
+// It returns an error if the resulting Timestamp is invalid.
+//
+// Deprecated: Call the timestamppb.New function instead.
+func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) {
+ ts := ×tamppb.Timestamp{
+ Seconds: t.Unix(),
+ Nanos: int32(t.Nanosecond()),
+ }
+ if err := validateTimestamp(ts); err != nil {
+ return nil, err
+ }
+ return ts, nil
+}
+
+// TimestampString returns the RFC 3339 string for valid Timestamps.
+// For invalid Timestamps, it returns an error message in parentheses.
+//
+// Deprecated: Call the ts.AsTime method instead,
+// followed by a call to the Format method on the time.Time value.
+func TimestampString(ts *timestamppb.Timestamp) string {
+ t, err := Timestamp(ts)
+ if err != nil {
+ return fmt.Sprintf("(%v)", err)
+ }
+ return t.Format(time.RFC3339Nano)
+}
+
+// validateTimestamp determines whether a Timestamp is valid.
+// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01)
+// and has a Nanos field in the range [0, 1e9).
+//
+// If the Timestamp is valid, validateTimestamp returns nil.
+// Otherwise, it returns an error that describes the problem.
+//
+// Every valid Timestamp can be represented by a time.Time,
+// but the converse is not true.
+func validateTimestamp(ts *timestamppb.Timestamp) error {
+ if ts == nil {
+ return errors.New("timestamp: nil Timestamp")
+ }
+ if ts.Seconds < minValidSeconds {
+ return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
+ }
+ if ts.Seconds >= maxValidSeconds {
+ return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
+ }
+ if ts.Nanos < 0 || ts.Nanos >= 1e9 {
+ return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
+ }
+ return nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
new file mode 100644
index 000000000000..a76f80760094
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
@@ -0,0 +1,64 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
+
+package timestamp
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ reflect "reflect"
+)
+
+// Symbols defined in public import of google/protobuf/timestamp.proto.
+
+type Timestamp = timestamppb.Timestamp
+
+var File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto protoreflect.FileDescriptor
+
+var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = []byte{
+ 0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
+ 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
+ 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69,
+ 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
+ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37,
+ 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
+ 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
+ 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69,
+ 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
+}
+
+var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = []interface{}{}
+var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() }
+func file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() {
+ if File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 0,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes,
+ DependencyIndexes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs,
+ }.Build()
+ File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto = out.File
+ file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = nil
+ file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = nil
+ file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/.gitignore b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/.gitignore
new file mode 100644
index 000000000000..042091d9b3b0
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/.gitignore
@@ -0,0 +1,16 @@
+cmd/snappytool/snappytool
+testdata/bench
+
+# These explicitly listed benchmark data files are for an obsolete version of
+# snappy_test.go.
+testdata/alice29.txt
+testdata/asyoulik.txt
+testdata/fireworks.jpeg
+testdata/geo.protodata
+testdata/html
+testdata/html_x_4
+testdata/kppkn.gtb
+testdata/lcet10.txt
+testdata/paper-100k.pdf
+testdata/plrabn12.txt
+testdata/urls.10K
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/AUTHORS b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/AUTHORS
new file mode 100644
index 000000000000..52ccb5a934d1
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/AUTHORS
@@ -0,0 +1,18 @@
+# This is the official list of Snappy-Go authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+
+# Names should be added to this file as
+# Name or Organization
+# The email address is not required for organizations.
+
+# Please keep the list sorted.
+
+Amazon.com, Inc
+Damian Gryski
+Eric Buth
+Google Inc.
+Jan Mercl <0xjnml@gmail.com>
+Klaus Post
+Rodolfo Carvalho
+Sebastien Binet
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/CONTRIBUTORS b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/CONTRIBUTORS
new file mode 100644
index 000000000000..ea6524ddd02f
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/CONTRIBUTORS
@@ -0,0 +1,41 @@
+# This is the official list of people who can contribute
+# (and typically have contributed) code to the Snappy-Go repository.
+# The AUTHORS file lists the copyright holders; this file
+# lists people. For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+# The submission process automatically checks to make sure
+# that people submitting code are listed in this file (by email address).
+#
+# Names should be added to this file only after verifying that
+# the individual or the individual's organization has agreed to
+# the appropriate Contributor License Agreement, found here:
+#
+# http://code.google.com/legal/individual-cla-v1.0.html
+# http://code.google.com/legal/corporate-cla-v1.0.html
+#
+# The agreement for individuals can be filled out on the web.
+#
+# When adding J Random Contributor's name to this file,
+# either J's name or J's organization's name should be
+# added to the AUTHORS file, depending on whether the
+# individual or corporate CLA was used.
+
+# Names should be added to this file like so:
+# Name
+
+# Please keep the list sorted.
+
+Alex Legg
+Damian Gryski
+Eric Buth
+Jan Mercl <0xjnml@gmail.com>
+Jonathan Swinney
+Kai Backman
+Klaus Post
+Marc-Antoine Ruel
+Nigel Tao
+Rob Pike
+Rodolfo Carvalho
+Russ Cox
+Sebastien Binet
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/LICENSE b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/LICENSE
new file mode 100644
index 000000000000..6050c10f4c8b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/README b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/README
new file mode 100644
index 000000000000..cea12879a0ea
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/README
@@ -0,0 +1,107 @@
+The Snappy compression format in the Go programming language.
+
+To download and install from source:
+$ go get github.com/golang/snappy
+
+Unless otherwise noted, the Snappy-Go source files are distributed
+under the BSD-style license found in the LICENSE file.
+
+
+
+Benchmarks.
+
+The golang/snappy benchmarks include compressing (Z) and decompressing (U) ten
+or so files, the same set used by the C++ Snappy code (github.com/google/snappy
+and note the "google", not "golang"). On an "Intel(R) Core(TM) i7-3770 CPU @
+3.40GHz", Go's GOARCH=amd64 numbers as of 2016-05-29:
+
+"go test -test.bench=."
+
+_UFlat0-8 2.19GB/s ± 0% html
+_UFlat1-8 1.41GB/s ± 0% urls
+_UFlat2-8 23.5GB/s ± 2% jpg
+_UFlat3-8 1.91GB/s ± 0% jpg_200
+_UFlat4-8 14.0GB/s ± 1% pdf
+_UFlat5-8 1.97GB/s ± 0% html4
+_UFlat6-8 814MB/s ± 0% txt1
+_UFlat7-8 785MB/s ± 0% txt2
+_UFlat8-8 857MB/s ± 0% txt3
+_UFlat9-8 719MB/s ± 1% txt4
+_UFlat10-8 2.84GB/s ± 0% pb
+_UFlat11-8 1.05GB/s ± 0% gaviota
+
+_ZFlat0-8 1.04GB/s ± 0% html
+_ZFlat1-8 534MB/s ± 0% urls
+_ZFlat2-8 15.7GB/s ± 1% jpg
+_ZFlat3-8 740MB/s ± 3% jpg_200
+_ZFlat4-8 9.20GB/s ± 1% pdf
+_ZFlat5-8 991MB/s ± 0% html4
+_ZFlat6-8 379MB/s ± 0% txt1
+_ZFlat7-8 352MB/s ± 0% txt2
+_ZFlat8-8 396MB/s ± 1% txt3
+_ZFlat9-8 327MB/s ± 1% txt4
+_ZFlat10-8 1.33GB/s ± 1% pb
+_ZFlat11-8 605MB/s ± 1% gaviota
+
+
+
+"go test -test.bench=. -tags=noasm"
+
+_UFlat0-8 621MB/s ± 2% html
+_UFlat1-8 494MB/s ± 1% urls
+_UFlat2-8 23.2GB/s ± 1% jpg
+_UFlat3-8 1.12GB/s ± 1% jpg_200
+_UFlat4-8 4.35GB/s ± 1% pdf
+_UFlat5-8 609MB/s ± 0% html4
+_UFlat6-8 296MB/s ± 0% txt1
+_UFlat7-8 288MB/s ± 0% txt2
+_UFlat8-8 309MB/s ± 1% txt3
+_UFlat9-8 280MB/s ± 1% txt4
+_UFlat10-8 753MB/s ± 0% pb
+_UFlat11-8 400MB/s ± 0% gaviota
+
+_ZFlat0-8 409MB/s ± 1% html
+_ZFlat1-8 250MB/s ± 1% urls
+_ZFlat2-8 12.3GB/s ± 1% jpg
+_ZFlat3-8 132MB/s ± 0% jpg_200
+_ZFlat4-8 2.92GB/s ± 0% pdf
+_ZFlat5-8 405MB/s ± 1% html4
+_ZFlat6-8 179MB/s ± 1% txt1
+_ZFlat7-8 170MB/s ± 1% txt2
+_ZFlat8-8 189MB/s ± 1% txt3
+_ZFlat9-8 164MB/s ± 1% txt4
+_ZFlat10-8 479MB/s ± 1% pb
+_ZFlat11-8 270MB/s ± 1% gaviota
+
+
+
+For comparison (Go's encoded output is byte-for-byte identical to C++'s), here
+are the numbers from C++ Snappy's
+
+make CXXFLAGS="-O2 -DNDEBUG -g" clean snappy_unittest.log && cat snappy_unittest.log
+
+BM_UFlat/0 2.4GB/s html
+BM_UFlat/1 1.4GB/s urls
+BM_UFlat/2 21.8GB/s jpg
+BM_UFlat/3 1.5GB/s jpg_200
+BM_UFlat/4 13.3GB/s pdf
+BM_UFlat/5 2.1GB/s html4
+BM_UFlat/6 1.0GB/s txt1
+BM_UFlat/7 959.4MB/s txt2
+BM_UFlat/8 1.0GB/s txt3
+BM_UFlat/9 864.5MB/s txt4
+BM_UFlat/10 2.9GB/s pb
+BM_UFlat/11 1.2GB/s gaviota
+
+BM_ZFlat/0 944.3MB/s html (22.31 %)
+BM_ZFlat/1 501.6MB/s urls (47.78 %)
+BM_ZFlat/2 14.3GB/s jpg (99.95 %)
+BM_ZFlat/3 538.3MB/s jpg_200 (73.00 %)
+BM_ZFlat/4 8.3GB/s pdf (83.30 %)
+BM_ZFlat/5 903.5MB/s html4 (22.52 %)
+BM_ZFlat/6 336.0MB/s txt1 (57.88 %)
+BM_ZFlat/7 312.3MB/s txt2 (61.91 %)
+BM_ZFlat/8 353.1MB/s txt3 (54.99 %)
+BM_ZFlat/9 289.9MB/s txt4 (66.26 %)
+BM_ZFlat/10 1.2GB/s pb (19.68 %)
+BM_ZFlat/11 527.4MB/s gaviota (37.72 %)
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/decode.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/decode.go
new file mode 100644
index 000000000000..23c6e26c6b9b
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/decode.go
@@ -0,0 +1,264 @@
+// Copyright 2011 The Snappy-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package snappy
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+var (
+ // ErrCorrupt reports that the input is invalid.
+ ErrCorrupt = errors.New("snappy: corrupt input")
+ // ErrTooLarge reports that the uncompressed length is too large.
+ ErrTooLarge = errors.New("snappy: decoded block is too large")
+ // ErrUnsupported reports that the input isn't supported.
+ ErrUnsupported = errors.New("snappy: unsupported input")
+
+ errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
+)
+
+// DecodedLen returns the length of the decoded block.
+func DecodedLen(src []byte) (int, error) {
+ v, _, err := decodedLen(src)
+ return v, err
+}
+
+// decodedLen returns the length of the decoded block and the number of bytes
+// that the length header occupied.
+func decodedLen(src []byte) (blockLen, headerLen int, err error) {
+ v, n := binary.Uvarint(src)
+ if n <= 0 || v > 0xffffffff {
+ return 0, 0, ErrCorrupt
+ }
+
+ const wordSize = 32 << (^uint(0) >> 32 & 1)
+ if wordSize == 32 && v > 0x7fffffff {
+ return 0, 0, ErrTooLarge
+ }
+ return int(v), n, nil
+}
+
+const (
+ decodeErrCodeCorrupt = 1
+ decodeErrCodeUnsupportedLiteralLength = 2
+)
+
+// Decode returns the decoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire decoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// Decode handles the Snappy block format, not the Snappy stream format.
+func Decode(dst, src []byte) ([]byte, error) {
+ dLen, s, err := decodedLen(src)
+ if err != nil {
+ return nil, err
+ }
+ if dLen <= len(dst) {
+ dst = dst[:dLen]
+ } else {
+ dst = make([]byte, dLen)
+ }
+ switch decode(dst, src[s:]) {
+ case 0:
+ return dst, nil
+ case decodeErrCodeUnsupportedLiteralLength:
+ return nil, errUnsupportedLiteralLength
+ }
+ return nil, ErrCorrupt
+}
+
+// NewReader returns a new Reader that decompresses from r, using the framing
+// format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ r: r,
+ decoded: make([]byte, maxBlockSize),
+ buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
+ }
+}
+
+// Reader is an io.Reader that can read Snappy-compressed bytes.
+//
+// Reader handles the Snappy stream format, not the Snappy block format.
+type Reader struct {
+ r io.Reader
+ err error
+ decoded []byte
+ buf []byte
+ // decoded[i:j] contains decoded bytes that have not yet been passed on.
+ i, j int
+ readHeader bool
+}
+
+// Reset discards any buffered data, resets all state, and switches the Snappy
+// reader to read from r. This permits reusing a Reader rather than allocating
+// a new one.
+func (r *Reader) Reset(reader io.Reader) {
+ r.r = reader
+ r.err = nil
+ r.i = 0
+ r.j = 0
+ r.readHeader = false
+}
+
+func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
+ if _, r.err = io.ReadFull(r.r, p); r.err != nil {
+ if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrCorrupt
+ }
+ return false
+ }
+ return true
+}
+
+func (r *Reader) fill() error {
+ for r.i >= r.j {
+ if !r.readFull(r.buf[:4], true) {
+ return r.err
+ }
+ chunkType := r.buf[0]
+ if !r.readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+ if chunkLen > len(r.buf) {
+ r.err = ErrUnsupported
+ return r.err
+ }
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ buf := r.buf[:chunkLen]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[checksumSize:]
+
+ n, err := DecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return r.err
+ }
+ if n > len(r.decoded) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if _, err := Decode(r.decoded, buf); err != nil {
+ r.err = err
+ return r.err
+ }
+ if crc(r.decoded[:n]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeUncompressedData:
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ buf := r.buf[:checksumSize]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read directly into r.decoded instead of via r.buf.
+ n := chunkLen - checksumSize
+ if n > len(r.decoded) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.decoded[:n], false) {
+ return r.err
+ }
+ if crc(r.decoded[:n]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.buf[:len(magicBody)], false) {
+ return r.err
+ }
+ for i := 0; i < len(magicBody); i++ {
+ if r.buf[i] != magicBody[i] {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ }
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ r.err = ErrUnsupported
+ return r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if !r.readFull(r.buf[:chunkLen], false) {
+ return r.err
+ }
+ }
+
+ return nil
+}
+
+// Read satisfies the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+
+ if err := r.fill(); err != nil {
+ return 0, err
+ }
+
+ n := copy(p, r.decoded[r.i:r.j])
+ r.i += n
+ return n, nil
+}
+
+// ReadByte satisfies the io.ByteReader interface.
+func (r *Reader) ReadByte() (byte, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+
+ if err := r.fill(); err != nil {
+ return 0, err
+ }
+
+ c := r.decoded[r.i]
+ r.i++
+ return c, nil
+}
diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/decode_amd64.s b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/decode_amd64.s
new file mode 100644
index 000000000000..e6179f65e351
--- /dev/null
+++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang/snappy/decode_amd64.s
@@ -0,0 +1,490 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+// +build gc
+// +build !noasm
+
+#include "textflag.h"
+
+// The asm code generally follows the pure Go code in decode_other.go, except
+// where marked with a "!!!".
+
+// func decode(dst, src []byte) int
+//
+// All local variables fit into registers. The non-zero stack size is only to
+// spill registers and push args when issuing a CALL. The register allocation:
+// - AX scratch
+// - BX scratch
+// - CX length or x
+// - DX offset
+// - SI &src[s]
+// - DI &dst[d]
+// + R8 dst_base
+// + R9 dst_len
+// + R10 dst_base + dst_len
+// + R11 src_base
+// + R12 src_len
+// + R13 src_base + src_len
+// - R14 used by doCopy
+// - R15 used by doCopy
+//
+// The registers R8-R13 (marked with a "+") are set at the start of the
+// function, and after a CALL returns, and are not otherwise modified.
+//
+// The d variable is implicitly DI - R8, and len(dst)-d is R10 - DI.
+// The s variable is implicitly SI - R11, and len(src)-s is R13 - SI.
+TEXT ·decode(SB), NOSPLIT, $48-56
+ // Initialize SI, DI and R8-R13.
+ MOVQ dst_base+0(FP), R8
+ MOVQ dst_len+8(FP), R9
+ MOVQ R8, DI
+ MOVQ R8, R10
+ ADDQ R9, R10
+ MOVQ src_base+24(FP), R11
+ MOVQ src_len+32(FP), R12
+ MOVQ R11, SI
+ MOVQ R11, R13
+ ADDQ R12, R13
+
+loop:
+ // for s < len(src)
+ CMPQ SI, R13
+ JEQ end
+
+ // CX = uint32(src[s])
+ //
+ // switch src[s] & 0x03
+ MOVBLZX (SI), CX
+ MOVL CX, BX
+ ANDL $3, BX
+ CMPL BX, $1
+ JAE tagCopy
+
+ // ----------------------------------------
+ // The code below handles literal tags.
+
+ // case tagLiteral:
+ // x := uint32(src[s] >> 2)
+ // switch
+ SHRL $2, CX
+ CMPL CX, $60
+ JAE tagLit60Plus
+
+ // case x < 60:
+ // s++
+ INCQ SI
+
+doLit:
+ // This is the end of the inner "switch", when we have a literal tag.
+ //
+ // We assume that CX == x and x fits in a uint32, where x is the variable
+ // used in the pure Go decode_other.go code.
+
+ // length = int(x) + 1
+ //
+ // Unlike the pure Go code, we don't need to check if length <= 0 because
+ // CX can hold 64 bits, so the increment cannot overflow.
+ INCQ CX
+
+ // Prepare to check if copying length bytes will run past the end of dst or
+ // src.
+ //
+ // AX = len(dst) - d
+ // BX = len(src) - s
+ MOVQ R10, AX
+ SUBQ DI, AX
+ MOVQ R13, BX
+ SUBQ SI, BX
+
+ // !!! Try a faster technique for short (16 or fewer bytes) copies.
+ //
+ // if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
+ // goto callMemmove // Fall back on calling runtime·memmove.
+ // }
+ //
+ // The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
+ // against 21 instead of 16, because it cannot assume that all of its input
+ // is contiguous in memory and so it needs to leave enough source bytes to
+ // read the next tag without refilling buffers, but Go's Decode assumes
+ // contiguousness (the src argument is a []byte).
+ CMPQ CX, $16
+ JGT callMemmove
+ CMPQ AX, $16
+ JLT callMemmove
+ CMPQ BX, $16
+ JLT callMemmove
+
+ // !!! Implement the copy from src to dst as a 16-byte load and store.
+ // (Decode's documentation says that dst and src must not overlap.)
+ //
+ // This always copies 16 bytes, instead of only length bytes, but that's
+ // OK. If the input is a valid Snappy encoding then subsequent iterations
+ // will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
+ // non-nil error), so the overrun will be ignored.
+ //
+ // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
+ // 16-byte loads and stores. This technique probably wouldn't be as
+ // effective on architectures that are fussier about alignment.
+ MOVOU 0(SI), X0
+ MOVOU X0, 0(DI)
+
+ // d += length
+ // s += length
+ ADDQ CX, DI
+ ADDQ CX, SI
+ JMP loop
+
+callMemmove:
+ // if length > len(dst)-d || length > len(src)-s { etc }
+ CMPQ CX, AX
+ JGT errCorrupt
+ CMPQ CX, BX
+ JGT errCorrupt
+
+ // copy(dst[d:], src[s:s+length])
+ //
+ // This means calling runtime·memmove(&dst[d], &src[s], length), so we push
+ // DI, SI and CX as arguments. Coincidentally, we also need to spill those
+ // three registers to the stack, to save local variables across the CALL.
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ CX, 16(SP)
+ MOVQ DI, 24(SP)
+ MOVQ SI, 32(SP)
+ MOVQ CX, 40(SP)
+ CALL runtime·memmove(SB)
+
+ // Restore local variables: unspill registers from the stack and
+ // re-calculate R8-R13.
+ MOVQ 24(SP), DI
+ MOVQ 32(SP), SI
+ MOVQ 40(SP), CX
+ MOVQ dst_base+0(FP), R8
+ MOVQ dst_len+8(FP), R9
+ MOVQ R8, R10
+ ADDQ R9, R10
+ MOVQ src_base+24(FP), R11
+ MOVQ src_len+32(FP), R12
+ MOVQ R11, R13
+ ADDQ R12, R13
+
+ // d += length
+ // s += length
+ ADDQ CX, DI
+ ADDQ CX, SI
+ JMP loop
+
+tagLit60Plus:
+ // !!! This fragment does the
+ //
+ // s += x - 58; if uint(s) > uint(len(src)) { etc }
+ //
+ // checks. In the asm version, we code it once instead of once per switch case.
+ ADDQ CX, SI
+ SUBQ $58, SI
+ MOVQ SI, BX
+ SUBQ R11, BX
+ CMPQ BX, R12
+ JA errCorrupt
+
+ // case x == 60:
+ CMPL CX, $61
+ JEQ tagLit61
+ JA tagLit62Plus
+
+ // x = uint32(src[s-1])
+ MOVBLZX -1(SI), CX
+ JMP doLit
+
+tagLit61:
+ // case x == 61:
+ // x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ MOVWLZX -2(SI), CX
+ JMP doLit
+
+tagLit62Plus:
+ CMPL CX, $62
+ JA tagLit63
+
+ // case x == 62:
+ // x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ MOVWLZX -3(SI), CX
+ MOVBLZX -1(SI), BX
+ SHLL $16, BX
+ ORL BX, CX
+ JMP doLit
+
+tagLit63:
+ // case x == 63:
+ // x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ MOVL -4(SI), CX
+ JMP doLit
+
+// The code above handles literal tags.
+// ----------------------------------------
+// The code below handles copy tags.
+
+tagCopy4:
+ // case tagCopy4:
+ // s += 5
+ ADDQ $5, SI
+
+ // if uint(s) > uint(len(src)) { etc }
+ MOVQ SI, BX
+ SUBQ R11, BX
+ CMPQ BX, R12
+ JA errCorrupt
+
+ // length = 1 + int(src[s-5])>>2
+ SHRQ $2, CX
+ INCQ CX
+
+ // offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ MOVLQZX -4(SI), DX
+ JMP doCopy
+
+tagCopy2:
+ // case tagCopy2:
+ // s += 3
+ ADDQ $3, SI
+
+ // if uint(s) > uint(len(src)) { etc }
+ MOVQ SI, BX
+ SUBQ R11, BX
+ CMPQ BX, R12
+ JA errCorrupt
+
+ // length = 1 + int(src[s-3])>>2
+ SHRQ $2, CX
+ INCQ CX
+
+ // offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+ MOVWQZX -2(SI), DX
+ JMP doCopy
+
+tagCopy:
+ // We have a copy tag. We assume that:
+ // - BX == src[s] & 0x03
+ // - CX == src[s]
+ CMPQ BX, $2
+ JEQ tagCopy2
+ JA tagCopy4
+
+ // case tagCopy1:
+ // s += 2
+ ADDQ $2, SI
+
+ // if uint(s) > uint(len(src)) { etc }
+ MOVQ SI, BX
+ SUBQ R11, BX
+ CMPQ BX, R12
+ JA errCorrupt
+
+ // offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+ MOVQ CX, DX
+ ANDQ $0xe0, DX
+ SHLQ $3, DX
+ MOVBQZX -1(SI), BX
+ ORQ BX, DX
+
+ // length = 4 + int(src[s-2])>>2&0x7
+ SHRQ $2, CX
+ ANDQ $7, CX
+ ADDQ $4, CX
+
+doCopy:
+ // This is the end of the outer "switch", when we have a copy tag.
+ //
+ // We assume that:
+ // - CX == length && CX > 0
+ // - DX == offset
+
+ // if offset <= 0 { etc }
+ CMPQ DX, $0
+ JLE errCorrupt
+
+ // if d < offset { etc }
+ MOVQ DI, BX
+ SUBQ R8, BX
+ CMPQ BX, DX
+ JLT errCorrupt
+
+ // if length > len(dst)-d { etc }
+ MOVQ R10, BX
+ SUBQ DI, BX
+ CMPQ CX, BX
+ JGT errCorrupt
+
+ // forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
+ //
+ // Set:
+ // - R14 = len(dst)-d
+ // - R15 = &dst[d-offset]
+ MOVQ R10, R14
+ SUBQ DI, R14
+ MOVQ DI, R15
+ SUBQ DX, R15
+
+ // !!! Try a faster technique for short (16 or fewer bytes) forward copies.
+ //
+ // First, try using two 8-byte load/stores, similar to the doLit technique
+ // above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
+ // still OK if offset >= 8. Note that this has to be two 8-byte load/stores
+ // and not one 16-byte load/store, and the first store has to be before the
+ // second load, due to the overlap if offset is in the range [8, 16).
+ //
+ // if length > 16 || offset < 8 || len(dst)-d < 16 {
+ // goto slowForwardCopy
+ // }
+ // copy 16 bytes
+ // d += length
+ CMPQ CX, $16
+ JGT slowForwardCopy
+ CMPQ DX, $8
+ JLT slowForwardCopy
+ CMPQ R14, $16
+ JLT slowForwardCopy
+ MOVQ 0(R15), AX
+ MOVQ AX, 0(DI)
+ MOVQ 8(R15), BX
+ MOVQ BX, 8(DI)
+ ADDQ CX, DI
+ JMP loop
+
+slowForwardCopy:
+ // !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
+ // can still try 8-byte load stores, provided we can overrun up to 10 extra
+ // bytes. As above, the overrun will be fixed up by subsequent iterations
+ // of the outermost loop.
+ //
+ // The C++ snappy code calls this technique IncrementalCopyFastPath. Its
+ // commentary says:
+ //
+ // ----
+ //
+ // The main part of this loop is a simple copy of eight bytes at a time
+ // until we've copied (at least) the requested amount of bytes. However,
+ // if d and d-offset are less than eight bytes apart (indicating a
+ // repeating pattern of length < 8), we first need to expand the pattern in
+ // order to get the correct results. For instance, if the buffer looks like
+ // this, with the eight-byte and patterns marked as
+ // intervals:
+ //
+ // abxxxxxxxxxxxx
+ // [------] d-offset
+ // [------] d
+ //
+ // a single eight-byte copy from to will repeat the pattern
+ // once, after which we can move two bytes without moving