def _thumb(row, cls, title=None): """ Return a column DIV thumbnail. """ caption = DIV(H3(row.chapter.title), H4('Chapter %i' % row.chapter.number), H5(row.published.strftime(date_format)), H3(row.intro_hanzi), H4(row.intro_en), _class='caption', _role='button', _title=title) anchor = A(caption, _class='ddj-thumbnail', _href=URL('poems', 'chapter', args=[row.chapter.number])) thumbnail = DIV(anchor, _class='thumbnail') return DIV(thumbnail, _class=cls)
def customize_pr_person(**attr): """ Customize pr_person controller """ # Load normal model table = current.s3db.pr_person # Custom CRUD Strings current.response.s3.crud_strings.pr_person.title_display = T("My Page") attr["rheader"] = H3(T("Saved Searches")) return attr
def customise_pr_person_controller(**attr): """ Customise pr_person controller @todo: pr_saved_search no longer supported (S3Search deprecated) """ s3db = current.s3db # Load normal model table = s3db.pr_person # Custom CRUD Strings current.response.s3.crud_strings.pr_person.title_display = T("My Page") # Customise saved search table = s3db.pr_saved_search table.url.label = T("Display Search") def url_represent(url): return TAG[""]( A(T("List"), _href = url, _class = "action-btn" ), A(T("Matrix"), # @ToDo: Fix for S3Search deprecation _href = url.replace("search", "report"), _class = "action-btn" ), A(T("Chart"), # @ToDo: Fix for S3Search deprecation _href = url.replace("search", "report?chart=breakdown%3Arows"), _class = "action-btn" ), A(T("Map"), # @ToDo: Fix for S3Search deprecation _href = url.replace("project/search", "location/map"), _class = "action-btn" ) ) table.url.represent = url_represent s3db.configure("pr_saved_search", list_fields = ["name", "url", ] ) attr["rheader"] = H3(T("Saved Searches")) return attr
def chapter(poem, db, uhdb): """ Return a bootstrap row for a poem row. """ if not poem: raise Exception('No such poem') qry = ((db.verse.book == 1) & (db.verse.chapter == poem.chapter)) verse = db(qry).select().first() title = H3(poem.chapter.title) subtitle = H4('Chapter %i' % poem.chapter.number) published = H5(poem.published.strftime(date_format)) stanzas = verse.en.split('\r\n\r\n') content = [] for stanza in stanzas: content.append(P(XML(stanza.replace('\r\n', '<br />')))) link = P(A(I('Go to the study version'), _href=URL('studies', 'chapter', args=[poem.chapter.number]), _style='color:inherit;', _title='Study version'), _style='font-size:0.9em;padding-top:1em') content.append(P(link)) column = DIV(title, subtitle, published, *content, _class=poem_class) return DIV(column, _class='row', _style='font-size:1.12em;white-space:nowrap;')
def __call__(self): T = current.T db = current.db s3db = current.s3db s3 = current.response.s3 session_s3 = current.session.s3 output = {} # Recent Updates etable = s3db.event_event stable = s3db.event_sitrep query = (stable.deleted == False) fields = [ etable.name, stable.id, stable.date, stable.name, stable.summary, ] left = [etable.on(etable.id == stable.event_id)] language = session_s3.language if language != current.deployment_settings.get_L10n_default_language(): ntable = s3db.event_event_name left.append(ntable.on((ntable.event_id == etable.id) & \ (ntable.language == language))) fields.append(ntable.name_l10n) use_local_event_name = True else: use_local_event_name = False sitreps = db(query).select(left=left, limitby=(0, 3), orderby=~stable.date, *fields) len_sitreps = len(sitreps) if len_sitreps == 0: from s3 import S3CRUD recent_updates = DIV(S3CRUD.crud_string("event_sitrep", "msg_list_empty"), _class="empty") else: recent_updates = DIV() rappend = recent_updates.append count = 0 for s in sitreps: count += 1 if use_local_event_name: event_name = s["event_event_name.name_l10n"] or s[ "event_event.name"] else: event_name = s["event_event.name"] if not event_name: event_name = s["event_sitrep.name"] rappend( H3( A( event_name, _href=URL( c="event", f="sitrep", args=[s["event_sitrep.id"]], ), ))) rappend(P(XML(s["event_sitrep.summary"]))) if count != len_sitreps: rappend(HR()) output["recent_updates"] = recent_updates map_btn = A( T("MAP OF CURRENT NEEDS"), #_href = URL(c="default", # f="index", # args="dashboard", # ), _href=URL( c="req", f="need_line", args="map", ), _class="small primary button", ) create_btn = A( T("CREATE A NEED"), _href=URL( c="req", f="need", args="create", ), _class="small primary button", ) output["needs_btn"] = DIV( SPAN(map_btn), SPAN(create_btn), _class="button-group radius", ) output["about_btn"] = A( "%s >" % T("Read More"), _href=URL( c="default", f="about", ), ) # Resources section if current.deployment_settings.has_module("cms"): system_roles = current.auth.get_system_roles() ADMIN = system_roles.ADMIN in session_s3.roles table = s3db.cms_post ltable = s3db.cms_post_module module = "default" resource = "index" query = (ltable.module == module) & \ ((ltable.resource == None) | \ (ltable.resource == resource)) & \ (ltable.post_id == table.id) & \ (table.deleted != True) item = current.db(query).select(table.body, table.id, limitby=(0, 1)).first() if item: if ADMIN: item = DIV( XML(item.body), BR(), A(T("Edit"), _href=URL(c="cms", f="post", args=[item.id, "update"]), _class="action-btn")) else: item = DIV(XML(item.body)) elif ADMIN: if s3.crud.formstyle == "bootstrap": _class = "btn" else: _class = "action-btn" item = A(T("Edit"), _href=URL(c="cms", f="post", args="create", vars={ "module": module, "resource": resource }), _class="%s cms-edit" % _class) else: item = "" else: item = "" output["item"] = item # Inject D3 scripts from s3 import S3Report S3Report.inject_d3() # Inject charts-script appname = current.request.application scripts = s3.scripts if s3.debug: script = "/%s/static/scripts/S3/s3.ui.charts.js" % appname if script not in scripts: scripts.append(script) else: script = "/%s/static/scripts/S3/s3.ui.charts.min.js" % appname if script not in scripts: scripts.append(script) # Instantiate charts scriptopts = { # Standard SHARE theme color set: "colors": [ '#0C9CD0', # blue '#E03158', # red '#FBA629', # amber '#8ABC3F', # green '#AFB8BF', # grey ], } script = '''$('.homepage-chart').uiChart(%s)''' % json.dumps( scriptopts) s3.jquery_ready.append(script) # Add last update time of chart data last_update = HomepageStatistics.last_update() if last_update: output["last_stats_update"] = T("Updated on %(date)s") % { "date": last_update } else: output["last_stats_update"] = None self._view(THEME, "index.html") return output
def layout(item): """ Layout Method (Item Renderer) """ # Manage flags: hide any disabled/unauthorized items if not item.authorized and not item.opts.always_display: item.enabled = False item.visible = False elif item.enabled is None or item.enabled: item.enabled = True item.visible = True if item.enabled and item.visible: items = item.render_components() if item.parent is None: # The menu itself number_of_links = 0 components = [] append = components.append for submenu in items: append(submenu) number_of_links += len(submenu.elements("a")) # Hide the entire menu if it doesn't contain any links if not number_of_links: return None title = H3(item.label) if item.label else "" menu = DIV( title, DIV( TAG[""](components), _class="icon-bar four-up", ), _id=item.attr._id, _class=item.attr._class, ) return menu else: # A menu item _class = item.attr._class if _class: _class = "%s item" % _class else: _class = "item" _id = item.attr._id icon = item.opts.icon if icon: label = LABEL(ICON(icon), item.label) else: label = LABEL(item.label) return A( label, _class=_class, _href=item.url(), _id=_id, ) else: return None
def __call__(self): output = {} T = current.T request = current.request response = current.response s3 = response.s3 # Check logged in and permissions auth = current.auth settings = current.deployment_settings roles = current.session.s3.roles system_roles = auth.get_system_roles() AUTHENTICATED = system_roles.AUTHENTICATED # Login/Registration forms self_registration = current.deployment_settings.get_security_registration_visible( ) registered = False login_form = None login_div = None register_form = None register_div = None if AUTHENTICATED not in roles: login_buttons = DIV(A(T("Login"), _id="show-login", _class="tiny secondary button"), _id="login-buttons") script = ''' $('#show-mailform').click(function(e){ e.preventDefault() $('#intro').slideDown(400, function() { $('#login_box').hide() }); }) $('#show-login').click(function(e){ e.preventDefault() $('#login_form').show() $('#register_form').hide() $('#login_box').show() $('#intro').slideUp() })''' s3.jquery_ready.append(script) # This user isn't yet logged-in if "registered" in request.cookies: # This browser has logged-in before registered = True if self_registration is True: # Provide a Registration box on front page login_buttons.append( A(T("Register"), _id="show-register", _class="tiny secondary button", _style="margin-left:5px")) script = ''' $('#show-register').click(function(e){ e.preventDefault() $('#login_form').hide() $('#register_form').show() $('#login_box').show() $('#intro').slideUp() })''' s3.jquery_ready.append(script) register_form = auth.register() register_div = DIV( H3(T("Register")), P( XML( T("If you would like to help, then please <b>sign up now</b>" )))) register_script = ''' $('#register-btn').click(function(e){ e.preventDefault() $('#register_form').show() $('#login_form').hide() }) $('#login-btn').click(function(e){ e.preventDefault() $('#register_form').hide() $('#login_form').show() })''' s3.jquery_ready.append(register_script) # Provide a login box on front page auth.messages.submit_button = T("Login") login_form = auth.login(inline=True) login_div = DIV( H3(T("Login")), #P(XML(T("Registered users can <b>login</b> to access the system"))), ) else: login_buttons = "" output["login_buttons"] = login_buttons output["self_registration"] = self_registration output["registered"] = registered output["login_div"] = login_div output["login_form"] = login_form output["register_div"] = register_div output["register_form"] = register_form s3.stylesheets.append("../themes/%s/homepage.css" % THEME) self._view(settings.get_theme_layouts(), "index.html") return output
def merge(self, r, **attr): """ Merge form for two records @param r: the S3Request @param **attr: the controller attributes for the request @note: this method can always only be POSTed, and requires both "selected" and "mode" in post_vars, as well as the duplicate bookmarks list in session.s3 """ T = current.T session = current.session response = current.response output = {} tablename = self.tablename # Get the duplicate bookmarks s3 = session.s3 DEDUPLICATE = self.DEDUPLICATE if DEDUPLICATE in s3: bookmarks = s3[DEDUPLICATE] if tablename in bookmarks: record_ids = bookmarks[tablename] # Process the post variables post_vars = r.post_vars mode = post_vars.get("mode") selected = post_vars.get("selected", "") selected = selected.split(",") if mode == "Inclusive": ids = selected elif mode == "Exclusive": ids = [i for i in record_ids if i not in selected] else: # Error ids = [] if len(ids) != 2: r.error(501, T("Please select exactly two records"), next=r.url(id=0, vars={})) # Get the selected records table = self.table query = (table._id == ids[0]) | (table._id == ids[1]) orderby = table.created_on if "created_on" in table else None rows = current.db(query).select(orderby=orderby, limitby=(0, 2)) if len(rows) != 2: r.error(404, current.ERROR.BAD_RECORD, next=r.url(id=0, vars={})) original = rows[0] duplicate = rows[1] # Prepare form construction formfields = [f for f in table if f.readable or f.writable] ORIGINAL, DUPLICATE, KEEP = self.ORIGINAL, self.DUPLICATE, self.KEEP keep_o = KEEP.o in post_vars and post_vars[KEEP.o] keep_d = KEEP.d in post_vars and post_vars[KEEP.d] trs = [] init_requires = self.init_requires index = 1 num_fields = len(formfields) for f in formfields: # Render the widgets oid = "%s_%s" % (ORIGINAL, f.name) did = "%s_%s" % (DUPLICATE, f.name) sid = "swap_%s" % f.name init_requires(f, original[f], duplicate[f]) if keep_o or not any((keep_o, keep_d)): owidget = self.widget(f, original[f], _name=oid, _id=oid, _tabindex=index) else: try: owidget = s3_represent_value(f, value=original[f]) except: owidget = s3_str(original[f]) if keep_d or not any((keep_o, keep_d)): dwidget = self.widget(f, duplicate[f], _name=did, _id=did) else: try: dwidget = s3_represent_value(f, value=duplicate[f]) except: dwidget = s3_str(duplicate[f]) # Swap button if not any((keep_o, keep_d)): swap = INPUT( _value="<-->", _class="swap-button", _id=sid, _type="button", _tabindex=index + num_fields, ) else: swap = DIV(_class="swap-button") if owidget is None or dwidget is None: continue # Render label row label = f.label trs.append( TR(TD(label, _class="w2p_fl"), TD(), TD(label, _class="w2p_fl"))) # Append widget row trs.append( TR(TD(owidget, _class="mwidget"), TD(swap), TD(dwidget, _class="mwidget"))) index = index + 1 # Show created_on/created_by for each record if "created_on" in table: original_date = original.created_on duplicate_date = duplicate.created_on if "created_by" in table: represent = table.created_by.represent original_author = represent(original.created_by) duplicate_author = represent(duplicate.created_by) created = T("Created on %s by %s") original_created = created % (original_date, original_author) duplicate_created = created % (duplicate_date, duplicate_author) else: created = T("Created on %s") original_created = created % original_date duplicate_created = created % duplicate_date else: original_created = "" duplicate_created = "" # Page title and subtitle output["title"] = T("Merge records") #output["subtitle"] = self.crud_string(tablename, "title_list") # Submit buttons if keep_o or not any((keep_o, keep_d)): submit_original = INPUT( _value=T("Keep Original"), _type="submit", _name=KEEP.o, _id=KEEP.o, ) else: submit_original = "" if keep_d or not any((keep_o, keep_d)): submit_duplicate = INPUT( _value=T("Keep Duplicate"), _type="submit", _name=KEEP.d, _id=KEEP.d, ) else: submit_duplicate = "" # Build the form form = FORM( TABLE( THEAD( TR( TH(H3(T("Original"))), TH(), TH(H3(T("Duplicate"))), ), TR( TD(original_created), TD(), TD(duplicate_created), _class="authorinfo", ), ), TBODY(trs), TFOOT(TR( TD(submit_original), TD(), TD(submit_duplicate), ), ), ), # Append mode and selected - required to get back here! hidden={ "mode": "Inclusive", "selected": ",".join(ids), }) output["form"] = form # Add RESET and CANCEL options output["reset"] = FORM( INPUT( _value=T("Reset"), _type="submit", _name="reset", _id="form-reset", ), A(T("Cancel"), _href=r.url(id=0, vars={}), _class="action-lnk"), hidden={ "mode": mode, "selected": ",".join(ids), }, ) # Process the merge form formname = "merge_%s_%s_%s" % (tablename, original[table._id], duplicate[table._id]) if form.accepts( post_vars, session, formname=formname, onvalidation=lambda form: self.onvalidation(tablename, form), keepvalues=False, hideerror=False): s3db = current.s3db if form.vars[KEEP.d]: prefix = "%s_" % DUPLICATE original, duplicate = duplicate, original else: prefix = "%s_" % ORIGINAL data = Storage() for key in form.vars: if key.startswith(prefix): fname = key.split("_", 1)[1] data[fname] = form.vars[key] search = False resource = s3db.resource(tablename) try: resource.merge(original[table._id], duplicate[table._id], update=data) except current.auth.permission.error: r.unauthorised() except KeyError: r.error(404, current.ERROR.BAD_RECORD) except Exception: import sys r.error(424, T("Could not merge records. (Internal Error: %s)") % sys.exc_info()[1], next=r.url()) else: # Cleanup bookmark list if mode == "Inclusive": bookmarks[tablename] = [ i for i in record_ids if i not in ids ] if not bookmarks[tablename]: del bookmarks[tablename] search = True elif mode == "Exclusive": bookmarks[tablename].extend(ids) if not selected: search = True # Confirmation message # @todo: Having the link to the merged record in the confirmation # message would be nice, but it's currently not clickable there :/ #result = A(T("Open the merged record"), #_href=r.url(method="read", #id=original[table._id], #vars={})) response.confirmation = T("Records merged successfully.") # Go back to bookmark list if search: self.next = r.url(method="", id=0, vars={}) else: self.next = r.url(id=0, vars={}) # View response.view = self._view(r, "merge.html") return output
def __call__(self): T = current.T db = current.db s3db = current.s3db output = {} # Recent Updates etable = s3db.event_event stable = s3db.event_sitrep query = (stable.deleted == False) fields = [ etable.name, stable.date, stable.name, stable.summary, ] left = [etable.on(etable.id == stable.event_id)] language = current.session.s3.language if language != current.deployment_settings.get_L10n_default_language(): ntable = s3db.event_event_name left.append(ntable.on((ntable.event_id == etable.id) & \ (ntable.language == language))) fields.append(ntable.name_l10n) use_local_event_name = True else: use_local_event_name = False sitreps = db(query).select(left=left, limitby=(0, 3), orderby=~stable.date, *fields) len_sitreps = len(sitreps) if len_sitreps == 0: from s3 import S3CRUD recent_updates = DIV(S3CRUD.crud_string("event_sitrep", "msg_list_empty"), _class="empty") else: recent_updates = DIV() rappend = recent_updates.append count = 0 for s in sitreps: count += 1 if use_local_event_name: event_name = s["event_event_name.name_l10n"] or s[ "event_event.name"] else: event_name = s["event_event.name"] if not event_name: event_name = s["event_sitrep.name"] rappend(H3(event_name)) rappend(P(XML(s["event_sitrep.summary"]))) if count != len_sitreps: rappend(HR()) output["recent_updates"] = recent_updates map_btn = A( T("MAP OF CURRENT NEEDS"), #_href = URL(c="default", # f="index", # args="dashboard", # ), _href=URL( c="req", f="need_line", args="map", ), _class="small primary button", ) create_btn = A( T("CREATE A NEED"), _href=URL( c="req", f="need", args="create", ), _class="small primary button", ) output["needs_btn"] = DIV( SPAN(map_btn), SPAN(create_btn), _class="button-group radius", ) output["about_btn"] = A( "%s >" % T("Read More"), _href=URL( c="default", f="about", ), ) self._view(THEME, "index.html") # Inject D3 scripts from s3 import S3Report S3Report.inject_d3() # Inject charts-script appname = current.request.application s3 = current.response.s3 scripts = s3.scripts if s3.debug: script = "/%s/static/scripts/S3/s3.ui.charts.js" % appname if script not in scripts: scripts.append(script) else: script = "/%s/static/scripts/S3/s3.ui.charts.min.js" % appname if script not in scripts: scripts.append(script) # Instantiate charts scriptopts = { # Standard SHARE theme color set: "colors": [ '#0C9CD0', # blue '#E03158', # red '#FBA629', # amber '#8ABC3F', # green '#AFB8BF', # grey ], } script = '''$('.homepage-chart').uiChart(%s)''' % json.dumps( scriptopts) s3.jquery_ready.append(script) # Add last update time of chart data last_update = HomepageStatistics.last_update() if last_update: output["last_stats_update"] = T("Updated on %(date)s") % { "date": last_update } else: output["last_stats_update"] = None return output
def MODAL(triggertext, headertext, body, footer=None, modal_classes='', trigger_classes=None, id='mymodal', trigger_type='link', attributes=None): ''' Returns a bootstrap 3 modal widget wrapped in a web2py CAT() helper. The returned widget can be included in a view as a single helper, in which case the hidden modal window is placed immediately following the trigger element in the DOM. This is not desireable, though, if the parent of the trigger element has relative positioning, since the modal window will appear behind its dark background mask (and possibly behind other page elements). In that case, one can include the link alone as MODAL()[0]. The modal window can then be included separately at a higher level of the html structure by calling MODAL()[1] at the appropriate point in the view. The following positional arguments are required: [0] triggertext (str) The text for the link to trigger the modal. [1] headertext (str or 0) The text for the modal header. If the value is 0, no header will be included. [2] body (str or helper obj) The content to be displayed in the modal body. If this is a LOAD helper the body content will be loaded via ajax *on page load*, not when the modal is shown. The following named arguments are optional: :footer (str, helper obj, or 0) The content to be displayed in the modal footer. If this argument is not provided, the default footer is a simple "Close" button. If the value is the integer 0, no footer will be included at all. :modal_classes (str) A string including the extra classes to be assigned to the modal div. :trigger_classes (str) A string including the extra classes to be assigned to the button/link triggering the modal. :id (str or int) The id to be assigned to the modal div. defaults to 'mymodal'. If multiple modals are present on a paget this value must be specified (and distinct) for each. The id for the trigger will always be this same string with the suffix '_trigger'. :trigger_type (str: 'button' | 'link') Specifies the html entity to be used to trigger the modal. Defaults to 'link' which returns an A() helper. :attributes (dict) The names and values of any attributes to be assigned to the modal trigger. These can include data-attributes for setting additional modal options (as per the bootstrap 2.3.2 api). These attributes can also include an _href url (if the trigger type is 'link'). Otherwise the trigger link will not have any href value, since it is not needed by the Bootstrap modal script. The close button in the default footer requires no extra javascript (beyond the Bootstrap modal plugin). ''' # create trigger t_classes = trigger_classes if trigger_classes else '' if trigger_type == 'button': t_classes += 'btn' t_args = { '_data-toggle': 'modal', '_data-target': '#{}'.format(id), '_data-keyboard': True, '_href': '#{}'.format(id), '_id': '{}_trigger'.format(id), '_class': t_classes } if attributes: t_args.update(attributes) if trigger_type == 'link': trigger = A(triggertext, **t_args) else: trigger = BUTTON(triggertext, **t_args) # create wrapper div for modal modal_attrs = { '_tabindex': '-1', '_role': 'dialog', '_data-keyboard': 'true', '_aria-labelledby': '{}_trigger'.format(id), '_aria-hidden': 'true' } modal = DIV(DIV(DIV(_class="modal-content"), _class="modal-dialog modal-lg"), _class="modal fade {}".format(modal_classes), _id=id, **modal_attrs) # add header if headertext != 0: m_head = DIV(H3(headertext, _id="myModalLabel", _class="modal-title"), _class="modal-header") modal[0][0].append(m_head) else: pass # add body content modal[0][0].append(DIV(body, _class='modal-body {}'.format(modal_classes))) # add footer if footer and footer != 0: modal[0][0].append(DIV(footer, _class='modal-footer')) elif not footer: attrs = { '_type': 'button', '_data-dismiss': "modal", '_class': "pull-right", '_aria-hidden': "true" } modal[0][0].append(DIV(BUTTON('Close', **attrs), _class='modal-footer')) else: pass return CAT(trigger, modal)
def stl_dvr_rheader(r, tabs=[]): """ DVR custom resource headers """ if r.representation != "html": # Resource headers only used in interactive views return None from s3 import s3_rheader_resource, \ S3ResourceHeader, \ s3_fullname tablename, record = s3_rheader_resource(r) if tablename != r.tablename: resource = current.s3db.resource(tablename, id=record.id) else: resource = r.resource rheader = None rheader_fields = [] if record: T = current.T if tablename == "pr_person": # "Invalid Case" warning hint = lambda record: H3( T("Invalid Case"), _class="alert label", ) if not tabs: tabs = [ (T("Basic Details"), None), (T("Contact"), "contacts"), (T("Household"), "household"), (T("Economy"), "economy"), (T("Activities"), "case_activity"), ] case = resource.select( [ "family_id.value", "dvr_case.status_id", "dvr_case.archived", "dvr_case.organisation_id", "dvr_case.disclosure_consent", "dvr_case.project_id", ], represent=True, raw_data=True, ).rows if not case: return None case = case[0] case_status = lambda row: case["dvr_case.status_id"] archived = case["_row"]["dvr_case.archived"] family_id = lambda row: case["pr_family_id_person_tag.value"] organisation_id = lambda row: case["dvr_case.organisation_id"] project_id = lambda row: case["dvr_case.project_id"] name = lambda row: s3_fullname(row) raw = case._row # Render disclosure consent flag as colored label consent = raw["dvr_case.disclosure_consent"] labels = {"Y": "success", "N/A": "warning", "N": "alert"} def disclosure(row): _class = labels.get(consent, "secondary") return SPAN( case["dvr_case.disclosure_consent"], _class="%s label" % _class, ) rheader_fields = [ [ (T("ID"), "pe_label"), (T("Case Status"), case_status), (T("Data Disclosure"), disclosure), ], [ (T("Family ID"), family_id), (T("Organisation"), organisation_id), ], [ (T("Name"), name), (T("Project Code"), project_id), ], [ "date_of_birth", ], ] if archived: rheader_fields.insert(0, [(None, hint)]) rheader = S3ResourceHeader(rheader_fields, tabs)( r, table=resource.table, record=record, ) return rheader