mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-21 14:07:30 -06:00
[chore]: Bump github.com/gin-contrib/gzip from 1.2.2 to 1.2.3
Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.2.2 to 1.2.3. - [Release notes](https://github.com/gin-contrib/gzip/releases) - [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml) - [Commits](https://github.com/gin-contrib/gzip/compare/v1.2.2...v1.2.3) --- updated-dependencies: - dependency-name: github.com/gin-contrib/gzip dependency-version: 1.2.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
parent
c803620531
commit
41a5f6e513
220 changed files with 127887 additions and 125516 deletions
23
vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go
generated
vendored
23
vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go
generated
vendored
|
|
@ -1,7 +1,6 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
|
|
@ -169,7 +168,9 @@ func (c *compiler) compileBasic(vt reflect.Type) decFunc {
|
|||
case reflect.Struct:
|
||||
return c.compileStruct(vt)
|
||||
default:
|
||||
panic(&json.UnmarshalTypeError{Type: vt})
|
||||
return &unsupportedTypeDecoder{
|
||||
typ: rt.UnpackType(vt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +264,7 @@ func (c *compiler) compileSlice(vt reflect.Type) decFunc {
|
|||
if et.IsUint64() {
|
||||
return &sliceU64Decoder{}
|
||||
}
|
||||
if et.Kind() == reflect.String {
|
||||
if et.Kind() == reflect.String && et != rt.JsonNumberType {
|
||||
return &sliceStringDecoder{}
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +344,7 @@ func (c *compiler) compileMap(vt reflect.Type) decFunc {
|
|||
// Some common integer map later
|
||||
mt := rt.MapType(rt.UnpackType(vt))
|
||||
|
||||
if mt.Key.Kind() == reflect.String {
|
||||
if mt.Key.Kind() == reflect.String && mt.Key != rt.JsonNumberType {
|
||||
return &mapStrKeyDecoder{
|
||||
mapType: mt,
|
||||
assign: rt.GetMapStrAssign(vt),
|
||||
|
|
@ -399,7 +400,7 @@ func tryCompileKeyUnmarshaler(vt reflect.Type) decKey {
|
|||
return decodeKeyTextUnmarshaler
|
||||
}
|
||||
|
||||
/* not support map key with `json.Unmarshaler` */
|
||||
/* NOTE: encoding/json not support map key with `json.Unmarshaler` */
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -413,8 +414,18 @@ func (c *compiler) compileMapKey(vt reflect.Type) decKey {
|
|||
return decodeKeyU8
|
||||
case reflect.Uint16:
|
||||
return decodeKeyU16
|
||||
// NOTE: actually, encoding/json can't use float as map key
|
||||
case reflect.Float32:
|
||||
return decodeFloat32Key
|
||||
case reflect.Float64:
|
||||
return decodeFloat64Key
|
||||
case reflect.String:
|
||||
if rt.UnpackType(vt.Key()) == rt.JsonNumberType {
|
||||
return decodeJsonNumberKey
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
panic(&json.UnmarshalTypeError{Type: vt})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
6
vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go
generated
vendored
6
vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go
generated
vendored
|
|
@ -70,4 +70,10 @@
|
|||
Msg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func error_unsuppoted(typ *rt.GoType) error {
|
||||
return &json.UnsupportedTypeError{
|
||||
Type: typ.Pack(),
|
||||
}
|
||||
}
|
||||
|
||||
13
vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go
generated
vendored
13
vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go
generated
vendored
|
|
@ -279,3 +279,16 @@ func (d *recuriveDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) er
|
|||
}
|
||||
return dec.FromDom(vp, node, ctx)
|
||||
}
|
||||
|
||||
type unsupportedTypeDecoder struct {
|
||||
typ *rt.GoType
|
||||
}
|
||||
|
||||
|
||||
func (d *unsupportedTypeDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
return error_unsuppoted(d.typ)
|
||||
}
|
||||
|
||||
|
|
|
|||
45
vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go
generated
vendored
45
vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go
generated
vendored
|
|
@ -13,32 +13,44 @@ type efaceDecoder struct {
|
|||
}
|
||||
|
||||
func (d *efaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*interface{})(vp) = interface{}(nil)
|
||||
return nil
|
||||
}
|
||||
/* check the defined pointer type for issue 379 */
|
||||
eface := (*rt.GoEface)(vp)
|
||||
|
||||
eface := *(*rt.GoEface)(vp)
|
||||
|
||||
// not pointer type, or nil pointer, or *interface{}
|
||||
if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || rt.PtrElem(eface.Type) == anyType {
|
||||
/*
|
||||
not pointer type, or nil pointer, or self-pointed interface{}, such as
|
||||
```go
|
||||
var v interface{}
|
||||
v = &v
|
||||
return v
|
||||
``` see `issue758_test.go`.
|
||||
*/
|
||||
if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || eface.Value == vp {
|
||||
ret, err := node.AsEface(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*interface{})(vp) = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.IsNull() {
|
||||
if eface.Type.Indirect() || (!eface.Type.Indirect() && eface.Type.Pack().Elem().Kind() != reflect.Ptr) {
|
||||
*(*interface{})(vp) = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
etp := rt.PtrElem(eface.Type)
|
||||
vp = eface.Value
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if eface.Type.IsNamed() {
|
||||
// check named pointer type, avoid call its `Unmarshaler`
|
||||
newp := vp
|
||||
etp = eface.Type
|
||||
vp = unsafe.Pointer(&newp)
|
||||
} else if !eface.Type.Indirect() {
|
||||
// check direct value
|
||||
etp = rt.UnpackType(eface.Type.Pack().Elem())
|
||||
}
|
||||
|
||||
dec, err := findOrCompile(etp)
|
||||
|
|
@ -65,19 +77,10 @@ func (d *ifaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error
|
|||
}
|
||||
|
||||
vt := iface.Itab.Vt
|
||||
|
||||
// not pointer type, or nil pointer, or *interface{}
|
||||
if vp == nil || vt.Kind() != reflect.Ptr || rt.PtrElem(vt) == anyType {
|
||||
ret, err := node.AsEface(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*interface{})(vp) = ret
|
||||
return nil
|
||||
if vt.Kind() != reflect.Ptr || iface.Value == nil {
|
||||
return error_type(d.typ)
|
||||
}
|
||||
|
||||
|
||||
etp := rt.PtrElem(vt)
|
||||
vp = iface.Value
|
||||
|
||||
|
|
|
|||
56
vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go
generated
vendored
56
vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go
generated
vendored
|
|
@ -292,9 +292,9 @@ func (d *mapU64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) e
|
|||
|
||||
/** Decoder for generic cases */
|
||||
|
||||
type decKey func(dec *mapDecoder, raw string, ctx *context) (interface{}, error)
|
||||
type decKey func(dec *mapDecoder, raw string) (interface{}, error)
|
||||
|
||||
func decodeKeyU8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
func decodeKeyU8(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -309,7 +309,7 @@ func decodeKeyU8(dec *mapDecoder, raw string, ctx *context) (interface{}, error)
|
|||
return uint8(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyU16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
func decodeKeyU16(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -324,7 +324,7 @@ func decodeKeyU16(dec *mapDecoder, raw string, ctx *context) (interface{}, error
|
|||
return uint16(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyI8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
func decodeKeyI8(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -339,7 +339,7 @@ func decodeKeyI8(dec *mapDecoder, raw string, ctx *context) (interface{}, error)
|
|||
return int8(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyI16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
func decodeKeyI16(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -354,26 +354,53 @@ func decodeKeyI16(dec *mapDecoder, raw string, ctx *context) (interface{}, error
|
|||
return int16(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyJSONUnmarshaler(dec *mapDecoder, raw string, _ *context) (interface{}, error) {
|
||||
func decodeKeyTextUnmarshaler(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := reflect.New(dec.mapType.Key.Pack()).Interface()
|
||||
err := ret.(json.Unmarshaler).UnmarshalJSON([]byte(raw))
|
||||
err = ret.(encoding.TextUnmarshaler).UnmarshalText(rt.Str2Mem(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func decodeKeyTextUnmarshaler(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
func decodeFloat32Key(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := reflect.New(dec.mapType.Key.Pack()).Interface()
|
||||
err = ret.(encoding.TextUnmarshaler).UnmarshalText([]byte(key))
|
||||
ret, err := ParseF64(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
if ret > math.MaxFloat32 || ret < -math.MaxFloat32 {
|
||||
return nil, error_value(key, dec.mapType.Key.Pack())
|
||||
}
|
||||
return float32(ret), nil
|
||||
}
|
||||
|
||||
func decodeFloat64Key(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParseF64(key)
|
||||
}
|
||||
|
||||
func decodeJsonNumberKey(dec *mapDecoder, raw string) (interface{}, error) {
|
||||
// skip the quote
|
||||
raw = raw[1:len(raw)-1]
|
||||
end, ok := SkipNumberFast(raw, 0)
|
||||
|
||||
// check trailing chars
|
||||
if !ok || end != len(raw) {
|
||||
return nil, error_value(raw, rt.JsonNumberType.Pack())
|
||||
}
|
||||
|
||||
return json.Number(raw[0:end]), nil
|
||||
}
|
||||
|
||||
type mapDecoder struct {
|
||||
|
|
@ -389,8 +416,8 @@ func (d *mapDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
|||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
if !ok || d.keyDec == nil {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
|
||||
// allocate map
|
||||
|
|
@ -404,7 +431,8 @@ func (d *mapDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
|||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
raw := keyn.AsRaw(ctx)
|
||||
key, err := d.keyDec(d, raw, ctx)
|
||||
|
||||
key, err := d.keyDec(d, raw)
|
||||
if err != nil {
|
||||
if gerr == nil {
|
||||
gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
|
||||
|
|
|
|||
7
vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go
generated
vendored
7
vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go
generated
vendored
|
|
@ -74,6 +74,7 @@ type nodeBuf struct {
|
|||
depth uint64
|
||||
nstart uintptr
|
||||
nend uintptr
|
||||
iskey bool
|
||||
stat jsonStat
|
||||
}
|
||||
|
||||
|
|
@ -196,14 +197,14 @@ func (p *Parser) parse() ErrorCode {
|
|||
|
||||
// check OoB here
|
||||
offset := p.nbuf.ncur - p.nbuf.nstart
|
||||
curLen := offset / unsafe.Sizeof(node{})
|
||||
if curLen != uintptr(len(p.nodes)) {
|
||||
curLen := int(offset / unsafe.Sizeof(node{}))
|
||||
if curLen != len(p.nodes) {
|
||||
panic(fmt.Sprintf("current len: %d, real len: %d cap: %d", curLen, len(p.nodes), cap(p.nodes)))
|
||||
}
|
||||
|
||||
// node buf is not enough, continue parse
|
||||
// the maxCap is always meet all valid JSON
|
||||
maxCap := calMaxNodeCap(len(p.Json))
|
||||
maxCap := curLen + calMaxNodeCap(len(p.Json) - int(p.cur - p.start))
|
||||
slice := rt.GoSlice{
|
||||
Ptr: rt.Mallocgc(uintptr(maxCap) * nodeType.Size, nodeType, false),
|
||||
Len: maxCap,
|
||||
|
|
|
|||
64
vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go
generated
vendored
64
vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go
generated
vendored
|
|
@ -301,6 +301,17 @@ func (self Node) AsI64(ctx *Context) (int64, bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (self Node) AsByte(ctx *Context) (uint8, bool) {
|
||||
typ := self.Type()
|
||||
if typ == KUint && self.U64() <= math.MaxUint8 {
|
||||
return uint8(self.U64()), true
|
||||
} else if typ == KSint && self.I64() == 0 {
|
||||
return 0, true
|
||||
} else {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
/********* Parse Node String into Value ***************/
|
||||
|
||||
func (val Node) ParseI64(ctx *Context) (int64, bool) {
|
||||
|
|
@ -457,20 +468,6 @@ func (val Node) AsStrRef(ctx *Context) (string, bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (val Node) AsBytesRef(ctx *Context) ([]byte, bool) {
|
||||
switch val.Type() {
|
||||
case KStringEscaped:
|
||||
node := ptrCast(val.cptr)
|
||||
offset := val.Position()
|
||||
len := int(node.val)
|
||||
return ctx.Parser.JsonBytes()[offset : offset + len], true
|
||||
case KStringCommon:
|
||||
return rt.Str2Mem(val.StringRef(ctx)), true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
func (val Node) AsStringText(ctx *Context) ([]byte, bool) {
|
||||
if !val.IsStr() {
|
||||
return nil, false
|
||||
|
|
@ -551,7 +548,7 @@ func (val Node) AsRaw(ctx *Context) string {
|
|||
node := ptrCast(val.cptr)
|
||||
len := int(node.val)
|
||||
offset := val.Position()
|
||||
// add start abd end quote
|
||||
// add start and end quote
|
||||
ref := rt.Str2Mem(ctx.Parser.Json)[offset-1 : offset+len+1]
|
||||
return rt.Mem2Str(ref)
|
||||
case KRawNumber: fallthrough
|
||||
|
|
@ -867,15 +864,38 @@ func (node *Node) AsSliceString(ctx *Context, vp unsafe.Pointer) error {
|
|||
return gerr
|
||||
}
|
||||
|
||||
func (node *Node) AsSliceBytes(ctx *Context) ([]byte, error) {
|
||||
b, ok := node.AsBytesRef(ctx)
|
||||
if !ok {
|
||||
return nil, newUnmatched(node.Position(), rt.BytesType)
|
||||
func (val *Node) AsSliceBytes(ctx *Context) ([]byte, error) {
|
||||
var origin []byte
|
||||
switch val.Type() {
|
||||
case KStringEscaped:
|
||||
node := ptrCast(val.cptr)
|
||||
offset := val.Position()
|
||||
len := int(node.val)
|
||||
origin = ctx.Parser.JsonBytes()[offset : offset + len]
|
||||
case KStringCommon:
|
||||
origin = rt.Str2Mem(val.StringRef(ctx))
|
||||
case KArray:
|
||||
arr := val.Array()
|
||||
size := arr.Len()
|
||||
a := make([]byte, size)
|
||||
elem := NewNode(arr.Children())
|
||||
var gerr error
|
||||
var ok bool
|
||||
for i := 0; i < size; i++ {
|
||||
a[i], ok = elem.AsByte(ctx)
|
||||
if !ok && gerr == nil {
|
||||
gerr = newUnmatched(val.Position(), rt.BytesType)
|
||||
}
|
||||
elem = NewNode(PtrOffset(elem.cptr, 1))
|
||||
}
|
||||
return a, gerr
|
||||
default:
|
||||
return nil, newUnmatched(val.Position(), rt.BytesType)
|
||||
}
|
||||
|
||||
b64, err := rt.DecodeBase64(b)
|
||||
|
||||
b64, err := rt.DecodeBase64(origin)
|
||||
if err != nil {
|
||||
return nil, newUnmatched(node.Position(), rt.BytesType)
|
||||
return nil, newUnmatched(val.Position(), rt.BytesType)
|
||||
}
|
||||
return b64, nil
|
||||
}
|
||||
|
|
|
|||
27
vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go
generated
vendored
27
vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go
generated
vendored
|
|
@ -80,9 +80,13 @@ func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error
|
|||
}
|
||||
|
||||
/* zero rest of array */
|
||||
ptr := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size)
|
||||
addr := uintptr(vp) + uintptr(i)*d.elemType.Size
|
||||
n := uintptr(d.len-i) * d.elemType.Size
|
||||
rt.ClearMemory(d.elemType, ptr, n)
|
||||
|
||||
/* the boundary pointer may points to another unknown object, so we need to avoid using it */
|
||||
if n != 0 {
|
||||
rt.ClearMemory(d.elemType, unsafe.Pointer(addr), n)
|
||||
}
|
||||
return gerr
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +99,18 @@ func (d *sliceEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context)
|
|||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceEface(ctx, vp)
|
||||
/* if slice is empty, just call `AsSliceEface` */
|
||||
if ((*rt.GoSlice)(vp)).Len == 0 {
|
||||
return node.AsSliceEface(ctx, vp)
|
||||
}
|
||||
|
||||
decoder := sliceDecoder{
|
||||
elemType: rt.AnyType,
|
||||
elemDec: &efaceDecoder{},
|
||||
typ: rt.SliceEfaceType.Pack(),
|
||||
}
|
||||
|
||||
return decoder.FromDom(vp, node, ctx)
|
||||
}
|
||||
|
||||
type sliceI32Decoder struct {
|
||||
|
|
@ -168,12 +183,8 @@ func (d *sliceBytesDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context)
|
|||
}
|
||||
|
||||
s, err := node.AsSliceBytes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*[]byte)(vp) = s
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
type sliceBytesUnmarshalerDecoder struct {
|
||||
|
|
|
|||
3
vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go
generated
vendored
3
vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go
generated
vendored
|
|
@ -4,6 +4,7 @@ import (
|
|||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/decoder/consts"
|
||||
caching "github.com/bytedance/sonic/internal/optcaching"
|
||||
"github.com/bytedance/sonic/internal/resolver"
|
||||
)
|
||||
|
|
@ -38,7 +39,7 @@ func (d *structDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) erro
|
|||
next = val.Next()
|
||||
|
||||
// find field idx
|
||||
idx := d.fieldMap.Get(key)
|
||||
idx := d.fieldMap.Get(key, ctx.Options()&uint64(consts.OptionCaseSensitive) != 0)
|
||||
if idx == -1 {
|
||||
if Options(ctx.Options())&OptionDisableUnknown != 0 {
|
||||
return error_field(key)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue