Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -23,6 +23,15 @@ from google.protobuf import symbol_database as _symbol_database
|
|||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
def _BuildNestedDescriptors(module, msg_des, prefix):
|
||||
for name, nested_msg in msg_des.nested_types_by_name.items():
|
||||
module_name = prefix + name.upper()
|
||||
module[module_name] = nested_msg
|
||||
_BuildNestedDescriptors(module, nested_msg, module_name + '_')
|
||||
for enum_des in msg_des.enum_types:
|
||||
module[prefix + enum_des.name.upper()] = enum_des
|
||||
|
||||
|
||||
def BuildMessageAndEnumDescriptors(file_des, module):
|
||||
"""Builds message and enum descriptors.
|
||||
|
||||
|
|
@ -30,19 +39,26 @@ def BuildMessageAndEnumDescriptors(file_des, module):
|
|||
file_des: FileDescriptor of the .proto file
|
||||
module: Generated _pb2 module
|
||||
"""
|
||||
|
||||
def BuildNestedDescriptors(msg_des, prefix):
|
||||
for (name, nested_msg) in msg_des.nested_types_by_name.items():
|
||||
module_name = prefix + name.upper()
|
||||
module[module_name] = nested_msg
|
||||
BuildNestedDescriptors(nested_msg, module_name + '_')
|
||||
for enum_des in msg_des.enum_types:
|
||||
module[prefix + enum_des.name.upper()] = enum_des
|
||||
|
||||
for (name, msg_des) in file_des.message_types_by_name.items():
|
||||
module_name = '_' + name.upper()
|
||||
module[module_name] = msg_des
|
||||
BuildNestedDescriptors(msg_des, module_name + '_')
|
||||
_BuildNestedDescriptors(module, msg_des, module_name + '_')
|
||||
|
||||
|
||||
def _BuildMessage(module_name, msg_des, prefix):
|
||||
create_dict = {}
|
||||
for name, nested_msg in msg_des.nested_types_by_name.items():
|
||||
create_dict[name] = _BuildMessage(
|
||||
module_name, nested_msg, prefix + msg_des.name + '.'
|
||||
)
|
||||
create_dict['DESCRIPTOR'] = msg_des
|
||||
create_dict['__module__'] = module_name
|
||||
create_dict['__qualname__'] = prefix + msg_des.name
|
||||
message_class = _reflection.GeneratedProtocolMessageType(
|
||||
msg_des.name, (_message.Message,), create_dict
|
||||
)
|
||||
_sym_db.RegisterMessage(message_class)
|
||||
return message_class
|
||||
|
||||
|
||||
def BuildTopDescriptorsAndMessages(file_des, module_name, module):
|
||||
|
|
@ -54,18 +70,6 @@ def BuildTopDescriptorsAndMessages(file_des, module_name, module):
|
|||
module: Generated _pb2 module
|
||||
"""
|
||||
|
||||
def BuildMessage(msg_des, prefix):
|
||||
create_dict = {}
|
||||
for (name, nested_msg) in msg_des.nested_types_by_name.items():
|
||||
create_dict[name] = BuildMessage(nested_msg, prefix + msg_des.name + '.')
|
||||
create_dict['DESCRIPTOR'] = msg_des
|
||||
create_dict['__module__'] = module_name
|
||||
create_dict['__qualname__'] = prefix + msg_des.name
|
||||
message_class = _reflection.GeneratedProtocolMessageType(
|
||||
msg_des.name, (_message.Message,), create_dict)
|
||||
_sym_db.RegisterMessage(message_class)
|
||||
return message_class
|
||||
|
||||
# top level enums
|
||||
for (name, enum_des) in file_des.enum_types_by_name.items():
|
||||
module['_' + name.upper()] = enum_des
|
||||
|
|
@ -84,7 +88,7 @@ def BuildTopDescriptorsAndMessages(file_des, module_name, module):
|
|||
|
||||
# Build messages.
|
||||
for (name, msg_des) in file_des.message_types_by_name.items():
|
||||
module[name] = BuildMessage(msg_des, '')
|
||||
module[name] = _BuildMessage(module_name, msg_des, '')
|
||||
|
||||
|
||||
def AddHelpersToExtensions(file_des):
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ _T = TypeVar('_T')
|
|||
_K = TypeVar('_K')
|
||||
_V = TypeVar('_V')
|
||||
|
||||
from google.protobuf.descriptor import FieldDescriptor
|
||||
|
||||
class BaseContainer(Sequence[_T]):
|
||||
"""Base container class."""
|
||||
|
|
@ -104,12 +105,13 @@ class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]):
|
|||
"""Simple, type-checked, list-like container for holding repeated scalars."""
|
||||
|
||||
# Disallows assignment to other attributes.
|
||||
__slots__ = ['_type_checker']
|
||||
__slots__ = ['_type_checker', '_field']
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message_listener: Any,
|
||||
type_checker: Any,
|
||||
field: Any = None,
|
||||
) -> None:
|
||||
"""Args:
|
||||
|
||||
|
|
@ -121,6 +123,7 @@ class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]):
|
|||
"""
|
||||
super().__init__(message_listener)
|
||||
self._type_checker = type_checker
|
||||
self._field = field
|
||||
|
||||
def append(self, value: _T) -> None:
|
||||
"""Appends an item to the list. Similar to list.append()."""
|
||||
|
|
@ -202,7 +205,8 @@ class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]):
|
|||
unused_memo: Any = None,
|
||||
) -> 'RepeatedScalarFieldContainer[_T]':
|
||||
clone = RepeatedScalarFieldContainer(
|
||||
copy.deepcopy(self._message_listener), self._type_checker)
|
||||
copy.deepcopy(self._message_listener), self._type_checker, self._field
|
||||
)
|
||||
clone.MergeFrom(self)
|
||||
return clone
|
||||
|
||||
|
|
@ -210,6 +214,38 @@ class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]):
|
|||
raise pickle.PickleError(
|
||||
"Can't pickle repeated scalar fields, convert to list first")
|
||||
|
||||
def __array__(self, dtype=None, copy=None):
|
||||
import numpy as np
|
||||
|
||||
if dtype is None:
|
||||
cpp_type = self._field.cpp_type
|
||||
if cpp_type == FieldDescriptor.CPPTYPE_INT32:
|
||||
dtype = np.int32
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_INT64:
|
||||
dtype = np.int64
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_UINT32:
|
||||
dtype = np.uint32
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_UINT64:
|
||||
dtype = np.uint64
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_DOUBLE:
|
||||
dtype = np.float64
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_FLOAT:
|
||||
dtype = np.float32
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_BOOL:
|
||||
dtype = np.bool
|
||||
elif cpp_type == FieldDescriptor.CPPTYPE_ENUM:
|
||||
dtype = np.int32
|
||||
elif self._field.type == FieldDescriptor.TYPE_BYTES:
|
||||
dtype = 'S'
|
||||
elif self._field.type == FieldDescriptor.TYPE_STRING:
|
||||
dtype = str
|
||||
else:
|
||||
raise SystemError(
|
||||
'Code should never reach here: message type detected in'
|
||||
' RepeatedScalarFieldContainer'
|
||||
)
|
||||
return np.array(self._values, dtype=dtype, copy=True)
|
||||
|
||||
|
||||
# TODO: Constrain T to be a subtype of Message.
|
||||
class RepeatedCompositeFieldContainer(BaseContainer[_T], MutableSequence[_T]):
|
||||
|
|
|
|||
|
|
@ -835,7 +835,7 @@ def MessageSetItemDecoder(descriptor):
|
|||
local_ReadTag = ReadTag
|
||||
local_DecodeVarint = _DecodeVarint
|
||||
|
||||
def DecodeItem(buffer, pos, end, message, field_dict):
|
||||
def DecodeItem(buffer, pos, end, message, field_dict, current_depth=0):
|
||||
"""Decode serialized message set to its value and new position.
|
||||
|
||||
Args:
|
||||
|
|
@ -888,10 +888,19 @@ def MessageSetItemDecoder(descriptor):
|
|||
message_factory.GetMessageClass(message_type)
|
||||
value = field_dict.setdefault(
|
||||
extension, message_type._concrete_class())
|
||||
if value._InternalParse(buffer, message_start,message_end) != message_end:
|
||||
current_depth += 1
|
||||
if current_depth > _recursion_limit:
|
||||
raise _DecodeError('Error parsing message: too many levels of nesting.')
|
||||
if (
|
||||
value._InternalParse(
|
||||
buffer, message_start, message_end, current_depth
|
||||
)
|
||||
!= message_end
|
||||
):
|
||||
# The only reason _InternalParse would return early is if it encountered
|
||||
# an end-group tag.
|
||||
raise _DecodeError('Unexpected end-group tag.')
|
||||
current_depth -= 1
|
||||
else:
|
||||
if not message._unknown_fields:
|
||||
message._unknown_fields = []
|
||||
|
|
@ -957,7 +966,6 @@ def MapDecoder(field_descriptor, new_default, is_message_map):
|
|||
message_type = field_descriptor.message_type
|
||||
|
||||
def DecodeMap(buffer, pos, end, message, field_dict, current_depth=0):
|
||||
del current_depth # Unused.
|
||||
submsg = message_type._concrete_class()
|
||||
value = field_dict.get(key)
|
||||
if value is None:
|
||||
|
|
@ -970,10 +978,14 @@ def MapDecoder(field_descriptor, new_default, is_message_map):
|
|||
raise _DecodeError('Truncated message.')
|
||||
# Read sub-message.
|
||||
submsg.Clear()
|
||||
if submsg._InternalParse(buffer, pos, new_pos) != new_pos:
|
||||
current_depth += 1
|
||||
if current_depth > _recursion_limit:
|
||||
raise _DecodeError('Error parsing message: too many levels of nesting.')
|
||||
if submsg._InternalParse(buffer, pos, new_pos, current_depth) != new_pos:
|
||||
# The only reason _InternalParse would return early is if it
|
||||
# encountered an end-group tag.
|
||||
raise _DecodeError('Unexpected end-group tag.')
|
||||
current_depth -= 1
|
||||
|
||||
if is_message_map:
|
||||
value[submsg.key].CopyFrom(submsg.value)
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ class FieldMask(object):
|
|||
__slots__ = ()
|
||||
|
||||
def ToJsonString(self):
|
||||
"""Converts FieldMask to string according to proto3 JSON spec."""
|
||||
"""Converts FieldMask to string according to ProtoJSON spec."""
|
||||
camelcase_paths = []
|
||||
for path in self.paths:
|
||||
camelcase_paths.append(_SnakeCaseToCamelCase(path))
|
||||
return ','.join(camelcase_paths)
|
||||
|
||||
def FromJsonString(self, value):
|
||||
"""Converts string to FieldMask according to proto3 JSON spec."""
|
||||
"""Converts string to FieldMask according to ProtoJSON spec."""
|
||||
if not isinstance(value, str):
|
||||
raise ValueError('FieldMask JSON value not a string: {!r}'.format(value))
|
||||
self.Clear()
|
||||
|
|
@ -237,9 +237,16 @@ class _FieldMaskTree(object):
|
|||
"""Adds leaf nodes begin with prefix to this tree."""
|
||||
if not node:
|
||||
self.AddPath(prefix)
|
||||
for name in node:
|
||||
child_path = prefix + '.' + name
|
||||
self.AddLeafNodes(child_path, node[name])
|
||||
return
|
||||
stack = [(prefix, node)]
|
||||
while stack:
|
||||
current_prefix, current_node = stack.pop()
|
||||
if not current_node:
|
||||
self.AddPath(current_prefix)
|
||||
continue
|
||||
for name in current_node:
|
||||
child_path = current_prefix + '.' + name
|
||||
stack.append((child_path, current_node[name]))
|
||||
|
||||
def MergeMessage(
|
||||
self, source, destination,
|
||||
|
|
@ -262,51 +269,58 @@ def _StrConvert(value):
|
|||
def _MergeMessage(
|
||||
node, source, destination, replace_message, replace_repeated):
|
||||
"""Merge all fields specified by a sub-tree from source to destination."""
|
||||
source_descriptor = source.DESCRIPTOR
|
||||
for name in node:
|
||||
child = node[name]
|
||||
field = source_descriptor.fields_by_name[name]
|
||||
if field is None:
|
||||
raise ValueError('Error: Can\'t find field {0} in message {1}.'.format(
|
||||
name, source_descriptor.full_name))
|
||||
if child:
|
||||
# Sub-paths are only allowed for singular message fields.
|
||||
if (field.is_repeated or
|
||||
field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE):
|
||||
raise ValueError('Error: Field {0} in message {1} is not a singular '
|
||||
'message field and cannot have sub-fields.'.format(
|
||||
name, source_descriptor.full_name))
|
||||
if source.HasField(name):
|
||||
_MergeMessage(
|
||||
child, getattr(source, name), getattr(destination, name),
|
||||
replace_message, replace_repeated)
|
||||
continue
|
||||
if field.is_repeated:
|
||||
if replace_repeated:
|
||||
destination.ClearField(_StrConvert(name))
|
||||
repeated_source = getattr(source, name)
|
||||
repeated_destination = getattr(destination, name)
|
||||
repeated_destination.MergeFrom(repeated_source)
|
||||
else:
|
||||
if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if replace_message:
|
||||
destination.ClearField(_StrConvert(name))
|
||||
if source.HasField(name):
|
||||
getattr(destination, name).MergeFrom(getattr(source, name))
|
||||
elif not field.has_presence or source.HasField(name):
|
||||
setattr(destination, name, getattr(source, name))
|
||||
stack = [(node, source, destination)]
|
||||
while stack:
|
||||
current_node, current_source, current_destination = stack.pop()
|
||||
source_descriptor = current_source.DESCRIPTOR
|
||||
for name in current_node:
|
||||
child = current_node[name]
|
||||
field = source_descriptor.fields_by_name[name]
|
||||
if field is None:
|
||||
raise ValueError('Error: Can\'t find field {0} in message {1}.'.format(
|
||||
name, source_descriptor.full_name))
|
||||
if child:
|
||||
# Sub-paths are only allowed for singular message fields.
|
||||
if (field.is_repeated or
|
||||
field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE):
|
||||
raise ValueError('Error: Field {0} in message {1} is not a singular '
|
||||
'message field and cannot have sub-fields.'.format(
|
||||
name, source_descriptor.full_name))
|
||||
if current_source.HasField(name):
|
||||
stack.append(
|
||||
(child, getattr(current_source, name),
|
||||
getattr(current_destination, name)))
|
||||
continue
|
||||
if field.is_repeated:
|
||||
if replace_repeated:
|
||||
current_destination.ClearField(_StrConvert(name))
|
||||
repeated_source = getattr(current_source, name)
|
||||
repeated_destination = getattr(current_destination, name)
|
||||
repeated_destination.MergeFrom(repeated_source)
|
||||
else:
|
||||
destination.ClearField(_StrConvert(name))
|
||||
if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if replace_message:
|
||||
current_destination.ClearField(_StrConvert(name))
|
||||
if current_source.HasField(name):
|
||||
getattr(current_destination, name).MergeFrom(
|
||||
getattr(current_source, name))
|
||||
elif not field.has_presence or current_source.HasField(name):
|
||||
setattr(current_destination, name, getattr(current_source, name))
|
||||
else:
|
||||
current_destination.ClearField(_StrConvert(name))
|
||||
|
||||
|
||||
def _AddFieldPaths(node, prefix, field_mask):
|
||||
"""Adds the field paths descended from node to field_mask."""
|
||||
if not node and prefix:
|
||||
field_mask.paths.append(prefix)
|
||||
return
|
||||
for name in sorted(node):
|
||||
if prefix:
|
||||
child_path = prefix + '.' + name
|
||||
else:
|
||||
child_path = name
|
||||
_AddFieldPaths(node[name], child_path, field_mask)
|
||||
stack = [(node, prefix)]
|
||||
while stack:
|
||||
current_node, current_prefix = stack.pop()
|
||||
if not current_node and current_prefix:
|
||||
field_mask.paths.append(current_prefix)
|
||||
continue
|
||||
for name in sorted(current_node, reverse=True):
|
||||
if current_prefix:
|
||||
child_path = current_prefix + '.' + name
|
||||
else:
|
||||
child_path = name
|
||||
stack.append((current_node[name], child_path))
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
This file contains the serialized FeatureSetDefaults object corresponding to
|
||||
the Pure Python runtime. This is used for feature resolution under Editions.
|
||||
"""
|
||||
_PROTOBUF_INTERNAL_PYTHON_EDITION_DEFAULTS = b"\n\027\030\204\007\"\000*\020\010\001\020\002\030\002 \003(\0010\0028\002@\001\n\027\030\347\007\"\000*\020\010\002\020\001\030\001 \002(\0010\0018\002@\001\n\027\030\350\007\"\014\010\001\020\001\030\001 \002(\0010\001*\0048\002@\001\n\027\030\351\007\"\020\010\001\020\001\030\001 \002(\0010\0018\001@\002*\000 \346\007(\351\007"
|
||||
_PROTOBUF_INTERNAL_PYTHON_EDITION_DEFAULTS = b"\n\027\030\204\007\"\000*\020\010\001\020\002\030\002 \003(\0010\0028\002@\001\n\027\030\347\007\"\000*\020\010\002\020\001\030\001 \002(\0010\0018\002@\001\n\027\030\350\007\"\014\010\001\020\001\030\001 \002(\0010\001*\0048\002@\001\n\027\030\351\007\"\020\010\001\020\001\030\001 \002(\0010\0018\001@\002*\000\n\027\030\217N\"\020\010\001\020\001\030\001 \002(\0010\0018\003@\002*\000 \346\007(\351\007"
|
||||
|
|
|
|||
|
|
@ -443,7 +443,8 @@ def _DefaultValueConstructorForField(field):
|
|||
type_checker = type_checkers.GetTypeChecker(field)
|
||||
def MakeRepeatedScalarDefault(message):
|
||||
return containers.RepeatedScalarFieldContainer(
|
||||
message._listener_for_children, type_checker)
|
||||
message._listener_for_children, type_checker, field
|
||||
)
|
||||
return MakeRepeatedScalarDefault
|
||||
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
|
|
@ -1240,7 +1241,9 @@ def _AddMergeFromStringMethod(message_descriptor, cls):
|
|||
tag_bytes, (None, None)
|
||||
)
|
||||
if field_decoder:
|
||||
pos = field_decoder(buffer, new_pos, end, self, field_dict)
|
||||
pos = field_decoder(
|
||||
buffer, new_pos, end, self, field_dict, current_depth
|
||||
)
|
||||
continue
|
||||
field_des, is_packed = fields_by_tag.get(tag_bytes, (None, None))
|
||||
if field_des is None:
|
||||
|
|
|
|||
|
|
@ -32,10 +32,6 @@ from google.protobuf.internal import encoder
|
|||
from google.protobuf.internal import wire_format
|
||||
|
||||
_FieldDescriptor = descriptor.FieldDescriptor
|
||||
# TODO: Remove this warning count after 34.0
|
||||
# Assign bool to int/enum warnings will print 100 times at most which should
|
||||
# be enough for users to notice and do not cause timeout.
|
||||
_BoolWarningCount = 100
|
||||
|
||||
def TruncateToFourByteFloat(original):
|
||||
return struct.unpack('<f', struct.pack('<f', original))[0]
|
||||
|
|
@ -145,20 +141,15 @@ class IntValueChecker(object):
|
|||
"""Checker used for integer fields. Performs type-check and range check."""
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
global _BoolWarningCount
|
||||
if type(proposed_value) == bool and _BoolWarningCount > 0:
|
||||
_BoolWarningCount -= 1
|
||||
if type(proposed_value) == bool:
|
||||
message = (
|
||||
'%.1024r has type %s, but expected one of: %s. This warning '
|
||||
'will turn into error in 7.34.0, please fix it before that.'
|
||||
'%.1024r has type %s, but expected one of: (int).'
|
||||
% (
|
||||
proposed_value,
|
||||
type(proposed_value),
|
||||
(int,),
|
||||
)
|
||||
)
|
||||
# TODO: Raise errors in 2026 Q1 release
|
||||
warnings.warn(message)
|
||||
raise TypeError(message)
|
||||
|
||||
if not hasattr(proposed_value, '__index__') or (
|
||||
type(proposed_value).__module__ == 'numpy' and
|
||||
|
|
@ -186,20 +177,16 @@ class EnumValueChecker(object):
|
|||
self._enum_type = enum_type
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
global _BoolWarningCount
|
||||
if type(proposed_value) == bool and _BoolWarningCount > 0:
|
||||
_BoolWarningCount -= 1
|
||||
if type(proposed_value) == bool:
|
||||
message = (
|
||||
'%.1024r has type %s, but expected one of: %s. This warning '
|
||||
'will turn into error in 7.34.0, please fix it before that.'
|
||||
'%.1024r has type %s, but expected one of: (int).'
|
||||
% (
|
||||
proposed_value,
|
||||
type(proposed_value),
|
||||
(int,),
|
||||
)
|
||||
)
|
||||
# TODO: Raise errors in 2026 Q1 release
|
||||
warnings.warn(message)
|
||||
raise TypeError(message)
|
||||
|
||||
if not isinstance(proposed_value, numbers.Integral):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), (int,)))
|
||||
|
|
|
|||
|
|
@ -279,6 +279,13 @@ class Timestamp(object):
|
|||
# manipulated into a long value of seconds. During the conversion from
|
||||
# struct_time to long, the source date in UTC, and so it follows that the
|
||||
# correct transformation is calendar.timegm()
|
||||
if type(dt).__name__ != 'datetime' and not isinstance(
|
||||
dt, datetime.datetime
|
||||
):
|
||||
raise TypeError(
|
||||
'Fail to convert to Timestamp. Expected a datetime object '
|
||||
'got {0}'.format(type(dt).__name__)
|
||||
)
|
||||
try:
|
||||
seconds = calendar.timegm(dt.utctimetuple())
|
||||
nanos = dt.microsecond * _NANOS_PER_MICROSECOND
|
||||
|
|
@ -445,6 +452,13 @@ class Duration(object):
|
|||
|
||||
def FromTimedelta(self, td):
|
||||
"""Converts timedelta to Duration."""
|
||||
if type(td).__name__ != 'timedelta' and not isinstance(
|
||||
td, datetime.timedelta
|
||||
):
|
||||
raise TypeError(
|
||||
'Fail to convert to Duration. Expected a timedelta object '
|
||||
'got {0}'.format(type(td).__name__)
|
||||
)
|
||||
try:
|
||||
self._NormalizeDuration(
|
||||
td.seconds + td.days * _SECONDS_PER_DAY,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue