Clean out metaprots, only use prototypes
This commit is contained in:
parent
c4d20c359b
commit
b009e0d33a
2 changed files with 67 additions and 73 deletions
|
|
@ -14,9 +14,9 @@ from evennia.utils.utils import inherits_from, class_from_module, get_all_typecl
|
||||||
from evennia.utils.eveditor import EvEditor
|
from evennia.utils.eveditor import EvEditor
|
||||||
from evennia.utils.evmore import EvMore
|
from evennia.utils.evmore import EvMore
|
||||||
from evennia.utils.spawner import (spawn, search_prototype, list_prototypes,
|
from evennia.utils.spawner import (spawn, search_prototype, list_prototypes,
|
||||||
save_db_prototype, build_metaproto, validate_prototype,
|
save_db_prototype, validate_prototype,
|
||||||
delete_db_prototype, PermissionError, start_olc,
|
delete_db_prototype, PermissionError, start_olc,
|
||||||
metaproto_to_str)
|
prototype_to_str)
|
||||||
from evennia.utils.ansi import raw
|
from evennia.utils.ansi import raw
|
||||||
|
|
||||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||||
|
|
@ -2885,12 +2885,12 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
return
|
return
|
||||||
return prototype
|
return prototype
|
||||||
|
|
||||||
def _search_show_prototype(query, metaprots=None):
|
def _search_show_prototype(query, prototypes=None):
|
||||||
# prototype detail
|
# prototype detail
|
||||||
if not metaprots:
|
if not prototypes:
|
||||||
metaprots = search_prototype(key=query, return_meta=True)
|
prototypes = search_prototype(key=query)
|
||||||
if metaprots:
|
if prototypes:
|
||||||
return "\n".join(metaproto_to_str(metaprot) for metaprot in metaprots)
|
return "\n".join(prototype_to_str(prot) for prot in prototypes)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -2898,18 +2898,18 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
||||||
if self.cmdstring == "olc" or 'menu' in self.switches or 'olc' in self.switches:
|
if self.cmdstring == "olc" or 'menu' in self.switches or 'olc' in self.switches:
|
||||||
# OLC menu mode
|
# OLC menu mode
|
||||||
metaprot = None
|
prototype = None
|
||||||
if self.lhs:
|
if self.lhs:
|
||||||
key = self.lhs
|
key = self.lhs
|
||||||
metaprot = search_prototype(key=key, return_meta=True)
|
prototype = search_prototype(key=key, return_meta=True)
|
||||||
if len(metaprot) > 1:
|
if len(prototype) > 1:
|
||||||
caller.msg("More than one match for {}:\n{}".format(
|
caller.msg("More than one match for {}:\n{}".format(
|
||||||
key, "\n".join(mproto.key for mproto in metaprot)))
|
key, "\n".join(proto.get('prototype_key', '') for proto in prototype)))
|
||||||
return
|
return
|
||||||
elif metaprot:
|
elif prototype:
|
||||||
# one match
|
# one match
|
||||||
metaprot = metaprot[0]
|
prototype = prototype[0]
|
||||||
start_olc(caller, session=self.session, metaproto=metaprot)
|
start_olc(caller, session=self.session, prototype=prototype)
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'search' in self.switches:
|
if 'search' in self.switches:
|
||||||
|
|
@ -3005,8 +3005,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
return
|
return
|
||||||
|
|
||||||
# present prototype to save
|
# present prototype to save
|
||||||
new_matchstring = _search_show_prototype(
|
new_matchstring = _search_show_prototype("", prototypes=[prototype])
|
||||||
"", metaprots=[build_metaproto(key, desc, [lockstring], tags, prototype)])
|
|
||||||
string = "|yCreating new prototype:|n\n{}".format(new_matchstring)
|
string = "|yCreating new prototype:|n\n{}".format(new_matchstring)
|
||||||
question = "\nDo you want to continue saving? [Y]/N"
|
question = "\nDo you want to continue saving? [Y]/N"
|
||||||
|
|
||||||
|
|
@ -3056,21 +3055,21 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
||||||
if isinstance(prototype, basestring):
|
if isinstance(prototype, basestring):
|
||||||
# A prototype key we are looking to apply
|
# A prototype key we are looking to apply
|
||||||
key = prototype
|
key = prototype
|
||||||
metaprotos = search_prototype(prototype)
|
prototypes = search_prototype(prototype)
|
||||||
nprots = len(metaprotos)
|
nprots = len(prototypes)
|
||||||
if not metaprotos:
|
if not prototypes:
|
||||||
caller.msg("No prototype named '%s'." % prototype)
|
caller.msg("No prototype named '%s'." % prototype)
|
||||||
return
|
return
|
||||||
elif nprots > 1:
|
elif nprots > 1:
|
||||||
caller.msg("Found {} prototypes matching '{}':\n {}".format(
|
caller.msg("Found {} prototypes matching '{}':\n {}".format(
|
||||||
nprots, prototype, ", ".join(metaproto.key for metaproto in metaprotos)))
|
nprots, prototype, ", ".join(prot.get('prototype_key', '')
|
||||||
|
for proto in prototypes)))
|
||||||
return
|
return
|
||||||
# we have a metaprot, check access
|
# we have a prototype, check access
|
||||||
metaproto = metaprotos[0]
|
prototype = prototypes[0]
|
||||||
if not caller.locks.check_lockstring(caller, metaproto.locks, access_type='use'):
|
if not caller.locks.check_lockstring(caller, prototype.get('prototype_locks', ''), access_type='use'):
|
||||||
caller.msg("You don't have access to use this prototype.")
|
caller.msg("You don't have access to use this prototype.")
|
||||||
return
|
return
|
||||||
prototype = metaproto.prototype
|
|
||||||
|
|
||||||
if "noloc" not in self.switches and "location" not in prototype:
|
if "noloc" not in self.switches and "location" not in prototype:
|
||||||
prototype["location"] = self.caller.location
|
prototype["location"] = self.caller.location
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ for mod in settings.PROTOTYPE_MODULES:
|
||||||
prots = [(prototype_key, prot) for prototype_key, prot in all_from_module(mod).items()
|
prots = [(prototype_key, prot) for prototype_key, prot in all_from_module(mod).items()
|
||||||
if prot and isinstance(prot, dict)]
|
if prot and isinstance(prot, dict)]
|
||||||
# assign module path to each prototype_key for easy reference
|
# assign module path to each prototype_key for easy reference
|
||||||
_MODULE_PROTOTYPE_MODULES.update({tup[0]: mod for tup in prots})
|
_MODULE_PROTOTYPE_MODULES.update({prototype_key: mod for prototype_key, _ in prots})
|
||||||
# make sure the prototype contains all meta info
|
# make sure the prototype contains all meta info
|
||||||
for prototype_key, prot in prots:
|
for prototype_key, prot in prots:
|
||||||
prot.update({
|
prot.update({
|
||||||
|
|
@ -153,7 +153,7 @@ for mod in settings.PROTOTYPE_MODULES:
|
||||||
"prototype_locks": prot['prototype_locks'] if 'prototype_locks' in prot else "use:all()",
|
"prototype_locks": prot['prototype_locks'] if 'prototype_locks' in prot else "use:all()",
|
||||||
"prototype_tags": set(make_iter(prot['prototype_tags'])
|
"prototype_tags": set(make_iter(prot['prototype_tags'])
|
||||||
if 'prototype_tags' in prot else ["base-prototype"])})
|
if 'prototype_tags' in prot else ["base-prototype"])})
|
||||||
_MODULE_PROTOTYPES.update(prot)
|
_MODULE_PROTOTYPES[prototype_key] = prot
|
||||||
|
|
||||||
|
|
||||||
# Prototype storage mechanisms
|
# Prototype storage mechanisms
|
||||||
|
|
@ -413,23 +413,25 @@ def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_ed
|
||||||
# this allows us to pass lists of empty strings
|
# this allows us to pass lists of empty strings
|
||||||
tags = [tag for tag in make_iter(tags) if tag]
|
tags = [tag for tag in make_iter(tags) if tag]
|
||||||
|
|
||||||
# get metaprotos for readonly and db-based prototypes
|
# get prototypes for readonly and db-based prototypes
|
||||||
prototypes = search_prototype(key, tags)
|
prototypes = search_prototype(key, tags)
|
||||||
|
|
||||||
# get use-permissions of readonly attributes (edit is always False)
|
# get use-permissions of readonly attributes (edit is always False)
|
||||||
display_tuples = []
|
display_tuples = []
|
||||||
for prototype in sorted(prototypes, key=lambda d: d['prototype_key']):
|
for prototype in sorted(prototypes, key=lambda d: d.get('prototype_key', '')):
|
||||||
lock_use = caller.locks.check_lockstring(caller, prototype['locks'], access_type='use')
|
lock_use = caller.locks.check_lockstring(
|
||||||
|
caller, prototype.get('prototype_locks', ''), access_type='use')
|
||||||
if not show_non_use and not lock_use:
|
if not show_non_use and not lock_use:
|
||||||
continue
|
continue
|
||||||
lock_edit = caller.locks.check_lockstring(caller, prototype['locks'], access_type='edit')
|
lock_edit = caller.locks.check_lockstring(
|
||||||
|
caller, prototype.get('prototype_locks', ''), access_type='edit')
|
||||||
if not show_non_edit and not lock_edit:
|
if not show_non_edit and not lock_edit:
|
||||||
continue
|
continue
|
||||||
display_tuples.append(
|
display_tuples.append(
|
||||||
(prototype.get('prototype_key', '<unset>',
|
(prototype.get('prototype_key', '<unset>'),
|
||||||
prototype['prototype_desc', ''],
|
prototype.get('prototype_desc', '<unset>'),
|
||||||
"{}/{}".format('Y' if lock_use else 'N', 'Y' if lock_edit else 'N'),
|
"{}/{}".format('Y' if lock_use else 'N', 'Y' if lock_edit else 'N'),
|
||||||
",".join(prototype.get('prototype_tags', [])))))
|
",".join(prototype.get('prototype_tags', []))))
|
||||||
|
|
||||||
if not display_tuples:
|
if not display_tuples:
|
||||||
return None
|
return None
|
||||||
|
|
@ -450,7 +452,7 @@ def prototype_to_str(prototype):
|
||||||
Format a prototype to a nice string representation.
|
Format a prototype to a nice string representation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
metaproto (NamedTuple): Represents the prototype.
|
prototype (dict): The prototype.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
header = (
|
header = (
|
||||||
|
|
@ -706,7 +708,7 @@ def _get_menu_prototype(caller):
|
||||||
if hasattr(caller.ndb._menutree, "olc_prototype"):
|
if hasattr(caller.ndb._menutree, "olc_prototype"):
|
||||||
prototype = caller.ndb._menutree.olc_prototype
|
prototype = caller.ndb._menutree.olc_prototype
|
||||||
if not prototype:
|
if not prototype:
|
||||||
caller.ndb._menutree.olc_prototype = {}
|
caller.ndb._menutree.olc_prototype = prototype = {}
|
||||||
caller.ndb._menutree.olc_new = True
|
caller.ndb._menutree.olc_new = True
|
||||||
return prototype
|
return prototype
|
||||||
|
|
||||||
|
|
@ -721,10 +723,10 @@ def _set_menu_prototype(caller, field, value):
|
||||||
caller.ndb._menutree.olc_prototype = prototype
|
caller.ndb._menutree.olc_prototype = prototype
|
||||||
|
|
||||||
|
|
||||||
def _format_property(key, required=False, prototype=None, cropper=None):
|
def _format_property(prop, required=False, prototype=None, cropper=None):
|
||||||
key = key.lower()
|
|
||||||
if prototype is not None:
|
if prototype is not None:
|
||||||
prop = prototype.get(key, '')
|
prop = prototype.get(prop, '')
|
||||||
|
|
||||||
out = prop
|
out = prop
|
||||||
if callable(prop):
|
if callable(prop):
|
||||||
|
|
@ -845,7 +847,7 @@ def node_index(caller):
|
||||||
cropper = _path_cropper
|
cropper = _path_cropper
|
||||||
options.append(
|
options.append(
|
||||||
{"desc": "|w{}|n{}".format(
|
{"desc": "|w{}|n{}".format(
|
||||||
key, _format_property(key, required, None, prototype, cropper=cropper)),
|
key, _format_property(key, required, prototype, cropper=cropper)),
|
||||||
"goto": "node_{}".format(key.lower())})
|
"goto": "node_{}".format(key.lower())})
|
||||||
required = False
|
required = False
|
||||||
for key in ('Desc', 'Tags', 'Locks'):
|
for key in ('Desc', 'Tags', 'Locks'):
|
||||||
|
|
@ -900,7 +902,7 @@ def node_prototype_key(caller):
|
||||||
text = ["The prototype name, or |wMeta-Key|n, uniquely identifies the prototype. "
|
text = ["The prototype name, or |wMeta-Key|n, uniquely identifies the prototype. "
|
||||||
"It is used to find and use the prototype to spawn new entities. "
|
"It is used to find and use the prototype to spawn new entities. "
|
||||||
"It is not case sensitive."]
|
"It is not case sensitive."]
|
||||||
old_key = prototype['prototype_key']
|
old_key = prototype.get('prototype_key', None)
|
||||||
if old_key:
|
if old_key:
|
||||||
text.append("Current key is '|w{key}|n'".format(key=old_key))
|
text.append("Current key is '|w{key}|n'".format(key=old_key))
|
||||||
else:
|
else:
|
||||||
|
|
@ -914,7 +916,8 @@ def node_prototype_key(caller):
|
||||||
|
|
||||||
|
|
||||||
def _all_prototypes(caller):
|
def _all_prototypes(caller):
|
||||||
return [mproto.key for mproto in search_prototype()]
|
return [prototype["prototype_key"]
|
||||||
|
for prototype in search_prototype() if "prototype_key" in prototype]
|
||||||
|
|
||||||
|
|
||||||
def _prototype_examine(caller, prototype_name):
|
def _prototype_examine(caller, prototype_name):
|
||||||
|
|
@ -1122,17 +1125,15 @@ def node_attrs(caller):
|
||||||
|
|
||||||
|
|
||||||
def _caller_tags(caller):
|
def _caller_tags(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
tags = prototype.get("tags")
|
||||||
tags = prot.get("tags")
|
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
|
||||||
def _add_tag(caller, tag, **kwargs):
|
def _add_tag(caller, tag, **kwargs):
|
||||||
tag = tag.strip().lower()
|
tag = tag.strip().lower()
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
tags = prototype.get('tags', [])
|
||||||
tags = prot.get('tags', [])
|
|
||||||
if tags:
|
if tags:
|
||||||
if tag not in tags:
|
if tag not in tags:
|
||||||
tags.append(tag)
|
tags.append(tag)
|
||||||
|
|
@ -1149,8 +1150,7 @@ def _add_tag(caller, tag, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def _edit_tag(caller, old_tag, new_tag, **kwargs):
|
def _edit_tag(caller, old_tag, new_tag, **kwargs):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prototype = metaprot.prototype
|
|
||||||
tags = prototype.get('tags', [])
|
tags = prototype.get('tags', [])
|
||||||
|
|
||||||
old_tag = old_tag.strip().lower()
|
old_tag = old_tag.strip().lower()
|
||||||
|
|
@ -1175,9 +1175,8 @@ def node_tags(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_locks(caller):
|
def node_locks(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
locks = prototype.get("locks")
|
||||||
locks = prot.get("locks")
|
|
||||||
|
|
||||||
text = ["Set the prototype's |yLock string|n. Separate multiple locks with semi-colons. "
|
text = ["Set the prototype's |yLock string|n. Separate multiple locks with semi-colons. "
|
||||||
"Will retain case sensitivity."]
|
"Will retain case sensitivity."]
|
||||||
|
|
@ -1196,9 +1195,8 @@ def node_locks(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_permissions(caller):
|
def node_permissions(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
permissions = prototype.get("permissions")
|
||||||
permissions = prot.get("permissions")
|
|
||||||
|
|
||||||
text = ["Set the prototype's |yPermissions|n. Separate multiple permissions with commas. "
|
text = ["Set the prototype's |yPermissions|n. Separate multiple permissions with commas. "
|
||||||
"Will retain case sensitivity."]
|
"Will retain case sensitivity."]
|
||||||
|
|
@ -1217,9 +1215,8 @@ def node_permissions(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_location(caller):
|
def node_location(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
location = prototype.get("location")
|
||||||
location = prot.get("location")
|
|
||||||
|
|
||||||
text = ["Set the prototype's |yLocation|n"]
|
text = ["Set the prototype's |yLocation|n"]
|
||||||
if location:
|
if location:
|
||||||
|
|
@ -1237,9 +1234,8 @@ def node_location(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_home(caller):
|
def node_home(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
home = prototype.get("home")
|
||||||
home = prot.get("home")
|
|
||||||
|
|
||||||
text = ["Set the prototype's |yHome location|n"]
|
text = ["Set the prototype's |yHome location|n"]
|
||||||
if home:
|
if home:
|
||||||
|
|
@ -1257,9 +1253,8 @@ def node_home(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_destination(caller):
|
def node_destination(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
prot = metaprot.prototype
|
dest = prototype.get("dest")
|
||||||
dest = prot.get("dest")
|
|
||||||
|
|
||||||
text = ["Set the prototype's |yDestination|n. This is usually only used for Exits."]
|
text = ["Set the prototype's |yDestination|n. This is usually only used for Exits."]
|
||||||
if dest:
|
if dest:
|
||||||
|
|
@ -1278,9 +1273,9 @@ def node_destination(caller):
|
||||||
|
|
||||||
def node_prototype_desc(caller):
|
def node_prototype_desc(caller):
|
||||||
|
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
text = ["The |wMeta-Description|n briefly describes the prototype for viewing in listings."]
|
text = ["The |wMeta-Description|n briefly describes the prototype for viewing in listings."]
|
||||||
desc = metaprot.desc
|
desc = prototype.get("prototype_desc", None)
|
||||||
|
|
||||||
if desc:
|
if desc:
|
||||||
text.append("The current meta desc is:\n\"|w{desc}|n\"".format(desc=desc))
|
text.append("The current meta desc is:\n\"|w{desc}|n\"".format(desc=desc))
|
||||||
|
|
@ -1298,10 +1293,10 @@ def node_prototype_desc(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_prototype_tags(caller):
|
def node_prototype_tags(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
text = ["|wMeta-Tags|n can be used to classify and find prototypes. Tags are case-insensitive. "
|
text = ["|wMeta-Tags|n can be used to classify and find prototypes. Tags are case-insensitive. "
|
||||||
"Separate multiple by tags by commas."]
|
"Separate multiple by tags by commas."]
|
||||||
tags = metaprot.tags
|
tags = prototype.get('prototype_tags', [])
|
||||||
|
|
||||||
if tags:
|
if tags:
|
||||||
text.append("The current tags are:\n|w{tags}|n".format(tags=tags))
|
text.append("The current tags are:\n|w{tags}|n".format(tags=tags))
|
||||||
|
|
@ -1319,11 +1314,11 @@ def node_prototype_tags(caller):
|
||||||
|
|
||||||
|
|
||||||
def node_prototype_locks(caller):
|
def node_prototype_locks(caller):
|
||||||
metaprot = _get_menu_prototype(caller)
|
prototype = _get_menu_prototype(caller)
|
||||||
text = ["Set |wMeta-Locks|n on the prototype. There are two valid lock types: "
|
text = ["Set |wMeta-Locks|n on the prototype. There are two valid lock types: "
|
||||||
"'edit' (who can edit the prototype) and 'use' (who can apply the prototype)\n"
|
"'edit' (who can edit the prototype) and 'use' (who can apply the prototype)\n"
|
||||||
"(If you are unsure, leave as default.)"]
|
"(If you are unsure, leave as default.)"]
|
||||||
locks = metaprot.locks
|
locks = prototype.get('prototype_locks', '')
|
||||||
if locks:
|
if locks:
|
||||||
text.append("Current lock is |w'{lockstring}'|n".format(lockstring=locks))
|
text.append("Current lock is |w'{lockstring}'|n".format(lockstring=locks))
|
||||||
else:
|
else:
|
||||||
|
|
@ -1367,14 +1362,14 @@ class OLCMenu(EvMenu):
|
||||||
return "{}{}{}".format(olc_options, sep, other_options)
|
return "{}{}{}".format(olc_options, sep, other_options)
|
||||||
|
|
||||||
|
|
||||||
def start_olc(caller, session=None, metaproto=None):
|
def start_olc(caller, session=None, prototype=None):
|
||||||
"""
|
"""
|
||||||
Start menu-driven olc system for prototypes.
|
Start menu-driven olc system for prototypes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity starting the menu.
|
caller (Object or Account): The entity starting the menu.
|
||||||
session (Session, optional): The individual session to get data.
|
session (Session, optional): The individual session to get data.
|
||||||
metaproto (MetaProto, optional): Given when editing an existing
|
prototype (dict, optional): Given when editing an existing
|
||||||
prototype rather than creating a new one.
|
prototype rather than creating a new one.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
@ -1396,7 +1391,7 @@ def start_olc(caller, session=None, metaproto=None):
|
||||||
"node_prototype_tags": node_prototype_tags,
|
"node_prototype_tags": node_prototype_tags,
|
||||||
"node_prototype_locks": node_prototype_locks,
|
"node_prototype_locks": node_prototype_locks,
|
||||||
}
|
}
|
||||||
OLCMenu(caller, menudata, startnode='node_index', session=session, olc_prototype=metaproto)
|
OLCMenu(caller, menudata, startnode='node_index', session=session, olc_prototype=prototype)
|
||||||
|
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue