Returns HTML index code for this entry.
        If 'relpath' is empty, renders complete index.html file.
        If 'relpath' is not empty, then index is being included into a top-level log, and
        relpath should be passed to all sub-renderers.
        In this case the entry may make use of its cached_include file, if that is valid.
        If 'refresh' is set to a timestamp, then any subproducts (thumbnails, HTML caches, etc.) older than the timestamp will need to be regenerated.
        If 'refresh_index' is set to a timestamp, then any index files older than the timestamp will need to be regenerated.
        If 'relpath' is empty and 'prev', 'next' and/or 'up' is set, then Prev/Next/Up links will be inserted

def renderIndex(self, relpath="", refresh=0, refresh_index=0):
        """Returns HTML index code for this entry.
        If 'relpath' is empty, renders complete index.html file.
        If 'relpath' is not empty, then index is being included into a top-level log, and
        relpath should be passed to all sub-renderers.
        In this case the entry may make use of its cached_include file, if that is valid.
        If 'refresh' is set to a timestamp, then any subproducts (thumbnails, HTML caches, etc.) older than the timestamp will need to be regenerated.
        If 'refresh_index' is set to a timestamp, then any index files older than the timestamp will need to be regenerated.
        If 'relpath' is empty and 'prev', 'next' and/or 'up' is set, then Prev/Next/Up links will be inserted
        """
        # check if cache can be used
        refresh_index = max(refresh, refresh_index)
        dprintf(2, "%s: rendering HTML index with relpath='%s', refresh=%s refresh_index=%s\n", self.pathname, relpath,
                time.strftime("%x %X", time.localtime(refresh)),
                time.strftime("%x %X", time.localtime(refresh_index)))
        if relpath and self.cached_include_valid:
            try:
                if os.path.getmtime(self.cached_include) >= refresh_index:
                    dprintf(2, "using include cache %s\n", self.cached_include)
                    return open(self.cached_include).read()
                else:
                    dprintf(2, "include cache %s out of date, will regenerate\n", self.cached_include)
                    self.cached_include_valid = False
            except:
                print("Error reading cached include code from %s, will regenerate" % self.cached_include)
                if verbosity.get_verbose() > 0:
                    dprint(1, "Error traceback follows:")
                    traceback.print_exc()
                self.cached_include_valid = False
        # form up attributes for % operator
        attrs = dict(self.__dict__)
        attrs['timestr'] = time.strftime("%x %X", time.localtime(self.timestamp))
        attrs['relpath'] = relpath
        html = ""
        # replace title and comments for ignored entries
        if self.ignore:
            attrs['title'] = "This is not a real log entry"
            attrs['comment'] = """This entry was saved by PURR because the user
      chose to ignore and/or banish some data products. PURR has stored this
      information here for its opwn internal and highly nefarious purposes.
      This entry is will not appear in the log."""
        # replace < and > in title and comments
        attrs['title'] = attrs['title'].replace("<", "&lt;").replace(">", "&gt;")
        # write header if asked
        if not relpath:
            icon = Purr.RenderIndex.renderIcon(24, "..")
            html += """<HTML><BODY>
      <TITLE>%(title)s</TITLE>""" % attrs
            if self._prev_link or self._next_link or self._up_link:
                html += """<DIV ALIGN=right><P>%s %s %s</P></DIV>""" % (
                    (self._prev_link and "<A HREF=\"%s\">&lt;&lt;Previous</A>" % self._prev_link) or "",
                    (self._up_link and "<A HREF=\"%s\">Up</A>" % self._up_link) or "",
                    (self._next_link and "<A HREF=\"%s\">Next&gt;&gt;</A>" % self._next_link) or ""
                )
            html += ("<H2>" + icon + """ <A CLASS="TITLE" TIMESTAMP=%(timestamp)d>%(title)s</A></H2>""") % attrs
        else:
            icon = Purr.RenderIndex.renderIcon(24)
            html += """
        <HR WIDTH=100%%>
        <H2>""" + icon + """ %(title)s</H2>""" % attrs
        # write comments
        html += """
        <DIV ALIGN=right><P><SMALL>Logged on %(timestr)s</SMALL></P></DIV>\n

        <A CLASS="COMMENTS">\n""" % attrs
        # add comments
        logmode = False
        for cmt in self.comment.split("\n"):
            cmt = cmt.replace("<", "&lt;").replace(">", "&gt;").replace("&lt;BR&gt;", "<BR>")
            html += """      <P>%s</P>\n""" % cmt
        html += """    </A>\n"""
        # add data products
        if self.dps:
            have_real_dps = bool([dp for dp in self.dps if not dp.ignored])
            if have_real_dps:
                html += """
        <H3>Data products</H3>
        <TABLE BORDER=1 FRAME=box RULES=all CELLPADDING=5>\n"""
            for dp in self.dps:
                dpattrs = dict(dp.__dict__)
                dpattrs['comment'] = dpattrs['comment'].replace("<", "&lt;"). \
                    replace(">", "&gt;").replace('"', "''")
                # if generating complete index, write empty anchor for each DP
                if not relpath:
                    if dp.ignored:
                        html += """
            <A CLASS="DP" SRC="%(sourcepath)s" POLICY="%(policy)s" COMMENT="%(comment)s"></A>\n""" % dpattrs
                    # write normal anchor for normal products
                    else:
                        dpattrs['relpath'] = relpath
                        dpattrs['basename'] = os.path.basename(dp.filename)
                        html += """
            <A CLASS="DP" FILENAME="%(filename)s" SRC="%(sourcepath)s" POLICY="%(policy)s" QUIET=%(quiet)d TIMESTAMP=%(timestamp).6f RENDER="%(render)s" COMMENT="%(comment)s"></A>\n""" % dpattrs
                # render a table row
                if not dp.ignored:
                    renderer = Purr.Render.makeRenderer(dp.render, dp, refresh=refresh)
                    html += Purr.Render.renderInTable(renderer, relpath)
            if have_real_dps:
                html += """
        </TABLE>"""
        # write footer
        if not relpath:
            html += "</BODY></HTML>\n"
        else:
            # now, write to include cache, if being included
            open(self.cached_include, 'w').write(html)
            self.cached_include_valid = True
        return html