<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# Author: Kees Cook &lt;kees@ubuntu.com&gt;
# Author: Jamie Strandboge &lt;jamie@ubuntu.com&gt;
# Copyright (C) 2005-2020 Canonical Ltd.
#
# This script is distributed under the terms and conditions of the GNU General
# Public License, Version 3 or later. See http://www.gnu.org/copyleft/gpl.html
# for details.
from __future__ import print_function

import re
import sys
import cve_lib
if sys.version_info[0] &lt; 3:
    from urllib import quote
    from cgi import escape
else:
    from urllib.parse import quote
    from html import escape
from time import gmtime, strftime

# FIXME: detect and safely quote URLs

# on-demand initialized during pkg exports
map = None

all_releases = cve_lib.all_releases
releases = [] + all_releases

for eol in cve_lib.eol_releases:
    if eol in releases:
        releases.remove(eol)

def html_header(title, description, outfd):
    print('''&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
&lt;!-- Global site tag (gtag.js) - Google Analytics --&gt;
&lt;script async src="https://www.googletagmanager.com/gtag/js?id=UA-96529618-15"&gt;&lt;/script&gt;
&lt;script&gt;
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-96529618-15');
&lt;/script&gt;
&lt;title&gt;%s&lt;/title&gt;
&lt;meta charset="utf-8"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;meta name="author" content="Canonical Ltd, and others" /&gt;
&lt;meta name="description" content="%s" /&gt;
&lt;meta name="copyright" content="Canonical Ltd, and others" /&gt;

&lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"&gt;
&lt;link rel="stylesheet" href="../css/starter-template.css"&gt;
&lt;link rel="stylesheet" href="../css/cve_tracker.css" type="text/css" /&gt;
&lt;link rel="stylesheet" href="../css/cve.css" type="text/css" /&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;nav class="navbar navbar-expand navbar-dark bg-dark navbar-fixed-top cve-tracker-navbar"&gt;
    &lt;a class="navbar-brand" href="https://launchpad.net/ubuntu-cve-tracker"&gt;Ubuntu CVE Tracker&lt;/a&gt;
    &lt;div id="cve-tracker-navbar" class="collapse navbar-collapse"&gt;
      &lt;ul class="navbar-nav"&gt;
        &lt;li class="nav-item"&gt;&lt;a class="nav-link" href=".."&gt;Home&lt;/a&gt;&lt;/li&gt;
        &lt;li class="nav-item"&gt;&lt;a class="nav-link" href="../main.html"&gt;Main&lt;/a&gt;&lt;/li&gt;
        &lt;li class="nav-item"&gt;&lt;a class="nav-link" href="../universe.html"&gt;Universe&lt;/a&gt;&lt;/li&gt;
        &lt;li class="nav-item"&gt;&lt;a class="nav-link" href="../partner.html"&gt;Partner&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;&lt;!--/.nav-collapse --&gt;
&lt;/nav&gt;

&lt;div id="container" class="container"&gt;

&lt;div class="starter-template"&gt;
&lt;div class="card" id="body-card"&gt;
''' % (escape(title), escape(description, quote=True)), file=outfd)

def html_footer(outfd, commit=None):
    print('&lt;p class="note commit"&gt;&lt;a href="https://code.launchpad.net/ubuntu-cve-tracker/+git"&gt;Updated&lt;/a&gt;: %s' % (strftime("%F %T UTC", gmtime())), end=' ', file=outfd)
    if commit:
        print(' (commit &lt;a href="https://git.launchpad.net/ubuntu-cve-tracker/commit/?id=%s"&gt;%s&lt;/a&gt;)' % (commit, commit), end=' ', file=outfd)
    print('&lt;/p&gt;', file=outfd)

    print('&lt;div id="footer"&gt;', file=outfd)
    print('&amp;copy; Canonical Ltd. 2007-%s' % (strftime("%Y", gmtime())), file=outfd)
    print('&lt;/div&gt;&lt;!-- footer --&gt;', file=outfd)
    print('&lt;/div&gt;&lt;!-- card-body --&gt;', file=outfd)
    print('&lt;/div&gt;&lt;!-- card --&gt;', file=outfd)
    print('&lt;/div&gt;&lt;!-- starter-template --&gt;', file=outfd)
    print('&lt;/div&gt; &lt;!-- container --&gt;', file=outfd)
    print('&lt;!-- Bootstrap core JavaScript', file=outfd)
    print('================================================== --&gt;', file=outfd)
    print('&lt;!-- Placed at the end of the document so the pages load faster --&gt;', file=outfd)
    print('&lt;script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"&gt;&lt;/script&gt;', file=outfd)
    print('&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"&gt;&lt;/script&gt;', file=outfd)
    print('&lt;/body&gt;', file=outfd)
    print('&lt;/html&gt;', file=outfd)


def lookup_priority_class(priority):
    '''Takes priority string, converts to html div class'''

    canon_pri = escape(priority).lower()
    value_class = "value"
    if canon_pri == "negligible":
        value_class = "negligible-value"
    elif canon_pri == "low":
        value_class = "low-value"
    elif canon_pri == "medium":
        value_class = "medium-value"
    elif canon_pri == "high":
        value_class = "high-value"
    elif canon_pri == "critical":
        value_class = "critical-value"

    return value_class

def htmlize_field(field, text):
    escaped_body = ""
    pre_block = False
    for line in text.split('\n'):
        if ((field == "References" or field == "Bugs") and
            re.match('^http[s]?://', line)):
            # Drop trailing information from URL
            url = line.split()[0]
            escaped_body += ('&lt;a href="%s"&gt;%s&lt;/a&gt;&lt;br /&gt;' %
                             (quote(escape(url), ':/?&amp;;=#'), escape(line)))
        else:
            # ensure line is escaped
            line = escape(line)
            if line[0] == ' ' and line[1] == ' ':
                # lines starting with double spaces get pre-formatted
                if pre_block:
                    escaped_body += '\n' + line[2:]
                else:
                    pre_block = True
                    escaped_body += '\n&lt;pre&gt;%s' % line[2:]
            else:
                if pre_block:
                    escaped_body += '&lt;/pre&gt;\n'
                escaped_body += '%s&lt;br /&gt;' % line
                pre_block = False
    return escaped_body


def htmlize_cve(cvefile, outfd, commit=None):
    data = cve_lib.load_cve(cvefile)

    #import pprint
    #pp = pprint.PrettyPrinter(indent=4)
    #pp.pprint(data)

    cve = data['Candidate']

    html_header('%s in Ubuntu' % cve, 'Ubuntu %s Entry' % cve, outfd)

    # CVE cross links
    heading = quote(cve)
    print('&lt;h3 class="card-header"&gt;%s&lt;/h3&gt;' % (heading), file=outfd)
    print('&lt;div class="card-body text-left"&gt;', file=outfd)

    # Handle "free-form" text
    for field in ['Priority', 'Description', 'Ubuntu-Description', 'References', 'Bugs', 'Mitigation', 'Assigned-to']:
        if field not in data:
            continue
        text = data[field].strip()
        if len(text) == 0:
            continue
        escaped_body = htmlize_field(field, text)
        if field == "Priority":
            # CVEs that are marked not-for-us should not display priority.
            if text == 'not-for-us':
                continue
            escaped_body = '&lt;a href="../priority.html"&gt;' + escaped_body.capitalize() + '&lt;/a&gt;'

        print('&lt;div class="item"&gt;&lt;div class="field"&gt;%s&lt;/div&gt; &lt;div&gt;%s&lt;/div&gt;&lt;/div&gt;' % (escape(field), escaped_body), file=outfd)

    # Notes are special
    if 'Notes' in data:
        print('&lt;div class="item"&gt;&lt;div class="field"&gt;Notes&lt;/div&gt;&lt;div&gt;', file=outfd)
        print('&lt;table class="table table-responsive"&gt;', file=outfd)
        for (user, note) in data['Notes']:
            print(('&lt;tr&gt;&lt;td class="user"&gt;%s&lt;/td&gt;&lt;td class="note"&gt;%s&lt;/td&gt;&lt;/tr&gt;' %
                            # preserve line breaks
                            (escape(user), escape(note).replace("\n", "&lt;br /&gt;\n"))), file=outfd)
        print('&lt;/table&gt;', file=outfd)
        print('&lt;/div&gt;&lt;/div&gt;', file=outfd)

    # Handle package logic
    for pkg in sorted(data['pkgs']):
        print('&lt;div class="pkg"&gt;', file=outfd)
        if 'product' in data['pkgs'][pkg].keys():
            print('&lt;div class="field"&gt;Product&lt;/div&gt;&lt;div class="value"&gt;Source tree: ' + \
                '&lt;a href="%s"&gt;%s&lt;/a&gt;' % (escape(cve_lib.supported_products[pkg][0]), escape(cve_lib.supported_products[pkg][0])) + \
                '&lt;/div&gt;', file=outfd)
        elif 'snap' in data['pkgs'][pkg].keys():
            print('&lt;div class="field"&gt;Snap&lt;/div&gt;&lt;div class="value"&gt;Store: ' + \
                '&lt;a href="https://snapcraft.io/%s"&gt;%s&lt;/a&gt;' % (escape(pkg), escape(pkg)) + \
                '&lt;/div&gt;', file=outfd)
        else:
            print('&lt;div class="field"&gt;Package&lt;/div&gt;&lt;div&gt;Source: ' + \
                '&lt;a href="../pkg/%s.html"&gt;%s&lt;/a&gt; ' % (quote(pkg), escape(pkg)) + \
                '(' + \
                '&lt;a href="https://launchpad.net/distros/ubuntu/+source/%s"&gt;LP&lt;/a&gt; ' % (quote(pkg)) + \
                '&lt;a href="https://packages.ubuntu.com/search?suite=all&amp;amp;section=all&amp;amp;arch=any&amp;amp;searchon=sourcenames&amp;amp;keywords=%s"&gt;Ubuntu&lt;/a&gt; ' % (quote(pkg)) + \
                '&lt;a href="https://tracker.debian.org/%s"&gt;Debian&lt;/a&gt;' % (quote(pkg)) + \
                ')&lt;/div&gt;', file=outfd)

        if 'Priority_%s' % pkg in data:
            # per package priority override exists
            priority_override = escape(data['Priority_%s' % pkg]).capitalize()
            #value_class = lookup_priority_class(priority_override)
            print('&lt;div&gt;Priority: %s&lt;/div&gt;' % (priority_override), file=outfd)
            #print('&lt;div class="item"&gt;&lt;div class="value"&gt;Priority:&lt;/div&gt; &lt;div class="%s"&gt;%s&lt;/div&gt;&lt;/div&gt;' % (value_class, priority_override), file=outfd)

        print('&lt;table class="table table-responsive"&gt;', file=outfd)

        # figure out what the development release was based on the releases
        # in the CVE
        # Bah, this should just be a separate function to determine the
        # devel release given a list of releases.
        cve_devel_release = cve_lib.devel_release
        cve_releases = data['pkgs'][pkg].keys()
        for skip_release in ['upstream', 'devel', 'product', 'snap']:
            if skip_release  in cve_releases:
                cve_releases.remove(skip_release)

        if len(cve_releases) &gt; 0:
            cve_releases = cve_lib.release_sort(cve_releases)
            try:
                index = all_releases.index(cve_releases[-1]) + 1
                if index &lt; len(all_releases) and all_releases[index]:
                    cve_devel_release = all_releases[index]
            except:
                pass
        if cve_devel_release not in releases:
            cve_devel_release = 'EOL ' + cve_devel_release

        release_list = ['upstream', 'product', 'snap'] + releases
        for release in release_list:
            relname = release

            if relname == cve_devel_release:
                release = 'devel'

            if release not in data['pkgs'][pkg]:
                continue

            status = data['pkgs'][pkg][release][0]
            notes  = data['pkgs'][pkg][release][1]

            release_title = cve_lib.release_name(relname)
            if not release_title:
                release_title = relname.capitalize()
                if relname == 'product' or relname == 'snap':
                    release_title = quote(pkg)
            name = '%s' % (escape(release_title))
            if status != 'DNE' and relname != 'upstream' and relname != 'product' and relname != 'snap' and '/' not in relname:
                name = '&lt;a href="https://launchpad.net/ubuntu/%s/+source/%s"&gt;%s&lt;/a&gt;' % (quote(relname), quote(pkg), escape(release_title))

            status_class = "default"
            if status in ['needed', 'active', 'deferred']:
                status_class = "vuln"
            elif status in cve_lib.status_closed:
                status_class = "safe"
            elif status == 'pending':
                status_class = "pending"

            print('&lt;tr&gt;&lt;td&gt;%s:&lt;/td&gt;&lt;td&gt;&lt;span class="%s"&gt;%s&lt;/span&gt;' % (name, status_class, status), file=outfd)
            if len(notes):
                print('(%s)' % (escape(notes)), file=outfd)
            print('&lt;/td&gt;&lt;/tr&gt;', file=outfd)
        print('&lt;/table&gt;', file=outfd)

        if pkg in data['patches']:
            print('&lt;div class="patches"&gt;Patches:&lt;/div&gt;', file=outfd)
            print('&lt;table class="table table-responsive patches"&gt;', file=outfd)
            for source, url in data['patches'][pkg]:
                # We need to handle the line info first, since it may have
                # additional info as (master) or something else after the patch
                # url.
                url_line_info = url.split(' ')[1:]
                url_additional_info = ''
                if len(url_line_info) &gt; 1:
                    url = url_line_info[0]
                    url_additional_info = url_line_info[1]
                    url_additional_info.strip()

                url = url.strip()
                if source == "break-fix" and " " in url:
                    introduced, fixed = url.split(' ', 1)
                    if introduced == '-':
                        # First commit to Linux git tree
                        introduced = '1da177e4c3f41524e886b7f1b8a0c1fc7321cac2'
                    print('&lt;tr&gt;&lt;td&gt;Introduced by &lt;pre&gt;&lt;a href="https://git.kernel.org/linus/%s"&gt;%s&lt;/a&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;Fixed by &lt;pre&gt;&lt;a href="https://git.kernel.org/linus/%s"&gt;%s&lt;/a&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;' % (introduced, introduced, fixed, fixed), file=outfd)
                else:
                    if re.match('^(ftp|http)[s]?://', url):
                        print('&lt;tr&gt;&lt;td&gt;%s:&lt;/td&gt;&lt;td&gt;&lt;a href="%s"&gt;%s %s&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;' % (escape(source).capitalize(), url.replace('"', '%22'), escape(url), url_additional_info), file=outfd)
                    else:
                        print('&lt;tr&gt;&lt;td&gt;%s:&lt;/td&gt;&lt;td&gt;%s&lt;/td&gt;&lt;/tr&gt;' % (escape(source).capitalize(), escape(url)), file=outfd)
            print('&lt;/table&gt;', file=outfd)

        # tags
        urlregex = re.compile(r"(http[^\s]+)")
        if pkg in data['tags']:
            tags = data['tags'][pkg]
            for tag in tags:
                # linkify any url in description
                description = cve_lib.valid_tags[tag]
                description = re.sub(urlregex, '&lt;a href="\\1"&gt;\\1&lt;/a&gt;',
                                     description)
                print('&lt;div&gt;%s&lt;/div&gt;' % (description), file=outfd)

        print('&lt;/div&gt;', file=outfd)

    print('&lt;div class="item"&gt;', file=outfd)
    print('&lt;div class="field"&gt;More Information&lt;/div&gt;', file=outfd)
    print('&lt;ul class="links"&gt;&lt;li&gt;&lt;a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=%s"&gt;Mitre&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://nvd.nist.gov/nvd.cfm?cvename=%s"&gt;NVD&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://launchpad.net/bugs/cve/%s"&gt;Launchpad&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://security-tracker.debian.org/tracker/%s"&gt;Debian&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;' % (quote(cve), quote(cve), quote(cve), quote(cve)), file=outfd)
    print('&lt;/div&gt;', file=outfd)

    html_footer(outfd, commit)

def htmlTableHeader(headings):
    header = '&lt;thead class="thead-dark"&gt;&lt;tr&gt;&lt;th&gt;CVE&lt;/th&gt;'
    for heading in headings:
        name = heading
        header += "&lt;th&gt;%s&lt;/th&gt;" % (name.capitalize())
    #header += '&lt;th&gt;Links&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;'
    header += '&lt;/tr&gt;&lt;/thead&gt;'
    return header

# Produces HTML for a given source package.
def htmlize_package(outfd, pkg, cvefiles, commit=None):
    html_header('%s CVEs in Ubuntu' % pkg, 'Ubuntu Package CVE Entry for %s' % pkg, outfd)
    print('&lt;h2 class="card-header"&gt;Package: %s&lt;/h2&gt;' % (quote(pkg)), file=outfd)
    print('&lt;div class="card-body text-left"&gt;', file=outfd)

    notes = set()

    # Loading the source map is expensive, which is unfortunate.  We will
    # do it only for pkg html output, since the generate-pkg-makefile script
    # is already trying to minimize how much we run this function.
    global map
    if not map:
        import source_map
        map = source_map.load()

    # Merged package reports (linux-source-2.6.15 should appear in
    # linux) only work when a package (linux) does not exist in a given
    # release (dapper) but the replacement does (linux-source-2.6.15).
    # So, figure out which pkg should be used for lookups in each in release:
    pkgname = dict()
    for rel in releases:
        rel_orig = rel
        if rel == cve_lib.devel_release:
            rel = 'devel'
        pkgname[rel_orig] = pkg
        if pkg not in map[rel_orig] and pkg in cve_lib.pkg_aliases:
            # Aliases: 'linux-source-2.6.15' should appear in 'linux' output
            for alias in cve_lib.pkg_aliases[pkg]:
                if alias in map[rel_orig]:
                    #print &gt;&gt;sys.stderr, "\tfound alias '%s' for '%s'" % (alias, pkg)
                    pkgname[rel_orig] = alias
                    notes.add('CVEs from &lt;a href="%s.html"&gt;%s&lt;/a&gt; in %s have been merged into this report' % (quote(alias), escape(alias), escape(rel_orig)))
                    break

    # For a given source package, if it is supported for a release, but
    # there is a CVE that is marked as affecting a universe binary only,
    # we need to mark it as "community supported".  Start by building up
    # a map of supportability per-release for the source package.
    starred = False
    src_supported = dict()
    headings = []
    entire_release_starred = set()
    for rel in releases:
        heading = rel
        if '/' in rel:
            (base, ppa) = rel.split('/')
            heading = "%s/" % (base)
            if ppa == "ubuntu-core":
                heading += "Core"
            elif ppa == "stable-phone-overlay":
                heading += "Touch"
            else:  # abbreviate the ppa name if we don't know about it
                for i in ppa.split('-'):
                    heading += i[0]

        src_supported[rel] = False
        if pkgname[rel] and pkgname[rel] in map[rel]:
            src_supported[rel] = cve_lib.is_supported(map, pkgname[rel], rel)
            if not src_supported[rel]:
                starred = True
                entire_release_starred.add(rel)
                heading += "*"
        headings.append(heading)

    if len(cvefiles) == 0:
        print('&lt;div class="item text-center"&gt;&lt;h3&gt;Status&lt;/h3&gt; &lt;div class="value"&gt;No known vulnerable public CVEs&lt;/div&gt;&lt;/div&gt;', file=outfd)
    else:
        cvefiles.sort(cve_lib.cve_sort)
        print('&lt;div class="item text-center"&gt;&lt;h3&gt;Status&lt;/h3&gt; &lt;div class="value"&gt;%d known public CVEs&lt;/div&gt;&lt;/div&gt;' % (len(cvefiles)), file=outfd)

        if len(notes) &gt; 0:
            print('&lt;div class="item text-center"&gt;&lt;h3&gt;Notes&lt;/h3&gt;', file=outfd)
            for note in sorted(notes):
                print('&lt;div class="value"&gt;%s&lt;/div&gt;' % (note), file=outfd)
            print('&lt;/div&gt;', file=outfd)

        print('&lt;h3 class="text-center"&gt;CVEs&lt;/h3&gt;', file=outfd)
        print('&lt;table id="cves" class="table table-bordered table-hover text-center"&gt;' + htmlTableHeader(headings), file=outfd)
        for cvefile in cvefiles:
            data = cve_lib.load_cve(cvefile)

            # Sort out priority
            priority = cve_lib.contextual_priority(data)[1]
            print('&lt;tr class="%s"&gt;' % (quote(priority)), end=' ', file=outfd)

            # fields...
            # 'pkgs' -&gt; dict(  pkg -&gt; dict(  release -&gt;  (state, notes)   ) )
            cve = data['Candidate']
            #print &gt;&gt;sys.stderr, 'cve: %s' % (cve)
            print('&lt;td class="cve"&gt;&lt;a href="../%s"&gt;%s&lt;/a&gt;&lt;/td&gt;' % (quote(cve), escape(cve)), end=' ', file=outfd)
            for rel in releases:
                rel_orig = rel
                if rel == cve_lib.devel_release:
                    rel = 'devel'

                report_pkg = pkgname[rel_orig]

                # Sort out priority override
                priority_override = cve_lib.contextual_priority(data, pkg=report_pkg, rel=rel)[1]
                #print &gt;&gt;sys.stderr, '\tlooking for %s' % (report_pkg)
                if report_pkg in data['pkgs'] and rel in data['pkgs'][report_pkg]:
                    pkgstatus = data['pkgs'][report_pkg][rel][0]
                    pkgnotes = data['pkgs'][report_pkg][rel][1]
                    pkgclass = pkgstatus
                    #print &gt;&gt;sys.stderr, '\t\tstatus for %s is %s' % (report_pkg, pkgclass)

                    if pkgclass == 'DNE':
                        pkgstatus = "--"
                    if pkgstatus == 'pending' and pkgnotes != '':
                        pkgclass = 'pendingversion'
                    priority_class = ""
                    priority_start = ""
                    priority_end = ""
                    if priority_override != priority:
                        priority_class = " override"
                        priority_start = '&lt;div class="%s"&gt;' % (quote(priority_override))
                        priority_end = '&lt;/div&gt;'

                    # Sort out supportability override
                    if pkgstatus not in ["--", "not-affected"] and \
                       src_supported[rel_orig] and \
                       not cve_lib.is_supported(map, report_pkg, rel_orig, data):
                        starred = True
                        pkgstatus += "*"

                    print('&lt;td class="%s%s"&gt;%s%s%s&lt;/td&gt;' % (quote(pkgclass), priority_class, priority_start, escape(pkgstatus), priority_end), end=' ', file=outfd)
                else:
                    print('&lt;td class="DNE"&gt;--&lt;/td&gt;', end=' ', file=outfd)
            print('&lt;/tr&gt;', file=outfd)
        print('&lt;/table&gt;', file=outfd)
        if starred:
            print('&lt;p class="note text-right"&gt;* community supported&lt;/p&gt;', file=outfd)

    html_footer(outfd, commit)
</pre></body></html>