def button(self: Any, label: str, url: Optional[str] = '#', css: Optional[str] = 'primary', id_: Optional[str] = None, onclick: Optional[str] = '') -> str: return display.button(label, url, css, id_, onclick)
def download_button(self: Any, entity: Entity) -> str: if entity.class_.view != 'file': return '' html = '<span class="error">{msg}</span>'.format(msg=display.uc_first(_('missing file'))) if entity.image_id: path = display.get_file_path(entity.image_id) html = display.button(_('download'), url_for('download_file', filename=path.name)) return Markup(html)
def get_buttons(view: str) -> List[str]: buttons = [] names = [view] if view in ['artifact', 'place' ] else g.view_class_mapping[view] for name in names: if is_authorized(g.classes[name].write_access): buttons.append( button(g.classes[name].label, url_for('insert', class_=name))) return buttons
def display_move_form(self: Any, form: Any, root_name: str) -> str: from openatlas.forms.field import TreeField html = '' for field in form: if isinstance(field, TreeField): html += '<p>' + root_name + ' ' + str(field) + '</p>' table = Table( header=['#', display.uc_first(_('selection'))], rows=[[item, item.label.text] for item in form.selection]) return html + """ <div class="toolbar"> {select_all} {deselect_all} </div> {table}""".format( select_all=display.button(_('select all'), id_="select-all"), deselect_all=display.button(_('deselect all'), id_="select-none"), table=table.display('move'))
def siblings_pager(self: Any, entity: Entity, structure: Optional[Dict[str, Any]]) -> str: if not structure or len(structure['siblings']) < 2: return '' structure['siblings'].sort(key=lambda x: x.id) prev_id = None next_id = None position = None for counter, sibling in enumerate(structure['siblings']): position = counter + 1 prev_id = sibling.id if sibling.id < entity.id else prev_id if sibling.id > entity.id: next_id = sibling.id position = counter break return Markup('{previous} {next} {position} {of_label} {count}'.format( previous=display.button('<', url_for('entity_view', id_=prev_id)) if prev_id else '', next=display.button('>', url_for('entity_view', id_=next_id)) if next_id else '', position=position, of_label=_('of'), count=len(structure['siblings'])))
def note_view(id_: int) -> str: note = User.get_note_by_id(id_) if not note['public'] and note['user_id'] != current_user.id: abort(403) # pragma: no cover entity = Entity.get_by_id(note['entity_id']) buttons: List[str] = [] if note['user_id'] == current_user.id: buttons = [ button(_('edit'), url_for('note_update', id_=note['id'])), button(_('delete'), url_for('note_delete', id_=note['id']))] elif is_authorized('manager'): # pragma: no cover buttons = [button(_('set private'), url_for('note_set_private', id_=note['id']))] return render_template( 'user/note.html', entity=entity, note=note, tabs={'info': Tab('info')}, buttons=buttons, crumbs=[ [_(entity.class_.view), url_for('index', view=entity.class_.view)], link(entity), _('note')])
def add_buttons(entity: Entity) -> List[str]: if not is_authorized(entity.class_.write_access): return [] # pragma: no cover buttons = [] if isinstance(entity, Node): if entity.root and not g.nodes[entity.root[0]].locked: buttons.append(button(_('edit'), url_for('update', id_=entity.id))) if not entity.locked and entity.count < 1 and not entity.subs: buttons.append(display_delete_link(entity)) elif isinstance(entity, ReferenceSystem): buttons.append(button(_('edit'), url_for('update', id_=entity.id))) if not entity.forms and not entity.system: buttons.append(display_delete_link(entity)) elif entity.class_.name == 'source_translation': buttons.append( button(_('edit'), url_for('translation_update', id_=entity.id))) buttons.append(display_delete_link(entity)) else: buttons.append(button(_('edit'), url_for('update', id_=entity.id))) if entity.class_.view != 'place' or not entity.get_linked_entities( 'P46'): buttons.append(display_delete_link(entity)) return buttons
def entity_view(id_: int) -> Union[str, Response]: if id_ in g.nodes: # Nodes have their own view entity = g.nodes[id_] if not entity.root: if entity.class_.name == 'administrative_unit': tab_hash = '#menu-tab-places_collapse-' elif entity.standard: tab_hash = '#menu-tab-standard_collapse-' elif entity.value_type: tab_hash = '#menu-tab-value_collapse-' else: tab_hash = '#menu-tab-custom_collapse-' return redirect(url_for('node_index') + tab_hash + str(id_)) elif id_ in g.reference_systems: entity = g.reference_systems[id_] else: entity = Entity.get_by_id(id_, nodes=True, aliases=True) if not entity.class_.view: flash(_("This entity can't be viewed directly."), 'error') abort(400) event_links = None # Needed for actor overlays = None # Needed for place tabs = {'info': Tab('info')} if isinstance(entity, Node): tabs['subs'] = Tab('subs', entity) tabs['entities'] = Tab('entities', entity) root = g.nodes[entity.root[-1]] if entity.root else None if root and root.value_type: # pragma: no cover tabs['entities'].table.header = [ _('name'), _('value'), _('class'), _('info') ] for item in entity.get_linked_entities(['P2', 'P89'], inverse=True, nodes=True): if item.class_.name in ['location', 'reference_system']: continue # pragma: no cover if item.class_.name == 'object_location': # pragma: no cover item = item.get_linked_entity_safe('P53', inverse=True) data = [link(item)] if root and root.value_type: # pragma: no cover data.append(format_number(item.nodes[entity])) data.append(item.class_.label) data.append(item.description) tabs['entities'].table.rows.append(data) for sub_id in entity.subs: sub = g.nodes[sub_id] tabs['subs'].table.rows.append( [link(sub), sub.count, sub.description]) if not tabs[ 'entities'].table.rows: # If no entities available get links with this type_id tabs['entities'].table.header = [_('domain'), _('range')] for row in Link.get_entities_by_node(entity): tabs['entities'].table.rows.append([ link(Entity.get_by_id(row['domain_id'])), link(Entity.get_by_id(row['range_id'])) ]) elif isinstance(entity, ReferenceSystem): for form_id, form in entity.get_forms().items(): tabs[form['name']] = Tab(form['name'], origin=entity) tabs[form['name']].table = Table( [_('entity'), 'id', _('precision')]) for link_ in entity.get_links('P67'): name = link_.description if entity.resolver_url: name = \ '<a href="{url}" target="_blank" rel="noopener noreferrer">{name}</a>'.format( url=entity.resolver_url + name, name=name) tab_name = link_.range.class_.name tabs[tab_name].table.rows.append( [link(link_.range), name, link_.type.name]) for form_id, form in entity.get_forms().items(): if not tabs[form['name']].table.rows and is_authorized('manager'): tabs[form['name']].buttons = [ button( _('remove'), url_for('reference_system_remove_form', system_id=entity.id, form_id=form_id)) ] elif entity.class_.view == 'actor': for name in ['source', 'event', 'relation', 'member_of', 'member']: tabs[name] = Tab(name, entity) event_links = entity.get_links(['P11', 'P14', 'P22', 'P23', 'P25'], True) for link_ in event_links: event = link_.domain places = event.get_linked_entities(['P7', 'P26', 'P27']) link_.object_ = None for place in places: object_ = place.get_linked_entity_safe('P53', True) entity.linked_places.append(object_) link_.object_ = object_ # Needed later for first/last appearance info first = link_.first if not link_.first and event.first: first = '<span class="inactive">' + event.first + '</span>' last = link_.last if not link_.last and event.last: last = '<span class="inactive">' + event.last + '</span>' data = [ link(event), event.class_.label, link(link_.type), first, last, link_.description ] data = add_edit_link( data, url_for('involvement_update', id_=link_.id, origin_id=entity.id)) data = add_remove_link(data, link_.domain.name, link_, entity, 'event') tabs['event'].table.rows.append(data) for link_ in entity.get_links('OA7') + entity.get_links('OA7', True): type_ = '' if entity.id == link_.domain.id: related = link_.range if link_.type: type_ = link(link_.type.get_name_directed(), url_for('entity_view', id_=link_.type.id)) else: related = link_.domain if link_.type: type_ = link(link_.type.get_name_directed(True), url_for('entity_view', id_=link_.type.id)) data = [ type_, link(related), link_.first, link_.last, link_.description ] data = add_edit_link( data, url_for('relation_update', id_=link_.id, origin_id=entity.id)) data = add_remove_link(data, related.name, link_, entity, 'relation') tabs['relation'].table.rows.append(data) for link_ in entity.get_links('P107', True): data = [ link(link_.domain), link(link_.type), link_.first, link_.last, link_.description ] data = add_edit_link( data, url_for('member_update', id_=link_.id, origin_id=entity.id)) data = add_remove_link(data, link_.domain.name, link_, entity, 'member-of') tabs['member_of'].table.rows.append(data) if entity.class_.name != 'group': del tabs['member'] else: for link_ in entity.get_links('P107'): data = [ link(link_.range), link(link_.type), link_.first, link_.last, link_.description ] data = add_edit_link( data, url_for('member_update', id_=link_.id, origin_id=entity.id)) data = add_remove_link(data, link_.range.name, link_, entity, 'member') tabs['member'].table.rows.append(data) elif entity.class_.view == 'artifact': tabs['source'] = Tab('source', entity) elif entity.class_.view == 'event': for name in ['subs', 'source', 'actor']: tabs[name] = Tab(name, entity) for sub_event in entity.get_linked_entities('P117', inverse=True, nodes=True): tabs['subs'].table.rows.append(get_base_table_data(sub_event)) tabs['actor'].table.header.insert( 5, _('activity')) # Add a table column for activity for link_ in entity.get_links(['P11', 'P14', 'P22', 'P23']): first = link_.first if not link_.first and entity.first: first = '<span class="inactive">' + entity.first + '</span>' last = link_.last if not link_.last and entity.last: last = '<span class="inactive">' + entity.last + '</span>' data = [ link(link_.range), link_.range.class_.label, link_.type.name if link_.type else '', first, last, g.properties[link_.property.code].name_inverse, link_.description ] data = add_edit_link( data, url_for('involvement_update', id_=link_.id, origin_id=entity.id)) data = add_remove_link(data, link_.range.name, link_, entity, 'actor') tabs['actor'].table.rows.append(data) entity.linked_places = [ location.get_linked_entity_safe('P53', True) for location in entity.get_linked_entities(['P7', 'P26', 'P27']) ] elif entity.class_.view == 'file': for name in [ 'source', 'event', 'actor', 'place', 'feature', 'stratigraphic_unit', 'artifact', 'human_remains', 'reference', 'type' ]: tabs[name] = Tab(name, entity) entity.image_id = entity.id if get_file_path(entity.id) else None for link_ in entity.get_links('P67'): range_ = link_.range data = get_base_table_data(range_) data = add_remove_link(data, range_.name, link_, entity, range_.class_.name) tabs[range_.class_.view].table.rows.append(data) for link_ in entity.get_links('P67', True): data = get_base_table_data(link_.domain) data.append(link_.description) data = add_edit_link( data, url_for('reference_link_update', link_id=link_.id, origin_id=entity.id)) data = add_remove_link(data, link_.domain.name, link_, entity, 'reference') tabs['reference'].table.rows.append(data) elif entity.class_.view == 'place': tabs['source'] = Tab('source', entity) tabs['event'] = Tab('event', entity) tabs['reference'] = Tab('reference', entity) if entity.class_.name == 'place': tabs['actor'] = Tab('actor', entity) tabs['feature'] = Tab('feature', origin=entity) elif entity.class_.name == 'feature': tabs['stratigraphic_unit'] = Tab('stratigraphic_unit', origin=entity) elif entity.class_.name == 'stratigraphic_unit': tabs['find'] = Tab('find', origin=entity) tabs['human_remains'] = Tab('human_remains', origin=entity) entity.location = entity.get_linked_entity_safe('P53', nodes=True) event_ids = [ ] # Keep track of already inserted events to prevent doubles for event in entity.location.get_linked_entities(['P7', 'P26', 'P27'], inverse=True): tabs['event'].table.rows.append(get_base_table_data(event)) event_ids.append(event.id) for event in entity.get_linked_entities('P24', inverse=True): if event.id not in event_ids: # Don't add again if already in table tabs['event'].table.rows.append(get_base_table_data(event)) if 'actor' in tabs: for link_ in entity.location.get_links(['P74', 'OA8', 'OA9'], inverse=True): actor = Entity.get_by_id(link_.domain.id) tabs['actor'].table.rows.append([ link(actor), g.properties[link_.property.code].name, actor.class_.name, actor.first, actor.last, actor.description ]) elif entity.class_.view == 'reference': for name in [ 'source', 'event', 'actor', 'place', 'feature', 'stratigraphic_unit', 'human_remains', 'artifact', 'file' ]: tabs[name] = Tab(name, entity) for link_ in entity.get_links('P67'): range_ = link_.range data = get_base_table_data(range_) data.append(link_.description) data = add_edit_link( data, url_for('reference_link_update', link_id=link_.id, origin_id=entity.id)) data = add_remove_link(data, range_.name, link_, entity, range_.class_.name) tabs[range_.class_.view].table.rows.append(data) elif entity.class_.view == 'source': for name in [ 'actor', 'artifact', 'feature', 'event', 'human_remains', 'place', 'stratigraphic_unit', 'text' ]: tabs[name] = Tab(name, entity) for text in entity.get_linked_entities('P73', nodes=True): tabs['text'].table.rows.append([ link(text), next(iter(text.nodes)).name if text.nodes else '', text.description ]) for link_ in entity.get_links('P67'): range_ = link_.range data = get_base_table_data(range_) data = add_remove_link(data, range_.name, link_, entity, range_.class_.name) tabs[range_.class_.view].table.rows.append(data) if entity.class_.view in [ 'actor', 'artifact', 'event', 'place', 'source', 'type' ]: if entity.class_.view != 'reference' and not isinstance(entity, Node): tabs['reference'] = Tab('reference', entity) if entity.class_.view == 'artifact': tabs['event'] = Tab('event', entity) for link_ in entity.get_links('P25', True): data = get_base_table_data(link_.domain) tabs['event'].table.rows.append(data) tabs['file'] = Tab('file', entity) entity.image_id = entity.get_profile_image_id() tabs['file'].table.header.append(uc_first(_('overlay'))) for link_ in entity.get_links('P67', inverse=True): domain = link_.domain data = get_base_table_data(domain) if domain.class_.view == 'file': # pragma: no cover extension = data[3] data.append( get_profile_image_table_link(domain, entity, extension, entity.image_id)) if not entity.image_id and extension in app.config[ 'DISPLAY_FILE_EXTENSIONS']: entity.image_id = domain.id if entity.class_.view == 'place' and is_authorized('editor') and \ current_user.settings['module_map_overlay']: overlays = Overlay.get_by_object(entity) if extension in app.config['DISPLAY_FILE_EXTENSIONS']: if domain.id in overlays: data = add_edit_link( data, url_for('overlay_update', id_=overlays[domain.id].id)) else: data.append( link( _('link'), url_for('overlay_insert', image_id=domain.id, place_id=entity.id, link_id=link_.id))) else: # pragma: no cover data.append('') if domain.class_.view not in ['source', 'file']: data.append(link_.description) data = add_edit_link( data, url_for('reference_link_update', link_id=link_.id, origin_id=entity.id)) if domain.class_.view == 'reference_system': entity.reference_systems.append(link_) continue data = add_remove_link(data, domain.name, link_, entity, domain.class_.view) tabs[domain.class_.view].table.rows.append(data) structure = None # Needed for place gis_data = None # Needed for place if entity.class_.view in ['artifact', 'place']: structure = get_structure(entity) if structure: for item in structure['subunits']: tabs[item.class_.name].table.rows.append( get_base_table_data(item)) gis_data = Gis.get_all([entity], structure) if gis_data['gisPointSelected'] == '[]' \ and gis_data['gisPolygonSelected'] == '[]' \ and gis_data['gisLineSelected'] == '[]' \ and (not structure or not structure['super_id']): gis_data = {} if not gis_data: gis_data = Gis.get_all( entity.linked_places) if entity.linked_places else None entity.info_data = get_entity_data(entity, event_links=event_links) tabs['note'] = Tab('note', entity) for note in current_user.get_notes_by_entity_id(entity.id): data = [ format_date(note['created']), uc_first(_('public')) if note['public'] else uc_first(_('private')), link(User.get_by_id(note['user_id'])), note['text'], '<a href="{url}">{label}</a>'.format(url=url_for('note_view', id_=note['id']), label=uc_first(_('view'))) ] tabs['note'].table.rows.append(data) return render_template( 'entity/view.html', entity=entity, tabs=tabs, buttons=add_buttons(entity), structure=structure, # Needed for place views overlays=overlays, # Needed for place views gis_data=gis_data, title=entity.name, crumbs=add_crumbs(entity, structure))
def __init__(self, name: str, origin: Optional[Entity] = None) -> None: self.name = name self.title = uc_first(_(name.replace('_', ' '))) self.origin = origin if not origin: return id_ = origin.id buttons: List[str] = [] table = Table(g.table_headers[name]) view = origin.class_.view class_ = origin.class_ if name == 'reference': table.header = table.header + ['page'] if name == 'actor': if view == 'place': table.header = [ 'actor', 'property', 'class', 'first', 'last', 'description' ] elif view == 'file': buttons = [ button('link', url_for('file_add', id_=id_, view=name)) ] elif view == 'reference': buttons = [ button('link', url_for('reference_add', id_=id_, view=name)) ] elif view == 'source': buttons = [ button('link', url_for('source_add', id_=id_, view=name)) ] elif view == 'event': table.header = [ 'actor', 'class', 'involvement', 'first', 'last', 'description' ] buttons = [ button('link', url_for('involvement_insert', origin_id=id_)) ] for item in g.view_class_mapping['actor']: buttons.append( button(g.classes[item].label, url_for('insert', class_=item, origin_id=id_))) elif name == 'artifact': buttons = [ button('link', url_for('source_add', id_=id_, view='artifact')), button(g.classes['artifact'].label, url_for('insert', class_='artifact', origin_id=id_)) ] elif name == 'entities': buttons = [ button(_('move entities'), url_for('node_move_entities', id_=id_)) ] elif name == 'event': if view == 'file': buttons = [ button('link', url_for('file_add', id_=id_, view='event')) ] elif view == 'actor': table.header = [ 'event', 'class', 'involvement', 'first', 'last', 'description' ] buttons = [ button('link', url_for('involvement_insert', origin_id=id_)) ] elif view == 'source': buttons = [ button('link', url_for('source_add', id_=id_, view='event')) ] elif view == 'reference': buttons = [ button('link', url_for('reference_add', id_=id_, view='event')) ] for item in g.view_class_mapping['event']: buttons.append( button(g.classes[item].label, url_for('insert', class_=item, origin_id=id_))) if view == 'artifact': buttons = [ button(g.classes['move'].label, url_for('insert', class_='move', origin_id=id_)) ] elif name == 'feature': if current_user.settings[ 'module_sub_units'] and class_.name == 'place': buttons = [ button(g.classes[name].label, url_for('insert', class_=name, origin_id=id_)) ] elif name == 'find': if current_user.settings[ 'module_sub_units'] and class_.name == 'stratigraphic_unit': buttons = [ button(g.classes[name].label, url_for('insert', class_=name, origin_id=id_)) ] elif name == 'file': if view == 'reference': buttons = [ button('link', url_for('reference_add', id_=id_, view=name)) ] else: table.header += [_('main image')] buttons = [button('link', url_for('entity_add_file', id_=id_))] buttons.append( button(g.classes[name].label, url_for('insert', class_=name, origin_id=id_))) elif name == 'human_remains': if current_user.settings[ 'module_sub_units'] and class_.name == 'stratigraphic_unit': buttons = [ button(g.classes[name].label, url_for('insert', origin_id=id_, class_=name)) ] elif name == 'member': buttons = [button('link', url_for('member_insert', origin_id=id_))] elif name == 'member_of': buttons = [ button( 'link', url_for('member_insert', origin_id=id_, code='membership')) ] elif name == 'note': if util.is_authorized('contributor'): buttons = [ button(_('note'), url_for('note_insert', entity_id=id_)) ] elif name == 'place': if class_.name == 'file': buttons = [ button('link', url_for('file_add', id_=id_, view=name)) ] elif view == 'reference': buttons = [ button('link', url_for('reference_add', id_=id_, view=name)) ] elif view == 'source': buttons = [ button('link', url_for('source_add', id_=id_, view=name)) ] buttons.append( button(g.classes[name].label, url_for('insert', class_=name, origin_id=id_))) elif name == 'reference': buttons = [ button('link', url_for('entity_add_reference', id_=id_)) ] for item in g.view_class_mapping['reference']: buttons.append( button(g.classes[item].label, url_for('insert', class_=item, origin_id=id_))) elif name == 'relation': buttons = [ button('link', url_for('relation_insert', origin_id=id_)) ] for item in g.view_class_mapping['actor']: buttons.append( button(g.classes[item].label, url_for('insert', class_=item, origin_id=id_))) elif name == 'source': if class_.name == 'file': buttons = [ button(_('link'), url_for('file_add', id_=id_, view=name)) ] elif view == 'reference': buttons = [ button('link', url_for('reference_add', id_=id_, view=name)) ] else: buttons = [ button('link', url_for('entity_add_source', id_=id_)) ] buttons.append( button(g.classes['source'].label, url_for('insert', class_=name, origin_id=id_))) elif name == 'subs': table.header = [_('name'), _('count'), _('info')] if view == 'event': table.header = g.table_headers['event'] elif name == 'stratigraphic_unit': if current_user.settings[ 'module_sub_units'] and class_.name == 'feature': buttons = [ button(g.classes['stratigraphic_unit'].label, url_for('insert', class_=name, origin_id=id_)) ] elif name == 'text': buttons = [ button(_('text'), url_for('translation_insert', source_id=id_)) ] self.table = table if is_authorized('contributor'): self.buttons = buttons
def display_form(self: Any, form: Any, form_id: Optional[str] = None, for_persons: bool = False, manual_page: Optional[str] = None) -> str: from openatlas.forms.field import ValueFloatField def display_value_type_fields(node_: Node, root: Optional[Node] = None) -> str: root = root if root else node_ html_ = '' for sub_id in node_.subs: sub = g.nodes[sub_id] field_ = getattr(form, str(sub_id)) html_ += """ <div class="table-row value-type-switch{id}"> <div>{label}</div> <div class="table-cell">{field} {unit}</div> </div> {value_fields}""".format( id=root.id, label=sub.name, unit=sub.description, field=field_(class_='value-type'), value_fields=display_value_type_fields(sub, root)) return html_ html = '' for field in form: if isinstance(field, ValueFloatField) or field.id.startswith( ('insert_', 'reference_system_precision')): continue # These fields will be added in combination with other fields if field.type in ['CSRFTokenField', 'HiddenField']: html += str(field) continue if field.id.split('_', 1)[0] in ('begin', 'end'): # If it's a date field use a function if field.id == 'begin_year_from': html += display.add_dates_to_form(form, for_persons) continue if field.type in ['TreeField', 'TreeMultiField']: hierarchy_id = int(field.id) node = g.nodes[hierarchy_id] label = node.name if node.standard and node.class_.name == 'type': label = display.uc_first(_('type')) if field.label.text == 'super': label = display.uc_first(_('super')) if node.value_type and 'is_node_form' not in form: field.description = node.description onclick = 'switch_value_type({id})'.format(id=node.id) html += add_row( field, label, display.button(_('show'), onclick=onclick, css='secondary')) html += display_value_type_fields(node) continue tooltip = '' if 'is_node_form' in form else ' ' + display.tooltip(node.description) html += add_row(field, label + tooltip) continue if field.id == 'save': field.label.text = display.uc_first(field.label.text) class_ = app.config['CSS']['button']['primary'] buttons = [] if manual_page: buttons.append(escape(manual(None, manual_page))) buttons.append(field(class_=class_)) if 'insert_and_continue' in form: buttons.append(form.insert_and_continue(class_=class_)) if 'insert_continue_sub' in form: buttons.append(form.insert_continue_sub(class_=class_)) if 'insert_continue_human_remains' in form: buttons.append(form.insert_continue_human_remains(class_=class_)) text = '<div class ="toolbar">{buttons}</div>'.format(buttons=' '.join(buttons)) html += add_row(field, '', text) continue # External reference system if field.id.startswith('reference_system_id_'): precision_field = getattr(form, field.id.replace('id_', 'precision_')) class_ = field.label.text if field.label.text in ['GeoNames', 'Wikidata'] else '' html += add_row(field, field.label, ' '.join([ str(field(class_=class_)), str(precision_field.label), str(precision_field)])) continue html += add_row(field, form_id=form_id) return Markup(""" <form method="post" {id} {multi}> <div class="data-table">{html}</div> </form>""".format( id=('id="' + form_id + '" ') if form_id else '', html=html, multi='enctype="multipart/form-data"' if hasattr(form, 'file') else ''))