shithub: riscv

Download patch

ref: 4e5f39796d548fc1b530ae87e25f2db0830b5851
parent: e94f3a16677feafdddce8e38576eb2d6373308f9
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Sep 22 11:52:08 EDT 2023

hg: actually remove hg this time

--- a/sys/src/cmd/hg/hgext/convert/__init__.py
+++ /dev/null
@@ -1,296 +1,0 @@
-# convert.py Foreign SCM converter
-#
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-'''import revisions from foreign VCS repositories into Mercurial'''
-
-import convcmd
-import cvsps
-import subversion
-from mercurial import commands
-from mercurial.i18n import _
-
-# Commands definition was moved elsewhere to ease demandload job.
-
-def convert(ui, src, dest=None, revmapfile=None, **opts):
-    """convert a foreign SCM repository to a Mercurial one.
-
-    Accepted source formats [identifiers]:
-
-    - Mercurial [hg]
-    - CVS [cvs]
-    - Darcs [darcs]
-    - git [git]
-    - Subversion [svn]
-    - Monotone [mtn]
-    - GNU Arch [gnuarch]
-    - Bazaar [bzr]
-    - Perforce [p4]
-
-    Accepted destination formats [identifiers]:
-
-    - Mercurial [hg]
-    - Subversion [svn] (history on branches is not preserved)
-
-    If no revision is given, all revisions will be converted.
-    Otherwise, convert will only import up to the named revision
-    (given in a format understood by the source).
-
-    If no destination directory name is specified, it defaults to the
-    basename of the source with '-hg' appended. If the destination
-    repository doesn't exist, it will be created.
-
-    By default, all sources except Mercurial will use --branchsort.
-    Mercurial uses --sourcesort to preserve original revision numbers
-    order. Sort modes have the following effects:
-
-    --branchsort  convert from parent to child revision when possible,
-                  which means branches are usually converted one after
-                  the other. It generates more compact repositories.
-
-    --datesort    sort revisions by date. Converted repositories have
-                  good-looking changelogs but are often an order of
-                  magnitude larger than the same ones generated by
-                  --branchsort.
-
-    --sourcesort  try to preserve source revisions order, only
-                  supported by Mercurial sources.
-
-    If <REVMAP> isn't given, it will be put in a default location
-    (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file
-    that maps each source commit ID to the destination ID for that
-    revision, like so::
-
-      <source ID> <destination ID>
-
-    If the file doesn't exist, it's automatically created. It's
-    updated on each commit copied, so convert-repo can be interrupted
-    and can be run repeatedly to copy new commits.
-
-    The [username mapping] file is a simple text file that maps each
-    source commit author to a destination commit author. It is handy
-    for source SCMs that use unix logins to identify authors (eg:
-    CVS). One line per author mapping and the line format is:
-    srcauthor=whatever string you want
-
-    The filemap is a file that allows filtering and remapping of files
-    and directories. Comment lines start with '#'. Each line can
-    contain one of the following directives::
-
-      include path/to/file
-
-      exclude path/to/file
-
-      rename from/file to/file
-
-    The 'include' directive causes a file, or all files under a
-    directory, to be included in the destination repository, and the
-    exclusion of all other files and directories not explicitly
-    included. The 'exclude' directive causes files or directories to
-    be omitted. The 'rename' directive renames a file or directory. To
-    rename from a subdirectory into the root of the repository, use
-    '.' as the path to rename to.
-
-    The splicemap is a file that allows insertion of synthetic
-    history, letting you specify the parents of a revision. This is
-    useful if you want to e.g. give a Subversion merge two parents, or
-    graft two disconnected series of history together. Each entry
-    contains a key, followed by a space, followed by one or two
-    comma-separated values. The key is the revision ID in the source
-    revision control system whose parents should be modified (same
-    format as a key in .hg/shamap). The values are the revision IDs
-    (in either the source or destination revision control system) that
-    should be used as the new parents for that node.
-
-    The branchmap is a file that allows you to rename a branch when it is
-    being brought in from whatever external repository. When used in
-    conjunction with a splicemap, it allows for a powerful combination
-    to help fix even the most badly mismanaged repositories and turn them
-    into nicely structured Mercurial repositories. The branchmap contains
-    lines of the form "original_branch_name new_branch_name".
-    "original_branch_name" is the name of the branch in the source
-    repository, and "new_branch_name" is the name of the branch is the
-    destination repository. This can be used to (for instance) move code
-    in one repository from "default" to a named branch.
-
-    Mercurial Source
-    ----------------
-
-    --config convert.hg.ignoreerrors=False    (boolean)
-        ignore integrity errors when reading. Use it to fix Mercurial
-        repositories with missing revlogs, by converting from and to
-        Mercurial.
-    --config convert.hg.saverev=False         (boolean)
-        store original revision ID in changeset (forces target IDs to
-        change)
-    --config convert.hg.startrev=0            (hg revision identifier)
-        convert start revision and its descendants
-
-    CVS Source
-    ----------
-
-    CVS source will use a sandbox (i.e. a checked-out copy) from CVS
-    to indicate the starting point of what will be converted. Direct
-    access to the repository files is not needed, unless of course the
-    repository is :local:. The conversion uses the top level directory
-    in the sandbox to find the CVS repository, and then uses CVS rlog
-    commands to find files to convert. This means that unless a
-    filemap is given, all files under the starting directory will be
-    converted, and that any directory reorganization in the CVS
-    sandbox is ignored.
-
-    Because CVS does not have changesets, it is necessary to collect
-    individual commits to CVS and merge them into changesets. CVS
-    source uses its internal changeset merging code by default but can
-    be configured to call the external 'cvsps' program by setting::
-
-      --config convert.cvsps='cvsps -A -u --cvs-direct -q'
-
-    This option is deprecated and will be removed in Mercurial 1.4.
-
-    The options shown are the defaults.
-
-    Internal cvsps is selected by setting ::
-
-      --config convert.cvsps=builtin
-
-    and has a few more configurable options:
-
-    --config convert.cvsps.cache=True         (boolean)
-        Set to False to disable remote log caching, for testing and
-        debugging purposes.
-    --config convert.cvsps.fuzz=60            (integer)
-        Specify the maximum time (in seconds) that is allowed between
-        commits with identical user and log message in a single
-        changeset. When very large files were checked in as part of a
-        changeset then the default may not be long enough.
-    --config convert.cvsps.mergeto='{{mergetobranch ([-\\w]+)}}'
-        Specify a regular expression to which commit log messages are
-        matched. If a match occurs, then the conversion process will
-        insert a dummy revision merging the branch on which this log
-        message occurs to the branch indicated in the regex.
-    --config convert.cvsps.mergefrom='{{mergefrombranch ([-\\w]+)}}'
-        Specify a regular expression to which commit log messages are
-        matched. If a match occurs, then the conversion process will
-        add the most recent revision on the branch indicated in the
-        regex as the second parent of the changeset.
-
-    The hgext/convert/cvsps wrapper script allows the builtin
-    changeset merging code to be run without doing a conversion. Its
-    parameters and output are similar to that of cvsps 2.1.
-
-    Subversion Source
-    -----------------
-
-    Subversion source detects classical trunk/branches/tags layouts.
-    By default, the supplied "svn://repo/path/" source URL is
-    converted as a single branch. If "svn://repo/path/trunk" exists it
-    replaces the default branch. If "svn://repo/path/branches" exists,
-    its subdirectories are listed as possible branches. If
-    "svn://repo/path/tags" exists, it is looked for tags referencing
-    converted branches. Default "trunk", "branches" and "tags" values
-    can be overridden with following options. Set them to paths
-    relative to the source URL, or leave them blank to disable auto
-    detection.
-
-    --config convert.svn.branches=branches    (directory name)
-        specify the directory containing branches
-    --config convert.svn.tags=tags            (directory name)
-        specify the directory containing tags
-    --config convert.svn.trunk=trunk          (directory name)
-        specify the name of the trunk branch
-
-    Source history can be retrieved starting at a specific revision,
-    instead of being integrally converted. Only single branch
-    conversions are supported.
-
-    --config convert.svn.startrev=0           (svn revision number)
-        specify start Subversion revision.
-
-    Perforce Source
-    ---------------
-
-    The Perforce (P4) importer can be given a p4 depot path or a
-    client specification as source. It will convert all files in the
-    source to a flat Mercurial repository, ignoring labels, branches
-    and integrations. Note that when a depot path is given you then
-    usually should specify a target directory, because otherwise the
-    target may be named ...-hg.
-
-    It is possible to limit the amount of source history to be
-    converted by specifying an initial Perforce revision.
-
-    --config convert.p4.startrev=0            (perforce changelist number)
-        specify initial Perforce revision.
-
-    Mercurial Destination
-    ---------------------
-
-    --config convert.hg.clonebranches=False   (boolean)
-        dispatch source branches in separate clones.
-    --config convert.hg.tagsbranch=default    (branch name)
-        tag revisions branch name
-    --config convert.hg.usebranchnames=True   (boolean)
-        preserve branch names
-
-    """
-    return convcmd.convert(ui, src, dest, revmapfile, **opts)
-
-def debugsvnlog(ui, **opts):
-    return subversion.debugsvnlog(ui, **opts)
-
-def debugcvsps(ui, *args, **opts):
-    '''create changeset information from CVS
-
-    This command is intended as a debugging tool for the CVS to
-    Mercurial converter, and can be used as a direct replacement for
-    cvsps.
-
-    Hg debugcvsps reads the CVS rlog for current directory (or any
-    named directory) in the CVS repository, and converts the log to a
-    series of changesets based on matching commit log entries and
-    dates.'''
-    return cvsps.debugcvsps(ui, *args, **opts)
-
-commands.norepo += " convert debugsvnlog debugcvsps"
-
-cmdtable = {
-    "convert":
-        (convert,
-         [('A', 'authors', '', _('username mapping filename')),
-          ('d', 'dest-type', '', _('destination repository type')),
-          ('', 'filemap', '', _('remap file names using contents of file')),
-          ('r', 'rev', '', _('import up to target revision REV')),
-          ('s', 'source-type', '', _('source repository type')),
-          ('', 'splicemap', '', _('splice synthesized history into place')),
-          ('', 'branchmap', '', _('change branch names while converting')),
-          ('', 'branchsort', None, _('try to sort changesets by branches')),
-          ('', 'datesort', None, _('try to sort changesets by date')),
-          ('', 'sourcesort', None, _('preserve source changesets order'))],
-         _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]')),
-    "debugsvnlog":
-        (debugsvnlog,
-         [],
-         'hg debugsvnlog'),
-    "debugcvsps":
-        (debugcvsps,
-         [
-          # Main options shared with cvsps-2.1
-          ('b', 'branches', [], _('only return changes on specified branches')),
-          ('p', 'prefix', '', _('prefix to remove from file names')),
-          ('r', 'revisions', [], _('only return changes after or between specified tags')),
-          ('u', 'update-cache', None, _("update cvs log cache")),
-          ('x', 'new-cache', None, _("create new cvs log cache")),
-          ('z', 'fuzz', 60, _('set commit time fuzz in seconds')),
-          ('', 'root', '', _('specify cvsroot')),
-          # Options specific to builtin cvsps
-          ('', 'parents', '', _('show parent changesets')),
-          ('', 'ancestors', '', _('show current changeset in ancestor branches')),
-          # Options that are ignored for compatibility with cvsps-2.1
-          ('A', 'cvs-direct', None, _('ignored for compatibility')),
-         ],
-         _('hg debugcvsps [OPTION]... [PATH]...')),
-}
--- a/sys/src/cmd/hg/hgext/convert/bzr.py
+++ /dev/null
@@ -1,259 +1,0 @@
-# bzr.py - bzr support for the convert extension
-#
-#  Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-# This module is for handling 'bzr', that was formerly known as Bazaar-NG;
-# it cannot access 'bar' repositories, but they were never used very much
-
-import os
-from mercurial import demandimport
-# these do not work with demandimport, blacklist
-demandimport.ignore.extend([
-        'bzrlib.transactions',
-        'bzrlib.urlutils',
-    ])
-
-from mercurial.i18n import _
-from mercurial import util
-from common import NoRepo, commit, converter_source
-
-try:
-    # bazaar imports
-    from bzrlib import branch, revision, errors
-    from bzrlib.revisionspec import RevisionSpec
-except ImportError:
-    pass
-
-supportedkinds = ('file', 'symlink')
-
-class bzr_source(converter_source):
-    """Reads Bazaar repositories by using the Bazaar Python libraries"""
-
-    def __init__(self, ui, path, rev=None):
-        super(bzr_source, self).__init__(ui, path, rev=rev)
-
-        if not os.path.exists(os.path.join(path, '.bzr')):
-            raise NoRepo('%s does not look like a Bazaar repo' % path)
-
-        try:
-            # access bzrlib stuff
-            branch
-        except NameError:
-            raise NoRepo('Bazaar modules could not be loaded')
-
-        path = os.path.abspath(path)
-        self._checkrepotype(path)
-        self.branch = branch.Branch.open(path)
-        self.sourcerepo = self.branch.repository
-        self._parentids = {}
-
-    def _checkrepotype(self, path):
-        # Lightweight checkouts detection is informational but probably
-        # fragile at API level. It should not terminate the conversion.
-        try:
-            from bzrlib import bzrdir
-            dir = bzrdir.BzrDir.open_containing(path)[0]
-            try:
-                tree = dir.open_workingtree(recommend_upgrade=False)
-                branch = tree.branch
-            except (errors.NoWorkingTree, errors.NotLocalUrl), e:
-                tree = None
-                branch = dir.open_branch()
-            if (tree is not None and tree.bzrdir.root_transport.base !=
-                branch.bzrdir.root_transport.base):
-                self.ui.warn(_('warning: lightweight checkouts may cause '
-                               'conversion failures, try with a regular '
-                               'branch instead.\n'))
-        except:
-            self.ui.note(_('bzr source type could not be determined\n'))
-
-    def before(self):
-        """Before the conversion begins, acquire a read lock
-        for all the operations that might need it. Fortunately
-        read locks don't block other reads or writes to the
-        repository, so this shouldn't have any impact on the usage of
-        the source repository.
-
-        The alternative would be locking on every operation that
-        needs locks (there are currently two: getting the file and
-        getting the parent map) and releasing immediately after,
-        but this approach can take even 40% longer."""
-        self.sourcerepo.lock_read()
-
-    def after(self):
-        self.sourcerepo.unlock()
-
-    def getheads(self):
-        if not self.rev:
-            return [self.branch.last_revision()]
-        try:
-            r = RevisionSpec.from_string(self.rev)
-            info = r.in_history(self.branch)
-        except errors.BzrError:
-            raise util.Abort(_('%s is not a valid revision in current branch')
-                             % self.rev)
-        return [info.rev_id]
-
-    def getfile(self, name, rev):
-        revtree = self.sourcerepo.revision_tree(rev)
-        fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
-        kind = None
-        if fileid is not None:
-            kind = revtree.kind(fileid)
-        if kind not in supportedkinds:
-            # the file is not available anymore - was deleted
-            raise IOError(_('%s is not available in %s anymore') %
-                    (name, rev))
-        if kind == 'symlink':
-            target = revtree.get_symlink_target(fileid)
-            if target is None:
-                raise util.Abort(_('%s.%s symlink has no target')
-                                 % (name, rev))
-            return target
-        else:
-            sio = revtree.get_file(fileid)
-            return sio.read()
-
-    def getmode(self, name, rev):
-        return self._modecache[(name, rev)]
-
-    def getchanges(self, version):
-        # set up caches: modecache and revtree
-        self._modecache = {}
-        self._revtree = self.sourcerepo.revision_tree(version)
-        # get the parentids from the cache
-        parentids = self._parentids.pop(version)
-        # only diff against first parent id
-        prevtree = self.sourcerepo.revision_tree(parentids[0])
-        return self._gettreechanges(self._revtree, prevtree)
-
-    def getcommit(self, version):
-        rev = self.sourcerepo.get_revision(version)
-        # populate parent id cache
-        if not rev.parent_ids:
-            parents = []
-            self._parentids[version] = (revision.NULL_REVISION,)
-        else:
-            parents = self._filterghosts(rev.parent_ids)
-            self._parentids[version] = parents
-
-        return commit(parents=parents,
-                date='%d %d' % (rev.timestamp, -rev.timezone),
-                author=self.recode(rev.committer),
-                # bzr returns bytestrings or unicode, depending on the content
-                desc=self.recode(rev.message),
-                rev=version)
-
-    def gettags(self):
-        if not self.branch.supports_tags():
-            return {}
-        tagdict = self.branch.tags.get_tag_dict()
-        bytetags = {}
-        for name, rev in tagdict.iteritems():
-            bytetags[self.recode(name)] = rev
-        return bytetags
-
-    def getchangedfiles(self, rev, i):
-        self._modecache = {}
-        curtree = self.sourcerepo.revision_tree(rev)
-        if i is not None:
-            parentid = self._parentids[rev][i]
-        else:
-            # no parent id, get the empty revision
-            parentid = revision.NULL_REVISION
-
-        prevtree = self.sourcerepo.revision_tree(parentid)
-        changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
-        return changes
-
-    def _gettreechanges(self, current, origin):
-        revid = current._revision_id;
-        changes = []
-        renames = {}
-        for (fileid, paths, changed_content, versioned, parent, name,
-            kind, executable) in current.iter_changes(origin):
-
-            if paths[0] == u'' or paths[1] == u'':
-                # ignore changes to tree root
-                continue
-
-            # bazaar tracks directories, mercurial does not, so
-            # we have to rename the directory contents
-            if kind[1] == 'directory':
-                if kind[0] not in (None, 'directory'):
-                    # Replacing 'something' with a directory, record it
-                    # so it can be removed.
-                    changes.append((self.recode(paths[0]), revid))
-
-                if None not in paths and paths[0] != paths[1]:
-                    # neither an add nor an delete - a move
-                    # rename all directory contents manually
-                    subdir = origin.inventory.path2id(paths[0])
-                    # get all child-entries of the directory
-                    for name, entry in origin.inventory.iter_entries(subdir):
-                        # hg does not track directory renames
-                        if entry.kind == 'directory':
-                            continue
-                        frompath = self.recode(paths[0] + '/' + name)
-                        topath = self.recode(paths[1] + '/' + name)
-                        # register the files as changed
-                        changes.append((frompath, revid))
-                        changes.append((topath, revid))
-                        # add to mode cache
-                        mode = ((entry.executable and 'x') or (entry.kind == 'symlink' and 's')
-                                or '')
-                        self._modecache[(topath, revid)] = mode
-                        # register the change as move
-                        renames[topath] = frompath
-
-                # no futher changes, go to the next change
-                continue
-
-            # we got unicode paths, need to convert them
-            path, topath = [self.recode(part) for part in paths]
-
-            if topath is None:
-                # file deleted
-                changes.append((path, revid))
-                continue
-
-            # renamed
-            if path and path != topath:
-                renames[topath] = path
-                changes.append((path, revid))
-
-            # populate the mode cache
-            kind, executable = [e[1] for e in (kind, executable)]
-            mode = ((executable and 'x') or (kind == 'symlink' and 'l')
-                    or '')
-            self._modecache[(topath, revid)] = mode
-            changes.append((topath, revid))
-
-        return changes, renames
-
-    def _filterghosts(self, ids):
-        """Filters out ghost revisions which hg does not support, see
-        <http://bazaar-vcs.org/GhostRevision>
-        """
-        parentmap = self.sourcerepo.get_parent_map(ids)
-        parents = tuple([parent for parent in ids if parent in parentmap])
-        return parents
-
-    def recode(self, s, encoding=None):
-        """This version of recode tries to encode unicode to bytecode,
-        and preferably using the UTF-8 codec.
-        Other types than Unicode are silently returned, this is by
-        intention, e.g. the None-type is not going to be encoded but instead
-        just passed through
-        """
-        if not encoding:
-            encoding = self.encoding or 'utf-8'
-
-        if isinstance(s, unicode):
-            return s.encode(encoding)
-        else:
-            # leave it alone
-            return s
--- a/sys/src/cmd/hg/hgext/convert/common.py
+++ /dev/null
@@ -1,389 +1,0 @@
-# common.py - common code for the convert extension
-#
-#  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import base64, errno
-import os
-import cPickle as pickle
-from mercurial import util
-from mercurial.i18n import _
-
-def encodeargs(args):
-    def encodearg(s):
-        lines = base64.encodestring(s)
-        lines = [l.splitlines()[0] for l in lines]
-        return ''.join(lines)
-
-    s = pickle.dumps(args)
-    return encodearg(s)
-
-def decodeargs(s):
-    s = base64.decodestring(s)
-    return pickle.loads(s)
-
-class MissingTool(Exception): pass
-
-def checktool(exe, name=None, abort=True):
-    name = name or exe
-    if not util.find_exe(exe):
-        exc = abort and util.Abort or MissingTool
-        raise exc(_('cannot find required "%s" tool') % name)
-
-class NoRepo(Exception): pass
-
-SKIPREV = 'SKIP'
-
-class commit(object):
-    def __init__(self, author, date, desc, parents, branch=None, rev=None,
-                 extra={}, sortkey=None):
-        self.author = author or 'unknown'
-        self.date = date or '0 0'
-        self.desc = desc
-        self.parents = parents
-        self.branch = branch
-        self.rev = rev
-        self.extra = extra
-        self.sortkey = sortkey
-
-class converter_source(object):
-    """Conversion source interface"""
-
-    def __init__(self, ui, path=None, rev=None):
-        """Initialize conversion source (or raise NoRepo("message")
-        exception if path is not a valid repository)"""
-        self.ui = ui
-        self.path = path
-        self.rev = rev
-
-        self.encoding = 'utf-8'
-
-    def before(self):
-        pass
-
-    def after(self):
-        pass
-
-    def setrevmap(self, revmap):
-        """set the map of already-converted revisions"""
-        pass
-
-    def getheads(self):
-        """Return a list of this repository's heads"""
-        raise NotImplementedError()
-
-    def getfile(self, name, rev):
-        """Return file contents as a string. rev is the identifier returned
-        by a previous call to getchanges(). Raise IOError to indicate that
-        name was deleted in rev.
-        """
-        raise NotImplementedError()
-
-    def getmode(self, name, rev):
-        """Return file mode, eg. '', 'x', or 'l'. rev is the identifier
-        returned by a previous call to getchanges().
-        """
-        raise NotImplementedError()
-
-    def getchanges(self, version):
-        """Returns a tuple of (files, copies).
-
-        files is a sorted list of (filename, id) tuples for all files
-        changed between version and its first parent returned by
-        getcommit(). id is the source revision id of the file.
-
-        copies is a dictionary of dest: source
-        """
-        raise NotImplementedError()
-
-    def getcommit(self, version):
-        """Return the commit object for version"""
-        raise NotImplementedError()
-
-    def gettags(self):
-        """Return the tags as a dictionary of name: revision
-
-        Tag names must be UTF-8 strings.
-        """
-        raise NotImplementedError()
-
-    def recode(self, s, encoding=None):
-        if not encoding:
-            encoding = self.encoding or 'utf-8'
-
-        if isinstance(s, unicode):
-            return s.encode("utf-8")
-        try:
-            return s.decode(encoding).encode("utf-8")
-        except:
-            try:
-                return s.decode("latin-1").encode("utf-8")
-            except:
-                return s.decode(encoding, "replace").encode("utf-8")
-
-    def getchangedfiles(self, rev, i):
-        """Return the files changed by rev compared to parent[i].
-
-        i is an index selecting one of the parents of rev.  The return
-        value should be the list of files that are different in rev and
-        this parent.
-
-        If rev has no parents, i is None.
-
-        This function is only needed to support --filemap
-        """
-        raise NotImplementedError()
-
-    def converted(self, rev, sinkrev):
-        '''Notify the source that a revision has been converted.'''
-        pass
-
-    def hasnativeorder(self):
-        """Return true if this source has a meaningful, native revision
-        order. For instance, Mercurial revisions are store sequentially
-        while there is no such global ordering with Darcs.
-        """
-        return False
-
-    def lookuprev(self, rev):
-        """If rev is a meaningful revision reference in source, return
-        the referenced identifier in the same format used by getcommit().
-        return None otherwise.
-        """
-        return None
-
-class converter_sink(object):
-    """Conversion sink (target) interface"""
-
-    def __init__(self, ui, path):
-        """Initialize conversion sink (or raise NoRepo("message")
-        exception if path is not a valid repository)
-
-        created is a list of paths to remove if a fatal error occurs
-        later"""
-        self.ui = ui
-        self.path = path
-        self.created = []
-
-    def getheads(self):
-        """Return a list of this repository's heads"""
-        raise NotImplementedError()
-
-    def revmapfile(self):
-        """Path to a file that will contain lines
-        source_rev_id sink_rev_id
-        mapping equivalent revision identifiers for each system."""
-        raise NotImplementedError()
-
-    def authorfile(self):
-        """Path to a file that will contain lines
-        srcauthor=dstauthor
-        mapping equivalent authors identifiers for each system."""
-        return None
-
-    def putcommit(self, files, copies, parents, commit, source, revmap):
-        """Create a revision with all changed files listed in 'files'
-        and having listed parents. 'commit' is a commit object
-        containing at a minimum the author, date, and message for this
-        changeset.  'files' is a list of (path, version) tuples,
-        'copies' is a dictionary mapping destinations to sources,
-        'source' is the source repository, and 'revmap' is a mapfile
-        of source revisions to converted revisions. Only getfile(),
-        getmode(), and lookuprev() should be called on 'source'.
-
-        Note that the sink repository is not told to update itself to
-        a particular revision (or even what that revision would be)
-        before it receives the file data.
-        """
-        raise NotImplementedError()
-
-    def puttags(self, tags):
-        """Put tags into sink.
-
-        tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
-        """
-        raise NotImplementedError()
-
-    def setbranch(self, branch, pbranches):
-        """Set the current branch name. Called before the first putcommit
-        on the branch.
-        branch: branch name for subsequent commits
-        pbranches: (converted parent revision, parent branch) tuples"""
-        pass
-
-    def setfilemapmode(self, active):
-        """Tell the destination that we're using a filemap
-
-        Some converter_sources (svn in particular) can claim that a file
-        was changed in a revision, even if there was no change.  This method
-        tells the destination that we're using a filemap and that it should
-        filter empty revisions.
-        """
-        pass
-
-    def before(self):
-        pass
-
-    def after(self):
-        pass
-
-
-class commandline(object):
-    def __init__(self, ui, command):
-        self.ui = ui
-        self.command = command
-
-    def prerun(self):
-        pass
-
-    def postrun(self):
-        pass
-
-    def _cmdline(self, cmd, *args, **kwargs):
-        cmdline = [self.command, cmd] + list(args)
-        for k, v in kwargs.iteritems():
-            if len(k) == 1:
-                cmdline.append('-' + k)
-            else:
-                cmdline.append('--' + k.replace('_', '-'))
-            try:
-                if len(k) == 1:
-                    cmdline.append('' + v)
-                else:
-                    cmdline[-1] += '=' + v
-            except TypeError:
-                pass
-        cmdline = [util.shellquote(arg) for arg in cmdline]
-        if not self.ui.debugflag:
-            cmdline += ['2>', util.nulldev]
-        cmdline += ['<', util.nulldev]
-        cmdline = ' '.join(cmdline)
-        return cmdline
-
-    def _run(self, cmd, *args, **kwargs):
-        cmdline = self._cmdline(cmd, *args, **kwargs)
-        self.ui.debug(_('running: %s\n') % (cmdline,))
-        self.prerun()
-        try:
-            return util.popen(cmdline)
-        finally:
-            self.postrun()
-
-    def run(self, cmd, *args, **kwargs):
-        fp = self._run(cmd, *args, **kwargs)
-        output = fp.read()
-        self.ui.debug(output)
-        return output, fp.close()
-
-    def runlines(self, cmd, *args, **kwargs):
-        fp = self._run(cmd, *args, **kwargs)
-        output = fp.readlines()
-        self.ui.debug(''.join(output))
-        return output, fp.close()
-
-    def checkexit(self, status, output=''):
-        if status:
-            if output:
-                self.ui.warn(_('%s error:\n') % self.command)
-                self.ui.warn(output)
-            msg = util.explain_exit(status)[0]
-            raise util.Abort('%s %s' % (self.command, msg))
-
-    def run0(self, cmd, *args, **kwargs):
-        output, status = self.run(cmd, *args, **kwargs)
-        self.checkexit(status, output)
-        return output
-
-    def runlines0(self, cmd, *args, **kwargs):
-        output, status = self.runlines(cmd, *args, **kwargs)
-        self.checkexit(status, ''.join(output))
-        return output
-
-    def getargmax(self):
-        if '_argmax' in self.__dict__:
-            return self._argmax
-
-        # POSIX requires at least 4096 bytes for ARG_MAX
-        self._argmax = 4096
-        try:
-            self._argmax = os.sysconf("SC_ARG_MAX")
-        except:
-            pass
-
-        # Windows shells impose their own limits on command line length,
-        # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
-        # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
-        # details about cmd.exe limitations.
-
-        # Since ARG_MAX is for command line _and_ environment, lower our limit
-        # (and make happy Windows shells while doing this).
-
-        self._argmax = self._argmax/2 - 1
-        return self._argmax
-
-    def limit_arglist(self, arglist, cmd, *args, **kwargs):
-        limit = self.getargmax() - len(self._cmdline(cmd, *args, **kwargs))
-        bytes = 0
-        fl = []
-        for fn in arglist:
-            b = len(fn) + 3
-            if bytes + b < limit or len(fl) == 0:
-                fl.append(fn)
-                bytes += b
-            else:
-                yield fl
-                fl = [fn]
-                bytes = b
-        if fl:
-            yield fl
-
-    def xargs(self, arglist, cmd, *args, **kwargs):
-        for l in self.limit_arglist(arglist, cmd, *args, **kwargs):
-            self.run0(cmd, *(list(args) + l), **kwargs)
-
-class mapfile(dict):
-    def __init__(self, ui, path):
-        super(mapfile, self).__init__()
-        self.ui = ui
-        self.path = path
-        self.fp = None
-        self.order = []
-        self._read()
-
-    def _read(self):
-        if not self.path:
-            return
-        try:
-            fp = open(self.path, 'r')
-        except IOError, err:
-            if err.errno != errno.ENOENT:
-                raise
-            return
-        for i, line in enumerate(fp):
-            try:
-                key, value = line[:-1].rsplit(' ', 1)
-            except ValueError:
-                raise util.Abort(_('syntax error in %s(%d): key/value pair expected')
-                                 % (self.path, i+1))
-            if key not in self:
-                self.order.append(key)
-            super(mapfile, self).__setitem__(key, value)
-        fp.close()
-
-    def __setitem__(self, key, value):
-        if self.fp is None:
-            try:
-                self.fp = open(self.path, 'a')
-            except IOError, err:
-                raise util.Abort(_('could not open map file %r: %s') %
-                                 (self.path, err.strerror))
-        self.fp.write('%s %s\n' % (key, value))
-        self.fp.flush()
-        super(mapfile, self).__setitem__(key, value)
-
-    def close(self):
-        if self.fp:
-            self.fp.close()
-            self.fp = None
--- a/sys/src/cmd/hg/hgext/convert/convcmd.py
+++ /dev/null
@@ -1,396 +1,0 @@
-# convcmd - convert extension commands definition
-#
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-from common import NoRepo, MissingTool, SKIPREV, mapfile
-from cvs import convert_cvs
-from darcs import darcs_source
-from git import convert_git
-from hg import mercurial_source, mercurial_sink
-from subversion import svn_source, svn_sink
-from monotone import monotone_source
-from gnuarch import gnuarch_source
-from bzr import bzr_source
-from p4 import p4_source
-import filemap
-
-import os, shutil
-from mercurial import hg, util, encoding
-from mercurial.i18n import _
-
-orig_encoding = 'ascii'
-
-def recode(s):
-    if isinstance(s, unicode):
-        return s.encode(orig_encoding, 'replace')
-    else:
-        return s.decode('utf-8').encode(orig_encoding, 'replace')
-
-source_converters = [
-    ('cvs', convert_cvs, 'branchsort'),
-    ('git', convert_git, 'branchsort'),
-    ('svn', svn_source, 'branchsort'),
-    ('hg', mercurial_source, 'sourcesort'),
-    ('darcs', darcs_source, 'branchsort'),
-    ('mtn', monotone_source, 'branchsort'),
-    ('gnuarch', gnuarch_source, 'branchsort'),
-    ('bzr', bzr_source, 'branchsort'),
-    ('p4', p4_source, 'branchsort'),
-    ]
-
-sink_converters = [
-    ('hg', mercurial_sink),
-    ('svn', svn_sink),
-    ]
-
-def convertsource(ui, path, type, rev):
-    exceptions = []
-    for name, source, sortmode in source_converters:
-        try:
-            if not type or name == type:
-                return source(ui, path, rev), sortmode
-        except (NoRepo, MissingTool), inst:
-            exceptions.append(inst)
-    if not ui.quiet:
-        for inst in exceptions:
-            ui.write("%s\n" % inst)
-    raise util.Abort(_('%s: missing or unsupported repository') % path)
-
-def convertsink(ui, path, type):
-    for name, sink in sink_converters:
-        try:
-            if not type or name == type:
-                return sink(ui, path)
-        except NoRepo, inst:
-            ui.note(_("convert: %s\n") % inst)
-    raise util.Abort(_('%s: unknown repository type') % path)
-
-class converter(object):
-    def __init__(self, ui, source, dest, revmapfile, opts):
-
-        self.source = source
-        self.dest = dest
-        self.ui = ui
-        self.opts = opts
-        self.commitcache = {}
-        self.authors = {}
-        self.authorfile = None
-
-        # Record converted revisions persistently: maps source revision
-        # ID to target revision ID (both strings).  (This is how
-        # incremental conversions work.)
-        self.map = mapfile(ui, revmapfile)
-
-        # Read first the dst author map if any
-        authorfile = self.dest.authorfile()
-        if authorfile and os.path.exists(authorfile):
-            self.readauthormap(authorfile)
-        # Extend/Override with new author map if necessary
-        if opts.get('authors'):
-            self.readauthormap(opts.get('authors'))
-            self.authorfile = self.dest.authorfile()
-
-        self.splicemap = mapfile(ui, opts.get('splicemap'))
-        self.branchmap = mapfile(ui, opts.get('branchmap'))
-
-    def walktree(self, heads):
-        '''Return a mapping that identifies the uncommitted parents of every
-        uncommitted changeset.'''
-        visit = heads
-        known = set()
-        parents = {}
-        while visit:
-            n = visit.pop(0)
-            if n in known or n in self.map: continue
-            known.add(n)
-            commit = self.cachecommit(n)
-            parents[n] = []
-            for p in commit.parents:
-                parents[n].append(p)
-                visit.append(p)
-
-        return parents
-
-    def toposort(self, parents, sortmode):
-        '''Return an ordering such that every uncommitted changeset is
-        preceeded by all its uncommitted ancestors.'''
-
-        def mapchildren(parents):
-            """Return a (children, roots) tuple where 'children' maps parent
-            revision identifiers to children ones, and 'roots' is the list of
-            revisions without parents. 'parents' must be a mapping of revision
-            identifier to its parents ones.
-            """
-            visit = parents.keys()
-            seen = set()
-            children = {}
-            roots = []
-
-            while visit:
-                n = visit.pop(0)
-                if n in seen:
-                    continue
-                seen.add(n)
-                # Ensure that nodes without parents are present in the
-                # 'children' mapping.
-                children.setdefault(n, [])
-                hasparent = False
-                for p in parents[n]:
-                    if not p in self.map:
-                        visit.append(p)
-                        hasparent = True
-                    children.setdefault(p, []).append(n)
-                if not hasparent:
-                    roots.append(n)
-
-            return children, roots
-
-        # Sort functions are supposed to take a list of revisions which
-        # can be converted immediately and pick one
-
-        def makebranchsorter():
-            """If the previously converted revision has a child in the
-            eligible revisions list, pick it. Return the list head
-            otherwise. Branch sort attempts to minimize branch
-            switching, which is harmful for Mercurial backend
-            compression.
-            """
-            prev = [None]
-            def picknext(nodes):
-                next = nodes[0]
-                for n in nodes:
-                    if prev[0] in parents[n]:
-                        next = n
-                        break
-                prev[0] = next
-                return next
-            return picknext
-
-        def makesourcesorter():
-            """Source specific sort."""
-            keyfn = lambda n: self.commitcache[n].sortkey
-            def picknext(nodes):
-                return sorted(nodes, key=keyfn)[0]
-            return picknext
-
-        def makedatesorter():
-            """Sort revisions by date."""
-            dates = {}
-            def getdate(n):
-                if n not in dates:
-                    dates[n] = util.parsedate(self.commitcache[n].date)
-                return dates[n]
-
-            def picknext(nodes):
-                return min([(getdate(n), n) for n in nodes])[1]
-
-            return picknext
-
-        if sortmode == 'branchsort':
-            picknext = makebranchsorter()
-        elif sortmode == 'datesort':
-            picknext = makedatesorter()
-        elif sortmode == 'sourcesort':
-            picknext = makesourcesorter()
-        else:
-            raise util.Abort(_('unknown sort mode: %s') % sortmode)
-
-        children, actives = mapchildren(parents)
-
-        s = []
-        pendings = {}
-        while actives:
-            n = picknext(actives)
-            actives.remove(n)
-            s.append(n)
-
-            # Update dependents list
-            for c in children.get(n, []):
-                if c not in pendings:
-                    pendings[c] = [p for p in parents[c] if p not in self.map]
-                try:
-                    pendings[c].remove(n)
-                except ValueError:
-                    raise util.Abort(_('cycle detected between %s and %s')
-                                       % (recode(c), recode(n)))
-                if not pendings[c]:
-                    # Parents are converted, node is eligible
-                    actives.insert(0, c)
-                    pendings[c] = None
-
-        if len(s) != len(parents):
-            raise util.Abort(_("not all revisions were sorted"))
-
-        return s
-
-    def writeauthormap(self):
-        authorfile = self.authorfile
-        if authorfile:
-            self.ui.status(_('Writing author map file %s\n') % authorfile)
-            ofile = open(authorfile, 'w+')
-            for author in self.authors:
-                ofile.write("%s=%s\n" % (author, self.authors[author]))
-            ofile.close()
-
-    def readauthormap(self, authorfile):
-        afile = open(authorfile, 'r')
-        for line in afile:
-
-            line = line.strip()
-            if not line or line.startswith('#'):
-                continue
-
-            try:
-                srcauthor, dstauthor = line.split('=', 1)
-            except ValueError:
-                msg = _('Ignoring bad line in author map file %s: %s\n')
-                self.ui.warn(msg % (authorfile, line.rstrip()))
-                continue
-
-            srcauthor = srcauthor.strip()
-            dstauthor = dstauthor.strip()
-            if self.authors.get(srcauthor) in (None, dstauthor):
-                msg = _('mapping author %s to %s\n')
-                self.ui.debug(msg % (srcauthor, dstauthor))
-                self.authors[srcauthor] = dstauthor
-                continue
-
-            m = _('overriding mapping for author %s, was %s, will be %s\n')
-            self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor))
-
-        afile.close()
-
-    def cachecommit(self, rev):
-        commit = self.source.getcommit(rev)
-        commit.author = self.authors.get(commit.author, commit.author)
-        commit.branch = self.branchmap.get(commit.branch, commit.branch)
-        self.commitcache[rev] = commit
-        return commit
-
-    def copy(self, rev):
-        commit = self.commitcache[rev]
-
-        changes = self.source.getchanges(rev)
-        if isinstance(changes, basestring):
-            if changes == SKIPREV:
-                dest = SKIPREV
-            else:
-                dest = self.map[changes]
-            self.map[rev] = dest
-            return
-        files, copies = changes
-        pbranches = []
-        if commit.parents:
-            for prev in commit.parents:
-                if prev not in self.commitcache:
-                    self.cachecommit(prev)
-                pbranches.append((self.map[prev],
-                                  self.commitcache[prev].branch))
-        self.dest.setbranch(commit.branch, pbranches)
-        try:
-            parents = self.splicemap[rev].replace(',', ' ').split()
-            self.ui.status(_('spliced in %s as parents of %s\n') %
-                           (parents, rev))
-            parents = [self.map.get(p, p) for p in parents]
-        except KeyError:
-            parents = [b[0] for b in pbranches]
-        newnode = self.dest.putcommit(files, copies, parents, commit,
-                                      self.source, self.map)
-        self.source.converted(rev, newnode)
-        self.map[rev] = newnode
-
-    def convert(self, sortmode):
-        try:
-            self.source.before()
-            self.dest.before()
-            self.source.setrevmap(self.map)
-            self.ui.status(_("scanning source...\n"))
-            heads = self.source.getheads()
-            parents = self.walktree(heads)
-            self.ui.status(_("sorting...\n"))
-            t = self.toposort(parents, sortmode)
-            num = len(t)
-            c = None
-
-            self.ui.status(_("converting...\n"))
-            for c in t:
-                num -= 1
-                desc = self.commitcache[c].desc
-                if "\n" in desc:
-                    desc = desc.splitlines()[0]
-                # convert log message to local encoding without using
-                # tolocal() because encoding.encoding conver() use it as
-                # 'utf-8'
-                self.ui.status("%d %s\n" % (num, recode(desc)))
-                self.ui.note(_("source: %s\n") % recode(c))
-                self.copy(c)
-
-            tags = self.source.gettags()
-            ctags = {}
-            for k in tags:
-                v = tags[k]
-                if self.map.get(v, SKIPREV) != SKIPREV:
-                    ctags[k] = self.map[v]
-
-            if c and ctags:
-                nrev = self.dest.puttags(ctags)
-                # write another hash correspondence to override the previous
-                # one so we don't end up with extra tag heads
-                if nrev:
-                    self.map[c] = nrev
-
-            self.writeauthormap()
-        finally:
-            self.cleanup()
-
-    def cleanup(self):
-        try:
-            self.dest.after()
-        finally:
-            self.source.after()
-        self.map.close()
-
-def convert(ui, src, dest=None, revmapfile=None, **opts):
-    global orig_encoding
-    orig_encoding = encoding.encoding
-    encoding.encoding = 'UTF-8'
-
-    if not dest:
-        dest = hg.defaultdest(src) + "-hg"
-        ui.status(_("assuming destination %s\n") % dest)
-
-    destc = convertsink(ui, dest, opts.get('dest_type'))
-
-    try:
-        srcc, defaultsort = convertsource(ui, src, opts.get('source_type'),
-                                          opts.get('rev'))
-    except Exception:
-        for path in destc.created:
-            shutil.rmtree(path, True)
-        raise
-
-    sortmodes = ('branchsort', 'datesort', 'sourcesort')
-    sortmode = [m for m in sortmodes if opts.get(m)]
-    if len(sortmode) > 1:
-        raise util.Abort(_('more than one sort mode specified'))
-    sortmode = sortmode and sortmode[0] or defaultsort
-    if sortmode == 'sourcesort' and not srcc.hasnativeorder():
-        raise util.Abort(_('--sourcesort is not supported by this data source'))
-
-    fmap = opts.get('filemap')
-    if fmap:
-        srcc = filemap.filemap_source(ui, srcc, fmap)
-        destc.setfilemapmode(True)
-
-    if not revmapfile:
-        try:
-            revmapfile = destc.revmapfile()
-        except:
-            revmapfile = os.path.join(destc, "map")
-
-    c = converter(ui, srcc, destc, revmapfile, opts)
-    c.convert(sortmode)
-
--- a/sys/src/cmd/hg/hgext/convert/cvs.py
+++ /dev/null
@@ -1,372 +1,0 @@
-# cvs.py: CVS conversion code inspired by hg-cvs-import and git-cvsimport
-#
-#  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os, locale, re, socket, errno
-from cStringIO import StringIO
-from mercurial import util
-from mercurial.i18n import _
-
-from common import NoRepo, commit, converter_source, checktool
-import cvsps
-
-class convert_cvs(converter_source):
-    def __init__(self, ui, path, rev=None):
-        super(convert_cvs, self).__init__(ui, path, rev=rev)
-
-        cvs = os.path.join(path, "CVS")
-        if not os.path.exists(cvs):
-            raise NoRepo("%s does not look like a CVS checkout" % path)
-
-        checktool('cvs')
-        self.cmd = ui.config('convert', 'cvsps', 'builtin')
-        cvspsexe = self.cmd.split(None, 1)[0]
-        self.builtin = cvspsexe == 'builtin'
-        if not self.builtin:
-            ui.warn(_('warning: support for external cvsps is deprecated and '
-                      'will be removed in Mercurial 1.4\n'))
-
-        if not self.builtin:
-            checktool(cvspsexe)
-
-        self.changeset = None
-        self.files = {}
-        self.tags = {}
-        self.lastbranch = {}
-        self.parent = {}
-        self.socket = None
-        self.cvsroot = open(os.path.join(cvs, "Root")).read()[:-1]
-        self.cvsrepo = open(os.path.join(cvs, "Repository")).read()[:-1]
-        self.encoding = locale.getpreferredencoding()
-
-        self._connect()
-
-    def _parse(self):
-        if self.changeset is not None:
-            return
-        self.changeset = {}
-
-        maxrev = 0
-        cmd = self.cmd
-        if self.rev:
-            # TODO: handle tags
-            try:
-                # patchset number?
-                maxrev = int(self.rev)
-            except ValueError:
-                try:
-                    # date
-                    util.parsedate(self.rev, ['%Y/%m/%d %H:%M:%S'])
-                    cmd = '%s -d "1970/01/01 00:00:01" -d "%s"' % (cmd, self.rev)
-                except util.Abort:
-                    raise util.Abort(_('revision %s is not a patchset number or date') % self.rev)
-
-        d = os.getcwd()
-        try:
-            os.chdir(self.path)
-            id = None
-            state = 0
-            filerevids = {}
-
-            if self.builtin:
-                # builtin cvsps code
-                self.ui.status(_('using builtin cvsps\n'))
-
-                cache = 'update'
-                if not self.ui.configbool('convert', 'cvsps.cache', True):
-                    cache = None
-                db = cvsps.createlog(self.ui, cache=cache)
-                db = cvsps.createchangeset(self.ui, db,
-                      fuzz=int(self.ui.config('convert', 'cvsps.fuzz', 60)),
-                      mergeto=self.ui.config('convert', 'cvsps.mergeto', None),
-                      mergefrom=self.ui.config('convert', 'cvsps.mergefrom', None))
-
-                for cs in db:
-                    if maxrev and cs.id>maxrev:
-                        break
-                    id = str(cs.id)
-                    cs.author = self.recode(cs.author)
-                    self.lastbranch[cs.branch] = id
-                    cs.comment = self.recode(cs.comment)
-                    date = util.datestr(cs.date)
-                    self.tags.update(dict.fromkeys(cs.tags, id))
-
-                    files = {}
-                    for f in cs.entries:
-                        files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
-                                                  ['', '(DEAD)'][f.dead])
-
-                    # add current commit to set
-                    c = commit(author=cs.author, date=date,
-                             parents=[str(p.id) for p in cs.parents],
-                             desc=cs.comment, branch=cs.branch or '')
-                    self.changeset[id] = c
-                    self.files[id] = files
-            else:
-                # external cvsps
-                for l in util.popen(cmd):
-                    if state == 0: # header
-                        if l.startswith("PatchSet"):
-                            id = l[9:-2]
-                            if maxrev and int(id) > maxrev:
-                                # ignore everything
-                                state = 3
-                        elif l.startswith("Date:"):
-                            date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
-                            date = util.datestr(date)
-                        elif l.startswith("Branch:"):
-                            branch = l[8:-1]
-                            self.parent[id] = self.lastbranch.get(branch, 'bad')
-                            self.lastbranch[branch] = id
-                        elif l.startswith("Ancestor branch:"):
-                            ancestor = l[17:-1]
-                            # figure out the parent later
-                            self.parent[id] = self.lastbranch[ancestor]
-                        elif l.startswith("Author:"):
-                            author = self.recode(l[8:-1])
-                        elif l.startswith("Tag:") or l.startswith("Tags:"):
-                            t = l[l.index(':')+1:]
-                            t = [ut.strip() for ut in t.split(',')]
-                            if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
-                                self.tags.update(dict.fromkeys(t, id))
-                        elif l.startswith("Log:"):
-                            # switch to gathering log
-                            state = 1
-                            log = ""
-                    elif state == 1: # log
-                        if l == "Members: \n":
-                            # switch to gathering members
-                            files = {}
-                            oldrevs = []
-                            log = self.recode(log[:-1])
-                            state = 2
-                        else:
-                            # gather log
-                            log += l
-                    elif state == 2: # members
-                        if l == "\n": # start of next entry
-                            state = 0
-                            p = [self.parent[id]]
-                            if id == "1":
-                                p = []
-                            if branch == "HEAD":
-                                branch = ""
-                            if branch:
-                                latest = 0
-                                # the last changeset that contains a base
-                                # file is our parent
-                                for r in oldrevs:
-                                    latest = max(filerevids.get(r, 0), latest)
-                                if latest:
-                                    p = [latest]
-
-                            # add current commit to set
-                            c = commit(author=author, date=date, parents=p,
-                                       desc=log, branch=branch)
-                            self.changeset[id] = c
-                            self.files[id] = files
-                        else:
-                            colon = l.rfind(':')
-                            file = l[1:colon]
-                            rev = l[colon+1:-2]
-                            oldrev, rev = rev.split("->")
-                            files[file] = rev
-
-                            # save some information for identifying branch points
-                            oldrevs.append("%s:%s" % (oldrev, file))
-                            filerevids["%s:%s" % (rev, file)] = id
-                    elif state == 3:
-                        # swallow all input
-                        continue
-
-            self.heads = self.lastbranch.values()
-        finally:
-            os.chdir(d)
-
-    def _connect(self):
-        root = self.cvsroot
-        conntype = None
-        user, host = None, None
-        cmd = ['cvs', 'server']
-
-        self.ui.status(_("connecting to %s\n") % root)
-
-        if root.startswith(":pserver:"):
-            root = root[9:]
-            m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)',
-                         root)
-            if m:
-                conntype = "pserver"
-                user, passw, serv, port, root = m.groups()
-                if not user:
-                    user = "anonymous"
-                if not port:
-                    port = 2401
-                else:
-                    port = int(port)
-                format0 = ":pserver:%s@%s:%s" % (user, serv, root)
-                format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root)
-
-                if not passw:
-                    passw = "A"
-                    cvspass = os.path.expanduser("~/.cvspass")
-                    try:
-                        pf = open(cvspass)
-                        for line in pf.read().splitlines():
-                            part1, part2 = line.split(' ', 1)
-                            if part1 == '/1':
-                                # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
-                                part1, part2 = part2.split(' ', 1)
-                                format = format1
-                            else:
-                                # :pserver:user@example.com:/cvsroot/foo Ah<Z
-                                format = format0
-                            if part1 == format:
-                                passw = part2
-                                break
-                        pf.close()
-                    except IOError, inst:
-                        if inst.errno != errno.ENOENT:
-                            if not getattr(inst, 'filename', None):
-                                inst.filename = cvspass
-                            raise
-
-                sck = socket.socket()
-                sck.connect((serv, port))
-                sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw,
-                                    "END AUTH REQUEST", ""]))
-                if sck.recv(128) != "I LOVE YOU\n":
-                    raise util.Abort(_("CVS pserver authentication failed"))
-
-                self.writep = self.readp = sck.makefile('r+')
-
-        if not conntype and root.startswith(":local:"):
-            conntype = "local"
-            root = root[7:]
-
-        if not conntype:
-            # :ext:user@host/home/user/path/to/cvsroot
-            if root.startswith(":ext:"):
-                root = root[5:]
-            m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
-            # Do not take Windows path "c:\foo\bar" for a connection strings
-            if os.path.isdir(root) or not m:
-                conntype = "local"
-            else:
-                conntype = "rsh"
-                user, host, root = m.group(1), m.group(2), m.group(3)
-
-        if conntype != "pserver":
-            if conntype == "rsh":
-                rsh = os.environ.get("CVS_RSH") or "ssh"
-                if user:
-                    cmd = [rsh, '-l', user, host] + cmd
-                else:
-                    cmd = [rsh, host] + cmd
-
-            # popen2 does not support argument lists under Windows
-            cmd = [util.shellquote(arg) for arg in cmd]
-            cmd = util.quotecommand(' '.join(cmd))
-            self.writep, self.readp = util.popen2(cmd)
-
-        self.realroot = root
-
-        self.writep.write("Root %s\n" % root)
-        self.writep.write("Valid-responses ok error Valid-requests Mode"
-                          " M Mbinary E Checked-in Created Updated"
-                          " Merged Removed\n")
-        self.writep.write("valid-requests\n")
-        self.writep.flush()
-        r = self.readp.readline()
-        if not r.startswith("Valid-requests"):
-            raise util.Abort(_("unexpected response from CVS server "
-                               "(expected \"Valid-requests\", but got %r)")
-                             % r)
-        if "UseUnchanged" in r:
-            self.writep.write("UseUnchanged\n")
-            self.writep.flush()
-            r = self.readp.readline()
-
-    def getheads(self):
-        self._parse()
-        return self.heads
-
-    def _getfile(self, name, rev):
-
-        def chunkedread(fp, count):
-            # file-objects returned by socked.makefile() do not handle
-            # large read() requests very well.
-            chunksize = 65536
-            output = StringIO()
-            while count > 0:
-                data = fp.read(min(count, chunksize))
-                if not data:
-                    raise util.Abort(_("%d bytes missing from remote file") % count)
-                count -= len(data)
-                output.write(data)
-            return output.getvalue()
-
-        if rev.endswith("(DEAD)"):
-            raise IOError
-
-        args = ("-N -P -kk -r %s --" % rev).split()
-        args.append(self.cvsrepo + '/' + name)
-        for x in args:
-            self.writep.write("Argument %s\n" % x)
-        self.writep.write("Directory .\n%s\nco\n" % self.realroot)
-        self.writep.flush()
-
-        data = ""
-        while 1:
-            line = self.readp.readline()
-            if line.startswith("Created ") or line.startswith("Updated "):
-                self.readp.readline() # path
-                self.readp.readline() # entries
-                mode = self.readp.readline()[:-1]
-                count = int(self.readp.readline()[:-1])
-                data = chunkedread(self.readp, count)
-            elif line.startswith(" "):
-                data += line[1:]
-            elif line.startswith("M "):
-                pass
-            elif line.startswith("Mbinary "):
-                count = int(self.readp.readline()[:-1])
-                data = chunkedread(self.readp, count)
-            else:
-                if line == "ok\n":
-                    return (data, "x" in mode and "x" or "")
-                elif line.startswith("E "):
-                    self.ui.warn(_("cvs server: %s\n") % line[2:])
-                elif line.startswith("Remove"):
-                    self.readp.readline()
-                else:
-                    raise util.Abort(_("unknown CVS response: %s") % line)
-
-    def getfile(self, file, rev):
-        self._parse()
-        data, mode = self._getfile(file, rev)
-        self.modecache[(file, rev)] = mode
-        return data
-
-    def getmode(self, file, rev):
-        return self.modecache[(file, rev)]
-
-    def getchanges(self, rev):
-        self._parse()
-        self.modecache = {}
-        return sorted(self.files[rev].iteritems()), {}
-
-    def getcommit(self, rev):
-        self._parse()
-        return self.changeset[rev]
-
-    def gettags(self):
-        self._parse()
-        return self.tags
-
-    def getchangedfiles(self, rev, i):
-        self._parse()
-        return sorted(self.files[rev])
--- a/sys/src/cmd/hg/hgext/convert/cvsps.py
+++ /dev/null
@@ -1,831 +1,0 @@
-#
-# Mercurial built-in replacement for cvsps.
-#
-# Copyright 2008, Frank Kingswood <frank@kingswood-consulting.co.uk>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os
-import re
-import cPickle as pickle
-from mercurial import util
-from mercurial.i18n import _
-
-class logentry(object):
-    '''Class logentry has the following attributes:
-        .author    - author name as CVS knows it
-        .branch    - name of branch this revision is on
-        .branches  - revision tuple of branches starting at this revision
-        .comment   - commit message
-        .date      - the commit date as a (time, tz) tuple
-        .dead      - true if file revision is dead
-        .file      - Name of file
-        .lines     - a tuple (+lines, -lines) or None
-        .parent    - Previous revision of this entry
-        .rcs       - name of file as returned from CVS
-        .revision  - revision number as tuple
-        .tags      - list of tags on the file
-        .synthetic - is this a synthetic "file ... added on ..." revision?
-        .mergepoint- the branch that has been merged from
-                     (if present in rlog output)
-        .branchpoints- the branches that start at the current entry
-    '''
-    def __init__(self, **entries):
-        self.__dict__.update(entries)
-
-    def __repr__(self):
-        return "<%s at 0x%x: %s %s>" % (self.__class__.__name__,
-                                        id(self),
-                                        self.file,
-                                        ".".join(map(str, self.revision)))
-
-class logerror(Exception):
-    pass
-
-def getrepopath(cvspath):
-    """Return the repository path from a CVS path.
-
-    >>> getrepopath('/foo/bar')
-    '/foo/bar'
-    >>> getrepopath('c:/foo/bar')
-    'c:/foo/bar'
-    >>> getrepopath(':pserver:10/foo/bar')
-    '/foo/bar'
-    >>> getrepopath(':pserver:10c:/foo/bar')
-    '/foo/bar'
-    >>> getrepopath(':pserver:/foo/bar')
-    '/foo/bar'
-    >>> getrepopath(':pserver:c:/foo/bar')
-    'c:/foo/bar'
-    >>> getrepopath(':pserver:truc@foo.bar:/foo/bar')
-    '/foo/bar'
-    >>> getrepopath(':pserver:truc@foo.bar:c:/foo/bar')
-    'c:/foo/bar'
-    """
-    # According to CVS manual, CVS paths are expressed like:
-    # [:method:][[user][:password]@]hostname[:[port]]/path/to/repository
-    #
-    # Unfortunately, Windows absolute paths start with a drive letter
-    # like 'c:' making it harder to parse. Here we assume that drive
-    # letters are only one character long and any CVS component before
-    # the repository path is at least 2 characters long, and use this
-    # to disambiguate.
-    parts = cvspath.split(':')
-    if len(parts) == 1:
-        return parts[0]
-    # Here there is an ambiguous case if we have a port number
-    # immediately followed by a Windows driver letter. We assume this
-    # never happens and decide it must be CVS path component,
-    # therefore ignoring it.
-    if len(parts[-2]) > 1:
-        return parts[-1].lstrip('0123456789')
-    return parts[-2] + ':' + parts[-1]
-
-def createlog(ui, directory=None, root="", rlog=True, cache=None):
-    '''Collect the CVS rlog'''
-
-    # Because we store many duplicate commit log messages, reusing strings
-    # saves a lot of memory and pickle storage space.
-    _scache = {}
-    def scache(s):
-        "return a shared version of a string"
-        return _scache.setdefault(s, s)
-
-    ui.status(_('collecting CVS rlog\n'))
-
-    log = []      # list of logentry objects containing the CVS state
-
-    # patterns to match in CVS (r)log output, by state of use
-    re_00 = re.compile('RCS file: (.+)$')
-    re_01 = re.compile('cvs \\[r?log aborted\\]: (.+)$')
-    re_02 = re.compile('cvs (r?log|server): (.+)\n$')
-    re_03 = re.compile("(Cannot access.+CVSROOT)|"
-                       "(can't create temporary directory.+)$")
-    re_10 = re.compile('Working file: (.+)$')
-    re_20 = re.compile('symbolic names:')
-    re_30 = re.compile('\t(.+): ([\\d.]+)$')
-    re_31 = re.compile('----------------------------$')
-    re_32 = re.compile('======================================='
-                       '======================================$')
-    re_50 = re.compile('revision ([\\d.]+)(\s+locked by:\s+.+;)?$')
-    re_60 = re.compile(r'date:\s+(.+);\s+author:\s+(.+);\s+state:\s+(.+?);'
-                       r'(\s+lines:\s+(\+\d+)?\s+(-\d+)?;)?'
-                       r'(.*mergepoint:\s+([^;]+);)?')
-    re_70 = re.compile('branches: (.+);$')
-
-    file_added_re = re.compile(r'file [^/]+ was (initially )?added on branch')
-
-    prefix = ''   # leading path to strip of what we get from CVS
-
-    if directory is None:
-        # Current working directory
-
-        # Get the real directory in the repository
-        try:
-            prefix = open(os.path.join('CVS','Repository')).read().strip()
-            if prefix == ".":
-                prefix = ""
-            directory = prefix
-        except IOError:
-            raise logerror('Not a CVS sandbox')
-
-        if prefix and not prefix.endswith(os.sep):
-            prefix += os.sep
-
-        # Use the Root file in the sandbox, if it exists
-        try:
-            root = open(os.path.join('CVS','Root')).read().strip()
-        except IOError:
-            pass
-
-    if not root:
-        root = os.environ.get('CVSROOT', '')
-
-    # read log cache if one exists
-    oldlog = []
-    date = None
-
-    if cache:
-        cachedir = os.path.expanduser('~/.hg.cvsps')
-        if not os.path.exists(cachedir):
-            os.mkdir(cachedir)
-
-        # The cvsps cache pickle needs a uniquified name, based on the
-        # repository location. The address may have all sort of nasties
-        # in it, slashes, colons and such. So here we take just the
-        # alphanumerics, concatenated in a way that does not mix up the
-        # various components, so that
-        #    :pserver:user@server:/path
-        # and
-        #    /pserver/user/server/path
-        # are mapped to different cache file names.
-        cachefile = root.split(":") + [directory, "cache"]
-        cachefile = ['-'.join(re.findall(r'\w+', s)) for s in cachefile if s]
-        cachefile = os.path.join(cachedir,
-                                 '.'.join([s for s in cachefile if s]))
-
-    if cache == 'update':
-        try:
-            ui.note(_('reading cvs log cache %s\n') % cachefile)
-            oldlog = pickle.load(open(cachefile))
-            ui.note(_('cache has %d log entries\n') % len(oldlog))
-        except Exception, e:
-            ui.note(_('error reading cache: %r\n') % e)
-
-        if oldlog:
-            date = oldlog[-1].date    # last commit date as a (time,tz) tuple
-            date = util.datestr(date, '%Y/%m/%d %H:%M:%S %1%2')
-
-    # build the CVS commandline
-    cmd = ['cvs', '-q']
-    if root:
-        cmd.append('-d%s' % root)
-        p = util.normpath(getrepopath(root))
-        if not p.endswith('/'):
-            p += '/'
-        prefix = p + util.normpath(prefix)
-    cmd.append(['log', 'rlog'][rlog])
-    if date:
-        # no space between option and date string
-        cmd.append('-d>%s' % date)
-    cmd.append(directory)
-
-    # state machine begins here
-    tags = {}     # dictionary of revisions on current file with their tags
-    branchmap = {} # mapping between branch names and revision numbers
-    state = 0
-    store = False # set when a new record can be appended
-
-    cmd = [util.shellquote(arg) for arg in cmd]
-    ui.note(_("running %s\n") % (' '.join(cmd)))
-    ui.debug(_("prefix=%r directory=%r root=%r\n") % (prefix, directory, root))
-
-    pfp = util.popen(' '.join(cmd))
-    peek = pfp.readline()
-    while True:
-        line = peek
-        if line == '':
-            break
-        peek = pfp.readline()
-        if line.endswith('\n'):
-            line = line[:-1]
-        #ui.debug('state=%d line=%r\n' % (state, line))
-
-        if state == 0:
-            # initial state, consume input until we see 'RCS file'
-            match = re_00.match(line)
-            if match:
-                rcs = match.group(1)
-                tags = {}
-                if rlog:
-                    filename = util.normpath(rcs[:-2])
-                    if filename.startswith(prefix):
-                        filename = filename[len(prefix):]
-                    if filename.startswith('/'):
-                        filename = filename[1:]
-                    if filename.startswith('Attic/'):
-                        filename = filename[6:]
-                    else:
-                        filename = filename.replace('/Attic/', '/')
-                    state = 2
-                    continue
-                state = 1
-                continue
-            match = re_01.match(line)
-            if match:
-                raise Exception(match.group(1))
-            match = re_02.match(line)
-            if match:
-                raise Exception(match.group(2))
-            if re_03.match(line):
-                raise Exception(line)
-
-        elif state == 1:
-            # expect 'Working file' (only when using log instead of rlog)
-            match = re_10.match(line)
-            assert match, _('RCS file must be followed by working file')
-            filename = util.normpath(match.group(1))
-            state = 2
-
-        elif state == 2:
-            # expect 'symbolic names'
-            if re_20.match(line):
-                branchmap = {}
-                state = 3
-
-        elif state == 3:
-            # read the symbolic names and store as tags
-            match = re_30.match(line)
-            if match:
-                rev = [int(x) for x in match.group(2).split('.')]
-
-                # Convert magic branch number to an odd-numbered one
-                revn = len(rev)
-                if revn > 3 and (revn % 2) == 0 and rev[-2] == 0:
-                    rev = rev[:-2] + rev[-1:]
-                rev = tuple(rev)
-
-                if rev not in tags:
-                    tags[rev] = []
-                tags[rev].append(match.group(1))
-                branchmap[match.group(1)] = match.group(2)
-
-            elif re_31.match(line):
-                state = 5
-            elif re_32.match(line):
-                state = 0
-
-        elif state == 4:
-            # expecting '------' separator before first revision
-            if re_31.match(line):
-                state = 5
-            else:
-                assert not re_32.match(line), _('must have at least '
-                                                'some revisions')
-
-        elif state == 5:
-            # expecting revision number and possibly (ignored) lock indication
-            # we create the logentry here from values stored in states 0 to 4,
-            # as this state is re-entered for subsequent revisions of a file.
-            match = re_50.match(line)
-            assert match, _('expected revision number')
-            e = logentry(rcs=scache(rcs), file=scache(filename),
-                    revision=tuple([int(x) for x in match.group(1).split('.')]),
-                    branches=[], parent=None,
-                    synthetic=False)
-            state = 6
-
-        elif state == 6:
-            # expecting date, author, state, lines changed
-            match = re_60.match(line)
-            assert match, _('revision must be followed by date line')
-            d = match.group(1)
-            if d[2] == '/':
-                # Y2K
-                d = '19' + d
-
-            if len(d.split()) != 3:
-                # cvs log dates always in GMT
-                d = d + ' UTC'
-            e.date = util.parsedate(d, ['%y/%m/%d %H:%M:%S',
-                                        '%Y/%m/%d %H:%M:%S',
-                                        '%Y-%m-%d %H:%M:%S'])
-            e.author = scache(match.group(2))
-            e.dead = match.group(3).lower() == 'dead'
-
-            if match.group(5):
-                if match.group(6):
-                    e.lines = (int(match.group(5)), int(match.group(6)))
-                else:
-                    e.lines = (int(match.group(5)), 0)
-            elif match.group(6):
-                e.lines = (0, int(match.group(6)))
-            else:
-                e.lines = None
-
-            if match.group(7): # cvsnt mergepoint
-                myrev = match.group(8).split('.')
-                if len(myrev) == 2: # head
-                    e.mergepoint = 'HEAD'
-                else:
-                    myrev = '.'.join(myrev[:-2] + ['0', myrev[-2]])
-                    branches = [b for b in branchmap if branchmap[b] == myrev]
-                    assert len(branches) == 1, 'unknown branch: %s' % e.mergepoint
-                    e.mergepoint = branches[0]
-            else:
-                e.mergepoint = None
-            e.comment = []
-            state = 7
-
-        elif state == 7:
-            # read the revision numbers of branches that start at this revision
-            # or store the commit log message otherwise
-            m = re_70.match(line)
-            if m:
-                e.branches = [tuple([int(y) for y in x.strip().split('.')])
-                                for x in m.group(1).split(';')]
-                state = 8
-            elif re_31.match(line) and re_50.match(peek):
-                state = 5
-                store = True
-            elif re_32.match(line):
-                state = 0
-                store = True
-            else:
-                e.comment.append(line)
-
-        elif state == 8:
-            # store commit log message
-            if re_31.match(line):
-                state = 5
-                store = True
-            elif re_32.match(line):
-                state = 0
-                store = True
-            else:
-                e.comment.append(line)
-
-        # When a file is added on a branch B1, CVS creates a synthetic
-        # dead trunk revision 1.1 so that the branch has a root.
-        # Likewise, if you merge such a file to a later branch B2 (one
-        # that already existed when the file was added on B1), CVS
-        # creates a synthetic dead revision 1.1.x.1 on B2.  Don't drop
-        # these revisions now, but mark them synthetic so
-        # createchangeset() can take care of them.
-        if (store and
-              e.dead and
-              e.revision[-1] == 1 and      # 1.1 or 1.1.x.1
-              len(e.comment) == 1 and
-              file_added_re.match(e.comment[0])):
-            ui.debug(_('found synthetic revision in %s: %r\n')
-                     % (e.rcs, e.comment[0]))
-            e.synthetic = True
-
-        if store:
-            # clean up the results and save in the log.
-            store = False
-            e.tags = sorted([scache(x) for x in tags.get(e.revision, [])])
-            e.comment = scache('\n'.join(e.comment))
-
-            revn = len(e.revision)
-            if revn > 3 and (revn % 2) == 0:
-                e.branch = tags.get(e.revision[:-1], [None])[0]
-            else:
-                e.branch = None
-
-            # find the branches starting from this revision
-            branchpoints = set()
-            for branch, revision in branchmap.iteritems():
-                revparts = tuple([int(i) for i in revision.split('.')])
-                if revparts[-2] == 0 and revparts[-1] % 2 == 0:
-                    # normal branch
-                    if revparts[:-2] == e.revision:
-                        branchpoints.add(branch)
-                elif revparts == (1,1,1): # vendor branch
-                    if revparts in e.branches:
-                        branchpoints.add(branch)
-            e.branchpoints = branchpoints
-
-            log.append(e)
-
-            if len(log) % 100 == 0:
-                ui.status(util.ellipsis('%d %s' % (len(log), e.file), 80)+'\n')
-
-    log.sort(key=lambda x: (x.rcs, x.revision))
-
-    # find parent revisions of individual files
-    versions = {}
-    for e in log:
-        branch = e.revision[:-1]
-        p = versions.get((e.rcs, branch), None)
-        if p is None:
-            p = e.revision[:-2]
-        e.parent = p
-        versions[(e.rcs, branch)] = e.revision
-
-    # update the log cache
-    if cache:
-        if log:
-            # join up the old and new logs
-            log.sort(key=lambda x: x.date)
-
-            if oldlog and oldlog[-1].date >= log[0].date:
-                raise logerror('Log cache overlaps with new log entries,'
-                               ' re-run without cache.')
-
-            log = oldlog + log
-
-            # write the new cachefile
-            ui.note(_('writing cvs log cache %s\n') % cachefile)
-            pickle.dump(log, open(cachefile, 'w'))
-        else:
-            log = oldlog
-
-    ui.status(_('%d log entries\n') % len(log))
-
-    return log
-
-
-class changeset(object):
-    '''Class changeset has the following attributes:
-        .id        - integer identifying this changeset (list index)
-        .author    - author name as CVS knows it
-        .branch    - name of branch this changeset is on, or None
-        .comment   - commit message
-        .date      - the commit date as a (time,tz) tuple
-        .entries   - list of logentry objects in this changeset
-        .parents   - list of one or two parent changesets
-        .tags      - list of tags on this changeset
-        .synthetic - from synthetic revision "file ... added on branch ..."
-        .mergepoint- the branch that has been merged from
-                     (if present in rlog output)
-        .branchpoints- the branches that start at the current entry
-    '''
-    def __init__(self, **entries):
-        self.__dict__.update(entries)
-
-    def __repr__(self):
-        return "<%s at 0x%x: %s>" % (self.__class__.__name__,
-                                     id(self),
-                                     getattr(self, 'id', "(no id)"))
-
-def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None):
-    '''Convert log into changesets.'''
-
-    ui.status(_('creating changesets\n'))
-
-    # Merge changesets
-
-    log.sort(key=lambda x: (x.comment, x.author, x.branch, x.date))
-
-    changesets = []
-    files = set()
-    c = None
-    for i, e in enumerate(log):
-
-        # Check if log entry belongs to the current changeset or not.
-
-        # Since CVS is file centric, two different file revisions with
-        # different branchpoints should be treated as belonging to two
-        # different changesets (and the ordering is important and not
-        # honoured by cvsps at this point).
-        #
-        # Consider the following case:
-        # foo 1.1 branchpoints: [MYBRANCH]
-        # bar 1.1 branchpoints: [MYBRANCH, MYBRANCH2]
-        #
-        # Here foo is part only of MYBRANCH, but not MYBRANCH2, e.g. a
-        # later version of foo may be in MYBRANCH2, so foo should be the
-        # first changeset and bar the next and MYBRANCH and MYBRANCH2
-        # should both start off of the bar changeset. No provisions are
-        # made to ensure that this is, in fact, what happens.
-        if not (c and
-                  e.comment == c.comment and
-                  e.author == c.author and
-                  e.branch == c.branch and
-                  (not hasattr(e, 'branchpoints') or
-                    not hasattr (c, 'branchpoints') or
-                    e.branchpoints == c.branchpoints) and
-                  ((c.date[0] + c.date[1]) <=
-                   (e.date[0] + e.date[1]) <=
-                   (c.date[0] + c.date[1]) + fuzz) and
-                  e.file not in files):
-            c = changeset(comment=e.comment, author=e.author,
-                          branch=e.branch, date=e.date, entries=[],
-                          mergepoint=getattr(e, 'mergepoint', None),
-                          branchpoints=getattr(e, 'branchpoints', set()))
-            changesets.append(c)
-            files = set()
-            if len(changesets) % 100 == 0:
-                t = '%d %s' % (len(changesets), repr(e.comment)[1:-1])
-                ui.status(util.ellipsis(t, 80) + '\n')
-
-        c.entries.append(e)
-        files.add(e.file)
-        c.date = e.date       # changeset date is date of latest commit in it
-
-    # Mark synthetic changesets
-
-    for c in changesets:
-        # Synthetic revisions always get their own changeset, because
-        # the log message includes the filename.  E.g. if you add file3
-        # and file4 on a branch, you get four log entries and three
-        # changesets:
-        #   "File file3 was added on branch ..." (synthetic, 1 entry)
-        #   "File file4 was added on branch ..." (synthetic, 1 entry)
-        #   "Add file3 and file4 to fix ..."     (real, 2 entries)
-        # Hence the check for 1 entry here.
-        synth = getattr(c.entries[0], 'synthetic', None)
-        c.synthetic = (len(c.entries) == 1 and synth)
-
-    # Sort files in each changeset
-
-    for c in changesets:
-        def pathcompare(l, r):
-            'Mimic cvsps sorting order'
-            l = l.split('/')
-            r = r.split('/')
-            nl = len(l)
-            nr = len(r)
-            n = min(nl, nr)
-            for i in range(n):
-                if i + 1 == nl and nl < nr:
-                    return -1
-                elif i + 1 == nr and nl > nr:
-                    return +1
-                elif l[i] < r[i]:
-                    return -1
-                elif l[i] > r[i]:
-                    return +1
-            return 0
-        def entitycompare(l, r):
-            return pathcompare(l.file, r.file)
-
-        c.entries.sort(entitycompare)
-
-    # Sort changesets by date
-
-    def cscmp(l, r):
-        d = sum(l.date) - sum(r.date)
-        if d:
-            return d
-
-        # detect vendor branches and initial commits on a branch
-        le = {}
-        for e in l.entries:
-            le[e.rcs] = e.revision
-        re = {}
-        for e in r.entries:
-            re[e.rcs] = e.revision
-
-        d = 0
-        for e in l.entries:
-            if re.get(e.rcs, None) == e.parent:
-                assert not d
-                d = 1
-                break
-
-        for e in r.entries:
-            if le.get(e.rcs, None) == e.parent:
-                assert not d
-                d = -1
-                break
-
-        return d
-
-    changesets.sort(cscmp)
-
-    # Collect tags
-
-    globaltags = {}
-    for c in changesets:
-        for e in c.entries:
-            for tag in e.tags:
-                # remember which is the latest changeset to have this tag
-                globaltags[tag] = c
-
-    for c in changesets:
-        tags = set()
-        for e in c.entries:
-            tags.update(e.tags)
-        # remember tags only if this is the latest changeset to have it
-        c.tags = sorted(tag for tag in tags if globaltags[tag] is c)
-
-    # Find parent changesets, handle {{mergetobranch BRANCHNAME}}
-    # by inserting dummy changesets with two parents, and handle
-    # {{mergefrombranch BRANCHNAME}} by setting two parents.
-
-    if mergeto is None:
-        mergeto = r'{{mergetobranch ([-\w]+)}}'
-    if mergeto:
-        mergeto = re.compile(mergeto)
-
-    if mergefrom is None:
-        mergefrom = r'{{mergefrombranch ([-\w]+)}}'
-    if mergefrom:
-        mergefrom = re.compile(mergefrom)
-
-    versions = {}    # changeset index where we saw any particular file version
-    branches = {}    # changeset index where we saw a branch
-    n = len(changesets)
-    i = 0
-    while i<n:
-        c = changesets[i]
-
-        for f in c.entries:
-            versions[(f.rcs, f.revision)] = i
-
-        p = None
-        if c.branch in branches:
-            p = branches[c.branch]
-        else:
-            # first changeset on a new branch
-            # the parent is a changeset with the branch in its
-            # branchpoints such that it is the latest possible
-            # commit without any intervening, unrelated commits.
-
-            for candidate in xrange(i):
-                if c.branch not in changesets[candidate].branchpoints:
-                    if p is not None:
-                        break
-                    continue
-                p = candidate
-
-        c.parents = []
-        if p is not None:
-            p = changesets[p]
-
-            # Ensure no changeset has a synthetic changeset as a parent.
-            while p.synthetic:
-                assert len(p.parents) <= 1, \
-                       _('synthetic changeset cannot have multiple parents')
-                if p.parents:
-                    p = p.parents[0]
-                else:
-                    p = None
-                    break
-
-            if p is not None:
-                c.parents.append(p)
-
-        if c.mergepoint:
-            if c.mergepoint == 'HEAD':
-                c.mergepoint = None
-            c.parents.append(changesets[branches[c.mergepoint]])
-
-        if mergefrom:
-            m = mergefrom.search(c.comment)
-            if m:
-                m = m.group(1)
-                if m == 'HEAD':
-                    m = None
-                try:
-                    candidate = changesets[branches[m]]
-                except KeyError:
-                    ui.warn(_("warning: CVS commit message references "
-                              "non-existent branch %r:\n%s\n")
-                            % (m, c.comment))
-                if m in branches and c.branch != m and not candidate.synthetic:
-                    c.parents.append(candidate)
-
-        if mergeto:
-            m = mergeto.search(c.comment)
-            if m:
-                try:
-                    m = m.group(1)
-                    if m == 'HEAD':
-                        m = None
-                except:
-                    m = None   # if no group found then merge to HEAD
-                if m in branches and c.branch != m:
-                    # insert empty changeset for merge
-                    cc = changeset(author=c.author, branch=m, date=c.date,
-                            comment='convert-repo: CVS merge from branch %s' % c.branch,
-                            entries=[], tags=[], parents=[changesets[branches[m]], c])
-                    changesets.insert(i + 1, cc)
-                    branches[m] = i + 1
-
-                    # adjust our loop counters now we have inserted a new entry
-                    n += 1
-                    i += 2
-                    continue
-
-        branches[c.branch] = i
-        i += 1
-
-    # Drop synthetic changesets (safe now that we have ensured no other
-    # changesets can have them as parents).
-    i = 0
-    while i < len(changesets):
-        if changesets[i].synthetic:
-            del changesets[i]
-        else:
-            i += 1
-
-    # Number changesets
-
-    for i, c in enumerate(changesets):
-        c.id = i + 1
-
-    ui.status(_('%d changeset entries\n') % len(changesets))
-
-    return changesets
-
-
-def debugcvsps(ui, *args, **opts):
-    '''Read CVS rlog for current directory or named path in
-    repository, and convert the log to changesets based on matching
-    commit log entries and dates.
-    '''
-    if opts["new_cache"]:
-        cache = "write"
-    elif opts["update_cache"]:
-        cache = "update"
-    else:
-        cache = None
-
-    revisions = opts["revisions"]
-
-    try:
-        if args:
-            log = []
-            for d in args:
-                log += createlog(ui, d, root=opts["root"], cache=cache)
-        else:
-            log = createlog(ui, root=opts["root"], cache=cache)
-    except logerror, e:
-        ui.write("%r\n"%e)
-        return
-
-    changesets = createchangeset(ui, log, opts["fuzz"])
-    del log
-
-    # Print changesets (optionally filtered)
-
-    off = len(revisions)
-    branches = {}    # latest version number in each branch
-    ancestors = {}   # parent branch
-    for cs in changesets:
-
-        if opts["ancestors"]:
-            if cs.branch not in branches and cs.parents and cs.parents[0].id:
-                ancestors[cs.branch] = (changesets[cs.parents[0].id-1].branch,
-                                        cs.parents[0].id)
-            branches[cs.branch] = cs.id
-
-        # limit by branches
-        if opts["branches"] and (cs.branch or 'HEAD') not in opts["branches"]:
-            continue
-
-        if not off:
-            # Note: trailing spaces on several lines here are needed to have
-            #       bug-for-bug compatibility with cvsps.
-            ui.write('---------------------\n')
-            ui.write('PatchSet %d \n' % cs.id)
-            ui.write('Date: %s\n' % util.datestr(cs.date,
-                                                 '%Y/%m/%d %H:%M:%S %1%2'))
-            ui.write('Author: %s\n' % cs.author)
-            ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
-            ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags)>1],
-                                  ','.join(cs.tags) or '(none)'))
-            branchpoints = getattr(cs, 'branchpoints', None)
-            if branchpoints:
-                ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
-            if opts["parents"] and cs.parents:
-                if len(cs.parents)>1:
-                    ui.write('Parents: %s\n' % (','.join([str(p.id) for p in cs.parents])))
-                else:
-                    ui.write('Parent: %d\n' % cs.parents[0].id)
-
-            if opts["ancestors"]:
-                b = cs.branch
-                r = []
-                while b:
-                    b, c = ancestors[b]
-                    r.append('%s:%d:%d' % (b or "HEAD", c, branches[b]))
-                if r:
-                    ui.write('Ancestors: %s\n' % (','.join(r)))
-
-            ui.write('Log:\n')
-            ui.write('%s\n\n' % cs.comment)
-            ui.write('Members: \n')
-            for f in cs.entries:
-                fn = f.file
-                if fn.startswith(opts["prefix"]):
-                    fn = fn[len(opts["prefix"]):]
-                ui.write('\t%s:%s->%s%s \n' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL',
-                                          '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead]))
-            ui.write('\n')
-
-        # have we seen the start tag?
-        if revisions and off:
-            if revisions[0] == str(cs.id) or \
-                revisions[0] in cs.tags:
-                off = False
-
-        # see if we reached the end tag
-        if len(revisions)>1 and not off:
-            if revisions[1] == str(cs.id) or \
-                revisions[1] in cs.tags:
-                break
--- a/sys/src/cmd/hg/hgext/convert/darcs.py
+++ /dev/null
@@ -1,135 +1,0 @@
-# darcs.py - darcs support for the convert extension
-#
-#  Copyright 2007-2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-from common import NoRepo, checktool, commandline, commit, converter_source
-from mercurial.i18n import _
-from mercurial import util
-import os, shutil, tempfile
-
-# The naming drift of ElementTree is fun!
-
-try: from xml.etree.cElementTree import ElementTree
-except ImportError:
-    try: from xml.etree.ElementTree import ElementTree
-    except ImportError:
-        try: from elementtree.cElementTree import ElementTree
-        except ImportError:
-            try: from elementtree.ElementTree import ElementTree
-            except ImportError: ElementTree = None
-
-
-class darcs_source(converter_source, commandline):
-    def __init__(self, ui, path, rev=None):
-        converter_source.__init__(self, ui, path, rev=rev)
-        commandline.__init__(self, ui, 'darcs')
-
-        # check for _darcs, ElementTree, _darcs/inventory so that we can
-        # easily skip test-convert-darcs if ElementTree is not around
-        if not os.path.exists(os.path.join(path, '_darcs', 'inventories')):
-            raise NoRepo("%s does not look like a darcs repo" % path)
-
-        if not os.path.exists(os.path.join(path, '_darcs')):
-            raise NoRepo("%s does not look like a darcs repo" % path)
-
-        checktool('darcs')
-        version = self.run0('--version').splitlines()[0].strip()
-        if version < '2.1':
-            raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') %
-                             version)
-
-        if ElementTree is None:
-            raise util.Abort(_("Python ElementTree module is not available"))
-
-        self.path = os.path.realpath(path)
-
-        self.lastrev = None
-        self.changes = {}
-        self.parents = {}
-        self.tags = {}
-
-    def before(self):
-        self.tmppath = tempfile.mkdtemp(
-            prefix='convert-' + os.path.basename(self.path) + '-')
-        output, status = self.run('init', repodir=self.tmppath)
-        self.checkexit(status)
-
-        tree = self.xml('changes', xml_output=True, summary=True,
-                        repodir=self.path)
-        tagname = None
-        child = None
-        for elt in tree.findall('patch'):
-            node = elt.get('hash')
-            name = elt.findtext('name', '')
-            if name.startswith('TAG '):
-                tagname = name[4:].strip()
-            elif tagname is not None:
-                self.tags[tagname] = node
-                tagname = None
-            self.changes[node] = elt
-            self.parents[child] = [node]
-            child = node
-        self.parents[child] = []
-
-    def after(self):
-        self.ui.debug(_('cleaning up %s\n') % self.tmppath)
-        shutil.rmtree(self.tmppath, ignore_errors=True)
-
-    def xml(self, cmd, **kwargs):
-        etree = ElementTree()
-        fp = self._run(cmd, **kwargs)
-        etree.parse(fp)
-        self.checkexit(fp.close())
-        return etree.getroot()
-
-    def getheads(self):
-        return self.parents[None]
-
-    def getcommit(self, rev):
-        elt = self.changes[rev]
-        date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y')
-        desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
-        return commit(author=elt.get('author'), date=util.datestr(date),
-                      desc=desc.strip(), parents=self.parents[rev])
-
-    def pull(self, rev):
-        output, status = self.run('pull', self.path, all=True,
-                                  match='hash %s' % rev,
-                                  no_test=True, no_posthook=True,
-                                  external_merge='/bin/false',
-                                  repodir=self.tmppath)
-        if status:
-            if output.find('We have conflicts in') == -1:
-                self.checkexit(status, output)
-            output, status = self.run('revert', all=True, repodir=self.tmppath)
-            self.checkexit(status, output)
-
-    def getchanges(self, rev):
-        self.pull(rev)
-        copies = {}
-        changes = []
-        for elt in self.changes[rev].find('summary').getchildren():
-            if elt.tag in ('add_directory', 'remove_directory'):
-                continue
-            if elt.tag == 'move':
-                changes.append((elt.get('from'), rev))
-                copies[elt.get('from')] = elt.get('to')
-            else:
-                changes.append((elt.text.strip(), rev))
-        self.lastrev = rev
-        return sorted(changes), copies
-
-    def getfile(self, name, rev):
-        if rev != self.lastrev:
-            raise util.Abort(_('internal calling inconsistency'))
-        return open(os.path.join(self.tmppath, name), 'rb').read()
-
-    def getmode(self, name, rev):
-        mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
-        return (mode & 0111) and 'x' or ''
-
-    def gettags(self):
-        return self.tags
--- a/sys/src/cmd/hg/hgext/convert/filemap.py
+++ /dev/null
@@ -1,359 +1,0 @@
-# Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
-# Copyright 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import shlex
-from mercurial.i18n import _
-from mercurial import util
-from common import SKIPREV, converter_source
-
-def rpairs(name):
-    yield '.', name
-    e = len(name)
-    while e != -1:
-        yield name[:e], name[e+1:]
-        e = name.rfind('/', 0, e)
-
-class filemapper(object):
-    '''Map and filter filenames when importing.
-    A name can be mapped to itself, a new name, or None (omit from new
-    repository).'''
-
-    def __init__(self, ui, path=None):
-        self.ui = ui
-        self.include = {}
-        self.exclude = {}
-        self.rename = {}
-        if path:
-            if self.parse(path):
-                raise util.Abort(_('errors in filemap'))
-
-    def parse(self, path):
-        errs = 0
-        def check(name, mapping, listname):
-            if name in mapping:
-                self.ui.warn(_('%s:%d: %r already in %s list\n') %
-                             (lex.infile, lex.lineno, name, listname))
-                return 1
-            return 0
-        lex = shlex.shlex(open(path), path, True)
-        lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
-        cmd = lex.get_token()
-        while cmd:
-            if cmd == 'include':
-                name = lex.get_token()
-                errs += check(name, self.exclude, 'exclude')
-                self.include[name] = name
-            elif cmd == 'exclude':
-                name = lex.get_token()
-                errs += check(name, self.include, 'include')
-                errs += check(name, self.rename, 'rename')
-                self.exclude[name] = name
-            elif cmd == 'rename':
-                src = lex.get_token()
-                dest = lex.get_token()
-                errs += check(src, self.exclude, 'exclude')
-                self.rename[src] = dest
-            elif cmd == 'source':
-                errs += self.parse(lex.get_token())
-            else:
-                self.ui.warn(_('%s:%d: unknown directive %r\n') %
-                             (lex.infile, lex.lineno, cmd))
-                errs += 1
-            cmd = lex.get_token()
-        return errs
-
-    def lookup(self, name, mapping):
-        for pre, suf in rpairs(name):
-            try:
-                return mapping[pre], pre, suf
-            except KeyError:
-                pass
-        return '', name, ''
-
-    def __call__(self, name):
-        if self.include:
-            inc = self.lookup(name, self.include)[0]
-        else:
-            inc = name
-        if self.exclude:
-            exc = self.lookup(name, self.exclude)[0]
-        else:
-            exc = ''
-        if not inc or exc:
-            return None
-        newpre, pre, suf = self.lookup(name, self.rename)
-        if newpre:
-            if newpre == '.':
-                return suf
-            if suf:
-                return newpre + '/' + suf
-            return newpre
-        return name
-
-    def active(self):
-        return bool(self.include or self.exclude or self.rename)
-
-# This class does two additional things compared to a regular source:
-#
-# - Filter and rename files.  This is mostly wrapped by the filemapper
-#   class above. We hide the original filename in the revision that is
-#   returned by getchanges to be able to find things later in getfile
-#   and getmode.
-#
-# - Return only revisions that matter for the files we're interested in.
-#   This involves rewriting the parents of the original revision to
-#   create a graph that is restricted to those revisions.
-#
-#   This set of revisions includes not only revisions that directly
-#   touch files we're interested in, but also merges that merge two
-#   or more interesting revisions.
-
-class filemap_source(converter_source):
-    def __init__(self, ui, baseconverter, filemap):
-        super(filemap_source, self).__init__(ui)
-        self.base = baseconverter
-        self.filemapper = filemapper(ui, filemap)
-        self.commits = {}
-        # if a revision rev has parent p in the original revision graph, then
-        # rev will have parent self.parentmap[p] in the restricted graph.
-        self.parentmap = {}
-        # self.wantedancestors[rev] is the set of all ancestors of rev that
-        # are in the restricted graph.
-        self.wantedancestors = {}
-        self.convertedorder = None
-        self._rebuilt = False
-        self.origparents = {}
-        self.children = {}
-        self.seenchildren = {}
-
-    def before(self):
-        self.base.before()
-
-    def after(self):
-        self.base.after()
-
-    def setrevmap(self, revmap):
-        # rebuild our state to make things restartable
-        #
-        # To avoid calling getcommit for every revision that has already
-        # been converted, we rebuild only the parentmap, delaying the
-        # rebuild of wantedancestors until we need it (i.e. until a
-        # merge).
-        #
-        # We assume the order argument lists the revisions in
-        # topological order, so that we can infer which revisions were
-        # wanted by previous runs.
-        self._rebuilt = not revmap
-        seen = {SKIPREV: SKIPREV}
-        dummyset = set()
-        converted = []
-        for rev in revmap.order:
-            mapped = revmap[rev]
-            wanted = mapped not in seen
-            if wanted:
-                seen[mapped] = rev
-                self.parentmap[rev] = rev
-            else:
-                self.parentmap[rev] = seen[mapped]
-            self.wantedancestors[rev] = dummyset
-            arg = seen[mapped]
-            if arg == SKIPREV:
-                arg = None
-            converted.append((rev, wanted, arg))
-        self.convertedorder = converted
-        return self.base.setrevmap(revmap)
-
-    def rebuild(self):
-        if self._rebuilt:
-            return True
-        self._rebuilt = True
-        self.parentmap.clear()
-        self.wantedancestors.clear()
-        self.seenchildren.clear()
-        for rev, wanted, arg in self.convertedorder:
-            if rev not in self.origparents:
-                self.origparents[rev] = self.getcommit(rev).parents
-            if arg is not None:
-                self.children[arg] = self.children.get(arg, 0) + 1
-
-        for rev, wanted, arg in self.convertedorder:
-            parents = self.origparents[rev]
-            if wanted:
-                self.mark_wanted(rev, parents)
-            else:
-                self.mark_not_wanted(rev, arg)
-            self._discard(arg, *parents)
-
-        return True
-
-    def getheads(self):
-        return self.base.getheads()
-
-    def getcommit(self, rev):
-        # We want to save a reference to the commit objects to be able
-        # to rewrite their parents later on.
-        c = self.commits[rev] = self.base.getcommit(rev)
-        for p in c.parents:
-            self.children[p] = self.children.get(p, 0) + 1
-        return c
-
-    def _discard(self, *revs):
-        for r in revs:
-            if r is None:
-                continue
-            self.seenchildren[r] = self.seenchildren.get(r, 0) + 1
-            if self.seenchildren[r] == self.children[r]:
-                del self.wantedancestors[r]
-                del self.parentmap[r]
-                del self.seenchildren[r]
-                if self._rebuilt:
-                    del self.children[r]
-
-    def wanted(self, rev, i):
-        # Return True if we're directly interested in rev.
-        #
-        # i is an index selecting one of the parents of rev (if rev
-        # has no parents, i is None).  getchangedfiles will give us
-        # the list of files that are different in rev and in the parent
-        # indicated by i.  If we're interested in any of these files,
-        # we're interested in rev.
-        try:
-            files = self.base.getchangedfiles(rev, i)
-        except NotImplementedError:
-            raise util.Abort(_("source repository doesn't support --filemap"))
-        for f in files:
-            if self.filemapper(f):
-                return True
-        return False
-
-    def mark_not_wanted(self, rev, p):
-        # Mark rev as not interesting and update data structures.
-
-        if p is None:
-            # A root revision. Use SKIPREV to indicate that it doesn't
-            # map to any revision in the restricted graph.  Put SKIPREV
-            # in the set of wanted ancestors to simplify code elsewhere
-            self.parentmap[rev] = SKIPREV
-            self.wantedancestors[rev] = set((SKIPREV,))
-            return
-
-        # Reuse the data from our parent.
-        self.parentmap[rev] = self.parentmap[p]
-        self.wantedancestors[rev] = self.wantedancestors[p]
-
-    def mark_wanted(self, rev, parents):
-        # Mark rev ss wanted and update data structures.
-
-        # rev will be in the restricted graph, so children of rev in
-        # the original graph should still have rev as a parent in the
-        # restricted graph.
-        self.parentmap[rev] = rev
-
-        # The set of wanted ancestors of rev is the union of the sets
-        # of wanted ancestors of its parents. Plus rev itself.
-        wrev = set()
-        for p in parents:
-            wrev.update(self.wantedancestors[p])
-        wrev.add(rev)
-        self.wantedancestors[rev] = wrev
-
-    def getchanges(self, rev):
-        parents = self.commits[rev].parents
-        if len(parents) > 1:
-            self.rebuild()
-
-        # To decide whether we're interested in rev we:
-        #
-        # - calculate what parents rev will have if it turns out we're
-        #   interested in it.  If it's going to have more than 1 parent,
-        #   we're interested in it.
-        #
-        # - otherwise, we'll compare it with the single parent we found.
-        #   If any of the files we're interested in is different in the
-        #   the two revisions, we're interested in rev.
-
-        # A parent p is interesting if its mapped version (self.parentmap[p]):
-        # - is not SKIPREV
-        # - is still not in the list of parents (we don't want duplicates)
-        # - is not an ancestor of the mapped versions of the other parents
-        mparents = []
-        wp = None
-        for i, p1 in enumerate(parents):
-            mp1 = self.parentmap[p1]
-            if mp1 == SKIPREV or mp1 in mparents:
-                continue
-            for p2 in parents:
-                if p1 == p2 or mp1 == self.parentmap[p2]:
-                    continue
-                if mp1 in self.wantedancestors[p2]:
-                    break
-            else:
-                mparents.append(mp1)
-                wp = i
-
-        if wp is None and parents:
-            wp = 0
-
-        self.origparents[rev] = parents
-
-        if len(mparents) < 2 and not self.wanted(rev, wp):
-            # We don't want this revision.
-            # Update our state and tell the convert process to map this
-            # revision to the same revision its parent as mapped to.
-            p = None
-            if parents:
-                p = parents[wp]
-            self.mark_not_wanted(rev, p)
-            self.convertedorder.append((rev, False, p))
-            self._discard(*parents)
-            return self.parentmap[rev]
-
-        # We want this revision.
-        # Rewrite the parents of the commit object
-        self.commits[rev].parents = mparents
-        self.mark_wanted(rev, parents)
-        self.convertedorder.append((rev, True, None))
-        self._discard(*parents)
-
-        # Get the real changes and do the filtering/mapping.
-        # To be able to get the files later on in getfile and getmode,
-        # we hide the original filename in the rev part of the return
-        # value.
-        changes, copies = self.base.getchanges(rev)
-        newnames = {}
-        files = []
-        for f, r in changes:
-            newf = self.filemapper(f)
-            if newf:
-                files.append((newf, (f, r)))
-                newnames[f] = newf
-
-        ncopies = {}
-        for c in copies:
-            newc = self.filemapper(c)
-            if newc:
-                newsource = self.filemapper(copies[c])
-                if newsource:
-                    ncopies[newc] = newsource
-
-        return files, ncopies
-
-    def getfile(self, name, rev):
-        realname, realrev = rev
-        return self.base.getfile(realname, realrev)
-
-    def getmode(self, name, rev):
-        realname, realrev = rev
-        return self.base.getmode(realname, realrev)
-
-    def gettags(self):
-        return self.base.gettags()
-
-    def hasnativeorder(self):
-        return self.base.hasnativeorder()
-
-    def lookuprev(self, rev):
-        return self.base.lookuprev(rev)
--- a/sys/src/cmd/hg/hgext/convert/git.py
+++ /dev/null
@@ -1,152 +1,0 @@
-# git.py - git support for the convert extension
-#
-#  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os
-from mercurial import util
-
-from common import NoRepo, commit, converter_source, checktool
-
-class convert_git(converter_source):
-    # Windows does not support GIT_DIR= construct while other systems
-    # cannot remove environment variable. Just assume none have
-    # both issues.
-    if hasattr(os, 'unsetenv'):
-        def gitcmd(self, s):
-            prevgitdir = os.environ.get('GIT_DIR')
-            os.environ['GIT_DIR'] = self.path
-            try:
-                return util.popen(s, 'rb')
-            finally:
-                if prevgitdir is None:
-                    del os.environ['GIT_DIR']
-                else:
-                    os.environ['GIT_DIR'] = prevgitdir
-    else:
-        def gitcmd(self, s):
-            return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
-
-    def __init__(self, ui, path, rev=None):
-        super(convert_git, self).__init__(ui, path, rev=rev)
-
-        if os.path.isdir(path + "/.git"):
-            path += "/.git"
-        if not os.path.exists(path + "/objects"):
-            raise NoRepo("%s does not look like a Git repo" % path)
-
-        checktool('git', 'git')
-
-        self.path = path
-
-    def getheads(self):
-        if not self.rev:
-            return self.gitcmd('git rev-parse --branches --remotes').read().splitlines()
-        else:
-            fh = self.gitcmd("git rev-parse --verify %s" % self.rev)
-            return [fh.read()[:-1]]
-
-    def catfile(self, rev, type):
-        if rev == "0" * 40: raise IOError()
-        fh = self.gitcmd("git cat-file %s %s" % (type, rev))
-        return fh.read()
-
-    def getfile(self, name, rev):
-        return self.catfile(rev, "blob")
-
-    def getmode(self, name, rev):
-        return self.modecache[(name, rev)]
-
-    def getchanges(self, version):
-        self.modecache = {}
-        fh = self.gitcmd("git diff-tree -z --root -m -r %s" % version)
-        changes = []
-        seen = set()
-        entry = None
-        for l in fh.read().split('\x00'):
-            if not entry:
-                if not l.startswith(':'):
-                    continue
-                entry = l
-                continue
-            f = l
-            if f not in seen:
-                seen.add(f)
-                entry = entry.split()
-                h = entry[3]
-                p = (entry[1] == "100755")
-                s = (entry[1] == "120000")
-                self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
-                changes.append((f, h))
-            entry = None
-        return (changes, {})
-
-    def getcommit(self, version):
-        c = self.catfile(version, "commit") # read the commit hash
-        end = c.find("\n\n")
-        message = c[end+2:]
-        message = self.recode(message)
-        l = c[:end].splitlines()
-        parents = []
-        author = committer = None
-        for e in l[1:]:
-            n, v = e.split(" ", 1)
-            if n == "author":
-                p = v.split()
-                tm, tz = p[-2:]
-                author = " ".join(p[:-2])
-                if author[0] == "<": author = author[1:-1]
-                author = self.recode(author)
-            if n == "committer":
-                p = v.split()
-                tm, tz = p[-2:]
-                committer = " ".join(p[:-2])
-                if committer[0] == "<": committer = committer[1:-1]
-                committer = self.recode(committer)
-            if n == "parent": parents.append(v)
-
-        if committer and committer != author:
-            message += "\ncommitter: %s\n" % committer
-        tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
-        tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
-        date = tm + " " + str(tz)
-
-        c = commit(parents=parents, date=date, author=author, desc=message,
-                   rev=version)
-        return c
-
-    def gettags(self):
-        tags = {}
-        fh = self.gitcmd('git ls-remote --tags "%s"' % self.path)
-        prefix = 'refs/tags/'
-        for line in fh:
-            line = line.strip()
-            if not line.endswith("^{}"):
-                continue
-            node, tag = line.split(None, 1)
-            if not tag.startswith(prefix):
-                continue
-            tag = tag[len(prefix):-3]
-            tags[tag] = node
-
-        return tags
-
-    def getchangedfiles(self, version, i):
-        changes = []
-        if i is None:
-            fh = self.gitcmd("git diff-tree --root -m -r %s" % version)
-            for l in fh:
-                if "\t" not in l:
-                    continue
-                m, f = l[:-1].split("\t")
-                changes.append(f)
-            fh.close()
-        else:
-            fh = self.gitcmd('git diff-tree --name-only --root -r %s "%s^%s" --'
-                             % (version, version, i+1))
-            changes = [f.rstrip('\n') for f in fh]
-            fh.close()
-
-        return changes
--- a/sys/src/cmd/hg/hgext/convert/gnuarch.py
+++ /dev/null
@@ -1,342 +1,0 @@
-# gnuarch.py - GNU Arch support for the convert extension
-#
-#  Copyright 2008, 2009 Aleix Conchillo Flaque <aleix@member.fsf.org>
-#  and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-from common import NoRepo, commandline, commit, converter_source
-from mercurial.i18n import _
-from mercurial import util
-import os, shutil, tempfile, stat, locale
-from email.Parser import Parser
-
-class gnuarch_source(converter_source, commandline):
-
-    class gnuarch_rev(object):
-        def __init__(self, rev):
-            self.rev = rev
-            self.summary = ''
-            self.date = None
-            self.author = ''
-            self.continuationof = None
-            self.add_files = []
-            self.mod_files = []
-            self.del_files = []
-            self.ren_files = {}
-            self.ren_dirs = {}
-
-    def __init__(self, ui, path, rev=None):
-        super(gnuarch_source, self).__init__(ui, path, rev=rev)
-
-        if not os.path.exists(os.path.join(path, '{arch}')):
-            raise NoRepo(_("%s does not look like a GNU Arch repo") % path)
-
-        # Could use checktool, but we want to check for baz or tla.
-        self.execmd = None
-        if util.find_exe('baz'):
-            self.execmd = 'baz'
-        else:
-            if util.find_exe('tla'):
-                self.execmd = 'tla'
-            else:
-                raise util.Abort(_('cannot find a GNU Arch tool'))
-
-        commandline.__init__(self, ui, self.execmd)
-
-        self.path = os.path.realpath(path)
-        self.tmppath = None
-
-        self.treeversion = None
-        self.lastrev = None
-        self.changes = {}
-        self.parents = {}
-        self.tags = {}
-        self.modecache = {}
-        self.catlogparser = Parser()
-        self.locale = locale.getpreferredencoding()
-        self.archives = []
-
-    def before(self):
-        # Get registered archives
-        self.archives = [i.rstrip('\n')
-                         for i in self.runlines0('archives', '-n')]
-
-        if self.execmd == 'tla':
-            output = self.run0('tree-version', self.path)
-        else:
-            output = self.run0('tree-version', '-d', self.path)
-        self.treeversion = output.strip()
-
-        # Get name of temporary directory
-        version = self.treeversion.split('/')
-        self.tmppath = os.path.join(tempfile.gettempdir(),
-                                    'hg-%s' % version[1])
-
-        # Generate parents dictionary
-        self.parents[None] = []
-        treeversion = self.treeversion
-        child = None
-        while treeversion:
-            self.ui.status(_('analyzing tree version %s...\n') % treeversion)
-
-            archive = treeversion.split('/')[0]
-            if archive not in self.archives:
-                self.ui.status(_('tree analysis stopped because it points to '
-                                 'an unregistered archive %s...\n') % archive)
-                break
-
-            # Get the complete list of revisions for that tree version
-            output, status = self.runlines('revisions', '-r', '-f', treeversion)
-            self.checkexit(status, 'failed retrieveing revisions for %s' % treeversion)
-
-            # No new iteration unless a revision has a continuation-of header
-            treeversion = None
-
-            for l in output:
-                rev = l.strip()
-                self.changes[rev] = self.gnuarch_rev(rev)
-                self.parents[rev] = []
-
-                # Read author, date and summary
-                catlog, status = self.run('cat-log', '-d', self.path, rev)
-                if status:
-                    catlog  = self.run0('cat-archive-log', rev)
-                self._parsecatlog(catlog, rev)
-
-                # Populate the parents map
-                self.parents[child].append(rev)
-
-                # Keep track of the current revision as the child of the next
-                # revision scanned
-                child = rev
-
-                # Check if we have to follow the usual incremental history
-                # or if we have to 'jump' to a different treeversion given
-                # by the continuation-of header.
-                if self.changes[rev].continuationof:
-                    treeversion = '--'.join(self.changes[rev].continuationof.split('--')[:-1])
-                    break
-
-                # If we reached a base-0 revision w/o any continuation-of
-                # header, it means the tree history ends here.
-                if rev[-6:] == 'base-0':
-                    break
-
-    def after(self):
-        self.ui.debug(_('cleaning up %s\n') % self.tmppath)
-        shutil.rmtree(self.tmppath, ignore_errors=True)
-
-    def getheads(self):
-        return self.parents[None]
-
-    def getfile(self, name, rev):
-        if rev != self.lastrev:
-            raise util.Abort(_('internal calling inconsistency'))
-
-        # Raise IOError if necessary (i.e. deleted files).
-        if not os.path.exists(os.path.join(self.tmppath, name)):
-            raise IOError
-
-        data, mode = self._getfile(name, rev)
-        self.modecache[(name, rev)] = mode
-
-        return data
-
-    def getmode(self, name, rev):
-        return self.modecache[(name, rev)]
-
-    def getchanges(self, rev):
-        self.modecache = {}
-        self._update(rev)
-        changes = []
-        copies = {}
-
-        for f in self.changes[rev].add_files:
-            changes.append((f, rev))
-
-        for f in self.changes[rev].mod_files:
-            changes.append((f, rev))
-
-        for f in self.changes[rev].del_files:
-            changes.append((f, rev))
-
-        for src in self.changes[rev].ren_files:
-            to = self.changes[rev].ren_files[src]
-            changes.append((src, rev))
-            changes.append((to, rev))
-            copies[to] = src
-
-        for src in self.changes[rev].ren_dirs:
-            to = self.changes[rev].ren_dirs[src]
-            chgs, cps = self._rendirchanges(src, to);
-            changes += [(f, rev) for f in chgs]
-            copies.update(cps)
-
-        self.lastrev = rev
-        return sorted(set(changes)), copies
-
-    def getcommit(self, rev):
-        changes = self.changes[rev]
-        return commit(author=changes.author, date=changes.date,
-                      desc=changes.summary, parents=self.parents[rev], rev=rev)
-
-    def gettags(self):
-        return self.tags
-
-    def _execute(self, cmd, *args, **kwargs):
-        cmdline = [self.execmd, cmd]
-        cmdline += args
-        cmdline = [util.shellquote(arg) for arg in cmdline]
-        cmdline += ['>', util.nulldev, '2>', util.nulldev]
-        cmdline = util.quotecommand(' '.join(cmdline))
-        self.ui.debug(cmdline, '\n')
-        return os.system(cmdline)
-
-    def _update(self, rev):
-        self.ui.debug(_('applying revision %s...\n') % rev)
-        changeset, status = self.runlines('replay', '-d', self.tmppath,
-                                              rev)
-        if status:
-            # Something went wrong while merging (baz or tla
-            # issue?), get latest revision and try from there
-            shutil.rmtree(self.tmppath, ignore_errors=True)
-            self._obtainrevision(rev)
-        else:
-            old_rev = self.parents[rev][0]
-            self.ui.debug(_('computing changeset between %s and %s...\n')
-                          % (old_rev, rev))
-            self._parsechangeset(changeset, rev)
-
-    def _getfile(self, name, rev):
-        mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
-        if stat.S_ISLNK(mode):
-            data = os.readlink(os.path.join(self.tmppath, name))
-            mode = mode and 'l' or ''
-        else:
-            data = open(os.path.join(self.tmppath, name), 'rb').read()
-            mode = (mode & 0111) and 'x' or ''
-        return data, mode
-
-    def _exclude(self, name):
-        exclude = [ '{arch}', '.arch-ids', '.arch-inventory' ]
-        for exc in exclude:
-            if name.find(exc) != -1:
-                return True
-        return False
-
-    def _readcontents(self, path):
-        files = []
-        contents = os.listdir(path)
-        while len(contents) > 0:
-            c = contents.pop()
-            p = os.path.join(path, c)
-            # os.walk could be used, but here we avoid internal GNU
-            # Arch files and directories, thus saving a lot time.
-            if not self._exclude(p):
-                if os.path.isdir(p):
-                    contents += [os.path.join(c, f) for f in os.listdir(p)]
-                else:
-                    files.append(c)
-        return files
-
-    def _rendirchanges(self, src, dest):
-        changes = []
-        copies = {}
-        files = self._readcontents(os.path.join(self.tmppath, dest))
-        for f in files:
-            s = os.path.join(src, f)
-            d = os.path.join(dest, f)
-            changes.append(s)
-            changes.append(d)
-            copies[d] = s
-        return changes, copies
-
-    def _obtainrevision(self, rev):
-        self.ui.debug(_('obtaining revision %s...\n') % rev)
-        output = self._execute('get', rev, self.tmppath)
-        self.checkexit(output)
-        self.ui.debug(_('analyzing revision %s...\n') % rev)
-        files = self._readcontents(self.tmppath)
-        self.changes[rev].add_files += files
-
-    def _stripbasepath(self, path):
-        if path.startswith('./'):
-            return path[2:]
-        return path
-
-    def _parsecatlog(self, data, rev):
-        try:
-            catlog = self.catlogparser.parsestr(data)
-
-            # Commit date
-            self.changes[rev].date = util.datestr(
-                util.strdate(catlog['Standard-date'],
-                             '%Y-%m-%d %H:%M:%S'))
-
-            # Commit author
-            self.changes[rev].author = self.recode(catlog['Creator'])
-
-            # Commit description
-            self.changes[rev].summary = '\n\n'.join((catlog['Summary'],
-                                                    catlog.get_payload()))
-            self.changes[rev].summary = self.recode(self.changes[rev].summary)
-
-            # Commit revision origin when dealing with a branch or tag
-            if catlog.has_key('Continuation-of'):
-                self.changes[rev].continuationof = self.recode(catlog['Continuation-of'])
-        except Exception:
-            raise util.Abort(_('could not parse cat-log of %s') % rev)
-
-    def _parsechangeset(self, data, rev):
-        for l in data:
-            l = l.strip()
-            # Added file (ignore added directory)
-            if l.startswith('A') and not l.startswith('A/'):
-                file = self._stripbasepath(l[1:].strip())
-                if not self._exclude(file):
-                    self.changes[rev].add_files.append(file)
-            # Deleted file (ignore deleted directory)
-            elif l.startswith('D') and not l.startswith('D/'):
-                file = self._stripbasepath(l[1:].strip())
-                if not self._exclude(file):
-                    self.changes[rev].del_files.append(file)
-            # Modified binary file
-            elif l.startswith('Mb'):
-                file = self._stripbasepath(l[2:].strip())
-                if not self._exclude(file):
-                    self.changes[rev].mod_files.append(file)
-            # Modified link
-            elif l.startswith('M->'):
-                file = self._stripbasepath(l[3:].strip())
-                if not self._exclude(file):
-                    self.changes[rev].mod_files.append(file)
-            # Modified file
-            elif l.startswith('M'):
-                file = self._stripbasepath(l[1:].strip())
-                if not self._exclude(file):
-                    self.changes[rev].mod_files.append(file)
-            # Renamed file (or link)
-            elif l.startswith('=>'):
-                files = l[2:].strip().split(' ')
-                if len(files) == 1:
-                    files = l[2:].strip().split('\t')
-                src = self._stripbasepath(files[0])
-                dst = self._stripbasepath(files[1])
-                if not self._exclude(src) and not self._exclude(dst):
-                    self.changes[rev].ren_files[src] = dst
-            # Conversion from file to link or from link to file (modified)
-            elif l.startswith('ch'):
-                file = self._stripbasepath(l[2:].strip())
-                if not self._exclude(file):
-                    self.changes[rev].mod_files.append(file)
-            # Renamed directory
-            elif l.startswith('/>'):
-                dirs = l[2:].strip().split(' ')
-                if len(dirs) == 1:
-                    dirs = l[2:].strip().split('\t')
-                src = self._stripbasepath(dirs[0])
-                dst = self._stripbasepath(dirs[1])
-                if not self._exclude(src) and not self._exclude(dst):
-                    self.changes[rev].ren_dirs[src] = dst
--- a/sys/src/cmd/hg/hgext/convert/hg.py
+++ /dev/null
@@ -1,363 +1,0 @@
-# hg.py - hg backend for convert extension
-#
-#  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-# Notes for hg->hg conversion:
-#
-# * Old versions of Mercurial didn't trim the whitespace from the ends
-#   of commit messages, but new versions do.  Changesets created by
-#   those older versions, then converted, may thus have different
-#   hashes for changesets that are otherwise identical.
-#
-# * Using "--config convert.hg.saverev=true" will make the source
-#   identifier to be stored in the converted revision. This will cause
-#   the converted revision to have a different identity than the
-#   source.
-
-
-import os, time, cStringIO
-from mercurial.i18n import _
-from mercurial.node import bin, hex, nullid
-from mercurial import hg, util, context, error
-
-from common import NoRepo, commit, converter_source, converter_sink
-
-class mercurial_sink(converter_sink):
-    def __init__(self, ui, path):
-        converter_sink.__init__(self, ui, path)
-        self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
-        self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
-        self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
-        self.lastbranch = None
-        if os.path.isdir(path) and len(os.listdir(path)) > 0:
-            try:
-                self.repo = hg.repository(self.ui, path)
-                if not self.repo.local():
-                    raise NoRepo(_('%s is not a local Mercurial repo') % path)
-            except error.RepoError, err:
-                ui.traceback()
-                raise NoRepo(err.args[0])
-        else:
-            try:
-                ui.status(_('initializing destination %s repository\n') % path)
-                self.repo = hg.repository(self.ui, path, create=True)
-                if not self.repo.local():
-                    raise NoRepo(_('%s is not a local Mercurial repo') % path)
-                self.created.append(path)
-            except error.RepoError:
-                ui.traceback()
-                raise NoRepo("could not create hg repo %s as sink" % path)
-        self.lock = None
-        self.wlock = None
-        self.filemapmode = False
-
-    def before(self):
-        self.ui.debug(_('run hg sink pre-conversion action\n'))
-        self.wlock = self.repo.wlock()
-        self.lock = self.repo.lock()
-
-    def after(self):
-        self.ui.debug(_('run hg sink post-conversion action\n'))
-        self.lock.release()
-        self.wlock.release()
-
-    def revmapfile(self):
-        return os.path.join(self.path, ".hg", "shamap")
-
-    def authorfile(self):
-        return os.path.join(self.path, ".hg", "authormap")
-
-    def getheads(self):
-        h = self.repo.changelog.heads()
-        return [ hex(x) for x in h ]
-
-    def setbranch(self, branch, pbranches):
-        if not self.clonebranches:
-            return
-
-        setbranch = (branch != self.lastbranch)
-        self.lastbranch = branch
-        if not branch:
-            branch = 'default'
-        pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
-        pbranch = pbranches and pbranches[0][1] or 'default'
-
-        branchpath = os.path.join(self.path, branch)
-        if setbranch:
-            self.after()
-            try:
-                self.repo = hg.repository(self.ui, branchpath)
-            except:
-                self.repo = hg.repository(self.ui, branchpath, create=True)
-            self.before()
-
-        # pbranches may bring revisions from other branches (merge parents)
-        # Make sure we have them, or pull them.
-        missings = {}
-        for b in pbranches:
-            try:
-                self.repo.lookup(b[0])
-            except:
-                missings.setdefault(b[1], []).append(b[0])
-
-        if missings:
-            self.after()
-            for pbranch, heads in missings.iteritems():
-                pbranchpath = os.path.join(self.path, pbranch)
-                prepo = hg.repository(self.ui, pbranchpath)
-                self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
-                self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
-            self.before()
-
-    def _rewritetags(self, source, revmap, data):
-        fp = cStringIO.StringIO()
-        for line in data.splitlines():
-            s = line.split(' ', 1)
-            if len(s) != 2:
-                continue
-            revid = revmap.get(source.lookuprev(s[0]))
-            if not revid:
-                continue
-            fp.write('%s %s\n' % (revid, s[1]))
-        return fp.getvalue()
-
-    def putcommit(self, files, copies, parents, commit, source, revmap):
-
-        files = dict(files)
-        def getfilectx(repo, memctx, f):
-            v = files[f]
-            data = source.getfile(f, v)
-            e = source.getmode(f, v)
-            if f == '.hgtags':
-                data = self._rewritetags(source, revmap, data)
-            return context.memfilectx(f, data, 'l' in e, 'x' in e, copies.get(f))
-
-        pl = []
-        for p in parents:
-            if p not in pl:
-                pl.append(p)
-        parents = pl
-        nparents = len(parents)
-        if self.filemapmode and nparents == 1:
-            m1node = self.repo.changelog.read(bin(parents[0]))[0]
-            parent = parents[0]
-
-        if len(parents) < 2: parents.append(nullid)
-        if len(parents) < 2: parents.append(nullid)
-        p2 = parents.pop(0)
-
-        text = commit.desc
-        extra = commit.extra.copy()
-        if self.branchnames and commit.branch:
-            extra['branch'] = commit.branch
-        if commit.rev:
-            extra['convert_revision'] = commit.rev
-
-        while parents:
-            p1 = p2
-            p2 = parents.pop(0)
-            ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx,
-                                 commit.author, commit.date, extra)
-            self.repo.commitctx(ctx)
-            text = "(octopus merge fixup)\n"
-            p2 = hex(self.repo.changelog.tip())
-
-        if self.filemapmode and nparents == 1:
-            man = self.repo.manifest
-            mnode = self.repo.changelog.read(bin(p2))[0]
-            if not man.cmp(m1node, man.revision(mnode)):
-                self.ui.status(_("filtering out empty revision\n"))
-                self.repo.rollback()
-                return parent
-        return p2
-
-    def puttags(self, tags):
-        try:
-            parentctx = self.repo[self.tagsbranch]
-            tagparent = parentctx.node()
-        except error.RepoError:
-            parentctx = None
-            tagparent = nullid
-
-        try:
-            oldlines = sorted(parentctx['.hgtags'].data().splitlines(True))
-        except:
-            oldlines = []
-
-        newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
-        if newlines == oldlines:
-            return None
-        data = "".join(newlines)
-        def getfilectx(repo, memctx, f):
-            return context.memfilectx(f, data, False, False, None)
-
-        self.ui.status(_("updating tags\n"))
-        date = "%s 0" % int(time.mktime(time.gmtime()))
-        extra = {'branch': self.tagsbranch}
-        ctx = context.memctx(self.repo, (tagparent, None), "update tags",
-                             [".hgtags"], getfilectx, "convert-repo", date,
-                             extra)
-        self.repo.commitctx(ctx)
-        return hex(self.repo.changelog.tip())
-
-    def setfilemapmode(self, active):
-        self.filemapmode = active
-
-class mercurial_source(converter_source):
-    def __init__(self, ui, path, rev=None):
-        converter_source.__init__(self, ui, path, rev)
-        self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
-        self.ignored = set()
-        self.saverev = ui.configbool('convert', 'hg.saverev', False)
-        try:
-            self.repo = hg.repository(self.ui, path)
-            # try to provoke an exception if this isn't really a hg
-            # repo, but some other bogus compatible-looking url
-            if not self.repo.local():
-                raise error.RepoError()
-        except error.RepoError:
-            ui.traceback()
-            raise NoRepo("%s is not a local Mercurial repo" % path)
-        self.lastrev = None
-        self.lastctx = None
-        self._changescache = None
-        self.convertfp = None
-        # Restrict converted revisions to startrev descendants
-        startnode = ui.config('convert', 'hg.startrev')
-        if startnode is not None:
-            try:
-                startnode = self.repo.lookup(startnode)
-            except error.RepoError:
-                raise util.Abort(_('%s is not a valid start revision')
-                                 % startnode)
-            startrev = self.repo.changelog.rev(startnode)
-            children = {startnode: 1}
-            for rev in self.repo.changelog.descendants(startrev):
-                children[self.repo.changelog.node(rev)] = 1
-            self.keep = children.__contains__
-        else:
-            self.keep = util.always
-
-    def changectx(self, rev):
-        if self.lastrev != rev:
-            self.lastctx = self.repo[rev]
-            self.lastrev = rev
-        return self.lastctx
-
-    def parents(self, ctx):
-        return [p.node() for p in ctx.parents()
-                if p and self.keep(p.node())]
-
-    def getheads(self):
-        if self.rev:
-            heads = [self.repo[self.rev].node()]
-        else:
-            heads = self.repo.heads()
-        return [hex(h) for h in heads if self.keep(h)]
-
-    def getfile(self, name, rev):
-        try:
-            return self.changectx(rev)[name].data()
-        except error.LookupError, err:
-            raise IOError(err)
-
-    def getmode(self, name, rev):
-        return self.changectx(rev).manifest().flags(name)
-
-    def getchanges(self, rev):
-        ctx = self.changectx(rev)
-        parents = self.parents(ctx)
-        if not parents:
-            files = sorted(ctx.manifest())
-            if self.ignoreerrors:
-                # calling getcopies() is a simple way to detect missing
-                # revlogs and populate self.ignored
-                self.getcopies(ctx, files)
-            return [(f, rev) for f in files if f not in self.ignored], {}
-        if self._changescache and self._changescache[0] == rev:
-            m, a, r = self._changescache[1]
-        else:
-            m, a, r = self.repo.status(parents[0], ctx.node())[:3]
-        # getcopies() detects missing revlogs early, run it before
-        # filtering the changes.
-        copies = self.getcopies(ctx, m + a)
-        changes = [(name, rev) for name in m + a + r
-                   if name not in self.ignored]
-        return sorted(changes), copies
-
-    def getcopies(self, ctx, files):
-        copies = {}
-        for name in files:
-            if name in self.ignored:
-                continue
-            try:
-                copysource, copynode = ctx.filectx(name).renamed()
-                if copysource in self.ignored or not self.keep(copynode):
-                    continue
-                copies[name] = copysource
-            except TypeError:
-                pass
-            except error.LookupError, e:
-                if not self.ignoreerrors:
-                    raise
-                self.ignored.add(name)
-                self.ui.warn(_('ignoring: %s\n') % e)
-        return copies
-
-    def getcommit(self, rev):
-        ctx = self.changectx(rev)
-        parents = [hex(p) for p in self.parents(ctx)]
-        if self.saverev:
-            crev = rev
-        else:
-            crev = None
-        return commit(author=ctx.user(), date=util.datestr(ctx.date()),
-                      desc=ctx.description(), rev=crev, parents=parents,
-                      branch=ctx.branch(), extra=ctx.extra(),
-                      sortkey=ctx.rev())
-
-    def gettags(self):
-        tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
-        return dict([(name, hex(node)) for name, node in tags
-                     if self.keep(node)])
-
-    def getchangedfiles(self, rev, i):
-        ctx = self.changectx(rev)
-        parents = self.parents(ctx)
-        if not parents and i is None:
-            i = 0
-            changes = [], ctx.manifest().keys(), []
-        else:
-            i = i or 0
-            changes = self.repo.status(parents[i], ctx.node())[:3]
-        changes = [[f for f in l if f not in self.ignored] for l in changes]
-
-        if i == 0:
-            self._changescache = (rev, changes)
-
-        return changes[0] + changes[1] + changes[2]
-
-    def converted(self, rev, destrev):
-        if self.convertfp is None:
-            self.convertfp = open(os.path.join(self.path, '.hg', 'shamap'),
-                                  'a')
-        self.convertfp.write('%s %s\n' % (destrev, rev))
-        self.convertfp.flush()
-
-    def before(self):
-        self.ui.debug(_('run hg source pre-conversion action\n'))
-
-    def after(self):
-        self.ui.debug(_('run hg source post-conversion action\n'))
-
-    def hasnativeorder(self):
-        return True
-
-    def lookuprev(self, rev):
-        try:
-            return hex(self.repo.lookup(rev))
-        except error.RepoError:
-            return None
--- a/sys/src/cmd/hg/hgext/convert/monotone.py
+++ /dev/null
@@ -1,217 +1,0 @@
-# monotone.py - monotone support for the convert extension
-#
-#  Copyright 2008, 2009 Mikkel Fahnoe Jorgensen <mikkel@dvide.com> and
-#  others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os, re
-from mercurial import util
-from common import NoRepo, commit, converter_source, checktool
-from common import commandline
-from mercurial.i18n import _
-
-class monotone_source(converter_source, commandline):
-    def __init__(self, ui, path=None, rev=None):
-        converter_source.__init__(self, ui, path, rev)
-        commandline.__init__(self, ui, 'mtn')
-
-        self.ui = ui
-        self.path = path
-
-        norepo = NoRepo (_("%s does not look like a monotone repo") % path)
-        if not os.path.exists(os.path.join(path, '_MTN')):
-            # Could be a monotone repository (SQLite db file)
-            try:
-                header = file(path, 'rb').read(16)
-            except:
-                header = ''
-            if header != 'SQLite format 3\x00':
-                raise norepo
-
-        # regular expressions for parsing monotone output
-        space    = r'\s*'
-        name     = r'\s+"((?:\\"|[^"])*)"\s*'
-        value    = name
-        revision = r'\s+\[(\w+)\]\s*'
-        lines    = r'(?:.|\n)+'
-
-        self.dir_re      = re.compile(space + "dir" + name)
-        self.file_re     = re.compile(space + "file" + name + "content" + revision)
-        self.add_file_re = re.compile(space + "add_file" + name + "content" + revision)
-        self.patch_re    = re.compile(space + "patch" + name + "from" + revision + "to" + revision)
-        self.rename_re   = re.compile(space + "rename" + name + "to" + name)
-        self.delete_re   = re.compile(space + "delete" + name)
-        self.tag_re      = re.compile(space + "tag" + name + "revision" + revision)
-        self.cert_re     = re.compile(lines + space + "name" + name + "value" + value)
-
-        attr = space + "file" + lines + space + "attr" + space
-        self.attr_execute_re = re.compile(attr  + '"mtn:execute"' + space + '"true"')
-
-        # cached data
-        self.manifest_rev = None
-        self.manifest = None
-        self.files = None
-        self.dirs  = None
-
-        checktool('mtn', abort=False)
-
-        # test if there are any revisions
-        self.rev = None
-        try:
-            self.getheads()
-        except:
-            raise norepo
-        self.rev = rev
-
-    def mtnrun(self, *args, **kwargs):
-        kwargs['d'] = self.path
-        return self.run0('automate', *args, **kwargs)
-
-    def mtnloadmanifest(self, rev):
-        if self.manifest_rev == rev:
-            return
-        self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n")
-        self.manifest_rev = rev
-        self.files = {}
-        self.dirs = {}
-
-        for e in self.manifest:
-            m = self.file_re.match(e)
-            if m:
-                attr = ""
-                name = m.group(1)
-                node = m.group(2)
-                if self.attr_execute_re.match(e):
-                    attr += "x"
-                self.files[name] = (node, attr)
-            m = self.dir_re.match(e)
-            if m:
-                self.dirs[m.group(1)] = True
-
-    def mtnisfile(self, name, rev):
-        # a non-file could be a directory or a deleted or renamed file
-        self.mtnloadmanifest(rev)
-        return name in self.files
-
-    def mtnisdir(self, name, rev):
-        self.mtnloadmanifest(rev)
-        return name in self.dirs
-
-    def mtngetcerts(self, rev):
-        certs = {"author":"<missing>", "date":"<missing>",
-            "changelog":"<missing>", "branch":"<missing>"}
-        cert_list = self.mtnrun("certs", rev).split('\n\n      key "')
-        for e in cert_list:
-            m = self.cert_re.match(e)
-            if m:
-                name, value = m.groups()
-                value = value.replace(r'\"', '"')
-                value = value.replace(r'\\', '\\')
-                certs[name] = value
-        # Monotone may have subsecond dates: 2005-02-05T09:39:12.364306
-        # and all times are stored in UTC
-        certs["date"] = certs["date"].split('.')[0] + " UTC"
-        return certs
-
-    # implement the converter_source interface:
-
-    def getheads(self):
-        if not self.rev:
-            return self.mtnrun("leaves").splitlines()
-        else:
-            return [self.rev]
-
-    def getchanges(self, rev):
-        #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
-        revision = self.mtnrun("get_revision", rev).split("\n\n")
-        files = {}
-        ignoremove = {}
-        renameddirs = []
-        copies = {}
-        for e in revision:
-            m = self.add_file_re.match(e)
-            if m:
-                files[m.group(1)] = rev
-                ignoremove[m.group(1)] = rev
-            m = self.patch_re.match(e)
-            if m:
-                files[m.group(1)] = rev
-            # Delete/rename is handled later when the convert engine
-            # discovers an IOError exception from getfile,
-            # but only if we add the "from" file to the list of changes.
-            m = self.delete_re.match(e)
-            if m:
-                files[m.group(1)] = rev
-            m = self.rename_re.match(e)
-            if m:
-                toname = m.group(2)
-                fromname = m.group(1)
-                if self.mtnisfile(toname, rev):
-                    ignoremove[toname] = 1
-                    copies[toname] = fromname
-                    files[toname] = rev
-                    files[fromname] = rev
-                elif self.mtnisdir(toname, rev):
-                    renameddirs.append((fromname, toname))
-
-        # Directory renames can be handled only once we have recorded
-        # all new files
-        for fromdir, todir in renameddirs:
-            renamed = {}
-            for tofile in self.files:
-                if tofile in ignoremove:
-                    continue
-                if tofile.startswith(todir + '/'):
-                    renamed[tofile] = fromdir + tofile[len(todir):]
-                    # Avoid chained moves like:
-                    # d1(/a) => d3/d1(/a)
-                    # d2 => d3
-                    ignoremove[tofile] = 1
-            for tofile, fromfile in renamed.items():
-                self.ui.debug (_("copying file in renamed directory "
-                                 "from '%s' to '%s'")
-                               % (fromfile, tofile), '\n')
-                files[tofile] = rev
-                copies[tofile] = fromfile
-            for fromfile in renamed.values():
-                files[fromfile] = rev
-
-        return (files.items(), copies)
-
-    def getmode(self, name, rev):
-        self.mtnloadmanifest(rev)
-        node, attr = self.files.get(name, (None, ""))
-        return attr
-
-    def getfile(self, name, rev):
-        if not self.mtnisfile(name, rev):
-            raise IOError() # file was deleted or renamed
-        try:
-            return self.mtnrun("get_file_of", name, r=rev)
-        except:
-            raise IOError() # file was deleted or renamed
-
-    def getcommit(self, rev):
-        certs   = self.mtngetcerts(rev)
-        return commit(
-            author=certs["author"],
-            date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")),
-            desc=certs["changelog"],
-            rev=rev,
-            parents=self.mtnrun("parents", rev).splitlines(),
-            branch=certs["branch"])
-
-    def gettags(self):
-        tags = {}
-        for e in self.mtnrun("tags").split("\n\n"):
-            m = self.tag_re.match(e)
-            if m:
-                tags[m.group(1)] = m.group(2)
-        return tags
-
-    def getchangedfiles(self, rev, i):
-        # This function is only needed to support --filemap
-        # ... and we don't support that
-        raise NotImplementedError()
--- a/sys/src/cmd/hg/hgext/convert/p4.py
+++ /dev/null
@@ -1,205 +1,0 @@
-#
-# Perforce source for convert extension.
-#
-# Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-#
-
-from mercurial import util
-from mercurial.i18n import _
-
-from common import commit, converter_source, checktool, NoRepo
-import marshal
-import re
-
-def loaditer(f):
-    "Yield the dictionary objects generated by p4"
-    try:
-        while True:
-            d = marshal.load(f)
-            if not d:
-                break
-            yield d
-    except EOFError:
-        pass
-
-class p4_source(converter_source):
-    def __init__(self, ui, path, rev=None):
-        super(p4_source, self).__init__(ui, path, rev=rev)
-
-        if "/" in path and not path.startswith('//'):
-            raise NoRepo('%s does not look like a P4 repo' % path)
-
-        checktool('p4', abort=False)
-
-        self.p4changes = {}
-        self.heads = {}
-        self.changeset = {}
-        self.files = {}
-        self.tags = {}
-        self.lastbranch = {}
-        self.parent = {}
-        self.encoding = "latin_1"
-        self.depotname = {}           # mapping from local name to depot name
-        self.modecache = {}
-        self.re_type = re.compile("([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)(\+\w+)?$")
-        self.re_keywords = re.compile(r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author):[^$\n]*\$")
-        self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
-
-        self._parse(ui, path)
-
-    def _parse_view(self, path):
-        "Read changes affecting the path"
-        cmd = 'p4 -G changes -s submitted "%s"' % path
-        stdout = util.popen(cmd)
-        for d in loaditer(stdout):
-            c = d.get("change", None)
-            if c:
-                self.p4changes[c] = True
-
-    def _parse(self, ui, path):
-        "Prepare list of P4 filenames and revisions to import"
-        ui.status(_('reading p4 views\n'))
-
-        # read client spec or view
-        if "/" in path:
-            self._parse_view(path)
-            if path.startswith("//") and path.endswith("/..."):
-                views = {path[:-3]:""}
-            else:
-                views = {"//": ""}
-        else:
-            cmd = 'p4 -G client -o "%s"' % path
-            clientspec = marshal.load(util.popen(cmd))
-
-            views = {}
-            for client in clientspec:
-                if client.startswith("View"):
-                    sview, cview = clientspec[client].split()
-                    self._parse_view(sview)
-                    if sview.endswith("...") and cview.endswith("..."):
-                        sview = sview[:-3]
-                        cview = cview[:-3]
-                    cview = cview[2:]
-                    cview = cview[cview.find("/") + 1:]
-                    views[sview] = cview
-
-        # list of changes that affect our source files
-        self.p4changes = self.p4changes.keys()
-        self.p4changes.sort(key=int)
-
-        # list with depot pathnames, longest first
-        vieworder = views.keys()
-        vieworder.sort(key=len, reverse=True)
-
-        # handle revision limiting
-        startrev = self.ui.config('convert', 'p4.startrev', default=0)
-        self.p4changes = [x for x in self.p4changes
-                          if ((not startrev or int(x) >= int(startrev)) and
-                              (not self.rev or int(x) <= int(self.rev)))]
-
-        # now read the full changelists to get the list of file revisions
-        ui.status(_('collecting p4 changelists\n'))
-        lastid = None
-        for change in self.p4changes:
-            cmd = "p4 -G describe %s" % change
-            stdout = util.popen(cmd)
-            d = marshal.load(stdout)
-
-            desc = self.recode(d["desc"])
-            shortdesc = desc.split("\n", 1)[0]
-            t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
-            ui.status(util.ellipsis(t, 80) + '\n')
-
-            if lastid:
-                parents = [lastid]
-            else:
-                parents = []
-
-            date = (int(d["time"]), 0)     # timezone not set
-            c = commit(author=self.recode(d["user"]), date=util.datestr(date),
-                        parents=parents, desc=desc, branch='', extra={"p4": change})
-
-            files = []
-            i = 0
-            while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
-                oldname = d["depotFile%d" % i]
-                filename = None
-                for v in vieworder:
-                    if oldname.startswith(v):
-                        filename = views[v] + oldname[len(v):]
-                        break
-                if filename:
-                    files.append((filename, d["rev%d" % i]))
-                    self.depotname[filename] = oldname
-                i += 1
-            self.changeset[change] = c
-            self.files[change] = files
-            lastid = change
-
-        if lastid:
-            self.heads = [lastid]
-
-    def getheads(self):
-        return self.heads
-
-    def getfile(self, name, rev):
-        cmd = 'p4 -G print "%s#%s"' % (self.depotname[name], rev)
-        stdout = util.popen(cmd)
-
-        mode = None
-        contents = ""
-        keywords = None
-
-        for d in loaditer(stdout):
-            code = d["code"]
-            data = d.get("data")
-
-            if code == "error":
-                raise IOError(d["generic"], data)
-
-            elif code == "stat":
-                p4type = self.re_type.match(d["type"])
-                if p4type:
-                    mode = ""
-                    flags = (p4type.group(1) or "") + (p4type.group(3) or "")
-                    if "x" in flags:
-                        mode = "x"
-                    if p4type.group(2) == "symlink":
-                        mode = "l"
-                    if "ko" in flags:
-                        keywords = self.re_keywords_old
-                    elif "k" in flags:
-                        keywords = self.re_keywords
-
-            elif code == "text" or code == "binary":
-                contents += data
-
-        if mode is None:
-            raise IOError(0, "bad stat")
-
-        self.modecache[(name, rev)] = mode
-
-        if keywords:
-            contents = keywords.sub("$\\1$", contents)
-        if mode == "l" and contents.endswith("\n"):
-            contents = contents[:-1]
-
-        return contents
-
-    def getmode(self, name, rev):
-        return self.modecache[(name, rev)]
-
-    def getchanges(self, rev):
-        return self.files[rev], {}
-
-    def getcommit(self, rev):
-        return self.changeset[rev]
-
-    def gettags(self):
-        return self.tags
-
-    def getchangedfiles(self, rev, i):
-        return sorted([x[0] for x in self.files[rev]])
--- a/sys/src/cmd/hg/hgext/convert/subversion.py
+++ /dev/null
@@ -1,1136 +1,0 @@
-# Subversion 1.4/1.5 Python API backend
-#
-# Copyright(C) 2007 Daniel Holth et al
-
-import os
-import re
-import sys
-import cPickle as pickle
-import tempfile
-import urllib
-
-from mercurial import strutil, util, encoding
-from mercurial.i18n import _
-
-# Subversion stuff. Works best with very recent Python SVN bindings
-# e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing
-# these bindings.
-
-from cStringIO import StringIO
-
-from common import NoRepo, MissingTool, commit, encodeargs, decodeargs
-from common import commandline, converter_source, converter_sink, mapfile
-
-try:
-    from svn.core import SubversionException, Pool
-    import svn
-    import svn.client
-    import svn.core
-    import svn.ra
-    import svn.delta
-    import transport
-    import warnings
-    warnings.filterwarnings('ignore',
-            module='svn.core',
-            category=DeprecationWarning)
-
-except ImportError:
-    pass
-
-class SvnPathNotFound(Exception):
-    pass
-
-def geturl(path):
-    try:
-        return svn.client.url_from_path(svn.core.svn_path_canonicalize(path))
-    except SubversionException:
-        pass
-    if os.path.isdir(path):
-        path = os.path.normpath(os.path.abspath(path))
-        if os.name == 'nt':
-            path = '/' + util.normpath(path)
-        # Module URL is later compared with the repository URL returned
-        # by svn API, which is UTF-8.
-        path = encoding.tolocal(path)
-        return 'file://%s' % urllib.quote(path)
-    return path
-
-def optrev(number):
-    optrev = svn.core.svn_opt_revision_t()
-    optrev.kind = svn.core.svn_opt_revision_number
-    optrev.value.number = number
-    return optrev
-
-class changedpath(object):
-    def __init__(self, p):
-        self.copyfrom_path = p.copyfrom_path
-        self.copyfrom_rev = p.copyfrom_rev
-        self.action = p.action
-
-def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True,
-                    strict_node_history=False):
-    protocol = -1
-    def receiver(orig_paths, revnum, author, date, message, pool):
-        if orig_paths is not None:
-            for k, v in orig_paths.iteritems():
-                orig_paths[k] = changedpath(v)
-        pickle.dump((orig_paths, revnum, author, date, message),
-                    fp, protocol)
-
-    try:
-        # Use an ra of our own so that our parent can consume
-        # our results without confusing the server.
-        t = transport.SvnRaTransport(url=url)
-        svn.ra.get_log(t.ra, paths, start, end, limit,
-                       discover_changed_paths,
-                       strict_node_history,
-                       receiver)
-    except SubversionException, (inst, num):
-        pickle.dump(num, fp, protocol)
-    except IOError:
-        # Caller may interrupt the iteration
-        pickle.dump(None, fp, protocol)
-    else:
-        pickle.dump(None, fp, protocol)
-    fp.close()
-    # With large history, cleanup process goes crazy and suddenly
-    # consumes *huge* amount of memory. The output file being closed,
-    # there is no need for clean termination.
-    os._exit(0)
-
-def debugsvnlog(ui, **opts):
-    """Fetch SVN log in a subprocess and channel them back to parent to
-    avoid memory collection issues.
-    """
-    util.set_binary(sys.stdin)
-    util.set_binary(sys.stdout)
-    args = decodeargs(sys.stdin.read())
-    get_log_child(sys.stdout, *args)
-
-class logstream(object):
-    """Interruptible revision log iterator."""
-    def __init__(self, stdout):
-        self._stdout = stdout
-
-    def __iter__(self):
-        while True:
-            entry = pickle.load(self._stdout)
-            try:
-                orig_paths, revnum, author, date, message = entry
-            except:
-                if entry is None:
-                    break
-                raise SubversionException("child raised exception", entry)
-            yield entry
-
-    def close(self):
-        if self._stdout:
-            self._stdout.close()
-            self._stdout = None
-
-
-# Check to see if the given path is a local Subversion repo. Verify this by
-# looking for several svn-specific files and directories in the given
-# directory.
-def filecheck(path, proto):
-    for x in ('locks', 'hooks', 'format', 'db', ):
-        if not os.path.exists(os.path.join(path, x)):
-            return False
-    return True
-
-# Check to see if a given path is the root of an svn repo over http. We verify
-# this by requesting a version-controlled URL we know can't exist and looking
-# for the svn-specific "not found" XML.
-def httpcheck(path, proto):
-    return ('<m:human-readable errcode="160013">' in
-            urllib.urlopen('%s://%s/!svn/ver/0/.svn' % (proto, path)).read())
-
-protomap = {'http': httpcheck,
-            'https': httpcheck,
-            'file': filecheck,
-            }
-def issvnurl(url):
-    try:
-        proto, path = url.split('://', 1)
-        path = urllib.url2pathname(path)
-    except ValueError:
-        proto = 'file'
-        path = os.path.abspath(url)
-    path = path.replace(os.sep, '/')
-    check = protomap.get(proto, lambda p, p2: False)
-    while '/' in path:
-        if check(path, proto):
-            return True
-        path = path.rsplit('/', 1)[0]
-    return False
-
-# SVN conversion code stolen from bzr-svn and tailor
-#
-# Subversion looks like a versioned filesystem, branches structures
-# are defined by conventions and not enforced by the tool. First,
-# we define the potential branches (modules) as "trunk" and "branches"
-# children directories. Revisions are then identified by their
-# module and revision number (and a repository identifier).
-#
-# The revision graph is really a tree (or a forest). By default, a
-# revision parent is the previous revision in the same module. If the
-# module directory is copied/moved from another module then the
-# revision is the module root and its parent the source revision in
-# the parent module. A revision has at most one parent.
-#
-class svn_source(converter_source):
-    def __init__(self, ui, url, rev=None):
-        super(svn_source, self).__init__(ui, url, rev=rev)
-
-        if not (url.startswith('svn://') or url.startswith('svn+ssh://') or
-                (os.path.exists(url) and
-                 os.path.exists(os.path.join(url, '.svn'))) or
-                issvnurl(url)):
-            raise NoRepo("%s does not look like a Subversion repo" % url)
-
-        try:
-            SubversionException
-        except NameError:
-            raise MissingTool(_('Subversion python bindings could not be loaded'))
-
-        try:
-            version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
-            if version < (1, 4):
-                raise MissingTool(_('Subversion python bindings %d.%d found, '
-                                    '1.4 or later required') % version)
-        except AttributeError:
-            raise MissingTool(_('Subversion python bindings are too old, 1.4 '
-                                'or later required'))
-
-        self.lastrevs = {}
-
-        latest = None
-        try:
-            # Support file://path@rev syntax. Useful e.g. to convert
-            # deleted branches.
-            at = url.rfind('@')
-            if at >= 0:
-                latest = int(url[at+1:])
-                url = url[:at]
-        except ValueError:
-            pass
-        self.url = geturl(url)
-        self.encoding = 'UTF-8' # Subversion is always nominal UTF-8
-        try:
-            self.transport = transport.SvnRaTransport(url=self.url)
-            self.ra = self.transport.ra
-            self.ctx = self.transport.client
-            self.baseurl = svn.ra.get_repos_root(self.ra)
-            # Module is either empty or a repository path starting with
-            # a slash and not ending with a slash.
-            self.module = urllib.unquote(self.url[len(self.baseurl):])
-            self.prevmodule = None
-            self.rootmodule = self.module
-            self.commits = {}
-            self.paths = {}
-            self.uuid = svn.ra.get_uuid(self.ra)
-        except SubversionException:
-            ui.traceback()
-            raise NoRepo("%s does not look like a Subversion repo" % self.url)
-
-        if rev:
-            try:
-                latest = int(rev)
-            except ValueError:
-                raise util.Abort(_('svn: revision %s is not an integer') % rev)
-
-        self.startrev = self.ui.config('convert', 'svn.startrev', default=0)
-        try:
-            self.startrev = int(self.startrev)
-            if self.startrev < 0:
-                self.startrev = 0
-        except ValueError:
-            raise util.Abort(_('svn: start revision %s is not an integer')
-                             % self.startrev)
-
-        self.head = self.latest(self.module, latest)
-        if not self.head:
-            raise util.Abort(_('no revision found in module %s')
-                             % self.module)
-        self.last_changed = self.revnum(self.head)
-
-        self._changescache = None
-
-        if os.path.exists(os.path.join(url, '.svn/entries')):
-            self.wc = url
-        else:
-            self.wc = None
-        self.convertfp = None
-
-    def setrevmap(self, revmap):
-        lastrevs = {}
-        for revid in revmap.iterkeys():
-            uuid, module, revnum = self.revsplit(revid)
-            lastrevnum = lastrevs.setdefault(module, revnum)
-            if revnum > lastrevnum:
-                lastrevs[module] = revnum
-        self.lastrevs = lastrevs
-
-    def exists(self, path, optrev):
-        try:
-            svn.client.ls(self.url.rstrip('/') + '/' + urllib.quote(path),
-                                 optrev, False, self.ctx)
-            return True
-        except SubversionException:
-            return False
-
-    def getheads(self):
-
-        def isdir(path, revnum):
-            kind = self._checkpath(path, revnum)
-            return kind == svn.core.svn_node_dir
-
-        def getcfgpath(name, rev):
-            cfgpath = self.ui.config('convert', 'svn.' + name)
-            if cfgpath is not None and cfgpath.strip() == '':
-                return None
-            path = (cfgpath or name).strip('/')
-            if not self.exists(path, rev):
-                if cfgpath:
-                    raise util.Abort(_('expected %s to be at %r, but not found')
-                                 % (name, path))
-                return None
-            self.ui.note(_('found %s at %r\n') % (name, path))
-            return path
-
-        rev = optrev(self.last_changed)
-        oldmodule = ''
-        trunk = getcfgpath('trunk', rev)
-        self.tags = getcfgpath('tags', rev)
-        branches = getcfgpath('branches', rev)
-
-        # If the project has a trunk or branches, we will extract heads
-        # from them. We keep the project root otherwise.
-        if trunk:
-            oldmodule = self.module or ''
-            self.module += '/' + trunk
-            self.head = self.latest(self.module, self.last_changed)
-            if not self.head:
-                raise util.Abort(_('no revision found in module %s')
-                                 % self.module)
-
-        # First head in the list is the module's head
-        self.heads = [self.head]
-        if self.tags is not None:
-            self.tags = '%s/%s' % (oldmodule , (self.tags or 'tags'))
-
-        # Check if branches bring a few more heads to the list
-        if branches:
-            rpath = self.url.strip('/')
-            branchnames = svn.client.ls(rpath + '/' + urllib.quote(branches),
-                                        rev, False, self.ctx)
-            for branch in branchnames.keys():
-                module = '%s/%s/%s' % (oldmodule, branches, branch)
-                if not isdir(module, self.last_changed):
-                    continue
-                brevid = self.latest(module, self.last_changed)
-                if not brevid:
-                    self.ui.note(_('ignoring empty branch %s\n') % branch)
-                    continue
-                self.ui.note(_('found branch %s at %d\n') %
-                             (branch, self.revnum(brevid)))
-                self.heads.append(brevid)
-
-        if self.startrev and self.heads:
-            if len(self.heads) > 1:
-                raise util.Abort(_('svn: start revision is not supported '
-                                   'with more than one branch'))
-            revnum = self.revnum(self.heads[0])
-            if revnum < self.startrev:
-                raise util.Abort(_('svn: no revision found after start revision %d')
-                                 % self.startrev)
-
-        return self.heads
-
-    def getfile(self, file, rev):
-        data, mode = self._getfile(file, rev)
-        self.modecache[(file, rev)] = mode
-        return data
-
-    def getmode(self, file, rev):
-        return self.modecache[(file, rev)]
-
-    def getchanges(self, rev):
-        if self._changescache and self._changescache[0] == rev:
-            return self._changescache[1]
-        self._changescache = None
-        self.modecache = {}
-        (paths, parents) = self.paths[rev]
-        if parents:
-            files, copies = self.expandpaths(rev, paths, parents)
-        else:
-            # Perform a full checkout on roots
-            uuid, module, revnum = self.revsplit(rev)
-            entries = svn.client.ls(self.baseurl + urllib.quote(module),
-                                    optrev(revnum), True, self.ctx)
-            files = [n for n,e in entries.iteritems()
-                     if e.kind == svn.core.svn_node_file]
-            copies = {}
-
-        files.sort()
-        files = zip(files, [rev] * len(files))
-
-        # caller caches the result, so free it here to release memory
-        del self.paths[rev]
-        return (files, copies)
-
-    def getchangedfiles(self, rev, i):
-        changes = self.getchanges(rev)
-        self._changescache = (rev, changes)
-        return [f[0] for f in changes[0]]
-
-    def getcommit(self, rev):
-        if rev not in self.commits:
-            uuid, module, revnum = self.revsplit(rev)
-            self.module = module
-            self.reparent(module)
-            # We assume that:
-            # - requests for revisions after "stop" come from the
-            # revision graph backward traversal. Cache all of them
-            # down to stop, they will be used eventually.
-            # - requests for revisions before "stop" come to get
-            # isolated branches parents. Just fetch what is needed.
-            stop = self.lastrevs.get(module, 0)
-            if revnum < stop:
-                stop = revnum + 1
-            self._fetch_revisions(revnum, stop)
-        commit = self.commits[rev]
-        # caller caches the result, so free it here to release memory
-        del self.commits[rev]
-        return commit
-
-    def gettags(self):
-        tags = {}
-        if self.tags is None:
-            return tags
-
-        # svn tags are just a convention, project branches left in a
-        # 'tags' directory. There is no other relationship than
-        # ancestry, which is expensive to discover and makes them hard
-        # to update incrementally.  Worse, past revisions may be
-        # referenced by tags far away in the future, requiring a deep
-        # history traversal on every calculation.  Current code
-        # performs a single backward traversal, tracking moves within
-        # the tags directory (tag renaming) and recording a new tag
-        # everytime a project is copied from outside the tags
-        # directory. It also lists deleted tags, this behaviour may
-        # change in the future.
-        pendings = []
-        tagspath = self.tags
-        start = svn.ra.get_latest_revnum(self.ra)
-        try:
-            for entry in self._getlog([self.tags], start, self.startrev):
-                origpaths, revnum, author, date, message = entry
-                copies = [(e.copyfrom_path, e.copyfrom_rev, p) for p, e
-                          in origpaths.iteritems() if e.copyfrom_path]
-                # Apply moves/copies from more specific to general
-                copies.sort(reverse=True)
-
-                srctagspath = tagspath
-                if copies and copies[-1][2] == tagspath:
-                    # Track tags directory moves
-                    srctagspath = copies.pop()[0]
-
-                for source, sourcerev, dest in copies:
-                    if not dest.startswith(tagspath + '/'):
-                        continue
-                    for tag in pendings:
-                        if tag[0].startswith(dest):
-                            tagpath = source + tag[0][len(dest):]
-                            tag[:2] = [tagpath, sourcerev]
-                            break
-                    else:
-                        pendings.append([source, sourcerev, dest])
-
-                # Filter out tags with children coming from different
-                # parts of the repository like:
-                # /tags/tag.1 (from /trunk:10)
-                # /tags/tag.1/foo (from /branches/foo:12)
-                # Here/tags/tag.1 discarded as well as its children.
-                # It happens with tools like cvs2svn. Such tags cannot
-                # be represented in mercurial.
-                addeds = dict((p, e.copyfrom_path) for p, e
-                              in origpaths.iteritems()
-                              if e.action == 'A' and e.copyfrom_path)
-                badroots = set()
-                for destroot in addeds:
-                    for source, sourcerev, dest in pendings:
-                        if (not dest.startswith(destroot + '/')
-                            or source.startswith(addeds[destroot] + '/')):
-                            continue
-                        badroots.add(destroot)
-                        break
-
-                for badroot in badroots:
-                    pendings = [p for p in pendings if p[2] != badroot
-                                and not p[2].startswith(badroot + '/')]
-
-                # Tell tag renamings from tag creations
-                remainings = []
-                for source, sourcerev, dest in pendings:
-                    tagname = dest.split('/')[-1]
-                    if source.startswith(srctagspath):
-                        remainings.append([source, sourcerev, tagname])
-                        continue
-                    if tagname in tags:
-                        # Keep the latest tag value
-                        continue
-                    # From revision may be fake, get one with changes
-                    try:
-                        tagid = self.latest(source, sourcerev)
-                        if tagid and tagname not in tags:
-                            tags[tagname] = tagid
-                    except SvnPathNotFound:
-                        # It happens when we are following directories
-                        # we assumed were copied with their parents
-                        # but were really created in the tag
-                        # directory.
-                        pass
-                pendings = remainings
-                tagspath = srctagspath
-
-        except SubversionException:
-            self.ui.note(_('no tags found at revision %d\n') % start)
-        return tags
-
-    def converted(self, rev, destrev):
-        if not self.wc:
-            return
-        if self.convertfp is None:
-            self.convertfp = open(os.path.join(self.wc, '.svn', 'hg-shamap'),
-                                  'a')
-        self.convertfp.write('%s %d\n' % (destrev, self.revnum(rev)))
-        self.convertfp.flush()
-
-    def revid(self, revnum, module=None):
-        return 'svn:%s%s@%s' % (self.uuid, module or self.module, revnum)
-
-    def revnum(self, rev):
-        return int(rev.split('@')[-1])
-
-    def revsplit(self, rev):
-        url, revnum = rev.rsplit('@', 1)
-        revnum = int(revnum)
-        parts = url.split('/', 1)
-        uuid = parts.pop(0)[4:]
-        mod = ''
-        if parts:
-            mod = '/' + parts[0]
-        return uuid, mod, revnum
-
-    def latest(self, path, stop=0):
-        """Find the latest revid affecting path, up to stop. It may return
-        a revision in a different module, since a branch may be moved without
-        a change being reported. Return None if computed module does not
-        belong to rootmodule subtree.
-        """
-        if not path.startswith(self.rootmodule):
-            # Requests on foreign branches may be forbidden at server level
-            self.ui.debug(_('ignoring foreign branch %r\n') % path)
-            return None
-
-        if not stop:
-            stop = svn.ra.get_latest_revnum(self.ra)
-        try:
-            prevmodule = self.reparent('')
-            dirent = svn.ra.stat(self.ra, path.strip('/'), stop)
-            self.reparent(prevmodule)
-        except SubversionException:
-            dirent = None
-        if not dirent:
-            raise SvnPathNotFound(_('%s not found up to revision %d') % (path, stop))
-
-        # stat() gives us the previous revision on this line of
-        # development, but it might be in *another module*. Fetch the
-        # log and detect renames down to the latest revision.
-        stream = self._getlog([path], stop, dirent.created_rev)
-        try:
-            for entry in stream:
-                paths, revnum, author, date, message = entry
-                if revnum <= dirent.created_rev:
-                    break
-
-                for p in paths:
-                    if not path.startswith(p) or not paths[p].copyfrom_path:
-                        continue
-                    newpath = paths[p].copyfrom_path + path[len(p):]
-                    self.ui.debug(_("branch renamed from %s to %s at %d\n") %
-                                  (path, newpath, revnum))
-                    path = newpath
-                    break
-        finally:
-            stream.close()
-
-        if not path.startswith(self.rootmodule):
-            self.ui.debug(_('ignoring foreign branch %r\n') % path)
-            return None
-        return self.revid(dirent.created_rev, path)
-
-    def reparent(self, module):
-        """Reparent the svn transport and return the previous parent."""
-        if self.prevmodule == module:
-            return module
-        svnurl = self.baseurl + urllib.quote(module)
-        prevmodule = self.prevmodule
-        if prevmodule is None:
-            prevmodule = ''
-        self.ui.debug(_("reparent to %s\n") % svnurl)
-        svn.ra.reparent(self.ra, svnurl)
-        self.prevmodule = module
-        return prevmodule
-
-    def expandpaths(self, rev, paths, parents):
-        entries = []
-        # Map of entrypath, revision for finding source of deleted
-        # revisions.
-        copyfrom = {}
-        copies = {}
-
-        new_module, revnum = self.revsplit(rev)[1:]
-        if new_module != self.module:
-            self.module = new_module
-            self.reparent(self.module)
-
-        for path, ent in paths:
-            entrypath = self.getrelpath(path)
-
-            kind = self._checkpath(entrypath, revnum)
-            if kind == svn.core.svn_node_file:
-                entries.append(self.recode(entrypath))
-                if not ent.copyfrom_path or not parents:
-                    continue
-                # Copy sources not in parent revisions cannot be
-                # represented, ignore their origin for now
-                pmodule, prevnum = self.revsplit(parents[0])[1:]
-                if ent.copyfrom_rev < prevnum:
-                    continue
-                copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule)
-                if not copyfrom_path:
-                    continue
-                self.ui.debug(_("copied to %s from %s@%s\n") %
-                              (entrypath, copyfrom_path, ent.copyfrom_rev))
-                copies[self.recode(entrypath)] = self.recode(copyfrom_path)
-            elif kind == 0: # gone, but had better be a deleted *file*
-                self.ui.debug(_("gone from %s\n") % ent.copyfrom_rev)
-                pmodule, prevnum = self.revsplit(parents[0])[1:]
-                parentpath = pmodule + "/" + entrypath
-                self.ui.debug(_("entry %s\n") % parentpath)
-
-                # We can avoid the reparent calls if the module has
-                # not changed but it probably does not worth the pain.
-                prevmodule = self.reparent('')
-                fromkind = svn.ra.check_path(self.ra, parentpath.strip('/'), prevnum)
-                self.reparent(prevmodule)
-
-                if fromkind == svn.core.svn_node_file:
-                    entries.append(self.recode(entrypath))
-                elif fromkind == svn.core.svn_node_dir:
-                    if ent.action == 'C':
-                        children = self._find_children(path, prevnum)
-                    else:
-                        oroot = parentpath.strip('/')
-                        nroot = path.strip('/')
-                        children = self._find_children(oroot, prevnum)
-                        children = [s.replace(oroot,nroot) for s in children]
-
-                    for child in children:
-                        childpath = self.getrelpath("/" + child, pmodule)
-                        if not childpath:
-                            continue
-                        if childpath in copies:
-                            del copies[childpath]
-                        entries.append(childpath)
-                else:
-                    self.ui.debug(_('unknown path in revision %d: %s\n') % \
-                                  (revnum, path))
-            elif kind == svn.core.svn_node_dir:
-                # If the directory just had a prop change,
-                # then we shouldn't need to look for its children.
-                if ent.action == 'M':
-                    continue
-
-                children = sorted(self._find_children(path, revnum))
-                for child in children:
-                    # Can we move a child directory and its
-                    # parent in the same commit? (probably can). Could
-                    # cause problems if instead of revnum -1,
-                    # we have to look in (copyfrom_path, revnum - 1)
-                    entrypath = self.getrelpath("/" + child)
-                    if entrypath:
-                        # Need to filter out directories here...
-                        kind = self._checkpath(entrypath, revnum)
-                        if kind != svn.core.svn_node_dir:
-                            entries.append(self.recode(entrypath))
-
-                # Handle directory copies
-                if not ent.copyfrom_path or not parents:
-                    continue
-                # Copy sources not in parent revisions cannot be
-                # represented, ignore their origin for now
-                pmodule, prevnum = self.revsplit(parents[0])[1:]
-                if ent.copyfrom_rev < prevnum:
-                    continue
-                copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule)
-                if not copyfrompath:
-                    continue
-                copyfrom[path] = ent
-                self.ui.debug(_("mark %s came from %s:%d\n")
-                              % (path, copyfrompath, ent.copyfrom_rev))
-                children = self._find_children(ent.copyfrom_path, ent.copyfrom_rev)
-                children.sort()
-                for child in children:
-                    entrypath = self.getrelpath("/" + child, pmodule)
-                    if not entrypath:
-                        continue
-                    copytopath = path + entrypath[len(copyfrompath):]
-                    copytopath = self.getrelpath(copytopath)
-                    copies[self.recode(copytopath)] = self.recode(entrypath)
-
-        return (list(set(entries)), copies)
-
-    def _fetch_revisions(self, from_revnum, to_revnum):
-        if from_revnum < to_revnum:
-            from_revnum, to_revnum = to_revnum, from_revnum
-
-        self.child_cset = None
-
-        def parselogentry(orig_paths, revnum, author, date, message):
-            """Return the parsed commit object or None, and True if
-            the revision is a branch root.
-            """
-            self.ui.debug(_("parsing revision %d (%d changes)\n") %
-                          (revnum, len(orig_paths)))
-
-            branched = False
-            rev = self.revid(revnum)
-            # branch log might return entries for a parent we already have
-
-            if rev in self.commits or revnum < to_revnum:
-                return None, branched
-
-            parents = []
-            # check whether this revision is the start of a branch or part
-            # of a branch renaming
-            orig_paths = sorted(orig_paths.iteritems())
-            root_paths = [(p,e) for p,e in orig_paths if self.module.startswith(p)]
-            if root_paths:
-                path, ent = root_paths[-1]
-                if ent.copyfrom_path:
-                    branched = True
-                    newpath = ent.copyfrom_path + self.module[len(path):]
-                    # ent.copyfrom_rev may not be the actual last revision
-                    previd = self.latest(newpath, ent.copyfrom_rev)
-                    if previd is not None:
-                        prevmodule, prevnum = self.revsplit(previd)[1:]
-                        if prevnum >= self.startrev:
-                            parents = [previd]
-                            self.ui.note(_('found parent of branch %s at %d: %s\n') %
-                                         (self.module, prevnum, prevmodule))
-                else:
-                    self.ui.debug(_("no copyfrom path, don't know what to do.\n"))
-
-            paths = []
-            # filter out unrelated paths
-            for path, ent in orig_paths:
-                if self.getrelpath(path) is None:
-                    continue
-                paths.append((path, ent))
-
-            # Example SVN datetime. Includes microseconds.
-            # ISO-8601 conformant
-            # '2007-01-04T17:35:00.902377Z'
-            date = util.parsedate(date[:19] + " UTC", ["%Y-%m-%dT%H:%M:%S"])
-
-            log = message and self.recode(message) or ''
-            author = author and self.recode(author) or ''
-            try:
-                branch = self.module.split("/")[-1]
-                if branch == 'trunk':
-                    branch = ''
-            except IndexError:
-                branch = None
-
-            cset = commit(author=author,
-                          date=util.datestr(date),
-                          desc=log,
-                          parents=parents,
-                          branch=branch,
-                          rev=rev)
-
-            self.commits[rev] = cset
-            # The parents list is *shared* among self.paths and the
-            # commit object. Both will be updated below.
-            self.paths[rev] = (paths, cset.parents)
-            if self.child_cset and not self.child_cset.parents:
-                self.child_cset.parents[:] = [rev]
-            self.child_cset = cset
-            return cset, branched
-
-        self.ui.note(_('fetching revision log for "%s" from %d to %d\n') %
-                     (self.module, from_revnum, to_revnum))
-
-        try:
-            firstcset = None
-            lastonbranch = False
-            stream = self._getlog([self.module], from_revnum, to_revnum)
-            try:
-                for entry in stream:
-                    paths, revnum, author, date, message = entry
-                    if revnum < self.startrev:
-                        lastonbranch = True
-                        break
-                    if not paths:
-                        self.ui.debug(_('revision %d has no entries\n') % revnum)
-                        continue
-                    cset, lastonbranch = parselogentry(paths, revnum, author,
-                                                       date, message)
-                    if cset:
-                        firstcset = cset
-                    if lastonbranch:
-                        break
-            finally:
-                stream.close()
-
-            if not lastonbranch and firstcset and not firstcset.parents:
-                # The first revision of the sequence (the last fetched one)
-                # has invalid parents if not a branch root. Find the parent
-                # revision now, if any.
-                try:
-                    firstrevnum = self.revnum(firstcset.rev)
-                    if firstrevnum > 1:
-                        latest = self.latest(self.module, firstrevnum - 1)
-                        if latest:
-                            firstcset.parents.append(latest)
-                except SvnPathNotFound:
-                    pass
-        except SubversionException, (inst, num):
-            if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION:
-                raise util.Abort(_('svn: branch has no revision %s') % to_revnum)
-            raise
-
-    def _getfile(self, file, rev):
-        # TODO: ra.get_file transmits the whole file instead of diffs.
-        mode = ''
-        try:
-            new_module, revnum = self.revsplit(rev)[1:]
-            if self.module != new_module:
-                self.module = new_module
-                self.reparent(self.module)
-            io = StringIO()
-            info = svn.ra.get_file(self.ra, file, revnum, io)
-            data = io.getvalue()
-            # ra.get_files() seems to keep a reference on the input buffer
-            # preventing collection. Release it explicitely.
-            io.close()
-            if isinstance(info, list):
-                info = info[-1]
-            mode = ("svn:executable" in info) and 'x' or ''
-            mode = ("svn:special" in info) and 'l' or mode
-        except SubversionException, e:
-            notfound = (svn.core.SVN_ERR_FS_NOT_FOUND,
-                svn.core.SVN_ERR_RA_DAV_PATH_NOT_FOUND)
-            if e.apr_err in notfound: # File not found
-                raise IOError()
-            raise
-        if mode == 'l':
-            link_prefix = "link "
-            if data.startswith(link_prefix):
-                data = data[len(link_prefix):]
-        return data, mode
-
-    def _find_children(self, path, revnum):
-        path = path.strip('/')
-        pool = Pool()
-        rpath = '/'.join([self.baseurl, urllib.quote(path)]).strip('/')
-        return ['%s/%s' % (path, x) for x in
-                svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool).keys()]
-
-    def getrelpath(self, path, module=None):
-        if module is None:
-            module = self.module
-        # Given the repository url of this wc, say
-        #   "http://server/plone/CMFPlone/branches/Plone-2_0-branch"
-        # extract the "entry" portion (a relative path) from what
-        # svn log --xml says, ie
-        #   "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py"
-        # that is to say "tests/PloneTestCase.py"
-        if path.startswith(module):
-            relative = path.rstrip('/')[len(module):]
-            if relative.startswith('/'):
-                return relative[1:]
-            elif relative == '':
-                return relative
-
-        # The path is outside our tracked tree...
-        self.ui.debug(_('%r is not under %r, ignoring\n') % (path, module))
-        return None
-
-    def _checkpath(self, path, revnum):
-        # ra.check_path does not like leading slashes very much, it leads
-        # to PROPFIND subversion errors
-        return svn.ra.check_path(self.ra, path.strip('/'), revnum)
-
-    def _getlog(self, paths, start, end, limit=0, discover_changed_paths=True,
-                strict_node_history=False):
-        # Normalize path names, svn >= 1.5 only wants paths relative to
-        # supplied URL
-        relpaths = []
-        for p in paths:
-            if not p.startswith('/'):
-                p = self.module + '/' + p
-            relpaths.append(p.strip('/'))
-        args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths,
-                strict_node_history]
-        arg = encodeargs(args)
-        hgexe = util.hgexecutable()
-        cmd = '%s debugsvnlog' % util.shellquote(hgexe)
-        stdin, stdout = util.popen2(cmd)
-        stdin.write(arg)
-        stdin.close()
-        return logstream(stdout)
-
-pre_revprop_change = '''#!/bin/sh
-
-REPOS="$1"
-REV="$2"
-USER="$3"
-PROPNAME="$4"
-ACTION="$5"
-
-if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
-if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi
-if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi
-
-echo "Changing prohibited revision property" >&2
-exit 1
-'''
-
-class svn_sink(converter_sink, commandline):
-    commit_re = re.compile(r'Committed revision (\d+).', re.M)
-
-    def prerun(self):
-        if self.wc:
-            os.chdir(self.wc)
-
-    def postrun(self):
-        if self.wc:
-            os.chdir(self.cwd)
-
-    def join(self, name):
-        return os.path.join(self.wc, '.svn', name)
-
-    def revmapfile(self):
-        return self.join('hg-shamap')
-
-    def authorfile(self):
-        return self.join('hg-authormap')
-
-    def __init__(self, ui, path):
-        converter_sink.__init__(self, ui, path)
-        commandline.__init__(self, ui, 'svn')
-        self.delete = []
-        self.setexec = []
-        self.delexec = []
-        self.copies = []
-        self.wc = None
-        self.cwd = os.getcwd()
-
-        path = os.path.realpath(path)
-
-        created = False
-        if os.path.isfile(os.path.join(path, '.svn', 'entries')):
-            self.wc = path
-            self.run0('update')
-        else:
-            wcpath = os.path.join(os.getcwd(), os.path.basename(path) + '-wc')
-
-            if os.path.isdir(os.path.dirname(path)):
-                if not os.path.exists(os.path.join(path, 'db', 'fs-type')):
-                    ui.status(_('initializing svn repo %r\n') %
-                              os.path.basename(path))
-                    commandline(ui, 'svnadmin').run0('create', path)
-                    created = path
-                path = util.normpath(path)
-                if not path.startswith('/'):
-                    path = '/' + path
-                path = 'file://' + path
-
-            ui.status(_('initializing svn wc %r\n') % os.path.basename(wcpath))
-            self.run0('checkout', path, wcpath)
-
-            self.wc = wcpath
-        self.opener = util.opener(self.wc)
-        self.wopener = util.opener(self.wc)
-        self.childmap = mapfile(ui, self.join('hg-childmap'))
-        self.is_exec = util.checkexec(self.wc) and util.is_exec or None
-
-        if created:
-            hook = os.path.join(created, 'hooks', 'pre-revprop-change')
-            fp = open(hook, 'w')
-            fp.write(pre_revprop_change)
-            fp.close()
-            util.set_flags(hook, False, True)
-
-        xport = transport.SvnRaTransport(url=geturl(path))
-        self.uuid = svn.ra.get_uuid(xport.ra)
-
-    def wjoin(self, *names):
-        return os.path.join(self.wc, *names)
-
-    def putfile(self, filename, flags, data):
-        if 'l' in flags:
-            self.wopener.symlink(data, filename)
-        else:
-            try:
-                if os.path.islink(self.wjoin(filename)):
-                    os.unlink(filename)
-            except OSError:
-                pass
-            self.wopener(filename, 'w').write(data)
-
-            if self.is_exec:
-                was_exec = self.is_exec(self.wjoin(filename))
-            else:
-                # On filesystems not supporting execute-bit, there is no way
-                # to know if it is set but asking subversion. Setting it
-                # systematically is just as expensive and much simpler.
-                was_exec = 'x' not in flags
-
-            util.set_flags(self.wjoin(filename), False, 'x' in flags)
-            if was_exec:
-                if 'x' not in flags:
-                    self.delexec.append(filename)
-            else:
-                if 'x' in flags:
-                    self.setexec.append(filename)
-
-    def _copyfile(self, source, dest):
-        # SVN's copy command pukes if the destination file exists, but
-        # our copyfile method expects to record a copy that has
-        # already occurred.  Cross the semantic gap.
-        wdest = self.wjoin(dest)
-        exists = os.path.exists(wdest)
-        if exists:
-            fd, tempname = tempfile.mkstemp(
-                prefix='hg-copy-', dir=os.path.dirname(wdest))
-            os.close(fd)
-            os.unlink(tempname)
-            os.rename(wdest, tempname)
-        try:
-            self.run0('copy', source, dest)
-        finally:
-            if exists:
-                try:
-                    os.unlink(wdest)
-                except OSError:
-                    pass
-                os.rename(tempname, wdest)
-
-    def dirs_of(self, files):
-        dirs = set()
-        for f in files:
-            if os.path.isdir(self.wjoin(f)):
-                dirs.add(f)
-            for i in strutil.rfindall(f, '/'):
-                dirs.add(f[:i])
-        return dirs
-
-    def add_dirs(self, files):
-        add_dirs = [d for d in sorted(self.dirs_of(files))
-                    if not os.path.exists(self.wjoin(d, '.svn', 'entries'))]
-        if add_dirs:
-            self.xargs(add_dirs, 'add', non_recursive=True, quiet=True)
-        return add_dirs
-
-    def add_files(self, files):
-        if files:
-            self.xargs(files, 'add', quiet=True)
-        return files
-
-    def tidy_dirs(self, names):
-        deleted = []
-        for d in sorted(self.dirs_of(names), reverse=True):
-            wd = self.wjoin(d)
-            if os.listdir(wd) == '.svn':
-                self.run0('delete', d)
-                deleted.append(d)
-        return deleted
-
-    def addchild(self, parent, child):
-        self.childmap[parent] = child
-
-    def revid(self, rev):
-        return u"svn:%s@%s" % (self.uuid, rev)
-
-    def putcommit(self, files, copies, parents, commit, source, revmap):
-        # Apply changes to working copy
-        for f, v in files:
-            try:
-                data = source.getfile(f, v)
-            except IOError:
-                self.delete.append(f)
-            else:
-                e = source.getmode(f, v)
-                self.putfile(f, e, data)
-                if f in copies:
-                    self.copies.append([copies[f], f])
-        files = [f[0] for f in files]
-
-        for parent in parents:
-            try:
-                return self.revid(self.childmap[parent])
-            except KeyError:
-                pass
-        entries = set(self.delete)
-        files = frozenset(files)
-        entries.update(self.add_dirs(files.difference(entries)))
-        if self.copies:
-            for s, d in self.copies:
-                self._copyfile(s, d)
-            self.copies = []
-        if self.delete:
-            self.xargs(self.delete, 'delete')
-            self.delete = []
-        entries.update(self.add_files(files.difference(entries)))
-        entries.update(self.tidy_dirs(entries))
-        if self.delexec:
-            self.xargs(self.delexec, 'propdel', 'svn:executable')
-            self.delexec = []
-        if self.setexec:
-            self.xargs(self.setexec, 'propset', 'svn:executable', '*')
-            self.setexec = []
-
-        fd, messagefile = tempfile.mkstemp(prefix='hg-convert-')
-        fp = os.fdopen(fd, 'w')
-        fp.write(commit.desc)
-        fp.close()
-        try:
-            output = self.run0('commit',
-                               username=util.shortuser(commit.author),
-                               file=messagefile,
-                               encoding='utf-8')
-            try:
-                rev = self.commit_re.search(output).group(1)
-            except AttributeError:
-                self.ui.warn(_('unexpected svn output:\n'))
-                self.ui.warn(output)
-                raise util.Abort(_('unable to cope with svn output'))
-            if commit.rev:
-                self.run('propset', 'hg:convert-rev', commit.rev,
-                         revprop=True, revision=rev)
-            if commit.branch and commit.branch != 'default':
-                self.run('propset', 'hg:convert-branch', commit.branch,
-                         revprop=True, revision=rev)
-            for parent in parents:
-                self.addchild(parent, rev)
-            return self.revid(rev)
-        finally:
-            os.unlink(messagefile)
-
-    def puttags(self, tags):
-        self.ui.warn(_('XXX TAGS NOT IMPLEMENTED YET\n'))
--- a/sys/src/cmd/hg/hgext/convert/transport.py
+++ /dev/null
@@ -1,128 +1,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (C) 2007 Daniel Holth <dholth@fastmail.fm>
-# This is a stripped-down version of the original bzr-svn transport.py,
-# Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-from svn.core import SubversionException, Pool
-import svn.ra
-import svn.client
-import svn.core
-
-# Some older versions of the Python bindings need to be
-# explicitly initialized. But what we want to do probably
-# won't work worth a darn against those libraries anyway!
-svn.ra.initialize()
-
-svn_config = svn.core.svn_config_get_config(None)
-
-
-def _create_auth_baton(pool):
-    """Create a Subversion authentication baton. """
-    import svn.client
-    # Give the client context baton a suite of authentication
-    # providers.h
-    providers = [
-        svn.client.get_simple_provider(pool),
-        svn.client.get_username_provider(pool),
-        svn.client.get_ssl_client_cert_file_provider(pool),
-        svn.client.get_ssl_client_cert_pw_file_provider(pool),
-        svn.client.get_ssl_server_trust_file_provider(pool),
-        ]
-    # Platform-dependant authentication methods
-    getprovider = getattr(svn.core, 'svn_auth_get_platform_specific_provider',
-                          None)
-    if getprovider:
-        # Available in svn >= 1.6
-        for name in ('gnome_keyring', 'keychain', 'kwallet', 'windows'):
-            for type in ('simple', 'ssl_client_cert_pw', 'ssl_server_trust'):
-                p = getprovider(name, type, pool)
-                if p:
-                    providers.append(p)
-    else:
-        if hasattr(svn.client, 'get_windows_simple_provider'):
-            providers.append(svn.client.get_windows_simple_provider(pool))
-
-    return svn.core.svn_auth_open(providers, pool)
-
-class NotBranchError(SubversionException):
-    pass
-
-class SvnRaTransport(object):
-    """
-    Open an ra connection to a Subversion repository.
-    """
-    def __init__(self, url="", ra=None):
-        self.pool = Pool()
-        self.svn_url = url
-        self.username = ''
-        self.password = ''
-
-        # Only Subversion 1.4 has reparent()
-        if ra is None or not hasattr(svn.ra, 'reparent'):
-            self.client = svn.client.create_context(self.pool)
-            ab = _create_auth_baton(self.pool)
-            if False:
-                svn.core.svn_auth_set_parameter(
-                    ab, svn.core.SVN_AUTH_PARAM_DEFAULT_USERNAME, self.username)
-                svn.core.svn_auth_set_parameter(
-                    ab, svn.core.SVN_AUTH_PARAM_DEFAULT_PASSWORD, self.password)
-            self.client.auth_baton = ab
-            self.client.config = svn_config
-            try:
-                self.ra = svn.client.open_ra_session(
-                    self.svn_url.encode('utf8'),
-                    self.client, self.pool)
-            except SubversionException, (inst, num):
-                if num in (svn.core.SVN_ERR_RA_ILLEGAL_URL,
-                           svn.core.SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED,
-                           svn.core.SVN_ERR_BAD_URL):
-                    raise NotBranchError(url)
-                raise
-        else:
-            self.ra = ra
-            svn.ra.reparent(self.ra, self.svn_url.encode('utf8'))
-
-    class Reporter(object):
-        def __init__(self, (reporter, report_baton)):
-            self._reporter = reporter
-            self._baton = report_baton
-
-        def set_path(self, path, revnum, start_empty, lock_token, pool=None):
-            svn.ra.reporter2_invoke_set_path(self._reporter, self._baton,
-                        path, revnum, start_empty, lock_token, pool)
-
-        def delete_path(self, path, pool=None):
-            svn.ra.reporter2_invoke_delete_path(self._reporter, self._baton,
-                    path, pool)
-
-        def link_path(self, path, url, revision, start_empty, lock_token,
-                      pool=None):
-            svn.ra.reporter2_invoke_link_path(self._reporter, self._baton,
-                    path, url, revision, start_empty, lock_token,
-                    pool)
-
-        def finish_report(self, pool=None):
-            svn.ra.reporter2_invoke_finish_report(self._reporter,
-                    self._baton, pool)
-
-        def abort_report(self, pool=None):
-            svn.ra.reporter2_invoke_abort_report(self._reporter,
-                    self._baton, pool)
-
-    def do_update(self, revnum, path, *args, **kwargs):
-        return self.Reporter(svn.ra.do_update(self.ra, revnum, path, *args, **kwargs))
--- a/sys/src/cmd/hg/hgext/inotify/linux/__init__.py
+++ /dev/null
@@ -1,41 +1,0 @@
-# __init__.py - low-level interfaces to the Linux inotify subsystem
-
-# Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
-
-# This library is free software; you can redistribute it and/or modify
-# it under the terms of version 2.1 of the GNU Lesser General Public
-# License, incorporated herein by reference.
-
-'''Low-level interface to the Linux inotify subsystem.
-
-The inotify subsystem provides an efficient mechanism for file status
-monitoring and change notification.
-
-This package provides the low-level inotify system call interface and
-associated constants and helper functions.
-
-For a higher-level interface that remains highly efficient, use the
-inotify.watcher package.'''
-
-__author__ = "Bryan O'Sullivan <bos@serpentine.com>"
-
-from _inotify import *
-
-procfs_path = '/proc/sys/fs/inotify'
-
-def _read_procfs_value(name):
-    def read_value():
-        try:
-            return int(open(procfs_path + '/' + name).read())
-        except OSError:
-            return None
-
-    read_value.__doc__ = '''Return the value of the %s setting from /proc.
-
-    If inotify is not enabled on this system, return None.''' % name
-
-    return read_value
-
-max_queued_events = _read_procfs_value('max_queued_events')
-max_user_instances = _read_procfs_value('max_user_instances')
-max_user_watches = _read_procfs_value('max_user_watches')
--- a/sys/src/cmd/hg/hgext/inotify/linux/_inotify.c
+++ /dev/null
@@ -1,608 +1,0 @@
-/*
- * _inotify.c - Python extension interfacing to the Linux inotify subsystem
- *
- * Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of version 2.1 of the GNU Lesser General
- * Public License, incorporated herein by reference.
- */
-
-#include <Python.h>
-#include <alloca.h>
-#include <sys/inotify.h>
-#include <stdint.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-static PyObject *init(PyObject *self, PyObject *args)
-{
-    PyObject *ret = NULL;
-    int fd = -1;
-
-     if (!PyArg_ParseTuple(args, ":init"))
-	goto bail;
-
-    Py_BEGIN_ALLOW_THREADS
-    fd = inotify_init();
-    Py_END_ALLOW_THREADS
-
-    if (fd == -1) {
-	PyErr_SetFromErrno(PyExc_OSError);
-	goto bail;
-    }
-
-    ret = PyInt_FromLong(fd);
-    if (ret == NULL)
-	goto bail;
-
-    goto done;
-
-bail:
-    if (fd != -1)
-	close(fd);
-
-    Py_CLEAR(ret);
-
-done:
-    return ret;
-}
-
-PyDoc_STRVAR(
-    init_doc,
-    "init() -> fd\n"
-    "\n"
-    "Initialise an inotify instance.\n"
-    "Return a file descriptor associated with a new inotify event queue.");
-
-static PyObject *add_watch(PyObject *self, PyObject *args)
-{
-    PyObject *ret = NULL;
-    uint32_t mask;
-    int wd = -1;
-    char *path;
-    int fd;
-
-    if (!PyArg_ParseTuple(args, "isI:add_watch", &fd, &path, &mask))
-	goto bail;
-
-    Py_BEGIN_ALLOW_THREADS
-    wd = inotify_add_watch(fd, path, mask);
-    Py_END_ALLOW_THREADS
-
-    if (wd == -1) {
-	PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-	goto bail;
-    }
-
-    ret = PyInt_FromLong(wd);
-    if (ret == NULL)
-	goto bail;
-
-    goto done;
-
-bail:
-    if (wd != -1)
-	inotify_rm_watch(fd, wd);
-
-    Py_CLEAR(ret);
-
-done:
-    return ret;
-}
-
-PyDoc_STRVAR(
-    add_watch_doc,
-    "add_watch(fd, path, mask) -> wd\n"
-    "\n"
-    "Add a watch to an inotify instance, or modify an existing watch.\n"
-    "\n"
-    "        fd: file descriptor returned by init()\n"
-    "        path: path to watch\n"
-    "        mask: mask of events to watch for\n"
-    "\n"
-    "Return a unique numeric watch descriptor for the inotify instance\n"
-    "mapped by the file descriptor.");
-
-static PyObject *remove_watch(PyObject *self, PyObject *args)
-{
-    PyObject *ret = NULL;
-    uint32_t wd;
-    int fd;
-    int r;
-
-    if (!PyArg_ParseTuple(args, "iI:remove_watch", &fd, &wd))
-	goto bail;
-
-    Py_BEGIN_ALLOW_THREADS
-    r = inotify_rm_watch(fd, wd);
-    Py_END_ALLOW_THREADS
-
-    if (r == -1) {
-	PyErr_SetFromErrno(PyExc_OSError);
-	goto bail;
-    }
-
-    Py_INCREF(Py_None);
-
-    goto done;
-
-bail:
-    Py_CLEAR(ret);
-
-done:
-    return ret;
-}
-
-PyDoc_STRVAR(
-    remove_watch_doc,
-    "remove_watch(fd, wd)\n"
-    "\n"
-    "        fd: file descriptor returned by init()\n"
-    "        wd: watch descriptor returned by add_watch()\n"
-    "\n"
-    "Remove a watch associated with the watch descriptor wd from the\n"
-    "inotify instance associated with the file descriptor fd.\n"
-    "\n"
-    "Removing a watch causes an IN_IGNORED event to be generated for this\n"
-    "watch descriptor.");
-
-#define bit_name(x) {x, #x}
-
-static struct {
-    int bit;
-    const char *name;
-    PyObject *pyname;
-} bit_names[] = {
-    bit_name(IN_ACCESS),
-    bit_name(IN_MODIFY),
-    bit_name(IN_ATTRIB),
-    bit_name(IN_CLOSE_WRITE),
-    bit_name(IN_CLOSE_NOWRITE),
-    bit_name(IN_OPEN),
-    bit_name(IN_MOVED_FROM),
-    bit_name(IN_MOVED_TO),
-    bit_name(IN_CREATE),
-    bit_name(IN_DELETE),
-    bit_name(IN_DELETE_SELF),
-    bit_name(IN_MOVE_SELF),
-    bit_name(IN_UNMOUNT),
-    bit_name(IN_Q_OVERFLOW),
-    bit_name(IN_IGNORED),
-    bit_name(IN_ONLYDIR),
-    bit_name(IN_DONT_FOLLOW),
-    bit_name(IN_MASK_ADD),
-    bit_name(IN_ISDIR),
-    bit_name(IN_ONESHOT),
-    {0}
-};
-
-static PyObject *decode_mask(int mask)
-{
-    PyObject *ret = PyList_New(0);
-    int i;
-
-    if (ret == NULL)
-	goto bail;
-
-    for (i = 0; bit_names[i].bit; i++) {
-	if (mask & bit_names[i].bit) {
-	    if (bit_names[i].pyname == NULL) {
-		bit_names[i].pyname = PyString_FromString(bit_names[i].name);
-		if (bit_names[i].pyname == NULL)
-		    goto bail;
-	    }
-	    Py_INCREF(bit_names[i].pyname);
-	    if (PyList_Append(ret, bit_names[i].pyname) == -1)
-		goto bail;
-	}
-    }
-
-    goto done;
-
-bail:
-    Py_CLEAR(ret);
-
-done:
-    return ret;
-}
-
-static PyObject *pydecode_mask(PyObject *self, PyObject *args)
-{
-    int mask;
-
-    if (!PyArg_ParseTuple(args, "i:decode_mask", &mask))
-	return NULL;
-
-    return decode_mask(mask);
-}
-
-PyDoc_STRVAR(
-    decode_mask_doc,
-    "decode_mask(mask) -> list_of_strings\n"
-    "\n"
-    "Decode an inotify mask value into a list of strings that give the\n"
-    "name of each bit set in the mask.");
-
-static char doc[] = "Low-level inotify interface wrappers.";
-
-static void define_const(PyObject *dict, const char *name, uint32_t val)
-{
-    PyObject *pyval = PyInt_FromLong(val);
-    PyObject *pyname = PyString_FromString(name);
-
-    if (!pyname || !pyval)
-	goto bail;
-
-    PyDict_SetItem(dict, pyname, pyval);
-
-bail:
-    Py_XDECREF(pyname);
-    Py_XDECREF(pyval);
-}
-
-static void define_consts(PyObject *dict)
-{
-    define_const(dict, "IN_ACCESS", IN_ACCESS);
-    define_const(dict, "IN_MODIFY", IN_MODIFY);
-    define_const(dict, "IN_ATTRIB", IN_ATTRIB);
-    define_const(dict, "IN_CLOSE_WRITE", IN_CLOSE_WRITE);
-    define_const(dict, "IN_CLOSE_NOWRITE", IN_CLOSE_NOWRITE);
-    define_const(dict, "IN_OPEN", IN_OPEN);
-    define_const(dict, "IN_MOVED_FROM", IN_MOVED_FROM);
-    define_const(dict, "IN_MOVED_TO", IN_MOVED_TO);
-
-    define_const(dict, "IN_CLOSE", IN_CLOSE);
-    define_const(dict, "IN_MOVE", IN_MOVE);
-
-    define_const(dict, "IN_CREATE", IN_CREATE);
-    define_const(dict, "IN_DELETE", IN_DELETE);
-    define_const(dict, "IN_DELETE_SELF", IN_DELETE_SELF);
-    define_const(dict, "IN_MOVE_SELF", IN_MOVE_SELF);
-    define_const(dict, "IN_UNMOUNT", IN_UNMOUNT);
-    define_const(dict, "IN_Q_OVERFLOW", IN_Q_OVERFLOW);
-    define_const(dict, "IN_IGNORED", IN_IGNORED);
-
-    define_const(dict, "IN_ONLYDIR", IN_ONLYDIR);
-    define_const(dict, "IN_DONT_FOLLOW", IN_DONT_FOLLOW);
-    define_const(dict, "IN_MASK_ADD", IN_MASK_ADD);
-    define_const(dict, "IN_ISDIR", IN_ISDIR);
-    define_const(dict, "IN_ONESHOT", IN_ONESHOT);
-    define_const(dict, "IN_ALL_EVENTS", IN_ALL_EVENTS);
-}
-
-struct event {
-    PyObject_HEAD
-    PyObject *wd;
-    PyObject *mask;
-    PyObject *cookie;
-    PyObject *name;
-};
-
-static PyObject *event_wd(PyObject *self, void *x)
-{
-    struct event *evt = (struct event *) self;
-    Py_INCREF(evt->wd);
-    return evt->wd;
-}
-
-static PyObject *event_mask(PyObject *self, void *x)
-{
-    struct event *evt = (struct event *) self;
-    Py_INCREF(evt->mask);
-    return evt->mask;
-}
-
-static PyObject *event_cookie(PyObject *self, void *x)
-{
-    struct event *evt = (struct event *) self;
-    Py_INCREF(evt->cookie);
-    return evt->cookie;
-}
-
-static PyObject *event_name(PyObject *self, void *x)
-{
-    struct event *evt = (struct event *) self;
-    Py_INCREF(evt->name);
-    return evt->name;
-}
-
-static struct PyGetSetDef event_getsets[] = {
-    {"wd", event_wd, NULL,
-     "watch descriptor"},
-    {"mask", event_mask, NULL,
-     "event mask"},
-    {"cookie", event_cookie, NULL,
-     "rename cookie, if rename-related event"},
-    {"name", event_name, NULL,
-     "file name"},
-    {NULL}
-};
-
-PyDoc_STRVAR(
-    event_doc,
-    "event: Structure describing an inotify event.");
-
-static PyObject *event_new(PyTypeObject *t, PyObject *a, PyObject *k)
-{
-    return (*t->tp_alloc)(t, 0);
-}
-
-static void event_dealloc(struct event *evt)
-{
-    Py_XDECREF(evt->wd);
-    Py_XDECREF(evt->mask);
-    Py_XDECREF(evt->cookie);
-    Py_XDECREF(evt->name);
-
-    (*evt->ob_type->tp_free)(evt);
-}
-
-static PyObject *event_repr(struct event *evt)
-{
-    int wd = PyInt_AsLong(evt->wd);
-    int cookie = evt->cookie == Py_None ? -1 : PyInt_AsLong(evt->cookie);
-    PyObject *ret = NULL, *pymasks = NULL, *pymask = NULL;
-    PyObject *join = NULL;
-    char *maskstr;
-
-    join = PyString_FromString("|");
-    if (join == NULL)
-	goto bail;
-
-    pymasks = decode_mask(PyInt_AsLong(evt->mask));
-    if (pymasks == NULL)
-	goto bail;
-
-    pymask = _PyString_Join(join, pymasks);
-    if (pymask == NULL)
-	goto bail;
-
-    maskstr = PyString_AsString(pymask);
-
-    if (evt->name != Py_None) {
-	PyObject *pyname = PyString_Repr(evt->name, 1);
-	char *name = pyname ? PyString_AsString(pyname) : "???";
-
-	if (cookie == -1)
-	    ret = PyString_FromFormat("event(wd=%d, mask=%s, name=%s)",
-				      wd, maskstr, name);
-	else
-	    ret = PyString_FromFormat("event(wd=%d, mask=%s, "
-				      "cookie=0x%x, name=%s)",
-				      wd, maskstr, cookie, name);
-
-	Py_XDECREF(pyname);
-    } else {
-	if (cookie == -1)
-	    ret = PyString_FromFormat("event(wd=%d, mask=%s)",
-				      wd, maskstr);
-	else {
-	    ret = PyString_FromFormat("event(wd=%d, mask=%s, cookie=0x%x)",
-				      wd, maskstr, cookie);
-	}
-    }
-
-    goto done;
-bail:
-    Py_CLEAR(ret);
-
-done:
-    Py_XDECREF(pymask);
-    Py_XDECREF(pymasks);
-    Py_XDECREF(join);
-
-    return ret;
-}
-
-static PyTypeObject event_type = {
-    PyObject_HEAD_INIT(NULL)
-    0,                         /*ob_size*/
-    "_inotify.event",             /*tp_name*/
-    sizeof(struct event), /*tp_basicsize*/
-    0,                         /*tp_itemsize*/
-    (destructor)event_dealloc, /*tp_dealloc*/
-    0,                         /*tp_print*/
-    0,                         /*tp_getattr*/
-    0,                         /*tp_setattr*/
-    0,                         /*tp_compare*/
-    (reprfunc)event_repr,      /*tp_repr*/
-    0,                         /*tp_as_number*/
-    0,                         /*tp_as_sequence*/
-    0,                         /*tp_as_mapping*/
-    0,                         /*tp_hash */
-    0,                         /*tp_call*/
-    0,                         /*tp_str*/
-    0,                         /*tp_getattro*/
-    0,                         /*tp_setattro*/
-    0,                         /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-    event_doc,           /* tp_doc */
-    0,                         /* tp_traverse */
-    0,                         /* tp_clear */
-    0,                         /* tp_richcompare */
-    0,                         /* tp_weaklistoffset */
-    0,                         /* tp_iter */
-    0,                         /* tp_iternext */
-    0,                         /* tp_methods */
-    0,                         /* tp_members */
-    event_getsets,      /* tp_getset */
-    0,                         /* tp_base */
-    0,                         /* tp_dict */
-    0,                         /* tp_descr_get */
-    0,                         /* tp_descr_set */
-    0,                         /* tp_dictoffset */
-    0,                         /* tp_init */
-    0,                         /* tp_alloc */
-    event_new,          /* tp_new */
-};
-
-PyObject *read_events(PyObject *self, PyObject *args)
-{
-    PyObject *ctor_args = NULL;
-    PyObject *pybufsize = NULL;
-    PyObject *ret = NULL;
-    int bufsize = 65536;
-    char *buf = NULL;
-    int nread, pos;
-    int fd;
-
-    if (!PyArg_ParseTuple(args, "i|O:read", &fd, &pybufsize))
-	goto bail;
-
-    if (pybufsize && pybufsize != Py_None)
-	bufsize = PyInt_AsLong(pybufsize);
-
-    ret = PyList_New(0);
-    if (ret == NULL)
-	goto bail;
-
-    if (bufsize <= 0) {
-	int r;
-
-	Py_BEGIN_ALLOW_THREADS
-	r = ioctl(fd, FIONREAD, &bufsize);
-	Py_END_ALLOW_THREADS
-
-	if (r == -1) {
-	    PyErr_SetFromErrno(PyExc_OSError);
-	    goto bail;
-	}
-	if (bufsize == 0)
-	    goto done;
-    }
-    else {
-	static long name_max;
-	static long name_fd = -1;
-	long min;
-
-	if (name_fd != fd) {
-	    name_fd = fd;
-	    Py_BEGIN_ALLOW_THREADS
-	    name_max = fpathconf(fd, _PC_NAME_MAX);
-	    Py_END_ALLOW_THREADS
-	}
-
-	min = sizeof(struct inotify_event) + name_max + 1;
-
-	if (bufsize < min) {
-	    PyErr_Format(PyExc_ValueError, "bufsize must be at least %d",
-			 (int) min);
-	    goto bail;
-	}
-    }
-
-    buf = alloca(bufsize);
-
-    Py_BEGIN_ALLOW_THREADS
-    nread = read(fd, buf, bufsize);
-    Py_END_ALLOW_THREADS
-
-    if (nread == -1) {
-	PyErr_SetFromErrno(PyExc_OSError);
-	goto bail;
-    }
-
-    ctor_args = PyTuple_New(0);
-
-    if (ctor_args == NULL)
-	goto bail;
-
-    pos = 0;
-
-    while (pos < nread) {
-	struct inotify_event *in = (struct inotify_event *) (buf + pos);
-	struct event *evt;
-	PyObject *obj;
-
-	obj = PyObject_CallObject((PyObject *) &event_type, ctor_args);
-
-	if (obj == NULL)
-	    goto bail;
-
-	evt = (struct event *) obj;
-
-	evt->wd = PyInt_FromLong(in->wd);
-	evt->mask = PyInt_FromLong(in->mask);
-	if (in->mask & IN_MOVE)
-	    evt->cookie = PyInt_FromLong(in->cookie);
-	else {
-	    Py_INCREF(Py_None);
-	    evt->cookie = Py_None;
-	}
-	if (in->len)
-	    evt->name = PyString_FromString(in->name);
-	else {
-	    Py_INCREF(Py_None);
-	    evt->name = Py_None;
-	}
-
-	if (!evt->wd || !evt->mask || !evt->cookie || !evt->name)
-	    goto mybail;
-
-	if (PyList_Append(ret, obj) == -1)
-	    goto mybail;
-
-	pos += sizeof(struct inotify_event) + in->len;
-	continue;
-
-    mybail:
-	Py_CLEAR(evt->wd);
-	Py_CLEAR(evt->mask);
-	Py_CLEAR(evt->cookie);
-	Py_CLEAR(evt->name);
-	Py_DECREF(obj);
-
-	goto bail;
-    }
-
-    goto done;
-
-bail:
-    Py_CLEAR(ret);
-
-done:
-    Py_XDECREF(ctor_args);
-
-    return ret;
-}
-
-PyDoc_STRVAR(
-    read_doc,
-    "read(fd, bufsize[=65536]) -> list_of_events\n"
-    "\n"
-    "\nRead inotify events from a file descriptor.\n"
-    "\n"
-    "        fd: file descriptor returned by init()\n"
-    "        bufsize: size of buffer to read into, in bytes\n"
-    "\n"
-    "Return a list of event objects.\n"
-    "\n"
-    "If bufsize is > 0, block until events are available to be read.\n"
-    "Otherwise, immediately return all events that can be read without\n"
-    "blocking.");
-
-
-static PyMethodDef methods[] = {
-    {"init", init, METH_VARARGS, init_doc},
-    {"add_watch", add_watch, METH_VARARGS, add_watch_doc},
-    {"remove_watch", remove_watch, METH_VARARGS, remove_watch_doc},
-    {"read", read_events, METH_VARARGS, read_doc},
-    {"decode_mask", pydecode_mask, METH_VARARGS, decode_mask_doc},
-    {NULL},
-};
-
-void init_inotify(void)
-{
-    PyObject *mod, *dict;
-
-    if (PyType_Ready(&event_type) == -1)
-	return;
-
-    mod = Py_InitModule3("_inotify", methods, doc);
-
-    dict = PyModule_GetDict(mod);
-
-    if (dict)
-	define_consts(dict);
-}
--- a/sys/src/cmd/hg/hgext/inotify/linux/watcher.py
+++ /dev/null
@@ -1,335 +1,0 @@
-# watcher.py - high-level interfaces to the Linux inotify subsystem
-
-# Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
-
-# This library is free software; you can redistribute it and/or modify
-# it under the terms of version 2.1 of the GNU Lesser General Public
-# License, incorporated herein by reference.
-
-'''High-level interfaces to the Linux inotify subsystem.
-
-The inotify subsystem provides an efficient mechanism for file status
-monitoring and change notification.
-
-The watcher class hides the low-level details of the inotify
-interface, and provides a Pythonic wrapper around it.  It generates
-events that provide somewhat more information than raw inotify makes
-available.
-
-The autowatcher class is more useful, as it automatically watches
-newly-created directories on your behalf.'''
-
-__author__ = "Bryan O'Sullivan <bos@serpentine.com>"
-
-import _inotify as inotify
-import array
-import errno
-import fcntl
-import os
-import termios
-
-
-class event(object):
-    '''Derived inotify event class.
-
-    The following fields are available:
-
-        mask: event mask, indicating what kind of event this is
-
-        cookie: rename cookie, if a rename-related event
-
-        path: path of the directory in which the event occurred
-
-        name: name of the directory entry to which the event occurred
-        (may be None if the event happened to a watched directory)
-
-        fullpath: complete path at which the event occurred
-
-        wd: watch descriptor that triggered this event'''
-
-    __slots__ = (
-        'cookie',
-        'fullpath',
-        'mask',
-        'name',
-        'path',
-        'raw',
-        'wd',
-        )
-
-    def __init__(self, raw, path):
-        self.path = path
-        self.raw = raw
-        if raw.name:
-            self.fullpath = path + '/' + raw.name
-        else:
-            self.fullpath = path
-
-        self.wd = raw.wd
-        self.mask = raw.mask
-        self.cookie = raw.cookie
-        self.name = raw.name
-
-    def __repr__(self):
-        r = repr(self.raw)
-        return 'event(path=' + repr(self.path) + ', ' + r[r.find('(')+1:]
-
-
-_event_props = {
-    'access': 'File was accessed',
-    'modify': 'File was modified',
-    'attrib': 'Attribute of a directory entry was changed',
-    'close_write': 'File was closed after being written to',
-    'close_nowrite': 'File was closed without being written to',
-    'open': 'File was opened',
-    'moved_from': 'Directory entry was renamed from this name',
-    'moved_to': 'Directory entry was renamed to this name',
-    'create': 'Directory entry was created',
-    'delete': 'Directory entry was deleted',
-    'delete_self': 'The watched directory entry was deleted',
-    'move_self': 'The watched directory entry was renamed',
-    'unmount': 'Directory was unmounted, and can no longer be watched',
-    'q_overflow': 'Kernel dropped events due to queue overflow',
-    'ignored': 'Directory entry is no longer being watched',
-    'isdir': 'Event occurred on a directory',
-    }
-
-for k, v in _event_props.iteritems():
-    mask = getattr(inotify, 'IN_' + k.upper())
-    def getter(self):
-        return self.mask & mask
-    getter.__name__ = k
-    getter.__doc__ = v
-    setattr(event, k, property(getter, doc=v))
-
-del _event_props
-
-
-class watcher(object):
-    '''Provide a Pythonic interface to the low-level inotify API.
-
-    Also adds derived information to each event that is not available
-    through the normal inotify API, such as directory name.'''
-
-    __slots__ = (
-        'fd',
-        '_paths',
-        '_wds',
-        )
-
-    def __init__(self):
-        '''Create a new inotify instance.'''
-
-        self.fd = inotify.init()
-        self._paths = {}
-        self._wds = {}
-
-    def fileno(self):
-        '''Return the file descriptor this watcher uses.
-
-        Useful for passing to select and poll.'''
-
-        return self.fd
-
-    def add(self, path, mask):
-        '''Add or modify a watch.
-
-        Return the watch descriptor added or modified.'''
-
-        path = os.path.normpath(path)
-        wd = inotify.add_watch(self.fd, path, mask)
-        self._paths[path] = wd, mask
-        self._wds[wd] = path, mask
-        return wd
-
-    def remove(self, wd):
-        '''Remove the given watch.'''
-
-        inotify.remove_watch(self.fd, wd)
-        self._remove(wd)
-
-    def _remove(self, wd):
-        path_mask = self._wds.pop(wd, None)
-        if path_mask is not None:
-            self._paths.pop(path_mask[0])
-
-    def path(self, path):
-        '''Return a (watch descriptor, event mask) pair for the given path.
-
-        If the path is not being watched, return None.'''
-
-        return self._paths.get(path)
-
-    def wd(self, wd):
-        '''Return a (path, event mask) pair for the given watch descriptor.
-
-        If the watch descriptor is not valid or not associated with
-        this watcher, return None.'''
-
-        return self._wds.get(wd)
-
-    def read(self, bufsize=None):
-        '''Read a list of queued inotify events.
-
-        If bufsize is zero, only return those events that can be read
-        immediately without blocking.  Otherwise, block until events are
-        available.'''
-
-        events = []
-        for evt in inotify.read(self.fd, bufsize):
-            events.append(event(evt, self._wds[evt.wd][0]))
-            if evt.mask & inotify.IN_IGNORED:
-                self._remove(evt.wd)
-            elif evt.mask & inotify.IN_UNMOUNT:
-                self.close()
-        return events
-
-    def close(self):
-        '''Shut down this watcher.
-
-        All subsequent method calls are likely to raise exceptions.'''
-
-        os.close(self.fd)
-        self.fd = None
-        self._paths = None
-        self._wds = None
-
-    def __len__(self):
-        '''Return the number of active watches.'''
-
-        return len(self._paths)
-
-    def __iter__(self):
-        '''Yield a (path, watch descriptor, event mask) tuple for each
-        entry being watched.'''
-
-        for path, (wd, mask) in self._paths.iteritems():
-            yield path, wd, mask
-
-    def __del__(self):
-        if self.fd is not None:
-            os.close(self.fd)
-
-    ignored_errors = [errno.ENOENT, errno.EPERM, errno.ENOTDIR]
-
-    def add_iter(self, path, mask, onerror=None):
-        '''Add or modify watches over path and its subdirectories.
-
-        Yield each added or modified watch descriptor.
-
-        To ensure that this method runs to completion, you must
-        iterate over all of its results, even if you do not care what
-        they are.  For example:
-
-            for wd in w.add_iter(path, mask):
-                pass
-
-        By default, errors are ignored.  If optional arg "onerror" is
-        specified, it should be a function; it will be called with one
-        argument, an OSError instance.  It can report the error to
-        continue with the walk, or raise the exception to abort the
-        walk.'''
-
-        # Add the IN_ONLYDIR flag to the event mask, to avoid a possible
-        # race when adding a subdirectory.  In the time between the
-        # event being queued by the kernel and us processing it, the
-        # directory may have been deleted, or replaced with a different
-        # kind of entry with the same name.
-
-        submask = mask | inotify.IN_ONLYDIR
-
-        try:
-            yield self.add(path, mask)
-        except OSError, err:
-            if onerror and err.errno not in self.ignored_errors:
-                onerror(err)
-        for root, dirs, names in os.walk(path, topdown=False, onerror=onerror):
-            for d in dirs:
-                try:
-                    yield self.add(root + '/' + d, submask)
-                except OSError, err:
-                    if onerror and err.errno not in self.ignored_errors:
-                        onerror(err)
-
-    def add_all(self, path, mask, onerror=None):
-        '''Add or modify watches over path and its subdirectories.
-
-        Return a list of added or modified watch descriptors.
-
-        By default, errors are ignored.  If optional arg "onerror" is
-        specified, it should be a function; it will be called with one
-        argument, an OSError instance.  It can report the error to
-        continue with the walk, or raise the exception to abort the
-        walk.'''
-
-        return [w for w in self.add_iter(path, mask, onerror)]
-
-
-class autowatcher(watcher):
-    '''watcher class that automatically watches newly created directories.'''
-
-    __slots__ = (
-        'addfilter',
-        )
-
-    def __init__(self, addfilter=None):
-        '''Create a new inotify instance.
-
-        This instance will automatically watch newly created
-        directories.
-
-        If the optional addfilter parameter is not None, it must be a
-        callable that takes one parameter.  It will be called each time
-        a directory is about to be automatically watched.  If it returns
-        True, the directory will be watched if it still exists,
-        otherwise, it will beb skipped.'''
-
-        super(autowatcher, self).__init__()
-        self.addfilter = addfilter
-
-    _dir_create_mask = inotify.IN_ISDIR | inotify.IN_CREATE
-
-    def read(self, bufsize=None):
-        events = super(autowatcher, self).read(bufsize)
-        for evt in events:
-            if evt.mask & self._dir_create_mask == self._dir_create_mask:
-                if self.addfilter is None or self.addfilter(evt):
-                    parentmask = self._wds[evt.wd][1]
-                    # See note about race avoidance via IN_ONLYDIR above.
-                    mask = parentmask | inotify.IN_ONLYDIR
-                    try:
-                        self.add_all(evt.fullpath, mask)
-                    except OSError, err:
-                        if err.errno not in self.ignored_errors:
-                            raise
-        return events
-
-
-class threshold(object):
-    '''Class that indicates whether a file descriptor has reached a
-    threshold of readable bytes available.
-
-    This class is not thread-safe.'''
-
-    __slots__ = (
-        'fd',
-        'threshold',
-        '_iocbuf',
-        )
-
-    def __init__(self, fd, threshold=1024):
-        self.fd = fd
-        self.threshold = threshold
-        self._iocbuf = array.array('i', [0])
-
-    def readable(self):
-        '''Return the number of bytes readable on this file descriptor.'''
-
-        fcntl.ioctl(self.fd, termios.FIONREAD, self._iocbuf, True)
-        return self._iocbuf[0]
-
-    def __call__(self):
-        '''Indicate whether the number of readable bytes has met or
-        exceeded the threshold.'''
-
-        return self.readable() >= self.threshold
--- a/sys/src/cmd/hg/mercurial/hgweb/__init__.py
+++ /dev/null
@@ -1,16 +1,0 @@
-# hgweb/__init__.py - web interface to a mercurial repository
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import hgweb_mod, hgwebdir_mod
-
-def hgweb(*args, **kwargs):
-    return hgweb_mod.hgweb(*args, **kwargs)
-
-def hgwebdir(*args, **kwargs):
-    return hgwebdir_mod.hgwebdir(*args, **kwargs)
-
--- a/sys/src/cmd/hg/mercurial/hgweb/common.py
+++ /dev/null
@@ -1,105 +1,0 @@
-# hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import errno, mimetypes, os
-
-HTTP_OK = 200
-HTTP_BAD_REQUEST = 400
-HTTP_UNAUTHORIZED = 401
-HTTP_FORBIDDEN = 403
-HTTP_NOT_FOUND = 404
-HTTP_METHOD_NOT_ALLOWED = 405
-HTTP_SERVER_ERROR = 500
-
-class ErrorResponse(Exception):
-    def __init__(self, code, message=None, headers=[]):
-        Exception.__init__(self)
-        self.code = code
-        self.headers = headers
-        if message is not None:
-            self.message = message
-        else:
-            self.message = _statusmessage(code)
-
-def _statusmessage(code):
-    from BaseHTTPServer import BaseHTTPRequestHandler
-    responses = BaseHTTPRequestHandler.responses
-    return responses.get(code, ('Error', 'Unknown error'))[0]
-
-def statusmessage(code):
-    return '%d %s' % (code, _statusmessage(code))
-
-def get_mtime(repo_path):
-    store_path = os.path.join(repo_path, ".hg")
-    if not os.path.isdir(os.path.join(store_path, "data")):
-        store_path = os.path.join(store_path, "store")
-    cl_path = os.path.join(store_path, "00changelog.i")
-    if os.path.exists(cl_path):
-        return os.stat(cl_path).st_mtime
-    else:
-        return os.stat(store_path).st_mtime
-
-def staticfile(directory, fname, req):
-    """return a file inside directory with guessed Content-Type header
-
-    fname always uses '/' as directory separator and isn't allowed to
-    contain unusual path components.
-    Content-Type is guessed using the mimetypes module.
-    Return an empty string if fname is illegal or file not found.
-
-    """
-    parts = fname.split('/')
-    for part in parts:
-        if (part in ('', os.curdir, os.pardir) or
-            os.sep in part or os.altsep is not None and os.altsep in part):
-            return ""
-    fpath = os.path.join(*parts)
-    if isinstance(directory, str):
-        directory = [directory]
-    for d in directory:
-        path = os.path.join(d, fpath)
-        if os.path.exists(path):
-            break
-    try:
-        os.stat(path)
-        ct = mimetypes.guess_type(path)[0] or "text/plain"
-        req.respond(HTTP_OK, ct, length = os.path.getsize(path))
-        return open(path, 'rb').read()
-    except TypeError:
-        raise ErrorResponse(HTTP_SERVER_ERROR, 'illegal filename')
-    except OSError, err:
-        if err.errno == errno.ENOENT:
-            raise ErrorResponse(HTTP_NOT_FOUND)
-        else:
-            raise ErrorResponse(HTTP_SERVER_ERROR, err.strerror)
-
-def paritygen(stripecount, offset=0):
-    """count parity of horizontal stripes for easier reading"""
-    if stripecount and offset:
-        # account for offset, e.g. due to building the list in reverse
-        count = (stripecount + offset) % stripecount
-        parity = (stripecount + offset) / stripecount & 1
-    else:
-        count = 0
-        parity = 0
-    while True:
-        yield parity
-        count += 1
-        if stripecount and count >= stripecount:
-            parity = 1 - parity
-            count = 0
-
-def get_contact(config):
-    """Return repo contact information or empty string.
-
-    web.contact is the primary source, but if that is not set, try
-    ui.username or $EMAIL as a fallback to display something useful.
-    """
-    return (config("web", "contact") or
-            config("ui", "username") or
-            os.environ.get("EMAIL") or "")
--- a/sys/src/cmd/hg/mercurial/hgweb/hgweb_mod.py
+++ /dev/null
@@ -1,315 +1,0 @@
-# hgweb/hgweb_mod.py - Web interface for a repository.
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os
-from mercurial import ui, hg, hook, error, encoding, templater
-from common import get_mtime, ErrorResponse
-from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
-from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED
-from request import wsgirequest
-import webcommands, protocol, webutil
-
-perms = {
-    'changegroup': 'pull',
-    'changegroupsubset': 'pull',
-    'unbundle': 'push',
-    'stream_out': 'pull',
-}
-
-class hgweb(object):
-    def __init__(self, repo, name=None):
-        if isinstance(repo, str):
-            u = ui.ui()
-            u.setconfig('ui', 'report_untrusted', 'off')
-            u.setconfig('ui', 'interactive', 'off')
-            self.repo = hg.repository(u, repo)
-        else:
-            self.repo = repo
-
-        hook.redirect(True)
-        self.mtime = -1
-        self.reponame = name
-        self.archives = 'zip', 'gz', 'bz2'
-        self.stripecount = 1
-        # a repo owner may set web.templates in .hg/hgrc to get any file
-        # readable by the user running the CGI script
-        self.templatepath = self.config('web', 'templates')
-
-    # The CGI scripts are often run by a user different from the repo owner.
-    # Trust the settings from the .hg/hgrc files by default.
-    def config(self, section, name, default=None, untrusted=True):
-        return self.repo.ui.config(section, name, default,
-                                   untrusted=untrusted)
-
-    def configbool(self, section, name, default=False, untrusted=True):
-        return self.repo.ui.configbool(section, name, default,
-                                       untrusted=untrusted)
-
-    def configlist(self, section, name, default=None, untrusted=True):
-        return self.repo.ui.configlist(section, name, default,
-                                       untrusted=untrusted)
-
-    def refresh(self):
-        mtime = get_mtime(self.repo.root)
-        if mtime != self.mtime:
-            self.mtime = mtime
-            self.repo = hg.repository(self.repo.ui, self.repo.root)
-            self.maxchanges = int(self.config("web", "maxchanges", 10))
-            self.stripecount = int(self.config("web", "stripes", 1))
-            self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
-            self.maxfiles = int(self.config("web", "maxfiles", 10))
-            self.allowpull = self.configbool("web", "allowpull", True)
-            encoding.encoding = self.config("web", "encoding",
-                                            encoding.encoding)
-
-    def run(self):
-        if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
-            raise RuntimeError("This function is only intended to be "
-                               "called while running as a CGI script.")
-        import mercurial.hgweb.wsgicgi as wsgicgi
-        wsgicgi.launch(self)
-
-    def __call__(self, env, respond):
-        req = wsgirequest(env, respond)
-        return self.run_wsgi(req)
-
-    def run_wsgi(self, req):
-
-        self.refresh()
-
-        # work with CGI variables to create coherent structure
-        # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
-
-        req.url = req.env['SCRIPT_NAME']
-        if not req.url.endswith('/'):
-            req.url += '/'
-        if 'REPO_NAME' in req.env:
-            req.url += req.env['REPO_NAME'] + '/'
-
-        if 'PATH_INFO' in req.env:
-            parts = req.env['PATH_INFO'].strip('/').split('/')
-            repo_parts = req.env.get('REPO_NAME', '').split('/')
-            if parts[:len(repo_parts)] == repo_parts:
-                parts = parts[len(repo_parts):]
-            query = '/'.join(parts)
-        else:
-            query = req.env['QUERY_STRING'].split('&', 1)[0]
-            query = query.split(';', 1)[0]
-
-        # process this if it's a protocol request
-        # protocol bits don't need to create any URLs
-        # and the clients always use the old URL structure
-
-        cmd = req.form.get('cmd', [''])[0]
-        if cmd and cmd in protocol.__all__:
-            if query:
-                raise ErrorResponse(HTTP_NOT_FOUND)
-            try:
-                if cmd in perms:
-                    try:
-                        self.check_perm(req, perms[cmd])
-                    except ErrorResponse, inst:
-                        if cmd == 'unbundle':
-                            req.drain()
-                        raise
-                method = getattr(protocol, cmd)
-                return method(self.repo, req)
-            except ErrorResponse, inst:
-                req.respond(inst, protocol.HGTYPE)
-                if not inst.message:
-                    return []
-                return '0\n%s\n' % inst.message,
-
-        # translate user-visible url structure to internal structure
-
-        args = query.split('/', 2)
-        if 'cmd' not in req.form and args and args[0]:
-
-            cmd = args.pop(0)
-            style = cmd.rfind('-')
-            if style != -1:
-                req.form['style'] = [cmd[:style]]
-                cmd = cmd[style+1:]
-
-            # avoid accepting e.g. style parameter as command
-            if hasattr(webcommands, cmd):
-                req.form['cmd'] = [cmd]
-            else:
-                cmd = ''
-
-            if cmd == 'static':
-                req.form['file'] = ['/'.join(args)]
-            else:
-                if args and args[0]:
-                    node = args.pop(0)
-                    req.form['node'] = [node]
-                if args:
-                    req.form['file'] = args
-
-            if cmd == 'archive':
-                fn = req.form['node'][0]
-                for type_, spec in self.archive_specs.iteritems():
-                    ext = spec[2]
-                    if fn.endswith(ext):
-                        req.form['node'] = [fn[:-len(ext)]]
-                        req.form['type'] = [type_]
-
-        # process the web interface request
-
-        try:
-            tmpl = self.templater(req)
-            ctype = tmpl('mimetype', encoding=encoding.encoding)
-            ctype = templater.stringify(ctype)
-
-            # check read permissions non-static content
-            if cmd != 'static':
-                self.check_perm(req, None)
-
-            if cmd == '':
-                req.form['cmd'] = [tmpl.cache['default']]
-                cmd = req.form['cmd'][0]
-
-            if cmd not in webcommands.__all__:
-                msg = 'no such method: %s' % cmd
-                raise ErrorResponse(HTTP_BAD_REQUEST, msg)
-            elif cmd == 'file' and 'raw' in req.form.get('style', []):
-                self.ctype = ctype
-                content = webcommands.rawfile(self, req, tmpl)
-            else:
-                content = getattr(webcommands, cmd)(self, req, tmpl)
-                req.respond(HTTP_OK, ctype)
-
-            return content
-
-        except error.LookupError, err:
-            req.respond(HTTP_NOT_FOUND, ctype)
-            msg = str(err)
-            if 'manifest' not in msg:
-                msg = 'revision not found: %s' % err.name
-            return tmpl('error', error=msg)
-        except (error.RepoError, error.RevlogError), inst:
-            req.respond(HTTP_SERVER_ERROR, ctype)
-            return tmpl('error', error=str(inst))
-        except ErrorResponse, inst:
-            req.respond(inst, ctype)
-            return tmpl('error', error=inst.message)
-
-    def templater(self, req):
-
-        # determine scheme, port and server name
-        # this is needed to create absolute urls
-
-        proto = req.env.get('wsgi.url_scheme')
-        if proto == 'https':
-            proto = 'https'
-            default_port = "443"
-        else:
-            proto = 'http'
-            default_port = "80"
-
-        port = req.env["SERVER_PORT"]
-        port = port != default_port and (":" + port) or ""
-        urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
-        staticurl = self.config("web", "staticurl") or req.url + 'static/'
-        if not staticurl.endswith('/'):
-            staticurl += '/'
-
-        # some functions for the templater
-
-        def header(**map):
-            yield tmpl('header', encoding=encoding.encoding, **map)
-
-        def footer(**map):
-            yield tmpl("footer", **map)
-
-        def motd(**map):
-            yield self.config("web", "motd", "")
-
-        # figure out which style to use
-
-        vars = {}
-        style = self.config("web", "style", "paper")
-        if 'style' in req.form:
-            style = req.form['style'][0]
-            vars['style'] = style
-
-        start = req.url[-1] == '?' and '&' or '?'
-        sessionvars = webutil.sessionvars(vars, start)
-        mapfile = templater.stylemap(style, self.templatepath)
-
-        if not self.reponame:
-            self.reponame = (self.config("web", "name")
-                             or req.env.get('REPO_NAME')
-                             or req.url.strip('/') or self.repo.root)
-
-        # create the templater
-
-        tmpl = templater.templater(mapfile,
-                                   defaults={"url": req.url,
-                                             "staticurl": staticurl,
-                                             "urlbase": urlbase,
-                                             "repo": self.reponame,
-                                             "header": header,
-                                             "footer": footer,
-                                             "motd": motd,
-                                             "sessionvars": sessionvars
-                                            })
-        return tmpl
-
-    def archivelist(self, nodeid):
-        allowed = self.configlist("web", "allow_archive")
-        for i, spec in self.archive_specs.iteritems():
-            if i in allowed or self.configbool("web", "allow" + i):
-                yield {"type" : i, "extension" : spec[2], "node" : nodeid}
-
-    archive_specs = {
-        'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
-        'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
-        'zip': ('application/zip', 'zip', '.zip', None),
-        }
-
-    def check_perm(self, req, op):
-        '''Check permission for operation based on request data (including
-        authentication info). Return if op allowed, else raise an ErrorResponse
-        exception.'''
-
-        user = req.env.get('REMOTE_USER')
-
-        deny_read = self.configlist('web', 'deny_read')
-        if deny_read and (not user or deny_read == ['*'] or user in deny_read):
-            raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
-
-        allow_read = self.configlist('web', 'allow_read')
-        result = (not allow_read) or (allow_read == ['*'])
-        if not (result or user in allow_read):
-            raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
-
-        if op == 'pull' and not self.allowpull:
-            raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized')
-        elif op == 'pull' or op is None: # op is None for interface requests
-            return
-
-        # enforce that you can only push using POST requests
-        if req.env['REQUEST_METHOD'] != 'POST':
-            msg = 'push requires POST request'
-            raise ErrorResponse(HTTP_METHOD_NOT_ALLOWED, msg)
-
-        # require ssl by default for pushing, auth info cannot be sniffed
-        # and replayed
-        scheme = req.env.get('wsgi.url_scheme')
-        if self.configbool('web', 'push_ssl', True) and scheme != 'https':
-            raise ErrorResponse(HTTP_OK, 'ssl required')
-
-        deny = self.configlist('web', 'deny_push')
-        if deny and (not user or deny == ['*'] or user in deny):
-            raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
-
-        allow = self.configlist('web', 'allow_push')
-        result = allow and (allow == ['*'] or user in allow)
-        if not result:
-            raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
--- a/sys/src/cmd/hg/mercurial/hgweb/hgwebdir_mod.py
+++ /dev/null
@@ -1,333 +1,0 @@
-# hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os, re, time
-from mercurial.i18n import _
-from mercurial import ui, hg, util, templater
-from mercurial import error, encoding
-from common import ErrorResponse, get_mtime, staticfile, paritygen,\
-                   get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
-from hgweb_mod import hgweb
-from request import wsgirequest
-import webutil
-
-def cleannames(items):
-    return [(util.pconvert(name).strip('/'), path) for name, path in items]
-
-def findrepos(paths):
-    repos = {}
-    for prefix, root in cleannames(paths):
-        roothead, roottail = os.path.split(root)
-        # "foo = /bar/*" makes every subrepo of /bar/ to be
-        # mounted as foo/subrepo
-        # and "foo = /bar/**" also recurses into the subdirectories,
-        # remember to use it without working dir.
-        try:
-            recurse = {'*': False, '**': True}[roottail]
-        except KeyError:
-            repos[prefix] = root
-            continue
-        roothead = os.path.normpath(roothead)
-        for path in util.walkrepos(roothead, followsym=True, recurse=recurse):
-            path = os.path.normpath(path)
-            name = util.pconvert(path[len(roothead):]).strip('/')
-            if prefix:
-                name = prefix + '/' + name
-            repos[name] = path
-    return repos.items()
-
-class hgwebdir(object):
-    refreshinterval = 20
-
-    def __init__(self, conf, baseui=None):
-        self.conf = conf
-        self.baseui = baseui
-        self.lastrefresh = 0
-        self.refresh()
-
-    def refresh(self):
-        if self.lastrefresh + self.refreshinterval > time.time():
-            return
-
-        if self.baseui:
-            self.ui = self.baseui.copy()
-        else:
-            self.ui = ui.ui()
-            self.ui.setconfig('ui', 'report_untrusted', 'off')
-            self.ui.setconfig('ui', 'interactive', 'off')
-
-        if not isinstance(self.conf, (dict, list, tuple)):
-            map = {'paths': 'hgweb-paths'}
-            self.ui.readconfig(self.conf, remap=map, trust=True)
-            paths = self.ui.configitems('hgweb-paths')
-        elif isinstance(self.conf, (list, tuple)):
-            paths = self.conf
-        elif isinstance(self.conf, dict):
-            paths = self.conf.items()
-
-        encoding.encoding = self.ui.config('web', 'encoding',
-                                           encoding.encoding)
-        self.motd = self.ui.config('web', 'motd')
-        self.style = self.ui.config('web', 'style', 'paper')
-        self.stripecount = self.ui.config('web', 'stripes', 1)
-        if self.stripecount:
-            self.stripecount = int(self.stripecount)
-        self._baseurl = self.ui.config('web', 'baseurl')
-
-        self.repos = findrepos(paths)
-        for prefix, root in self.ui.configitems('collections'):
-            prefix = util.pconvert(prefix)
-            for path in util.walkrepos(root, followsym=True):
-                repo = os.path.normpath(path)
-                name = util.pconvert(repo)
-                if name.startswith(prefix):
-                    name = name[len(prefix):]
-                self.repos.append((name.lstrip('/'), repo))
-
-        self.repos.sort()
-        self.lastrefresh = time.time()
-
-    def run(self):
-        if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
-            raise RuntimeError("This function is only intended to be "
-                               "called while running as a CGI script.")
-        import mercurial.hgweb.wsgicgi as wsgicgi
-        wsgicgi.launch(self)
-
-    def __call__(self, env, respond):
-        req = wsgirequest(env, respond)
-        return self.run_wsgi(req)
-
-    def read_allowed(self, ui, req):
-        """Check allow_read and deny_read config options of a repo's ui object
-        to determine user permissions.  By default, with neither option set (or
-        both empty), allow all users to read the repo.  There are two ways a
-        user can be denied read access:  (1) deny_read is not empty, and the
-        user is unauthenticated or deny_read contains user (or *), and (2)
-        allow_read is not empty and the user is not in allow_read.  Return True
-        if user is allowed to read the repo, else return False."""
-
-        user = req.env.get('REMOTE_USER')
-
-        deny_read = ui.configlist('web', 'deny_read', untrusted=True)
-        if deny_read and (not user or deny_read == ['*'] or user in deny_read):
-            return False
-
-        allow_read = ui.configlist('web', 'allow_read', untrusted=True)
-        # by default, allow reading if no allow_read option has been set
-        if (not allow_read) or (allow_read == ['*']) or (user in allow_read):
-            return True
-
-        return False
-
-    def run_wsgi(self, req):
-        try:
-            try:
-                self.refresh()
-
-                virtual = req.env.get("PATH_INFO", "").strip('/')
-                tmpl = self.templater(req)
-                ctype = tmpl('mimetype', encoding=encoding.encoding)
-                ctype = templater.stringify(ctype)
-
-                # a static file
-                if virtual.startswith('static/') or 'static' in req.form:
-                    if virtual.startswith('static/'):
-                        fname = virtual[7:]
-                    else:
-                        fname = req.form['static'][0]
-                    static = templater.templatepath('static')
-                    return (staticfile(static, fname, req),)
-
-                # top-level index
-                elif not virtual:
-                    req.respond(HTTP_OK, ctype)
-                    return self.makeindex(req, tmpl)
-
-                # nested indexes and hgwebs
-
-                repos = dict(self.repos)
-                while virtual:
-                    real = repos.get(virtual)
-                    if real:
-                        req.env['REPO_NAME'] = virtual
-                        try:
-                            repo = hg.repository(self.ui, real)
-                            return hgweb(repo).run_wsgi(req)
-                        except IOError, inst:
-                            msg = inst.strerror
-                            raise ErrorResponse(HTTP_SERVER_ERROR, msg)
-                        except error.RepoError, inst:
-                            raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
-
-                    # browse subdirectories
-                    subdir = virtual + '/'
-                    if [r for r in repos if r.startswith(subdir)]:
-                        req.respond(HTTP_OK, ctype)
-                        return self.makeindex(req, tmpl, subdir)
-
-                    up = virtual.rfind('/')
-                    if up < 0:
-                        break
-                    virtual = virtual[:up]
-
-                # prefixes not found
-                req.respond(HTTP_NOT_FOUND, ctype)
-                return tmpl("notfound", repo=virtual)
-
-            except ErrorResponse, err:
-                req.respond(err, ctype)
-                return tmpl('error', error=err.message or '')
-        finally:
-            tmpl = None
-
-    def makeindex(self, req, tmpl, subdir=""):
-
-        def archivelist(ui, nodeid, url):
-            allowed = ui.configlist("web", "allow_archive", untrusted=True)
-            for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
-                if i[0] in allowed or ui.configbool("web", "allow" + i[0],
-                                                    untrusted=True):
-                    yield {"type" : i[0], "extension": i[1],
-                           "node": nodeid, "url": url}
-
-        sortdefault = 'name', False
-        def entries(sortcolumn="", descending=False, subdir="", **map):
-            rows = []
-            parity = paritygen(self.stripecount)
-            for name, path in self.repos:
-                if not name.startswith(subdir):
-                    continue
-                name = name[len(subdir):]
-
-                u = self.ui.copy()
-                try:
-                    u.readconfig(os.path.join(path, '.hg', 'hgrc'))
-                except Exception, e:
-                    u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
-                    continue
-                def get(section, name, default=None):
-                    return u.config(section, name, default, untrusted=True)
-
-                if u.configbool("web", "hidden", untrusted=True):
-                    continue
-
-                if not self.read_allowed(u, req):
-                    continue
-
-                parts = [name]
-                if 'PATH_INFO' in req.env:
-                    parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
-                if req.env['SCRIPT_NAME']:
-                    parts.insert(0, req.env['SCRIPT_NAME'])
-                m = re.match('((?:https?://)?)(.*)', '/'.join(parts))
-                # squish repeated slashes out of the path component
-                url = m.group(1) + re.sub('/+', '/', m.group(2)) + '/'
-
-                # update time with local timezone
-                try:
-                    d = (get_mtime(path), util.makedate()[1])
-                except OSError:
-                    continue
-
-                contact = get_contact(get)
-                description = get("web", "description", "")
-                name = get("web", "name", name)
-                row = dict(contact=contact or "unknown",
-                           contact_sort=contact.upper() or "unknown",
-                           name=name,
-                           name_sort=name,
-                           url=url,
-                           description=description or "unknown",
-                           description_sort=description.upper() or "unknown",
-                           lastchange=d,
-                           lastchange_sort=d[1]-d[0],
-                           archives=archivelist(u, "tip", url))
-                if (not sortcolumn or (sortcolumn, descending) == sortdefault):
-                    # fast path for unsorted output
-                    row['parity'] = parity.next()
-                    yield row
-                else:
-                    rows.append((row["%s_sort" % sortcolumn], row))
-            if rows:
-                rows.sort()
-                if descending:
-                    rows.reverse()
-                for key, row in rows:
-                    row['parity'] = parity.next()
-                    yield row
-
-        self.refresh()
-        sortable = ["name", "description", "contact", "lastchange"]
-        sortcolumn, descending = sortdefault
-        if 'sort' in req.form:
-            sortcolumn = req.form['sort'][0]
-            descending = sortcolumn.startswith('-')
-            if descending:
-                sortcolumn = sortcolumn[1:]
-            if sortcolumn not in sortable:
-                sortcolumn = ""
-
-        sort = [("sort_%s" % column,
-                 "%s%s" % ((not descending and column == sortcolumn)
-                            and "-" or "", column))
-                for column in sortable]
-
-        self.refresh()
-        if self._baseurl is not None:
-            req.env['SCRIPT_NAME'] = self._baseurl
-
-        return tmpl("index", entries=entries, subdir=subdir,
-                    sortcolumn=sortcolumn, descending=descending,
-                    **dict(sort))
-
-    def templater(self, req):
-
-        def header(**map):
-            yield tmpl('header', encoding=encoding.encoding, **map)
-
-        def footer(**map):
-            yield tmpl("footer", **map)
-
-        def motd(**map):
-            if self.motd is not None:
-                yield self.motd
-            else:
-                yield config('web', 'motd', '')
-
-        def config(section, name, default=None, untrusted=True):
-            return self.ui.config(section, name, default, untrusted)
-
-        if self._baseurl is not None:
-            req.env['SCRIPT_NAME'] = self._baseurl
-
-        url = req.env.get('SCRIPT_NAME', '')
-        if not url.endswith('/'):
-            url += '/'
-
-        vars = {}
-        style = self.style
-        if 'style' in req.form:
-            vars['style'] = style = req.form['style'][0]
-        start = url[-1] == '?' and '&' or '?'
-        sessionvars = webutil.sessionvars(vars, start)
-
-        staticurl = config('web', 'staticurl') or url + 'static/'
-        if not staticurl.endswith('/'):
-            staticurl += '/'
-
-        style = 'style' in req.form and req.form['style'][0] or self.style
-        mapfile = templater.stylemap(style)
-        tmpl = templater.templater(mapfile,
-                                   defaults={"header": header,
-                                             "footer": footer,
-                                             "motd": motd,
-                                             "url": url,
-                                             "staticurl": staticurl,
-                                             "sessionvars": sessionvars})
-        return tmpl
--- a/sys/src/cmd/hg/mercurial/hgweb/protocol.py
+++ /dev/null
@@ -1,206 +1,0 @@
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import cStringIO, zlib, tempfile, errno, os, sys, urllib
-from mercurial import util, streamclone
-from mercurial.node import bin, hex
-from mercurial import changegroup as changegroupmod
-from common import ErrorResponse, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
-
-# __all__ is populated with the allowed commands. Be sure to add to it if
-# you're adding a new command, or the new command won't work.
-
-__all__ = [
-   'lookup', 'heads', 'branches', 'between', 'changegroup',
-   'changegroupsubset', 'capabilities', 'unbundle', 'stream_out',
-   'branchmap',
-]
-
-HGTYPE = 'application/mercurial-0.1'
-
-def lookup(repo, req):
-    try:
-        r = hex(repo.lookup(req.form['key'][0]))
-        success = 1
-    except Exception, inst:
-        r = str(inst)
-        success = 0
-    resp = "%s %s\n" % (success, r)
-    req.respond(HTTP_OK, HGTYPE, length=len(resp))
-    yield resp
-
-def heads(repo, req):
-    resp = " ".join(map(hex, repo.heads())) + "\n"
-    req.respond(HTTP_OK, HGTYPE, length=len(resp))
-    yield resp
-
-def branchmap(repo, req):
-    branches = repo.branchmap()
-    heads = []
-    for branch, nodes in branches.iteritems():
-        branchname = urllib.quote(branch)
-        branchnodes = [hex(node) for node in nodes]
-        heads.append('%s %s' % (branchname, ' '.join(branchnodes)))
-    resp = '\n'.join(heads)
-    req.respond(HTTP_OK, HGTYPE, length=len(resp))
-    yield resp
-
-def branches(repo, req):
-    nodes = []
-    if 'nodes' in req.form:
-        nodes = map(bin, req.form['nodes'][0].split(" "))
-    resp = cStringIO.StringIO()
-    for b in repo.branches(nodes):
-        resp.write(" ".join(map(hex, b)) + "\n")
-    resp = resp.getvalue()
-    req.respond(HTTP_OK, HGTYPE, length=len(resp))
-    yield resp
-
-def between(repo, req):
-    if 'pairs' in req.form:
-        pairs = [map(bin, p.split("-"))
-                 for p in req.form['pairs'][0].split(" ")]
-    resp = cStringIO.StringIO()
-    for b in repo.between(pairs):
-        resp.write(" ".join(map(hex, b)) + "\n")
-    resp = resp.getvalue()
-    req.respond(HTTP_OK, HGTYPE, length=len(resp))
-    yield resp
-
-def changegroup(repo, req):
-    req.respond(HTTP_OK, HGTYPE)
-    nodes = []
-
-    if 'roots' in req.form:
-        nodes = map(bin, req.form['roots'][0].split(" "))
-
-    z = zlib.compressobj()
-    f = repo.changegroup(nodes, 'serve')
-    while 1:
-        chunk = f.read(4096)
-        if not chunk:
-            break
-        yield z.compress(chunk)
-
-    yield z.flush()
-
-def changegroupsubset(repo, req):
-    req.respond(HTTP_OK, HGTYPE)
-    bases = []
-    heads = []
-
-    if 'bases' in req.form:
-        bases = [bin(x) for x in req.form['bases'][0].split(' ')]
-    if 'heads' in req.form:
-        heads = [bin(x) for x in req.form['heads'][0].split(' ')]
-
-    z = zlib.compressobj()
-    f = repo.changegroupsubset(bases, heads, 'serve')
-    while 1:
-        chunk = f.read(4096)
-        if not chunk:
-            break
-        yield z.compress(chunk)
-
-    yield z.flush()
-
-def capabilities(repo, req):
-    caps = ['lookup', 'changegroupsubset', 'branchmap']
-    if repo.ui.configbool('server', 'uncompressed', untrusted=True):
-        caps.append('stream=%d' % repo.changelog.version)
-    if changegroupmod.bundlepriority:
-        caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
-    rsp = ' '.join(caps)
-    req.respond(HTTP_OK, HGTYPE, length=len(rsp))
-    yield rsp
-
-def unbundle(repo, req):
-
-    proto = req.env.get('wsgi.url_scheme') or 'http'
-    their_heads = req.form['heads'][0].split(' ')
-
-    def check_heads():
-        heads = map(hex, repo.heads())
-        return their_heads == [hex('force')] or their_heads == heads
-
-    # fail early if possible
-    if not check_heads():
-        req.drain()
-        raise ErrorResponse(HTTP_OK, 'unsynced changes')
-
-    # do not lock repo until all changegroup data is
-    # streamed. save to temporary file.
-
-    fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
-    fp = os.fdopen(fd, 'wb+')
-    try:
-        length = int(req.env['CONTENT_LENGTH'])
-        for s in util.filechunkiter(req, limit=length):
-            fp.write(s)
-
-        try:
-            lock = repo.lock()
-            try:
-                if not check_heads():
-                    raise ErrorResponse(HTTP_OK, 'unsynced changes')
-
-                fp.seek(0)
-                header = fp.read(6)
-                if header.startswith('HG') and not header.startswith('HG10'):
-                    raise ValueError('unknown bundle version')
-                elif header not in changegroupmod.bundletypes:
-                    raise ValueError('unknown bundle compression type')
-                gen = changegroupmod.unbundle(header, fp)
-
-                # send addchangegroup output to client
-
-                oldio = sys.stdout, sys.stderr
-                sys.stderr = sys.stdout = cStringIO.StringIO()
-
-                try:
-                    url = 'remote:%s:%s:%s' % (
-                          proto,
-                          urllib.quote(req.env.get('REMOTE_HOST', '')),
-                          urllib.quote(req.env.get('REMOTE_USER', '')))
-                    try:
-                        ret = repo.addchangegroup(gen, 'serve', url)
-                    except util.Abort, inst:
-                        sys.stdout.write("abort: %s\n" % inst)
-                        ret = 0
-                finally:
-                    val = sys.stdout.getvalue()
-                    sys.stdout, sys.stderr = oldio
-                req.respond(HTTP_OK, HGTYPE)
-                return '%d\n%s' % (ret, val),
-            finally:
-                lock.release()
-        except ValueError, inst:
-            raise ErrorResponse(HTTP_OK, inst)
-        except (OSError, IOError), inst:
-            filename = getattr(inst, 'filename', '')
-            # Don't send our filesystem layout to the client
-            if filename.startswith(repo.root):
-                filename = filename[len(repo.root)+1:]
-            else:
-                filename = ''
-            error = getattr(inst, 'strerror', 'Unknown error')
-            if inst.errno == errno.ENOENT:
-                code = HTTP_NOT_FOUND
-            else:
-                code = HTTP_SERVER_ERROR
-            raise ErrorResponse(code, '%s: %s' % (error, filename))
-    finally:
-        fp.close()
-        os.unlink(tempname)
-
-def stream_out(repo, req):
-    req.respond(HTTP_OK, HGTYPE)
-    try:
-        for chunk in streamclone.stream_out(repo, untrusted=True):
-            yield chunk
-    except streamclone.StreamException, inst:
-        yield str(inst)
--- a/sys/src/cmd/hg/mercurial/hgweb/request.py
+++ /dev/null
@@ -1,134 +1,0 @@
-# hgweb/request.py - An http request from either CGI or the standalone server.
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import socket, cgi, errno
-from mercurial import util
-from common import ErrorResponse, statusmessage
-
-shortcuts = {
-    'cl': [('cmd', ['changelog']), ('rev', None)],
-    'sl': [('cmd', ['shortlog']), ('rev', None)],
-    'cs': [('cmd', ['changeset']), ('node', None)],
-    'f': [('cmd', ['file']), ('filenode', None)],
-    'fl': [('cmd', ['filelog']), ('filenode', None)],
-    'fd': [('cmd', ['filediff']), ('node', None)],
-    'fa': [('cmd', ['annotate']), ('filenode', None)],
-    'mf': [('cmd', ['manifest']), ('manifest', None)],
-    'ca': [('cmd', ['archive']), ('node', None)],
-    'tags': [('cmd', ['tags'])],
-    'tip': [('cmd', ['changeset']), ('node', ['tip'])],
-    'static': [('cmd', ['static']), ('file', None)]
-}
-
-def expand(form):
-    for k in shortcuts.iterkeys():
-        if k in form:
-            for name, value in shortcuts[k]:
-                if value is None:
-                    value = form[k]
-                form[name] = value
-            del form[k]
-    return form
-
-class wsgirequest(object):
-    def __init__(self, wsgienv, start_response):
-        version = wsgienv['wsgi.version']
-        if (version < (1, 0)) or (version >= (2, 0)):
-            raise RuntimeError("Unknown and unsupported WSGI version %d.%d"
-                               % version)
-        self.inp = wsgienv['wsgi.input']
-        self.err = wsgienv['wsgi.errors']
-        self.threaded = wsgienv['wsgi.multithread']
-        self.multiprocess = wsgienv['wsgi.multiprocess']
-        self.run_once = wsgienv['wsgi.run_once']
-        self.env = wsgienv
-        self.form = expand(cgi.parse(self.inp, self.env, keep_blank_values=1))
-        self._start_response = start_response
-        self.server_write = None
-        self.headers = []
-
-    def __iter__(self):
-        return iter([])
-
-    def read(self, count=-1):
-        return self.inp.read(count)
-
-    def drain(self):
-        '''need to read all data from request, httplib is half-duplex'''
-        length = int(self.env.get('CONTENT_LENGTH', 0))
-        for s in util.filechunkiter(self.inp, limit=length):
-            pass
-
-    def respond(self, status, type=None, filename=None, length=0):
-        if self._start_response is not None:
-
-            self.httphdr(type, filename, length)
-            if not self.headers:
-                raise RuntimeError("request.write called before headers sent")
-
-            for k, v in self.headers:
-                if not isinstance(v, str):
-                    raise TypeError('header value must be string: %r' % v)
-
-            if isinstance(status, ErrorResponse):
-                self.header(status.headers)
-                status = statusmessage(status.code)
-            elif status == 200:
-                status = '200 Script output follows'
-            elif isinstance(status, int):
-                status = statusmessage(status)
-
-            self.server_write = self._start_response(status, self.headers)
-            self._start_response = None
-            self.headers = []
-
-    def write(self, thing):
-        if hasattr(thing, "__iter__"):
-            for part in thing:
-                self.write(part)
-        else:
-            thing = str(thing)
-            try:
-                self.server_write(thing)
-            except socket.error, inst:
-                if inst[0] != errno.ECONNRESET:
-                    raise
-
-    def writelines(self, lines):
-        for line in lines:
-            self.write(line)
-
-    def flush(self):
-        return None
-
-    def close(self):
-        return None
-
-    def header(self, headers=[('Content-Type','text/html')]):
-        self.headers.extend(headers)
-
-    def httphdr(self, type=None, filename=None, length=0, headers={}):
-        headers = headers.items()
-        if type is not None:
-            headers.append(('Content-Type', type))
-        if filename:
-            filename = (filename.split('/')[-1]
-                        .replace('\\', '\\\\').replace('"', '\\"'))
-            headers.append(('Content-Disposition',
-                            'inline; filename="%s"' % filename))
-        if length:
-            headers.append(('Content-Length', str(length)))
-        self.header(headers)
-
-def wsgiapplication(app_maker):
-    '''For compatibility with old CGI scripts. A plain hgweb() or hgwebdir()
-    can and should now be used as a WSGI application.'''
-    application = app_maker()
-    def run_wsgi(env, respond):
-        return application(env, respond)
-    return run_wsgi
--- a/sys/src/cmd/hg/mercurial/hgweb/server.py
+++ /dev/null
@@ -1,298 +1,0 @@
-# hgweb/server.py - The standalone hg web server.
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os, sys, errno, urllib, BaseHTTPServer, socket, SocketServer, traceback
-from mercurial import hg, util, error
-from hgweb_mod import hgweb
-from hgwebdir_mod import hgwebdir
-from mercurial.i18n import _
-
-def _splitURI(uri):
-    """ Return path and query splited from uri
-
-    Just like CGI environment, the path is unquoted, the query is
-    not.
-    """
-    if '?' in uri:
-        path, query = uri.split('?', 1)
-    else:
-        path, query = uri, ''
-    return urllib.unquote(path), query
-
-class _error_logger(object):
-    def __init__(self, handler):
-        self.handler = handler
-    def flush(self):
-        pass
-    def write(self, str):
-        self.writelines(str.split('\n'))
-    def writelines(self, seq):
-        for msg in seq:
-            self.handler.log_error("HG error:  %s", msg)
-
-class _hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
-
-    url_scheme = 'http'
-
-    def __init__(self, *args, **kargs):
-        self.protocol_version = 'HTTP/1.1'
-        BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
-
-    def _log_any(self, fp, format, *args):
-        fp.write("%s - - [%s] %s\n" % (self.client_address[0],
-                                       self.log_date_time_string(),
-                                       format % args))
-        fp.flush()
-
-    def log_error(self, format, *args):
-        self._log_any(self.server.errorlog, format, *args)
-
-    def log_message(self, format, *args):
-        self._log_any(self.server.accesslog, format, *args)
-
-    def do_write(self):
-        try:
-            self.do_hgweb()
-        except socket.error, inst:
-            if inst[0] != errno.EPIPE:
-                raise
-
-    def do_POST(self):
-        try:
-            self.do_write()
-        except StandardError:
-            self._start_response("500 Internal Server Error", [])
-            self._write("Internal Server Error")
-            tb = "".join(traceback.format_exception(*sys.exc_info()))
-            self.log_error("Exception happened during processing "
-                           "request '%s':\n%s", self.path, tb)
-
-    def do_GET(self):
-        self.do_POST()
-
-    def do_hgweb(self):
-        path, query = _splitURI(self.path)
-
-        env = {}
-        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
-        env['REQUEST_METHOD'] = self.command
-        env['SERVER_NAME'] = self.server.server_name
-        env['SERVER_PORT'] = str(self.server.server_port)
-        env['REQUEST_URI'] = self.path
-        env['SCRIPT_NAME'] = self.server.prefix
-        env['PATH_INFO'] = path[len(self.server.prefix):]
-        env['REMOTE_HOST'] = self.client_address[0]
-        env['REMOTE_ADDR'] = self.client_address[0]
-        if query:
-            env['QUERY_STRING'] = query
-
-        if self.headers.typeheader is None:
-            env['CONTENT_TYPE'] = self.headers.type
-        else:
-            env['CONTENT_TYPE'] = self.headers.typeheader
-        length = self.headers.getheader('content-length')
-        if length:
-            env['CONTENT_LENGTH'] = length
-        for header in [h for h in self.headers.keys()
-                       if h not in ('content-type', 'content-length')]:
-            hkey = 'HTTP_' + header.replace('-', '_').upper()
-            hval = self.headers.getheader(header)
-            hval = hval.replace('\n', '').strip()
-            if hval:
-                env[hkey] = hval
-        env['SERVER_PROTOCOL'] = self.request_version
-        env['wsgi.version'] = (1, 0)
-        env['wsgi.url_scheme'] = self.url_scheme
-        env['wsgi.input'] = self.rfile
-        env['wsgi.errors'] = _error_logger(self)
-        env['wsgi.multithread'] = isinstance(self.server,
-                                             SocketServer.ThreadingMixIn)
-        env['wsgi.multiprocess'] = isinstance(self.server,
-                                              SocketServer.ForkingMixIn)
-        env['wsgi.run_once'] = 0
-
-        self.close_connection = True
-        self.saved_status = None
-        self.saved_headers = []
-        self.sent_headers = False
-        self.length = None
-        for chunk in self.server.application(env, self._start_response):
-            self._write(chunk)
-
-    def send_headers(self):
-        if not self.saved_status:
-            raise AssertionError("Sending headers before "
-                                 "start_response() called")
-        saved_status = self.saved_status.split(None, 1)
-        saved_status[0] = int(saved_status[0])
-        self.send_response(*saved_status)
-        should_close = True
-        for h in self.saved_headers:
-            self.send_header(*h)
-            if h[0].lower() == 'content-length':
-                should_close = False
-                self.length = int(h[1])
-        # The value of the Connection header is a list of case-insensitive
-        # tokens separated by commas and optional whitespace.
-        if 'close' in [token.strip().lower() for token in
-                       self.headers.get('connection', '').split(',')]:
-            should_close = True
-        if should_close:
-            self.send_header('Connection', 'close')
-        self.close_connection = should_close
-        self.end_headers()
-        self.sent_headers = True
-
-    def _start_response(self, http_status, headers, exc_info=None):
-        code, msg = http_status.split(None, 1)
-        code = int(code)
-        self.saved_status = http_status
-        bad_headers = ('connection', 'transfer-encoding')
-        self.saved_headers = [h for h in headers
-                              if h[0].lower() not in bad_headers]
-        return self._write
-
-    def _write(self, data):
-        if not self.saved_status:
-            raise AssertionError("data written before start_response() called")
-        elif not self.sent_headers:
-            self.send_headers()
-        if self.length is not None:
-            if len(data) > self.length:
-                raise AssertionError("Content-length header sent, but more "
-                                     "bytes than specified are being written.")
-            self.length = self.length - len(data)
-        self.wfile.write(data)
-        self.wfile.flush()
-
-class _shgwebhandler(_hgwebhandler):
-
-    url_scheme = 'https'
-
-    def setup(self):
-        self.connection = self.request
-        self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
-        self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
-
-    def do_write(self):
-        from OpenSSL.SSL import SysCallError
-        try:
-            super(_shgwebhandler, self).do_write()
-        except SysCallError, inst:
-            if inst.args[0] != errno.EPIPE:
-                raise
-
-    def handle_one_request(self):
-        from OpenSSL.SSL import SysCallError, ZeroReturnError
-        try:
-            super(_shgwebhandler, self).handle_one_request()
-        except (SysCallError, ZeroReturnError):
-            self.close_connection = True
-            pass
-
-def create_server(ui, repo):
-    use_threads = True
-
-    def openlog(opt, default):
-        if opt and opt != '-':
-            return open(opt, 'a')
-        return default
-
-    if repo is None:
-        myui = ui
-    else:
-        myui = repo.ui
-    address = myui.config("web", "address", "")
-    port = int(myui.config("web", "port", 8000))
-    prefix = myui.config("web", "prefix", "")
-    if prefix:
-        prefix = "/" + prefix.strip("/")
-    use_ipv6 = myui.configbool("web", "ipv6")
-    webdir_conf = myui.config("web", "webdir_conf")
-    ssl_cert = myui.config("web", "certificate")
-    accesslog = openlog(myui.config("web", "accesslog", "-"), sys.stdout)
-    errorlog = openlog(myui.config("web", "errorlog", "-"), sys.stderr)
-
-    if use_threads:
-        try:
-            from threading import activeCount
-        except ImportError:
-            use_threads = False
-
-    if use_threads:
-        _mixin = SocketServer.ThreadingMixIn
-    else:
-        if hasattr(os, "fork"):
-            _mixin = SocketServer.ForkingMixIn
-        else:
-            class _mixin:
-                pass
-
-    class MercurialHTTPServer(object, _mixin, BaseHTTPServer.HTTPServer):
-
-        # SO_REUSEADDR has broken semantics on windows
-        if os.name == 'nt':
-            allow_reuse_address = 0
-
-        def __init__(self, *args, **kargs):
-            BaseHTTPServer.HTTPServer.__init__(self, *args, **kargs)
-            self.accesslog = accesslog
-            self.errorlog = errorlog
-            self.daemon_threads = True
-            def make_handler():
-                if webdir_conf:
-                    hgwebobj = hgwebdir(webdir_conf, ui)
-                elif repo is not None:
-                    hgwebobj = hgweb(hg.repository(repo.ui, repo.root))
-                else:
-                    raise error.RepoError(_("There is no Mercurial repository"
-                                            " here (.hg not found)"))
-                return hgwebobj
-            self.application = make_handler()
-
-            if ssl_cert:
-                try:
-                    from OpenSSL import SSL
-                    ctx = SSL.Context(SSL.SSLv23_METHOD)
-                except ImportError:
-                    raise util.Abort(_("SSL support is unavailable"))
-                ctx.use_privatekey_file(ssl_cert)
-                ctx.use_certificate_file(ssl_cert)
-                sock = socket.socket(self.address_family, self.socket_type)
-                self.socket = SSL.Connection(ctx, sock)
-                self.server_bind()
-                self.server_activate()
-
-            self.addr, self.port = self.socket.getsockname()[0:2]
-            self.prefix = prefix
-            self.fqaddr = socket.getfqdn(address)
-
-    class IPv6HTTPServer(MercurialHTTPServer):
-        address_family = getattr(socket, 'AF_INET6', None)
-
-        def __init__(self, *args, **kwargs):
-            if self.address_family is None:
-                raise error.RepoError(_('IPv6 is not available on this system'))
-            super(IPv6HTTPServer, self).__init__(*args, **kwargs)
-
-    if ssl_cert:
-        handler = _shgwebhandler
-    else:
-        handler = _hgwebhandler
-
-    # ugly hack due to python issue5853 (for threaded use)
-    import mimetypes; mimetypes.init()
-
-    try:
-        if use_ipv6:
-            return IPv6HTTPServer((address, port), handler)
-        else:
-            return MercurialHTTPServer((address, port), handler)
-    except socket.error, inst:
-        raise util.Abort(_("cannot start server at '%s:%d': %s")
-                         % (address, port, inst.args[1]))
--- a/sys/src/cmd/hg/mercurial/hgweb/webcommands.py
+++ /dev/null
@@ -1,690 +1,0 @@
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os, mimetypes, re, cgi, copy
-import webutil
-from mercurial import error, archival, templater, templatefilters
-from mercurial.node import short, hex
-from mercurial.util import binary
-from common import paritygen, staticfile, get_contact, ErrorResponse
-from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
-from mercurial import graphmod
-
-# __all__ is populated with the allowed commands. Be sure to add to it if
-# you're adding a new command, or the new command won't work.
-
-__all__ = [
-   'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
-   'manifest', 'tags', 'branches', 'summary', 'filediff', 'diff', 'annotate',
-   'filelog', 'archive', 'static', 'graph',
-]
-
-def log(web, req, tmpl):
-    if 'file' in req.form and req.form['file'][0]:
-        return filelog(web, req, tmpl)
-    else:
-        return changelog(web, req, tmpl)
-
-def rawfile(web, req, tmpl):
-    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
-    if not path:
-        content = manifest(web, req, tmpl)
-        req.respond(HTTP_OK, web.ctype)
-        return content
-
-    try:
-        fctx = webutil.filectx(web.repo, req)
-    except error.LookupError, inst:
-        try:
-            content = manifest(web, req, tmpl)
-            req.respond(HTTP_OK, web.ctype)
-            return content
-        except ErrorResponse:
-            raise inst
-
-    path = fctx.path()
-    text = fctx.data()
-    mt = mimetypes.guess_type(path)[0]
-    if mt is None:
-        mt = binary(text) and 'application/octet-stream' or 'text/plain'
-
-    req.respond(HTTP_OK, mt, path, len(text))
-    return [text]
-
-def _filerevision(web, tmpl, fctx):
-    f = fctx.path()
-    text = fctx.data()
-    parity = paritygen(web.stripecount)
-
-    if binary(text):
-        mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
-        text = '(binary:%s)' % mt
-
-    def lines():
-        for lineno, t in enumerate(text.splitlines(True)):
-            yield {"line": t,
-                   "lineid": "l%d" % (lineno + 1),
-                   "linenumber": "% 6d" % (lineno + 1),
-                   "parity": parity.next()}
-
-    return tmpl("filerevision",
-                file=f,
-                path=webutil.up(f),
-                text=lines(),
-                rev=fctx.rev(),
-                node=hex(fctx.node()),
-                author=fctx.user(),
-                date=fctx.date(),
-                desc=fctx.description(),
-                branch=webutil.nodebranchnodefault(fctx),
-                parent=webutil.parents(fctx),
-                child=webutil.children(fctx),
-                rename=webutil.renamelink(fctx),
-                permissions=fctx.manifest().flags(f))
-
-def file(web, req, tmpl):
-    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
-    if not path:
-        return manifest(web, req, tmpl)
-    try:
-        return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
-    except error.LookupError, inst:
-        try:
-            return manifest(web, req, tmpl)
-        except ErrorResponse:
-            raise inst
-
-def _search(web, tmpl, query):
-
-    def changelist(**map):
-        cl = web.repo.changelog
-        count = 0
-        qw = query.lower().split()
-
-        def revgen():
-            for i in xrange(len(cl) - 1, 0, -100):
-                l = []
-                for j in xrange(max(0, i - 100), i + 1):
-                    ctx = web.repo[j]
-                    l.append(ctx)
-                l.reverse()
-                for e in l:
-                    yield e
-
-        for ctx in revgen():
-            miss = 0
-            for q in qw:
-                if not (q in ctx.user().lower() or
-                        q in ctx.description().lower() or
-                        q in " ".join(ctx.files()).lower()):
-                    miss = 1
-                    break
-            if miss:
-                continue
-
-            count += 1
-            n = ctx.node()
-            showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
-            files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
-
-            yield tmpl('searchentry',
-                       parity=parity.next(),
-                       author=ctx.user(),
-                       parent=webutil.parents(ctx),
-                       child=webutil.children(ctx),
-                       changelogtag=showtags,
-                       desc=ctx.description(),
-                       date=ctx.date(),
-                       files=files,
-                       rev=ctx.rev(),
-                       node=hex(n),
-                       tags=webutil.nodetagsdict(web.repo, n),
-                       inbranch=webutil.nodeinbranch(web.repo, ctx),
-                       branches=webutil.nodebranchdict(web.repo, ctx))
-
-            if count >= web.maxchanges:
-                break
-
-    cl = web.repo.changelog
-    parity = paritygen(web.stripecount)
-
-    return tmpl('search',
-                query=query,
-                node=hex(cl.tip()),
-                entries=changelist,
-                archives=web.archivelist("tip"))
-
-def changelog(web, req, tmpl, shortlog = False):
-    if 'node' in req.form:
-        ctx = webutil.changectx(web.repo, req)
-    else:
-        if 'rev' in req.form:
-            hi = req.form['rev'][0]
-        else:
-            hi = len(web.repo) - 1
-        try:
-            ctx = web.repo[hi]
-        except error.RepoError:
-            return _search(web, tmpl, hi) # XXX redirect to 404 page?
-
-    def changelist(limit=0, **map):
-        l = [] # build a list in forward order for efficiency
-        for i in xrange(start, end):
-            ctx = web.repo[i]
-            n = ctx.node()
-            showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
-            files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
-
-            l.insert(0, {"parity": parity.next(),
-                         "author": ctx.user(),
-                         "parent": webutil.parents(ctx, i - 1),
-                         "child": webutil.children(ctx, i + 1),
-                         "changelogtag": showtags,
-                         "desc": ctx.description(),
-                         "date": ctx.date(),
-                         "files": files,
-                         "rev": i,
-                         "node": hex(n),
-                         "tags": webutil.nodetagsdict(web.repo, n),
-                         "inbranch": webutil.nodeinbranch(web.repo, ctx),
-                         "branches": webutil.nodebranchdict(web.repo, ctx)
-                        })
-
-        if limit > 0:
-            l = l[:limit]
-
-        for e in l:
-            yield e
-
-    maxchanges = shortlog and web.maxshortchanges or web.maxchanges
-    cl = web.repo.changelog
-    count = len(cl)
-    pos = ctx.rev()
-    start = max(0, pos - maxchanges + 1)
-    end = min(count, start + maxchanges)
-    pos = end - 1
-    parity = paritygen(web.stripecount, offset=start-end)
-
-    changenav = webutil.revnavgen(pos, maxchanges, count, web.repo.changectx)
-
-    return tmpl(shortlog and 'shortlog' or 'changelog',
-                changenav=changenav,
-                node=hex(ctx.node()),
-                rev=pos, changesets=count,
-                entries=lambda **x: changelist(limit=0,**x),
-                latestentry=lambda **x: changelist(limit=1,**x),
-                archives=web.archivelist("tip"))
-
-def shortlog(web, req, tmpl):
-    return changelog(web, req, tmpl, shortlog = True)
-
-def changeset(web, req, tmpl):
-    ctx = webutil.changectx(web.repo, req)
-    showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
-    showbranch = webutil.nodebranchnodefault(ctx)
-
-    files = []
-    parity = paritygen(web.stripecount)
-    for f in ctx.files():
-        template = f in ctx and 'filenodelink' or 'filenolink'
-        files.append(tmpl(template,
-                          node=ctx.hex(), file=f,
-                          parity=parity.next()))
-
-    parity = paritygen(web.stripecount)
-    diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity)
-    return tmpl('changeset',
-                diff=diffs,
-                rev=ctx.rev(),
-                node=ctx.hex(),
-                parent=webutil.parents(ctx),
-                child=webutil.children(ctx),
-                changesettag=showtags,
-                changesetbranch=showbranch,
-                author=ctx.user(),
-                desc=ctx.description(),
-                date=ctx.date(),
-                files=files,
-                archives=web.archivelist(ctx.hex()),
-                tags=webutil.nodetagsdict(web.repo, ctx.node()),
-                branch=webutil.nodebranchnodefault(ctx),
-                inbranch=webutil.nodeinbranch(web.repo, ctx),
-                branches=webutil.nodebranchdict(web.repo, ctx))
-
-rev = changeset
-
-def manifest(web, req, tmpl):
-    ctx = webutil.changectx(web.repo, req)
-    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
-    mf = ctx.manifest()
-    node = ctx.node()
-
-    files = {}
-    dirs = {}
-    parity = paritygen(web.stripecount)
-
-    if path and path[-1] != "/":
-        path += "/"
-    l = len(path)
-    abspath = "/" + path
-
-    for f, n in mf.iteritems():
-        if f[:l] != path:
-            continue
-        remain = f[l:]
-        elements = remain.split('/')
-        if len(elements) == 1:
-            files[remain] = f
-        else:
-            h = dirs # need to retain ref to dirs (root)
-            for elem in elements[0:-1]:
-                if elem not in h:
-                    h[elem] = {}
-                h = h[elem]
-                if len(h) > 1:
-                    break
-            h[None] = None # denotes files present
-
-    if mf and not files and not dirs:
-        raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
-
-    def filelist(**map):
-        for f in sorted(files):
-            full = files[f]
-
-            fctx = ctx.filectx(full)
-            yield {"file": full,
-                   "parity": parity.next(),
-                   "basename": f,
-                   "date": fctx.date(),
-                   "size": fctx.size(),
-                   "permissions": mf.flags(full)}
-
-    def dirlist(**map):
-        for d in sorted(dirs):
-
-            emptydirs = []
-            h = dirs[d]
-            while isinstance(h, dict) and len(h) == 1:
-                k,v = h.items()[0]
-                if v:
-                    emptydirs.append(k)
-                h = v
-
-            path = "%s%s" % (abspath, d)
-            yield {"parity": parity.next(),
-                   "path": path,
-                   "emptydirs": "/".join(emptydirs),
-                   "basename": d}
-
-    return tmpl("manifest",
-                rev=ctx.rev(),
-                node=hex(node),
-                path=abspath,
-                up=webutil.up(abspath),
-                upparity=parity.next(),
-                fentries=filelist,
-                dentries=dirlist,
-                archives=web.archivelist(hex(node)),
-                tags=webutil.nodetagsdict(web.repo, node),
-                inbranch=webutil.nodeinbranch(web.repo, ctx),
-                branches=webutil.nodebranchdict(web.repo, ctx))
-
-def tags(web, req, tmpl):
-    i = web.repo.tagslist()
-    i.reverse()
-    parity = paritygen(web.stripecount)
-
-    def entries(notip=False, limit=0, **map):
-        count = 0
-        for k, n in i:
-            if notip and k == "tip":
-                continue
-            if limit > 0 and count >= limit:
-                continue
-            count = count + 1
-            yield {"parity": parity.next(),
-                   "tag": k,
-                   "date": web.repo[n].date(),
-                   "node": hex(n)}
-
-    return tmpl("tags",
-                node=hex(web.repo.changelog.tip()),
-                entries=lambda **x: entries(False,0, **x),
-                entriesnotip=lambda **x: entries(True,0, **x),
-                latestentry=lambda **x: entries(True,1, **x))
-
-def branches(web, req, tmpl):
-    b = web.repo.branchtags()
-    tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
-    heads = web.repo.heads()
-    parity = paritygen(web.stripecount)
-    sortkey = lambda ctx: ('close' not in ctx.extra(), ctx.rev())
-
-    def entries(limit, **map):
-        count = 0
-        for ctx in sorted(tips, key=sortkey, reverse=True):
-            if limit > 0 and count >= limit:
-                return
-            count += 1
-            if ctx.node() not in heads:
-                status = 'inactive'
-            elif not web.repo.branchheads(ctx.branch()):
-                status = 'closed'
-            else:
-                status = 'open'
-            yield {'parity': parity.next(),
-                   'branch': ctx.branch(),
-                   'status': status,
-                   'node': ctx.hex(),
-                   'date': ctx.date()}
-
-    return tmpl('branches', node=hex(web.repo.changelog.tip()),
-                entries=lambda **x: entries(0, **x),
-                latestentry=lambda **x: entries(1, **x))
-
-def summary(web, req, tmpl):
-    i = web.repo.tagslist()
-    i.reverse()
-
-    def tagentries(**map):
-        parity = paritygen(web.stripecount)
-        count = 0
-        for k, n in i:
-            if k == "tip": # skip tip
-                continue
-
-            count += 1
-            if count > 10: # limit to 10 tags
-                break
-
-            yield tmpl("tagentry",
-                       parity=parity.next(),
-                       tag=k,
-                       node=hex(n),
-                       date=web.repo[n].date())
-
-    def branches(**map):
-        parity = paritygen(web.stripecount)
-
-        b = web.repo.branchtags()
-        l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
-        for r,n,t in sorted(l):
-            yield {'parity': parity.next(),
-                   'branch': t,
-                   'node': hex(n),
-                   'date': web.repo[n].date()}
-
-    def changelist(**map):
-        parity = paritygen(web.stripecount, offset=start-end)
-        l = [] # build a list in forward order for efficiency
-        for i in xrange(start, end):
-            ctx = web.repo[i]
-            n = ctx.node()
-            hn = hex(n)
-
-            l.insert(0, tmpl(
-               'shortlogentry',
-                parity=parity.next(),
-                author=ctx.user(),
-                desc=ctx.description(),
-                date=ctx.date(),
-                rev=i,
-                node=hn,
-                tags=webutil.nodetagsdict(web.repo, n),
-                inbranch=webutil.nodeinbranch(web.repo, ctx),
-                branches=webutil.nodebranchdict(web.repo, ctx)))
-
-        yield l
-
-    cl = web.repo.changelog
-    count = len(cl)
-    start = max(0, count - web.maxchanges)
-    end = min(count, start + web.maxchanges)
-
-    return tmpl("summary",
-                desc=web.config("web", "description", "unknown"),
-                owner=get_contact(web.config) or "unknown",
-                lastchange=cl.read(cl.tip())[2],
-                tags=tagentries,
-                branches=branches,
-                shortlog=changelist,
-                node=hex(cl.tip()),
-                archives=web.archivelist("tip"))
-
-def filediff(web, req, tmpl):
-    fctx, ctx = None, None
-    try:
-        fctx = webutil.filectx(web.repo, req)
-    except LookupError:
-        ctx = webutil.changectx(web.repo, req)
-        path = webutil.cleanpath(web.repo, req.form['file'][0])
-        if path not in ctx.files():
-            raise
-
-    if fctx is not None:
-        n = fctx.node()
-        path = fctx.path()
-    else:
-        n = ctx.node()
-        # path already defined in except clause
-
-    parity = paritygen(web.stripecount)
-    diffs = webutil.diffs(web.repo, tmpl, fctx or ctx, [path], parity)
-    rename = fctx and webutil.renamelink(fctx) or []
-    ctx = fctx and fctx or ctx
-    return tmpl("filediff",
-                file=path,
-                node=hex(n),
-                rev=ctx.rev(),
-                date=ctx.date(),
-                desc=ctx.description(),
-                author=ctx.user(),
-                rename=rename,
-                branch=webutil.nodebranchnodefault(ctx),
-                parent=webutil.parents(ctx),
-                child=webutil.children(ctx),
-                diff=diffs)
-
-diff = filediff
-
-def annotate(web, req, tmpl):
-    fctx = webutil.filectx(web.repo, req)
-    f = fctx.path()
-    parity = paritygen(web.stripecount)
-
-    def annotate(**map):
-        last = None
-        if binary(fctx.data()):
-            mt = (mimetypes.guess_type(fctx.path())[0]
-                  or 'application/octet-stream')
-            lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
-                                '(binary:%s)' % mt)])
-        else:
-            lines = enumerate(fctx.annotate(follow=True, linenumber=True))
-        for lineno, ((f, targetline), l) in lines:
-            fnode = f.filenode()
-
-            if last != fnode:
-                last = fnode
-
-            yield {"parity": parity.next(),
-                   "node": hex(f.node()),
-                   "rev": f.rev(),
-                   "author": f.user(),
-                   "desc": f.description(),
-                   "file": f.path(),
-                   "targetline": targetline,
-                   "line": l,
-                   "lineid": "l%d" % (lineno + 1),
-                   "linenumber": "% 6d" % (lineno + 1)}
-
-    return tmpl("fileannotate",
-                file=f,
-                annotate=annotate,
-                path=webutil.up(f),
-                rev=fctx.rev(),
-                node=hex(fctx.node()),
-                author=fctx.user(),
-                date=fctx.date(),
-                desc=fctx.description(),
-                rename=webutil.renamelink(fctx),
-                branch=webutil.nodebranchnodefault(fctx),
-                parent=webutil.parents(fctx),
-                child=webutil.children(fctx),
-                permissions=fctx.manifest().flags(f))
-
-def filelog(web, req, tmpl):
-
-    try:
-        fctx = webutil.filectx(web.repo, req)
-        f = fctx.path()
-        fl = fctx.filelog()
-    except error.LookupError:
-        f = webutil.cleanpath(web.repo, req.form['file'][0])
-        fl = web.repo.file(f)
-        numrevs = len(fl)
-        if not numrevs: # file doesn't exist at all
-            raise
-        rev = webutil.changectx(web.repo, req).rev()
-        first = fl.linkrev(0)
-        if rev < first: # current rev is from before file existed
-            raise
-        frev = numrevs - 1
-        while fl.linkrev(frev) > rev:
-            frev -= 1
-        fctx = web.repo.filectx(f, fl.linkrev(frev))
-
-    count = fctx.filerev() + 1
-    pagelen = web.maxshortchanges
-    start = max(0, fctx.filerev() - pagelen + 1) # first rev on this page
-    end = min(count, start + pagelen) # last rev on this page
-    parity = paritygen(web.stripecount, offset=start-end)
-
-    def entries(limit=0, **map):
-        l = []
-
-        repo = web.repo
-        for i in xrange(start, end):
-            iterfctx = fctx.filectx(i)
-
-            l.insert(0, {"parity": parity.next(),
-                         "filerev": i,
-                         "file": f,
-                         "node": hex(iterfctx.node()),
-                         "author": iterfctx.user(),
-                         "date": iterfctx.date(),
-                         "rename": webutil.renamelink(iterfctx),
-                         "parent": webutil.parents(iterfctx),
-                         "child": webutil.children(iterfctx),
-                         "desc": iterfctx.description(),
-                         "tags": webutil.nodetagsdict(repo, iterfctx.node()),
-                         "branch": webutil.nodebranchnodefault(iterfctx),
-                         "inbranch": webutil.nodeinbranch(repo, iterfctx),
-                         "branches": webutil.nodebranchdict(repo, iterfctx)})
-
-        if limit > 0:
-            l = l[:limit]
-
-        for e in l:
-            yield e
-
-    nodefunc = lambda x: fctx.filectx(fileid=x)
-    nav = webutil.revnavgen(end - 1, pagelen, count, nodefunc)
-    return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
-                entries=lambda **x: entries(limit=0, **x),
-                latestentry=lambda **x: entries(limit=1, **x))
-
-
-def archive(web, req, tmpl):
-    type_ = req.form.get('type', [None])[0]
-    allowed = web.configlist("web", "allow_archive")
-    key = req.form['node'][0]
-
-    if type_ not in web.archives:
-        msg = 'Unsupported archive type: %s' % type_
-        raise ErrorResponse(HTTP_NOT_FOUND, msg)
-
-    if not ((type_ in allowed or
-        web.configbool("web", "allow" + type_, False))):
-        msg = 'Archive type not allowed: %s' % type_
-        raise ErrorResponse(HTTP_FORBIDDEN, msg)
-
-    reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
-    cnode = web.repo.lookup(key)
-    arch_version = key
-    if cnode == key or key == 'tip':
-        arch_version = short(cnode)
-    name = "%s-%s" % (reponame, arch_version)
-    mimetype, artype, extension, encoding = web.archive_specs[type_]
-    headers = [
-        ('Content-Type', mimetype),
-        ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
-    ]
-    if encoding:
-        headers.append(('Content-Encoding', encoding))
-    req.header(headers)
-    req.respond(HTTP_OK)
-    archival.archive(web.repo, req, cnode, artype, prefix=name)
-    return []
-
-
-def static(web, req, tmpl):
-    fname = req.form['file'][0]
-    # a repo owner may set web.static in .hg/hgrc to get any file
-    # readable by the user running the CGI script
-    static = web.config("web", "static", None, untrusted=False)
-    if not static:
-        tp = web.templatepath or templater.templatepath()
-        if isinstance(tp, str):
-            tp = [tp]
-        static = [os.path.join(p, 'static') for p in tp]
-    return [staticfile(static, fname, req)]
-
-def graph(web, req, tmpl):
-    rev = webutil.changectx(web.repo, req).rev()
-    bg_height = 39
-
-    revcount = 25
-    if 'revcount' in req.form:
-        revcount = int(req.form.get('revcount', [revcount])[0])
-        tmpl.defaults['sessionvars']['revcount'] = revcount
-
-    lessvars = copy.copy(tmpl.defaults['sessionvars'])
-    lessvars['revcount'] = revcount / 2
-    morevars = copy.copy(tmpl.defaults['sessionvars'])
-    morevars['revcount'] = revcount * 2
-
-    max_rev = len(web.repo) - 1
-    revcount = min(max_rev, revcount)
-    revnode = web.repo.changelog.node(rev)
-    revnode_hex = hex(revnode)
-    uprev = min(max_rev, rev + revcount)
-    downrev = max(0, rev - revcount)
-    count = len(web.repo)
-    changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
-
-    dag = graphmod.revisions(web.repo, rev, downrev)
-    tree = list(graphmod.colored(dag))
-    canvasheight = (len(tree) + 1) * bg_height - 27;
-    data = []
-    for (id, type, ctx, vtx, edges) in tree:
-        if type != graphmod.CHANGESET:
-            continue
-        node = short(ctx.node())
-        age = templatefilters.age(ctx.date())
-        desc = templatefilters.firstline(ctx.description())
-        desc = cgi.escape(templatefilters.nonempty(desc))
-        user = cgi.escape(templatefilters.person(ctx.user()))
-        branch = ctx.branch()
-        branch = branch, web.repo.branchtags().get(branch) == ctx.node()
-        data.append((node, vtx, edges, desc, user, age, branch, ctx.tags()))
-
-    return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
-                lessvars=lessvars, morevars=morevars, downrev=downrev,
-                canvasheight=canvasheight, jsdata=data, bg_height=bg_height,
-                node=revnode_hex, changenav=changenav)
--- a/sys/src/cmd/hg/mercurial/hgweb/webutil.py
+++ /dev/null
@@ -1,218 +1,0 @@
-# hgweb/webutil.py - utility library for the web interface.
-#
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os, copy
-from mercurial import match, patch, util, error
-from mercurial.node import hex, nullid
-
-def up(p):
-    if p[0] != "/":
-        p = "/" + p
-    if p[-1] == "/":
-        p = p[:-1]
-    up = os.path.dirname(p)
-    if up == "/":
-        return "/"
-    return up + "/"
-
-def revnavgen(pos, pagelen, limit, nodefunc):
-    def seq(factor, limit=None):
-        if limit:
-            yield limit
-            if limit >= 20 and limit <= 40:
-                yield 50
-        else:
-            yield 1 * factor
-            yield 3 * factor
-        for f in seq(factor * 10):
-            yield f
-
-    def nav(**map):
-        l = []
-        last = 0
-        for f in seq(1, pagelen):
-            if f < pagelen or f <= last:
-                continue
-            if f > limit:
-                break
-            last = f
-            if pos + f < limit:
-                l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
-            if pos - f >= 0:
-                l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
-
-        try:
-            yield {"label": "(0)", "node": hex(nodefunc('0').node())}
-
-            for label, node in l:
-                yield {"label": label, "node": node}
-
-            yield {"label": "tip", "node": "tip"}
-        except error.RepoError:
-            pass
-
-    return nav
-
-def _siblings(siblings=[], hiderev=None):
-    siblings = [s for s in siblings if s.node() != nullid]
-    if len(siblings) == 1 and siblings[0].rev() == hiderev:
-        return
-    for s in siblings:
-        d = {'node': hex(s.node()), 'rev': s.rev()}
-        d['user'] = s.user()
-        d['date'] = s.date()
-        d['description'] = s.description()
-        d['branch'] = s.branch()
-        if hasattr(s, 'path'):
-            d['file'] = s.path()
-        yield d
-
-def parents(ctx, hide=None):
-    return _siblings(ctx.parents(), hide)
-
-def children(ctx, hide=None):
-    return _siblings(ctx.children(), hide)
-
-def renamelink(fctx):
-    r = fctx.renamed()
-    if r:
-        return [dict(file=r[0], node=hex(r[1]))]
-    return []
-
-def nodetagsdict(repo, node):
-    return [{"name": i} for i in repo.nodetags(node)]
-
-def nodebranchdict(repo, ctx):
-    branches = []
-    branch = ctx.branch()
-    # If this is an empty repo, ctx.node() == nullid,
-    # ctx.branch() == 'default', but branchtags() is
-    # an empty dict. Using dict.get avoids a traceback.
-    if repo.branchtags().get(branch) == ctx.node():
-        branches.append({"name": branch})
-    return branches
-
-def nodeinbranch(repo, ctx):
-    branches = []
-    branch = ctx.branch()
-    if branch != 'default' and repo.branchtags().get(branch) != ctx.node():
-        branches.append({"name": branch})
-    return branches
-
-def nodebranchnodefault(ctx):
-    branches = []
-    branch = ctx.branch()
-    if branch != 'default':
-        branches.append({"name": branch})
-    return branches
-
-def showtag(repo, tmpl, t1, node=nullid, **args):
-    for t in repo.nodetags(node):
-        yield tmpl(t1, tag=t, **args)
-
-def cleanpath(repo, path):
-    path = path.lstrip('/')
-    return util.canonpath(repo.root, '', path)
-
-def changectx(repo, req):
-    changeid = "tip"
-    if 'node' in req.form:
-        changeid = req.form['node'][0]
-    elif 'manifest' in req.form:
-        changeid = req.form['manifest'][0]
-
-    try:
-        ctx = repo[changeid]
-    except error.RepoError:
-        man = repo.manifest
-        ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
-
-    return ctx
-
-def filectx(repo, req):
-    path = cleanpath(repo, req.form['file'][0])
-    if 'node' in req.form:
-        changeid = req.form['node'][0]
-    else:
-        changeid = req.form['filenode'][0]
-    try:
-        fctx = repo[changeid][path]
-    except error.RepoError:
-        fctx = repo.filectx(path, fileid=changeid)
-
-    return fctx
-
-def listfilediffs(tmpl, files, node, max):
-    for f in files[:max]:
-        yield tmpl('filedifflink', node=hex(node), file=f)
-    if len(files) > max:
-        yield tmpl('fileellipses')
-
-def diffs(repo, tmpl, ctx, files, parity):
-
-    def countgen():
-        start = 1
-        while True:
-            yield start
-            start += 1
-
-    blockcount = countgen()
-    def prettyprintlines(diff):
-        blockno = blockcount.next()
-        for lineno, l in enumerate(diff.splitlines(True)):
-            lineno = "%d.%d" % (blockno, lineno + 1)
-            if l.startswith('+'):
-                ltype = "difflineplus"
-            elif l.startswith('-'):
-                ltype = "difflineminus"
-            elif l.startswith('@'):
-                ltype = "difflineat"
-            else:
-                ltype = "diffline"
-            yield tmpl(ltype,
-                       line=l,
-                       lineid="l%s" % lineno,
-                       linenumber="% 8s" % lineno)
-
-    if files:
-        m = match.exact(repo.root, repo.getcwd(), files)
-    else:
-        m = match.always(repo.root, repo.getcwd())
-
-    diffopts = patch.diffopts(repo.ui, untrusted=True)
-    parents = ctx.parents()
-    node1 = parents and parents[0].node() or nullid
-    node2 = ctx.node()
-
-    block = []
-    for chunk in patch.diff(repo, node1, node2, m, opts=diffopts):
-        if chunk.startswith('diff') and block:
-            yield tmpl('diffblock', parity=parity.next(),
-                       lines=prettyprintlines(''.join(block)))
-            block = []
-        if chunk.startswith('diff'):
-            chunk = ''.join(chunk.splitlines(True)[1:])
-        block.append(chunk)
-    yield tmpl('diffblock', parity=parity.next(),
-               lines=prettyprintlines(''.join(block)))
-
-class sessionvars(object):
-    def __init__(self, vars, start='?'):
-        self.start = start
-        self.vars = vars
-    def __getitem__(self, key):
-        return self.vars[key]
-    def __setitem__(self, key, value):
-        self.vars[key] = value
-    def __copy__(self):
-        return sessionvars(copy.copy(self.vars), self.start)
-    def __iter__(self):
-        separator = self.start
-        for key, value in self.vars.iteritems():
-            yield {'name': key, 'value': str(value), 'separator': separator}
-            separator = '&'
--- a/sys/src/cmd/hg/mercurial/hgweb/wsgicgi.py
+++ /dev/null
@@ -1,70 +1,0 @@
-# hgweb/wsgicgi.py - CGI->WSGI translator
-#
-# Copyright 2006 Eric Hopper <hopper@omnifarious.org>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-#
-# This was originally copied from the public domain code at
-# http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side
-
-import os, sys
-from mercurial import util
-
-def launch(application):
-    util.set_binary(sys.stdin)
-    util.set_binary(sys.stdout)
-
-    environ = dict(os.environ.iteritems())
-    environ.setdefault('PATH_INFO', '')
-    if '.cgi' in environ['PATH_INFO']:
-        environ['PATH_INFO'] = environ['PATH_INFO'].split('.cgi', 1)[1]
-
-    environ['wsgi.input'] = sys.stdin
-    environ['wsgi.errors'] = sys.stderr
-    environ['wsgi.version'] = (1, 0)
-    environ['wsgi.multithread'] = False
-    environ['wsgi.multiprocess'] = True
-    environ['wsgi.run_once'] = True
-
-    if environ.get('HTTPS','off').lower() in ('on','1','yes'):
-        environ['wsgi.url_scheme'] = 'https'
-    else:
-        environ['wsgi.url_scheme'] = 'http'
-
-    headers_set = []
-    headers_sent = []
-    out = sys.stdout
-
-    def write(data):
-        if not headers_set:
-            raise AssertionError("write() before start_response()")
-
-        elif not headers_sent:
-            # Before the first output, send the stored headers
-            status, response_headers = headers_sent[:] = headers_set
-            out.write('Status: %s\r\n' % status)
-            for header in response_headers:
-                out.write('%s: %s\r\n' % header)
-            out.write('\r\n')
-
-        out.write(data)
-        out.flush()
-
-    def start_response(status, response_headers, exc_info=None):
-        if exc_info:
-            try:
-                if headers_sent:
-                    # Re-raise original exception if headers sent
-                    raise exc_info[0](exc_info[1], exc_info[2])
-            finally:
-                exc_info = None     # avoid dangling circular ref
-        elif headers_set:
-            raise AssertionError("Headers already set!")
-
-        headers_set[:] = [status, response_headers]
-        return write
-
-    content = application(environ, start_response)
-    for chunk in content:
-        write(chunk)
--- a/sys/src/cmd/hg/mercurial/pure/base85.py
+++ /dev/null
@@ -1,74 +1,0 @@
-# base85.py: pure python base85 codec
-#
-# Copyright (C) 2009 Brendan Cully <brendan@kublai.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import struct
-
-_b85chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
-            "abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
-_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
-_b85dec = {}
-
-def _mkb85dec():
-    for i, c in enumerate(_b85chars):
-        _b85dec[c] = i
-
-def b85encode(text, pad=False):
-    """encode text in base85 format"""
-    l = len(text)
-    r = l % 4
-    if r:
-        text += '\0' * (4 - r)
-    longs = len(text) >> 2
-    words = struct.unpack('>%dL' % (longs), text)
-
-    out = ''.join(_b85chars[(word // 52200625) % 85] +
-                  _b85chars2[(word // 7225) % 7225] +
-                  _b85chars2[word % 7225]
-                  for word in words)
-
-    if pad:
-        return out
-
-    # Trim padding
-    olen = l % 4
-    if olen:
-        olen += 1
-    olen += l // 4 * 5
-    return out[:olen]
-
-def b85decode(text):
-    """decode base85-encoded text"""
-    if not _b85dec:
-        _mkb85dec()
-
-    l = len(text)
-    out = []
-    for i in range(0, len(text), 5):
-        chunk = text[i:i+5]
-        acc = 0
-        for j, c in enumerate(chunk):
-            try:
-                acc = acc * 85 + _b85dec[c]
-            except KeyError:
-                raise TypeError('Bad base85 character at byte %d' % (i + j))
-        if acc > 4294967295:
-            raise OverflowError('Base85 overflow in hunk starting at byte %d' % i)
-        out.append(acc)
-
-    # Pad final chunk if necessary
-    cl = l % 5
-    if cl:
-        acc *= 85 ** (5 - cl)
-        if cl > 1:
-            acc += 0xffffff >> (cl - 2) * 8
-        out[-1] = acc
-
-    out = struct.pack('>%dL' % (len(out)), *out)
-    if cl:
-        out = out[:-(5 - cl)]
-
-    return out
--- a/sys/src/cmd/hg/mercurial/pure/bdiff.py
+++ /dev/null
@@ -1,76 +1,0 @@
-# bdiff.py - Python implementation of bdiff.c
-#
-# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import struct, difflib
-
-def splitnewlines(text):
-    '''like str.splitlines, but only split on newlines.'''
-    lines = [l + '\n' for l in text.split('\n')]
-    if lines:
-        if lines[-1] == '\n':
-            lines.pop()
-        else:
-            lines[-1] = lines[-1][:-1]
-    return lines
-
-def _normalizeblocks(a, b, blocks):
-    prev = None
-    for curr in blocks:
-        if prev is None:
-            prev = curr
-            continue
-        shift = 0
-
-        a1, b1, l1 = prev
-        a1end = a1 + l1
-        b1end = b1 + l1
-
-        a2, b2, l2 = curr
-        a2end = a2 + l2
-        b2end = b2 + l2
-        if a1end == a2:
-            while a1end+shift < a2end and a[a1end+shift] == b[b1end+shift]:
-                shift += 1
-        elif b1end == b2:
-            while b1end+shift < b2end and a[a1end+shift] == b[b1end+shift]:
-                shift += 1
-        yield a1, b1, l1+shift
-        prev = a2+shift, b2+shift, l2-shift
-    yield prev
-
-def bdiff(a, b):
-    a = str(a).splitlines(True)
-    b = str(b).splitlines(True)
-
-    if not a:
-        s = "".join(b)
-        return s and (struct.pack(">lll", 0, 0, len(s)) + s)
-
-    bin = []
-    p = [0]
-    for i in a: p.append(p[-1] + len(i))
-
-    d = difflib.SequenceMatcher(None, a, b).get_matching_blocks()
-    d = _normalizeblocks(a, b, d)
-    la = 0
-    lb = 0
-    for am, bm, size in d:
-        s = "".join(b[lb:bm])
-        if am > la or s:
-            bin.append(struct.pack(">lll", p[la], p[am], len(s)) + s)
-        la = am + size
-        lb = bm + size
-
-    return "".join(bin)
-
-def blocks(a, b):
-    an = splitnewlines(a)
-    bn = splitnewlines(b)
-    d = difflib.SequenceMatcher(None, an, bn).get_matching_blocks()
-    d = _normalizeblocks(an, bn, d)
-    return [(i, i + n, j, j + n) for (i, j, n) in d]
-
--- a/sys/src/cmd/hg/mercurial/pure/diffhelpers.py
+++ /dev/null
@@ -1,56 +1,0 @@
-# diffhelpers.py - pure Python implementation of diffhelpers.c
-#
-# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-def addlines(fp, hunk, lena, lenb, a, b):
-    while True:
-        todoa = lena - len(a)
-        todob = lenb - len(b)
-        num = max(todoa, todob)
-        if num == 0:
-            break
-        for i in xrange(num):
-            s = fp.readline()
-            c = s[0]
-            if s == "\\ No newline at end of file\n":
-                fix_newline(hunk, a, b)
-                continue
-            if c == "\n":
-                # Some patches may be missing the control char
-                # on empty lines. Supply a leading space.
-                s = " \n"
-            hunk.append(s)
-            if c == "+":
-                b.append(s[1:])
-            elif c == "-":
-                a.append(s)
-            else:
-                b.append(s[1:])
-                a.append(s)
-    return 0
-
-def fix_newline(hunk, a, b):
-    l = hunk[-1]
-    c = l[0]
-    hline = l[:-1]
-
-    if c == " " or c == "+":
-        b[-1] = l[1:-1]
-    if c == " " or c == "-":
-        a[-1] = hline
-    hunk[-1] = hline
-    return 0
-
-
-def testhunk(a, b, bstart):
-    alen = len(a)
-    blen = len(b)
-    if alen > blen - bstart:
-        return -1
-    for i in xrange(alen):
-        if a[i][1:] != b[i + bstart]:
-            return -1
-    return 0
--- a/sys/src/cmd/hg/mercurial/pure/mpatch.py
+++ /dev/null
@@ -1,116 +1,0 @@
-# mpatch.py - Python implementation of mpatch.c
-#
-# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import struct
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-# This attempts to apply a series of patches in time proportional to
-# the total size of the patches, rather than patches * len(text). This
-# means rather than shuffling strings around, we shuffle around
-# pointers to fragments with fragment lists.
-#
-# When the fragment lists get too long, we collapse them. To do this
-# efficiently, we do all our operations inside a buffer created by
-# mmap and simply use memmove. This avoids creating a bunch of large
-# temporary string buffers.
-
-def patches(a, bins):
-    if not bins: return a
-
-    plens = [len(x) for x in bins]
-    pl = sum(plens)
-    bl = len(a) + pl
-    tl = bl + bl + pl # enough for the patches and two working texts
-    b1, b2 = 0, bl
-
-    if not tl: return a
-
-    m = StringIO()
-    def move(dest, src, count):
-        """move count bytes from src to dest
-
-        The file pointer is left at the end of dest.
-        """
-        m.seek(src)
-        buf = m.read(count)
-        m.seek(dest)
-        m.write(buf)
-
-    # load our original text
-    m.write(a)
-    frags = [(len(a), b1)]
-
-    # copy all the patches into our segment so we can memmove from them
-    pos = b2 + bl
-    m.seek(pos)
-    for p in bins: m.write(p)
-
-    def pull(dst, src, l): # pull l bytes from src
-        while l:
-            f = src.pop(0)
-            if f[0] > l: # do we need to split?
-                src.insert(0, (f[0] - l, f[1] + l))
-                dst.append((l, f[1]))
-                return
-            dst.append(f)
-            l -= f[0]
-
-    def collect(buf, list):
-        start = buf
-        for l, p in list:
-            move(buf, p, l)
-            buf += l
-        return (buf - start, start)
-
-    for plen in plens:
-        # if our list gets too long, execute it
-        if len(frags) > 128:
-            b2, b1 = b1, b2
-            frags = [collect(b1, frags)]
-
-        new = []
-        end = pos + plen
-        last = 0
-        while pos < end:
-            m.seek(pos)
-            p1, p2, l = struct.unpack(">lll", m.read(12))
-            pull(new, frags, p1 - last) # what didn't change
-            pull([], frags, p2 - p1)    # what got deleted
-            new.append((l, pos + 12))        # what got added
-            pos += l + 12
-            last = p2
-        frags = new + frags                    # what was left at the end
-
-    t = collect(b2, frags)
-
-    m.seek(t[1])
-    return m.read(t[0])
-
-def patchedsize(orig, delta):
-    outlen, last, bin = 0, 0, 0
-    binend = len(delta)
-    data = 12
-
-    while data <= binend:
-        decode = delta[bin:bin + 12]
-        start, end, length = struct.unpack(">lll", decode)
-        if start > end:
-            break
-        bin = data + length
-        data = bin + 12
-        outlen += start - last
-        last = end
-        outlen += length
-
-    if bin != binend:
-        raise Exception("patch cannot be decoded")
-
-    outlen += orig - last
-    return outlen
--- a/sys/src/cmd/hg/mercurial/pure/osutil.py
+++ /dev/null
@@ -1,52 +1,0 @@
-# osutil.py - pure Python version of osutil.c
-#
-#  Copyright 2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-import os
-import stat as _stat
-
-posixfile = open
-
-def _mode_to_kind(mode):
-    if _stat.S_ISREG(mode): return _stat.S_IFREG
-    if _stat.S_ISDIR(mode): return _stat.S_IFDIR
-    if _stat.S_ISLNK(mode): return _stat.S_IFLNK
-    if _stat.S_ISBLK(mode): return _stat.S_IFBLK
-    if _stat.S_ISCHR(mode): return _stat.S_IFCHR
-    if _stat.S_ISFIFO(mode): return _stat.S_IFIFO
-    if _stat.S_ISSOCK(mode): return _stat.S_IFSOCK
-    return mode
-
-def listdir(path, stat=False, skip=None):
-    '''listdir(path, stat=False) -> list_of_tuples
-
-    Return a sorted list containing information about the entries
-    in the directory.
-
-    If stat is True, each element is a 3-tuple:
-
-      (name, type, stat object)
-
-    Otherwise, each element is a 2-tuple:
-
-      (name, type)
-    '''
-    result = []
-    prefix = path
-    if not prefix.endswith(os.sep):
-        prefix += os.sep
-    names = os.listdir(path)
-    names.sort()
-    for fn in names:
-        st = os.lstat(prefix + fn)
-        if fn == skip and _stat.S_ISDIR(st.st_mode):
-            return []
-        if stat:
-            result.append((fn, _mode_to_kind(st.st_mode), st))
-        else:
-            result.append((fn, _mode_to_kind(st.st_mode)))
-    return result
-
--- a/sys/src/cmd/hg/mercurial/pure/parsers.py
+++ /dev/null
@@ -1,90 +1,0 @@
-# parsers.py - Python implementation of parsers.c
-#
-# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-
-from mercurial.node import bin, nullid, nullrev
-from mercurial import util
-import struct, zlib
-
-_pack = struct.pack
-_unpack = struct.unpack
-_compress = zlib.compress
-_decompress = zlib.decompress
-_sha = util.sha1
-
-def parse_manifest(mfdict, fdict, lines):
-    for l in lines.splitlines():
-        f, n = l.split('\0')
-        if len(n) > 40:
-            fdict[f] = n[40:]
-            mfdict[f] = bin(n[:40])
-        else:
-            mfdict[f] = bin(n)
-
-def parse_index(data, inline):
-    def gettype(q):
-        return int(q & 0xFFFF)
-
-    def offset_type(offset, type):
-        return long(long(offset) << 16 | type)
-
-    indexformatng = ">Qiiiiii20s12x"
-
-    s = struct.calcsize(indexformatng)
-    index = []
-    cache = None
-    nodemap = {nullid: nullrev}
-    n = off = 0
-    # if we're not using lazymap, always read the whole index
-    l = len(data) - s
-    append = index.append
-    if inline:
-        cache = (0, data)
-        while off <= l:
-            e = _unpack(indexformatng, data[off:off + s])
-            nodemap[e[7]] = n
-            append(e)
-            n += 1
-            if e[1] < 0:
-                break
-            off += e[1] + s
-    else:
-        while off <= l:
-            e = _unpack(indexformatng, data[off:off + s])
-            nodemap[e[7]] = n
-            append(e)
-            n += 1
-            off += s
-
-    e = list(index[0])
-    type = gettype(e[0])
-    e[0] = offset_type(0, type)
-    index[0] = tuple(e)
-
-    # add the magic null revision at -1
-    index.append((0, 0, 0, -1, -1, -1, -1, nullid))
-
-    return index, nodemap, cache
-
-def parse_dirstate(dmap, copymap, st):
-    parents = [st[:20], st[20: 40]]
-    # deref fields so they will be local in loop
-    format = ">cllll"
-    e_size = struct.calcsize(format)
-    pos1 = 40
-    l = len(st)
-
-    # the inner loop
-    while pos1 < l:
-        pos2 = pos1 + e_size
-        e = _unpack(">cllll", st[pos1:pos2]) # a literal here is faster
-        pos1 = pos2 + e[4]
-        f = st[pos2:pos1]
-        if '\0' in f:
-            f, c = f.split('\0')
-            copymap[f] = c
-        dmap[f] = e[:4]
-    return parents
--- a/sys/src/cmd/hg/templates/atom/changelog.tmpl
+++ /dev/null
@@ -1,10 +1,0 @@
-{header}
- <!-- Changelog -->
- <id>{urlbase}{url}</id>
- <link rel="self" href="{urlbase}{url}atom-log"/>
- <link rel="alternate" href="{urlbase}{url}"/>
- <title>{repo|escape} Changelog</title>
- {latestentry%feedupdated}
-
-{entries%changelogentry}
-</feed>
--- a/sys/src/cmd/hg/templates/atom/changelogentry.tmpl
+++ /dev/null
@@ -1,16 +1,0 @@
- <entry>
-  <title>{desc|strip|firstline|strip|escape|nonempty}</title>
-  <id>{urlbase}{url}#changeset-{node}</id>
-  <link href="{urlbase}{url}rev/{node}"/>
-  <author>
-   <name>{author|person|escape}</name>
-   <email>{author|email|obfuscate}</email>
-  </author>
-  <updated>{date|rfc3339date}</updated>
-  <published>{date|rfc3339date}</published>
-  <content type="xhtml">
-   <div xmlns="http://www.w3.org/1999/xhtml">
-    <pre xml:space="preserve">{desc|escape|nonempty}</pre>
-   </div>
-  </content>
- </entry>
--- a/sys/src/cmd/hg/templates/atom/error.tmpl
+++ /dev/null
@@ -1,17 +1,0 @@
-{header}
- <!-- Error -->
- <id>{urlbase}{url}</id>
- <link rel="self" href="{urlbase}{url}atom-log"/>
- <link rel="alternate" href="{urlbase}{url}"/>
- <title>Error</title>
- <updated>1970-01-01T00:00:00+00:00</updated>
- <entry>
-  <title>Error</title>
-  <id>http://mercurial.selenic.com/#error</id>
-  <author>
-    <name>mercurial</name>
-  </author>
-  <updated>1970-01-01T00:00:00+00:00</updated>
-  <content type="text">{error|escape}</content>
- </entry>
-</feed>
--- a/sys/src/cmd/hg/templates/atom/filelog.tmpl
+++ /dev/null
@@ -1,8 +1,0 @@
-{header}
- <id>{urlbase}{url}atom-log/tip/{file|escape}</id>
- <link rel="self" href="{urlbase}{url}atom-log/tip/{file|urlescape}"/>
- <title>{repo|escape}: {file|escape} history</title>
- {latestentry%feedupdated}
-
-{entries%changelogentry}
-</feed>
--- a/sys/src/cmd/hg/templates/atom/header.tmpl
+++ /dev/null
@@ -1,2 +1,0 @@
-<?xml version="1.0" encoding="{encoding}"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
\ No newline at end of file
--- a/sys/src/cmd/hg/templates/atom/map
+++ /dev/null
@@ -1,11 +1,0 @@
-default = 'changelog'
-feedupdated = '<updated>{date|rfc3339date}</updated>'
-mimetype = 'application/atom+xml; charset={encoding}'
-header = header.tmpl
-changelog = changelog.tmpl
-changelogentry = changelogentry.tmpl
-filelog = filelog.tmpl
-filelogentry = filelogentry.tmpl
-tags = tags.tmpl
-tagentry = tagentry.tmpl
-error = error.tmpl
--- a/sys/src/cmd/hg/templates/atom/tagentry.tmpl
+++ /dev/null
@@ -1,8 +1,0 @@
- <entry>
-  <title>{tag|escape}</title>
-  <link rel="alternate" href="{urlbase}{url}rev/{node}"/>
-  <id>{urlbase}{url}#tag-{node}</id>
-  <updated>{date|rfc3339date}</updated>
-  <published>{date|rfc3339date}</published>
-  <content type="text">{tag|strip|escape}</content>
- </entry>
--- a/sys/src/cmd/hg/templates/atom/tags.tmpl
+++ /dev/null
@@ -1,11 +1,0 @@
-{header}
- <id>{urlbase}{url}</id>
- <link rel="self" href="{urlbase}{url}atom-tags"/>
- <link rel="alternate" href="{urlbase}{url}tags"/>
- <title>{repo|escape}: tags</title>
- <summary>{repo|escape} tag history</summary>
- <author><name>Mercurial SCM</name></author>
- {latestentry%feedupdated}
-
-{entriesnotip%tagentry}
-</feed>
--- a/sys/src/cmd/hg/templates/coal/header.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-<head>
-<link rel="icon" href="{staticurl}hgicon.png" type="image/png" />
-<meta name="robots" content="index, nofollow" />
-<link rel="stylesheet" href="{staticurl}style-coal.css" type="text/css" />
--- a/sys/src/cmd/hg/templates/coal/map
+++ /dev/null
@@ -1,191 +1,0 @@
-default = 'shortlog'
-
-mimetype = 'text/html; charset={encoding}'
-header = header.tmpl
-footer = ../paper/footer.tmpl
-search = ../paper/search.tmpl
-
-changelog = ../paper/shortlog.tmpl
-shortlog = ../paper/shortlog.tmpl
-shortlogentry = ../paper/shortlogentry.tmpl
-graph = ../paper/graph.tmpl
-
-naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navgraphentry = '<a href="{url}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
-filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenodelink = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenolink = '{file|escape} '
-fileellipses = '...'
-changelogentry = ../paper/shortlogentry.tmpl
-searchentry = ../paper/shortlogentry.tmpl
-changeset = ../paper/changeset.tmpl
-manifest = ../paper/manifest.tmpl
-
-direntry = '
-  <tr class="fileline parity{parity}">
-    <td class="name">
-      <a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">
-        <img src="{staticurl}coal-folder.png" alt="dir."/> {basename|escape}/
-      </a>
-      <a href="{url}file/{node|short}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
-        {emptydirs|escape}
-      </a>
-    </td>
-    <td class="size"></td>
-    <td class="permissions">drwxr-xr-x</td>
-  </tr>'
-
-fileentry = '
-  <tr class="fileline parity{parity}">
-    <td class="filename">
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        <img src="{staticurl}coal-file.png" alt="file"/> {basename|escape}
-      </a>
-    </td>
-    <td class="size">{size}</td>
-    <td class="permissions">{permissions|permissions}</td>
-  </tr>'
-
-filerevision = ../paper/filerevision.tmpl
-fileannotate = ../paper/fileannotate.tmpl
-filediff = ../paper/filediff.tmpl
-filelog = ../paper/filelog.tmpl
-fileline = '
-  <div class="parity{parity} source"><a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</div>'
-filelogentry = ../paper/filelogentry.tmpl
-
-annotateline = '
-  <tr class="parity{parity}">
-    <td class="annotate">
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
-    </td>
-    <td class="source"><a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</td>
-  </tr>'
-
-diffblock = '<div class="source bottomline parity{parity}"><pre>{lines}</pre></div>'
-difflineplus = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="plusline">{line|escape}</span>'
-difflineminus = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="minusline">{line|escape}</span>'
-difflineat = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="atline">{line|escape}</span>'
-diffline = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}'
-
-changelogparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-
-changesetparent = '<a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
-
-filerevparent = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
-filerevchild = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
-
-filerename = '{file|escape}@'
-filelogrename = '
-  <tr>
-    <th>base:</th>
-    <td>
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {file|escape}@{node|short}
-      </a>
-    </td>
-  </tr>'
-fileannotateparent = '
-  <tr>
-    <td class="metatag">parent:</td>
-    <td>
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-changesetchild = ' <a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
-changelogchild = '
-  <tr>
-    <th class="child">child</th>
-    <td class="child">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-fileannotatechild = '
-  <tr>
-    <td class="metatag">child:</td>
-    <td>
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-tags = ../paper/tags.tmpl
-tagentry = '
-  <tr class="tagEntry parity{parity}">
-    <td>
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        {tag|escape}
-      </a>
-    </td>
-    <td class="node">
-      {node|short}
-    </td>
-  </tr>'
-branches = ../paper/branches.tmpl
-branchentry = '
-  <tr class="tagEntry parity{parity}">
-    <td>
-      <a href="{url}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">
-        {branch|escape}
-      </a>
-    </td>
-    <td class="node">
-      {node|short}
-    </td>
-  </tr>'
-changelogtag = '<span class="tag">{name|escape}</span> '
-changesettag = '<span class="tag">{tag|escape}</span> '
-changelogbranchhead = '<span class="branchhead">{name|escape}</span> '
-changelogbranchname = '<span class="branchname">{name|escape}</span> ' 
-
-filediffparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filelogparent = '
-  <tr>
-    <th>parent {rev}:</th>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filediffchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-  </td>
-  </tr>'
-filelogchild = '
-  <tr>
-    <th>child {rev}:</th>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-
-indexentry = '
-  <tr class="parity{parity}">
-    <td><a href="{url}{sessionvars%urlparameter}">{name|escape}</a></td>
-    <td>{description}</td>
-    <td>{contact|obfuscate}</td>
-    <td class="age">{lastchange|age} ago</td>
-    <td class="indexlinks">{archives%indexarchiveentry}</td>
-  </tr>\n'
-indexarchiveentry = '<a href="{url}archive/{node|short}{extension|urlescape}">&nbsp;&darr;{type|escape}</a>'
-index = ../paper/index.tmpl
-archiveentry = '
-  <li>
-    <a href="{url}archive/{node|short}{extension|urlescape}">{type|escape}</a>
-  </li>'
-notfound = ../paper/notfound.tmpl
-error = ../paper/error.tmpl
-urlparameter = '{separator}{name}={value|urlescape}'
-hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
--- a/sys/src/cmd/hg/templates/gitweb/branches.tmpl
+++ /dev/null
@@ -1,30 +1,0 @@
-{header}
-<title>{repo|escape}: Branches</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-tags" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-tags" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / branches
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-branches |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-<br/>
-</div>
-
-<div class="title">&nbsp;</div>
-<table cellspacing="0">
-{entries%branchentry}
-</table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/changelog.tmpl
+++ /dev/null
@@ -1,39 +1,0 @@
-{header}
-<title>{repo|escape}: Changelog</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / changelog
-</div>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<div class="search">
-<input type="text" name="rev"  />
-</div>
-</form>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a> |
-changelog |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}
-<br/>
-{changenav%naventry}<br/>
-</div>
-
-{entries%changelogentry}
-
-<div class="page_nav">
-{changenav%naventry}<br/>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/changelogentry.tmpl
+++ /dev/null
@@ -1,14 +1,0 @@
-<div>
-<a class="title" href="{url}rev/{node|short}{sessionvars%urlparameter}"><span class="age">{date|age} ago</span>{desc|strip|firstline|escape|nonempty}<span class="logtags"> {inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span></a>
-</div>
-<div class="title_text">
-<div class="log_link">
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a><br/>
-</div>
-<i>{author|obfuscate} [{date|rfc822date}] rev {rev}</i><br/>
-</div>
-<div class="log_body">
-{desc|strip|escape|addbreaks|nonempty}
-<br/>
-<br/>
-</div>
--- a/sys/src/cmd/hg/templates/gitweb/changeset.tmpl
+++ /dev/null
@@ -1,50 +1,0 @@
-{header}
-<title>{repo|escape}: changeset {rev}:{node|short}</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / changeset
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a> |
-changeset |
-<a href="{url}raw-rev/{node|short}">raw</a> {archives%archiveentry}<br/>
-</div>
-
-<div>
-<a class="title" href="{url}raw-rev/{node|short}">{desc|strip|escape|firstline|nonempty} <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span></a>
-</div>
-<div class="title_text">
-<table cellspacing="0">
-<tr><td>author</td><td>{author|obfuscate}</td></tr>
-<tr><td></td><td>{date|date} ({date|age} ago)</td></tr>
-{branch%changesetbranch}
-<tr><td>changeset {rev}</td><td style="font-family:monospace">{node|short}</td></tr>
-{parent%changesetparent}
-{child%changesetchild}
-</table></div>
-
-<div class="page_body">
-{desc|strip|escape|addbreaks|nonempty}
-</div>
-<div class="list_head"></div>
-<div class="title_text">
-<table cellspacing="0">
-{files}
-</table></div>
-
-<div class="page_body">{diff}</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/error.tmpl
+++ /dev/null
@@ -1,25 +1,0 @@
-{header}
-<title>{repo|escape}: Error</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / error
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> | <a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> | <a href="{url}log{sessionvars%urlparameter}">changelog</a> | <a href="{url}tags{sessionvars%urlparameter}">tags</a> | <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a><br/>
-</div>
-
-<div class="page_body">
-<br/>
-<i>An error occurred while processing your request</i><br/>
-<br/>
-{error|escape}
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/fileannotate.tmpl
+++ /dev/null
@@ -1,61 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape}@{node|short} (annotated)</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / annotate
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a> |
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
-annotate |
-<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-<a href="{url}raw-annotate/{node|short}/{file|urlescape}">raw</a><br/>
-</div>
-
-<div class="title">{file|escape}</div>
-
-<div class="title_text">
-<table cellspacing="0">
-<tr>
- <td>author</td>
- <td>{author|obfuscate}</td></tr>
-<tr>
- <td></td>
- <td>{date|date} ({date|age} ago)</td></tr>
-{branch%filerevbranch}
-<tr>
- <td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
-{parent%fileannotateparent}
-{child%fileannotatechild}
-<tr>
- <td>permissions</td>
- <td style="font-family:monospace">{permissions|permissions}</td></tr>
-</table>
-</div>
-
-<div class="page_path">
-{desc|strip|escape|addbreaks|nonempty}
-</div>
-<div class="page_body">
-<table>
-{annotate%annotateline}
-</table>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/filediff.tmpl
+++ /dev/null
@@ -1,47 +1,0 @@
-{header}
-<title>{repo|escape}: diff {file|escape}</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / diff
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a> |
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
-<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
-diff |
-<a href="{url}raw-diff/{node|short}/{file|urlescape}">raw</a><br/>
-</div>
-
-<div class="title">{file|escape}</div>
-
-<table>
-{branch%filerevbranch}
-<tr>
- <td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
-{parent%filediffparent}
-{child%filediffchild}
-</table>
-
-<div class="list_head"></div>
-
-<div class="page_body">
-{diff}
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/filelog.tmpl
+++ /dev/null
@@ -1,40 +1,0 @@
-{header}
-<title>{repo|escape}: File revisions</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / file revisions
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-revisions |
-<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
-<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-<a href="{url}rss-log/{node|short}/{file|urlescape}">rss</a>
-<br/>
-{nav%filenaventry}
-</div>
-
-<div class="title" >{file|urlescape}</div>
-
-<table>
-{entries%filelogentry}
-</table>
-
-<div class="page_nav">
-{nav%filenaventry}
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/filerevision.tmpl
+++ /dev/null
@@ -1,60 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape}@{node|short}</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / file revision
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a> |
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-file |
-<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
-<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
-<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-<a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a><br/>
-</div>
-
-<div class="title">{file|escape}</div>
-
-<div class="title_text">
-<table cellspacing="0">
-<tr>
- <td>author</td>
- <td>{author|obfuscate}</td></tr>
-<tr>
- <td></td>
- <td>{date|date} ({date|age} ago)</td></tr>
-{branch%filerevbranch}
-<tr>
- <td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
-{parent%filerevparent}
-{child%filerevchild}
-<tr>
- <td>permissions</td>
- <td style="font-family:monospace">{permissions|permissions}</td></tr>
-</table>
-</div>
-
-<div class="page_path">
-{desc|strip|escape|addbreaks|nonempty}
-</div>
-
-<div class="page_body">
-{text%fileline}
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/footer.tmpl
+++ /dev/null
@@ -1,11 +1,0 @@
-<div class="page_footer">
-<div class="page_footer_text">{repo|escape}</div>
-<div class="rss_logo">
-<a href="{url}rss-log">RSS</a>
-<a href="{url}atom-log">Atom</a>
-</div>
-<br />
-{motd}
-</div>
-</body>
-</html>
--- a/sys/src/cmd/hg/templates/gitweb/graph.tmpl
+++ /dev/null
@@ -1,121 +1,0 @@
-{header}
-<title>{repo|escape}: Graph</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-<!--[if IE]><script type="text/javascript" src="{staticurl}excanvas.js"></script><![endif]-->
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / graph
-</div>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<div class="search">
-<input type="text" name="rev"  />
-</div>
-</form>
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a> |
-graph |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-<br/>
-<a href="{url}graph/{rev}{lessvars%urlparameter}">less</a>
-<a href="{url}graph/{rev}{morevars%urlparameter}">more</a>
-| {changenav%navgraphentry}<br/>
-</div>
-
-<div class="title">&nbsp;</div>
-
-<noscript>The revision graph only works with JavaScript-enabled browsers.</noscript>
-
-<div id="wrapper">
-<ul id="nodebgs"></ul>
-<canvas id="graph" width="224" height="{canvasheight}"></canvas>
-<ul id="graphnodes"></ul>
-</div>
-
-<script type="text/javascript" src="{staticurl}graph.js"></script>
-<script>
-<!-- hide script content
-
-var data = {jsdata|json};
-var graph = new Graph();
-graph.scale({bg_height});
-
-graph.edge = function(x0, y0, x1, y1, color) {
-	
-	this.setColor(color, 0.0, 0.65);
-	this.ctx.beginPath();
-	this.ctx.moveTo(x0, y0);
-	this.ctx.lineTo(x1, y1);
-	this.ctx.stroke();
-	
-}
-
-var revlink = '<li style="_STYLE"><span class="desc">';
-revlink += '<a class="list" href="{url}rev/_NODEID{sessionvars%urlparameter}" title="_NODEID"><b>_DESC</b></a>';
-revlink += '</span> _TAGS';
-revlink += '<span class="info">_DATE ago, by _USER</span></li>';
-
-graph.vertex = function(x, y, color, parity, cur) {
-	
-	this.ctx.beginPath();
-	color = this.setColor(color, 0.25, 0.75);
-	this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
-	this.ctx.fill();
-	
-	var bg = '<li class="bg parity' + parity + '"></li>';
-	var left = (this.columns + 1) * this.bg_height;
-	var nstyle = 'padding-left: ' + left + 'px;';
-	var item = revlink.replace(/_STYLE/, nstyle);
-	item = item.replace(/_PARITY/, 'parity' + parity);
-	item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_DESC/, cur[3]);
-	item = item.replace(/_USER/, cur[4]);
-	item = item.replace(/_DATE/, cur[5]);
-	
-	var tagspan = '';
-	if (cur[7].length || (cur[6][0] != 'default' || cur[6][1])) {
-		tagspan = '<span class="logtags">';
-		if (cur[6][1]) {
-			tagspan += '<span class="branchtag" title="' + cur[6][0] + '">';
-			tagspan += cur[6][0] + '</span> ';
-		} else if (!cur[6][1] && cur[6][0] != 'default') {
-			tagspan += '<span class="inbranchtag" title="' + cur[6][0] + '">';
-			tagspan += cur[6][0] + '</span> ';
-		}
-		if (cur[7].length) {
-			for (var t in cur[7]) {
-				var tag = cur[7][t];
-				tagspan += '<span class="tagtag">' + tag + '</span> ';
-			}
-		}
-		tagspan += '</span>';
-	}
-	
-	item = item.replace(/_TAGS/, tagspan);
-	return [bg, item];
-	
-}
-
-graph.render(data);
-
-// stop hiding script -->
-</script>
-
-<div class="page_nav">
-<a href="{url}graph/{rev}{lessvars%urlparameter}">less</a>
-<a href="{url}graph/{rev}{morevars%urlparameter}">more</a>
-| {changenav%navgraphentry}
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/header.tmpl
+++ /dev/null
@@ -1,8 +1,0 @@
-<?xml version="1.0" encoding="{encoding}"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<head>
-<link rel="icon" href="{staticurl}hgicon.png" type="image/png" />
-<meta name="robots" content="index, nofollow"/>
-<link rel="stylesheet" href="{staticurl}style-gitweb.css" type="text/css" />
-
--- a/sys/src/cmd/hg/templates/gitweb/index.tmpl
+++ /dev/null
@@ -1,26 +1,0 @@
-{header}
-<title>Mercurial repositories index</title>
-</head>
-<body>
-
-<div class="page_header">
-    <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a>
-    Repositories list
-</div>
-
-<table cellspacing="0">
-    <tr>
-        <td><a href="?sort={sort_name}">Name</a></td>
-        <td><a href="?sort={sort_description}">Description</a></td>
-        <td><a href="?sort={sort_contact}">Contact</a></td>
-        <td><a href="?sort={sort_lastchange}">Last change</a></td>
-        <td>&nbsp;</td>
-        <td>&nbsp;</td>
-    </tr>
-    {entries%indexentry}
-</table>
-<div class="page_footer">
-{motd}
-</div>
-</body>
-</html>
--- a/sys/src/cmd/hg/templates/gitweb/manifest.tmpl
+++ /dev/null
@@ -1,38 +1,0 @@
-{header}
-<title>{repo|escape}: files</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / files
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-files |
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> {archives%archiveentry}<br/>
-</div>
-
-<div class="title">{path|escape} <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span></div>
-<table cellspacing="0">
-<tr class="parity{upparity}">
-<td style="font-family:monospace">drwxr-xr-x</td>
-<td style="font-family:monospace"></td>
-<td style="font-family:monospace"></td>
-<td><a href="{url}file/{node|short}{up|urlescape}{sessionvars%urlparameter}">[up]</a></td>
-<td class="link">&nbsp;</td>
-</tr>
-{dentries%direntry}
-{fentries%fileentry}
-</table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/map
+++ /dev/null
@@ -1,248 +1,0 @@
-default = 'summary'
-mimetype = 'text/html; charset={encoding}'
-header = header.tmpl
-footer = footer.tmpl
-search = search.tmpl
-changelog = changelog.tmpl
-summary = summary.tmpl
-error = error.tmpl
-notfound = notfound.tmpl
-naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navgraphentry = '<a href="{url}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
-filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenodelink = '
-  <tr class="parity{parity}">
-    <td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
-    <td></td>
-    <td class="link">
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
-      <a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-      <a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-    </td>
-  </tr>'
-filenolink = '
-  <tr class="parity{parity}">
-    <td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
-    <td></td>
-    <td class="link">
-      file |
-      annotate |
-      <a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-      <a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-    </td>
-  </tr>'
-fileellipses = '...'
-changelogentry = changelogentry.tmpl
-searchentry = changelogentry.tmpl
-changeset = changeset.tmpl
-manifest = manifest.tmpl
-direntry = '
-  <tr class="parity{parity}">
-    <td style="font-family:monospace">drwxr-xr-x</td>
-    <td style="font-family:monospace"></td>
-    <td style="font-family:monospace"></td>
-    <td>
-      <a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
-      <a href="{url}file/{node|short}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">{emptydirs|escape}</a>
-    </td>
-    <td class="link">
-      <a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-fileentry = '
-  <tr class="parity{parity}">
-    <td style="font-family:monospace">{permissions|permissions}</td>
-    <td style="font-family:monospace" align=right>{date|isodate}</td>
-    <td style="font-family:monospace" align=right>{size}</td>
-    <td class="list">
-      <a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
-    </td>
-    <td class="link">
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-      <a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
-    </td>
-  </tr>'
-filerevision = filerevision.tmpl
-fileannotate = fileannotate.tmpl
-filediff = filediff.tmpl
-filelog = filelog.tmpl
-fileline = '
-  <div style="font-family:monospace" class="parity{parity}">
-    <pre><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</pre>
-  </div>'
-annotateline = '
-  <tr style="font-family:monospace" class="parity{parity}">
-    <td class="linenr" style="text-align: right;">
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
-    </td>
-    <td><pre><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a></pre></td>
-    <td><pre>{line|escape}</pre></td>
-  </tr>'
-difflineplus = '<span style="color:#008800;"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineminus = '<span style="color:#cc0000;"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineat = '<span style="color:#990099;"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-diffline = '<span><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-changelogparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-    </td>
-  </tr>'
-changesetbranch = '<tr><td>branch</td><td>{name}</td></tr>'
-changesetparent = '
-  <tr>
-    <td>parent {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-    </td>
-  </tr>'
-filerevbranch = '<tr><td>branch</td><td>{name}</td></tr>'
-filerevparent = '
-  <tr>
-    <td>parent {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-filerename = '{file|escape}@'
-filelogrename = '| <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">base</a>'
-fileannotateparent = '
-  <tr>
-    <td>parent {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-changelogchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-changesetchild = '
-  <tr>
-    <td>child {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-    </td>
-  </tr>'
-filerevchild = '
-  <tr>
-    <td>child {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-    </tr>'
-fileannotatechild = '
-  <tr>
-    <td>child {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-    </tr>'
-tags = tags.tmpl
-tagentry = '
-  <tr class="parity{parity}">
-    <td class="age"><i>{date|age} ago</i></td>
-    <td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>{tag|escape}</b></a></td>
-    <td class="link">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-      <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
-      <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-branches = branches.tmpl
-branchentry = '
-  <tr class="parity{parity}">
-    <td class="age"><i>{date|age} ago</i></td>
-    <td><a class="list" href="{url}shortlog/{node|short}{sessionvars%urlparameter}"><b>{node|short}</b></a></td>
-    <td class="{status}">{branch|escape}</td>
-    <td class="link">
-      <a href="{url}changeset/{node|short}{sessionvars%urlparameter}">changeset</a> |
-      <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
-      <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-diffblock = '<pre>{lines}</pre>'
-filediffparent = '
-  <tr>
-    <td>parent {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-filelogparent = '
-  <tr>
-    <td align="right">parent {rev}:&nbsp;</td>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filediffchild = '
-  <tr>
-    <td>child {rev}</td>
-    <td style="font-family:monospace">
-      <a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
-    </td>
-  </tr>'
-filelogchild = '
-  <tr>
-    <td align="right">child {rev}:&nbsp;</td>
-    <td><a href="{url}file{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-shortlog = shortlog.tmpl
-graph = graph.tmpl
-tagtag = '<span class="tagtag" title="{name}">{name}</span> '
-branchtag = '<span class="branchtag" title="{name}">{name}</span> '
-inbranchtag = '<span class="inbranchtag" title="{name}">{name}</span> '
-shortlogentry = '
-  <tr class="parity{parity}">
-    <td class="age"><i>{date|age} ago</i></td>
-    <td><i>{author|person}</i></td>
-    <td>
-      <a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        <b>{desc|strip|firstline|escape|nonempty}</b>
-        <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span>
-      </a>
-    </td>
-    <td class="link" nowrap>
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-      <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-filelogentry = '
-  <tr class="parity{parity}">
-    <td class="age"><i>{date|age} ago</i></td>
-    <td>
-      <a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        <b>{desc|strip|firstline|escape|nonempty}</b>
-      </a>
-    </td>
-    <td class="link">
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> {rename%filelogrename}</td>
-    </tr>'
-archiveentry = ' | <a href="{url}archive/{node|short}{extension}">{type|escape}</a> '
-indexentry = '
-  <tr class="parity{parity}">
-    <td>
-      <a class="list" href="{url}{sessionvars%urlparameter}">
-        <b>{name|escape}</b>
-      </a>
-    </td>
-    <td>{description}</td>
-    <td>{contact|obfuscate}</td>
-    <td class="age">{lastchange|age} ago</td>
-    <td class="indexlinks">{archives%indexarchiveentry}</td>
-    <td><div class="rss_logo"><a href="{url}rss-log">RSS</a> <a href="{url}atom-log">Atom</a></div></td>
-  </tr>\n'
-indexarchiveentry = ' <a href="{url}archive/{node|short}{extension}">{type|escape}</a> '
-index = index.tmpl
-urlparameter = '{separator}{name}={value|urlescape}'
-hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
--- a/sys/src/cmd/hg/templates/gitweb/notfound.tmpl
+++ /dev/null
@@ -1,18 +1,0 @@
-{header}
-<title>Mercurial repository not found</title>
-</head>
-
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a> Not found: {repo|escape}
-</div>
-
-<div class="page_body">
-The specified repository "{repo|escape}" is unknown, sorry.
-<br/>
-<br/>
-Please go back to the <a href="{url}">main repository list page</a>.
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/search.tmpl
+++ /dev/null
@@ -1,36 +1,0 @@
-{header}
-<title>{repo|escape}: Search</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / search
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<div class="search">
-<input type="text" name="rev" value="{query|escape}" />
-</div>
-</form>
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}
-<br/>
-</div>
-
-<div class="title">searching for {query|escape}</div>
-
-{entries}
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/shortlog.tmpl
+++ /dev/null
@@ -1,41 +1,0 @@
-{header}
-<title>{repo|escape}: Shortlog</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / shortlog
-</div>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<div class="search">
-<input type="text" name="rev"  />
-</div>
-</form>
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-shortlog |
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}
-<br/>
-{changenav%navshortentry}<br/>
-</div>
-
-<div class="title">&nbsp;</div>
-<table cellspacing="0">
-{entries%shortlogentry}
-</table>
-
-<div class="page_nav">
-{changenav%navshortentry}
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/summary.tmpl
+++ /dev/null
@@ -1,58 +1,0 @@
-{header}
-<title>{repo|escape}: Summary</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / summary
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<div class="search">
-<input type="text" name="rev"  />
-</div>
-</form>
-</div>
-
-<div class="page_nav">
-summary |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}
-<br/>
-</div>
-
-<div class="title">&nbsp;</div>
-<table cellspacing="0">
-<tr><td>description</td><td>{desc}</td></tr>
-<tr><td>owner</td><td>{owner|obfuscate}</td></tr>
-<tr><td>last change</td><td>{lastchange|rfc822date}</td></tr>
-</table>
-
-<div><a  class="title" href="{url}shortlog{sessionvars%urlparameter}">changes</a></div>
-<table cellspacing="0">
-{shortlog}
-<tr class="light"><td colspan="4"><a class="list" href="{url}shortlog{sessionvars%urlparameter}">...</a></td></tr>
-</table>
-
-<div><a class="title" href="{url}tags{sessionvars%urlparameter}">tags</a></div>
-<table cellspacing="0">
-{tags}
-<tr class="light"><td colspan="3"><a class="list" href="{url}tags{sessionvars%urlparameter}">...</a></td></tr>
-</table>
-
-<div><a class="title" href="#">branches</a></div>
-<table cellspacing="0">
-{branches%branchentry}
-<tr class="light">
-  <td colspan="4"><a class="list"  href="#">...</a></td>
-</tr>
-</table>
-{footer}
--- a/sys/src/cmd/hg/templates/gitweb/tags.tmpl
+++ /dev/null
@@ -1,30 +1,0 @@
-{header}
-<title>{repo|escape}: Tags</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-tags" title="Atom feed for {repo|escape}"/>
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-tags" title="RSS feed for {repo|escape}"/>
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / tags
-</div>
-
-<div class="page_nav">
-<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
-<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
-<a href="{url}graph{sessionvars%urlparameter}">graph</a> |
-tags |
-<a href="{url}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-<br/>
-</div>
-
-<div class="title">&nbsp;</div>
-<table cellspacing="0">
-{entries%tagentry}
-</table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/branches.tmpl
+++ /dev/null
@@ -1,36 +1,0 @@
-{header}
-    <title>{repo|escape}: Branches</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / Branches</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}changelog{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li class="current">branches</li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">tags</h2>
-    <table cellspacing="0">
-{entries%branchentry}
-    </table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/changelog.tmpl
+++ /dev/null
@@ -1,40 +1,0 @@
-{header}
-    <title>{repo|escape}: changelog</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / changelog</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li class="current">changelog</li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}</li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">changelog</h2>
-    <div>
-    {entries%changelogentry}
-    </div>
-
-    <div class="page-path">
-{changenav%naventry}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/changelogentry.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-<h3 class="changelog"><a class="title" href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}<span class="logtags"> {inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span></a></h3>
-<ul class="changelog-entry">
-    <li class="age">{date|age} ago</li>
-    <li>by <span class="name">{author|obfuscate}</span> <span class="revdate">[{date|rfc822date}] rev {rev}</span></li>
-    <li class="description">{desc|strip|escape|addbreaks|nonempty}</li>
-</ul>
--- a/sys/src/cmd/hg/templates/monoblue/changeset.tmpl
+++ /dev/null
@@ -1,63 +1,0 @@
-{header}
-<title>{repo|escape}: changeset {rev}:{node|short}</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / files</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}changelog{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <ul class="submenu">
-        <li class="current">changeset</li>
-        <li><a href="{url}raw-rev/{node|short}">raw</a> {archives%archiveentry}</li>
-    </ul>
-
-    <h2 class="no-link no-border">changeset</h2>
-
-    <h3 class="changeset"><a href="{url}raw-rev/{node|short}">{desc|strip|escape|firstline|nonempty} <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span></a></h3>
-    <p class="changeset-age"><span>{date|age} ago</span></p>
-
-    <dl class="overview">
-        <dt>author</dt>
-        <dd>{author|obfuscate}</dd>
-        <dt>date</dt>
-        <dd>{date|date}</dd>
-        {branch%changesetbranch}
-        <dt>changeset {rev}</dt>
-        <dd>{node|short}</dd>
-        {parent%changesetparent}
-        {child%changesetchild}
-    </dl>
-
-    <p class="description">{desc|strip|escape|addbreaks|nonempty}</p>
-
-    <table>
-    {files}
-    </table>
-
-    <div class="diff">
-    {diff}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/error.tmpl
+++ /dev/null
@@ -1,34 +1,0 @@
-{header}
-    <title>{repo|escape}: Error</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / Not found: {repo|escape}</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li class="current">summary</li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">An error occurred while processing your request</h2>
-    <p class="normal">{error|escape}</p>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/fileannotate.tmpl
+++ /dev/null
@@ -1,63 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape}@{node|short} (annotated)</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / annotate</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <ul class="submenu">
-        <li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
-        <li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a></li>
-        <li class="current">annotate</li>
-        <li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
-        <li><a href="{url}raw-annotate/{node|short}/{file|urlescape}">raw</a></li>
-    </ul>
-
-    <h2 class="no-link no-border">{file|escape}@{node|short} (annotated)</h2>
-    <h3 class="changeset">{file|escape}</h3>
-    <p class="changeset-age"><span>{date|age} ago</span></p>
-
-    <dl class="overview">
-        <dt>author</dt>
-        <dd>{author|obfuscate}</dd>
-        <dt>date</dt>
-        <dd>{date|date}</dd>
-        {branch%filerevbranch}
-        <dt>changeset {rev}</dt>
-        <dd><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>
-        {parent%fileannotateparent}
-        {child%fileannotatechild}
-        <dt>permissions</dt>
-        <dd>{permissions|permissions}</dd>
-    </dl>
-
-    <p class="description">{desc|strip|escape|addbreaks|nonempty}</p>
-
-    <table class="annotated">
-    {annotate%annotateline}
-    </table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/filediff.tmpl
+++ /dev/null
@@ -1,54 +1,0 @@
-{header}
-<title>{repo|escape}: diff {file|escape}</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / file diff</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <ul class="submenu">
-        <li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
-        <li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a></li>
-        <li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
-        <li class="current">diff</li>
-        <li><a href="{url}raw-diff/{node|short}/{file|urlescape}">raw</a></li>
-    </ul>
-
-    <h2 class="no-link no-border">diff: {file|escape}</h2>
-    <h3 class="changeset">{file|escape}</h3>
-
-    <dl class="overview">
-        {branch%filerevbranch}
-        <dt>changeset {rev}</dt>
-        <dd><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>
-        {parent%filediffparent}
-        {child%filediffchild}
-    </dl>
-
-    <div class="diff">
-    {diff}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/filelog.tmpl
+++ /dev/null
@@ -1,49 +1,0 @@
-{header}
-<title>{repo|escape}: File revisions</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / file revisions</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <ul class="submenu">
-        <li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
-        <li class="current">revisions</li>
-        <li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
-        <li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
-        <li><a href="{url}rss-log/{node|short}/{file|urlescape}">rss</a></li>
-    </ul>
-
-    <h2 class="no-link no-border">{file|urlescape}</h2>
-
-    <table>
-    {entries%filelogentry}
-    </table>
-
-    <div class="page-path">
-    {nav%filenaventry}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/filerevision.tmpl
+++ /dev/null
@@ -1,63 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape}@{node|short}</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / file revision</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}changelog{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <ul class="submenu">
-        <li class="current">file</li>
-        <li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a></li>
-        <li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
-        <li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
-        <li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
-    </ul>
-
-    <h2 class="no-link no-border">{file|escape}@{node|short}</h2>
-    <h3 class="changeset">{file|escape}</h3>
-    <p class="changeset-age"><span>{date|age} ago</span></p>
-
-    <dl class="overview">
-        <dt>author</dt>
-        <dd>{author|obfuscate}</dd>
-        <dt>date</dt>
-        <dd>{date|date}</dd>
-        {branch%filerevbranch}
-        <dt>changeset {rev}</dt>
-        <dd><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>
-        {parent%filerevparent}
-        {child%filerevchild}
-        <dt>permissions</dt>
-        <dd>{permissions|permissions}</dd>
-    </dl>
-
-    <p class="description">{desc|strip|escape|addbreaks|nonempty}</p>
-
-    <div class="source">
-    {text%fileline}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/footer.tmpl
+++ /dev/null
@@ -1,22 +1,0 @@
-    <div class="page-footer">
-        <p>Mercurial Repository: {repo|escape}</p>
-        <ul class="rss-logo">
-            <li><a href="{url}rss-log">RSS</a></li>
-            <li><a href="{url}atom-log">Atom</a></li>
-        </ul>
-        {motd}
-    </div>
-
-    <div id="powered-by">
-        <p><a href="http://mercurial.selenic.com/" title="Mercurial"><img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a></p>
-    </div>
-
-    <div id="corner-top-left"></div>
-    <div id="corner-top-right"></div>
-    <div id="corner-bottom-left"></div>
-    <div id="corner-bottom-right"></div>
-
-</div>
-
-</body>
-</html>
--- a/sys/src/cmd/hg/templates/monoblue/graph.tmpl
+++ /dev/null
@@ -1,118 +1,0 @@
-{header}
-    <title>{repo|escape}: graph</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-    <!--[if IE]><script type="text/javascript" src="{staticurl}excanvas.js"></script><![endif]-->
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / graph</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}changelog{sessionvars%urlparameter}">changelog</a></li>
-            <li class="current">graph</li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">graph</h2>
-
-    <div id="noscript">The revision graph only works with JavaScript-enabled browsers.</div>
-    <div id="wrapper">
-        <ul id="nodebgs"></ul>
-        <canvas id="graph" width="224" height="{canvasheight}"></canvas>
-        <ul id="graphnodes"></ul>
-    </div>
-
-    <script type="text/javascript" src="{staticurl}graph.js"></script>
-    <script>
-    <!-- hide script content
-
-    document.getElementById('noscript').style.display = 'none';
-
-    var data = {jsdata|json};
-    var graph = new Graph();
-    graph.scale({bg_height});
-
-    graph.edge = function(x0, y0, x1, y1, color) {
-
-        this.setColor(color, 0.0, 0.65);
-        this.ctx.beginPath();
-        this.ctx.moveTo(x0, y0);
-        this.ctx.lineTo(x1, y1);
-        this.ctx.stroke();
-
-    }
-
-    var revlink = '<li style="_STYLE"><span class="desc">';
-    revlink += '<a href="{url}rev/_NODEID{sessionvars%urlparameter}" title="_NODEID">_DESC</a>';
-    revlink += '</span>_TAGS<span class="info">_DATE ago, by _USER</span></li>';
-
-    graph.vertex = function(x, y, color, parity, cur) {
-
-        this.ctx.beginPath();
-        color = this.setColor(color, 0.25, 0.75);
-        this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
-        this.ctx.fill();
-
-        var bg = '<li class="bg parity' + parity + '"></li>';
-        var left = (this.columns + 1) * this.bg_height;
-        var nstyle = 'padding-left: ' + left + 'px;';
-        var item = revlink.replace(/_STYLE/, nstyle);
-        item = item.replace(/_PARITY/, 'parity' + parity);
-        item = item.replace(/_NODEID/, cur[0]);
-        item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_DESC/, cur[3]);
-        item = item.replace(/_USER/, cur[4]);
-        item = item.replace(/_DATE/, cur[5]);
-
-        var tagspan = '';
-        if (cur[7].length || (cur[6][0] != 'default' || cur[6][1])) {
-            tagspan = '<span class="logtags">';
-            if (cur[6][1]) {
-                tagspan += '<span class="branchtag" title="' + cur[6][0] + '">';
-                tagspan += cur[6][0] + '</span> ';
-            } else if (!cur[6][1] && cur[6][0] != 'default') {
-                tagspan += '<span class="inbranchtag" title="' + cur[6][0] + '">';
-                tagspan += cur[6][0] + '</span> ';
-            }
-            if (cur[7].length) {
-                for (var t in cur[7]) {
-                    var tag = cur[7][t];
-                    tagspan += '<span class="tagtag">' + tag + '</span> ';
-                }
-            }
-            tagspan += '</span>';
-        }
-
-        item = item.replace(/_TAGS/, tagspan); 
-        return [bg, item];
-
-    }
-
-    graph.render(data);
-
-    // stop hiding script -->
-    </script>
-
-    <div class="page-path">
-        <a href="{url}graph/{rev}{lessvars%urlparameter}">less</a>
-        <a href="{url}graph/{rev}{morevars%urlparameter}">more</a>
-        | {changenav%navgraphentry}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/header.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-    <link rel="icon" href="{staticurl}hgicon.png" type="image/png" />
-    <meta name="robots" content="index, nofollow"/>
-    <link rel="stylesheet" href="{staticurl}style-monoblue.css" type="text/css" />
--- a/sys/src/cmd/hg/templates/monoblue/index.tmpl
+++ /dev/null
@@ -1,39 +1,0 @@
-{header}
-    <title>{repo|escape}: Mercurial repositories index</title>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1>Mercurial Repositories</h1>
-        <ul class="page-nav">
-        </ul>
-    </div>
-    
-    <table cellspacing="0">
-        <tr>
-            <td><a href="?sort={sort_name}">Name</a></td>
-            <td><a href="?sort={sort_description}">Description</a></td>
-            <td><a href="?sort={sort_contact}">Contact</a></td>
-            <td><a href="?sort={sort_lastchange}">Last change</a></td>
-            <td>&nbsp;</td>
-            <td>&nbsp;</td>
-        </tr>
-        {entries%indexentry}
-    </table>
-    <div class="page-footer">
-        {motd}
-    </div>
-
-    <div id="powered-by">
-        <p><a href="http://mercurial.selenic.com/" title="Mercurial"><img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a></p>
-    </div>
-
-    <div id="corner-top-left"></div>
-    <div id="corner-top-right"></div>
-    <div id="corner-bottom-left"></div>
-    <div id="corner-bottom-right"></div>
-
-</div>
-</body>
-</html>
--- a/sys/src/cmd/hg/templates/monoblue/manifest.tmpl
+++ /dev/null
@@ -1,51 +1,0 @@
-{header}
-<title>{repo|escape}: files</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / files</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}changelog{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li class="current">files</li>
-        </ul>
-    </div>
-
-    <ul class="submenu">
-        <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> {archives%archiveentry}</li>
-        {archives%archiveentry}
-    </ul>
-
-    <h2 class="no-link no-border">files</h2>
-    <p class="files">{path|escape} <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span></p>
-
-    <table>
-        <tr class="parity{upparity}">
-            <td>drwxr-xr-x</td>
-            <td></td>
-            <td></td>
-            <td><a href="{url}file/{node|short}{up|urlescape}{sessionvars%urlparameter}">[up]</a></td>
-            <td class="link">&nbsp;</td>
-        </tr>
-        {dentries%direntry}
-        {fentries%fileentry}
-    </table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/map
+++ /dev/null
@@ -1,214 +1,0 @@
-default = 'summary'
-mimetype = 'text/html; charset={encoding}'
-header = header.tmpl
-footer = footer.tmpl
-search = search.tmpl
-changelog = changelog.tmpl
-summary = summary.tmpl
-error = error.tmpl
-notfound = notfound.tmpl
-naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navgraphentry = '<a href="{url}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a>'
-filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenodelink = '
-  <tr class="parity{parity}">
-    <td><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
-    <td></td>
-    <td>
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
-      <a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-      <a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-    </td>
-  </tr>'
-filenolink = '
-  <tr class="parity{parity}">
-    <td>
-      <a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td><td></td><td>file |
-      annotate |
-      <a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
-      <a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-    </td>
-  </tr>'
-fileellipses = '...'
-changelogentry = changelogentry.tmpl
-searchentry = changelogentry.tmpl
-changeset = changeset.tmpl
-manifest = manifest.tmpl
-direntry = '
-  <tr class="parity{parity}">
-    <td>drwxr-xr-x</td>
-    <td></td>
-    <td></td>
-    <td><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a></td>
-    <td><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a></td>
-  </tr>'
-fileentry = '
-  <tr class="parity{parity}">
-    <td>{permissions|permissions}</td>
-    <td>{date|isodate}</td>
-    <td>{size}</td>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a></td>
-    <td>
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
-      <a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
-    </td>
-  </tr>'
-filerevision = filerevision.tmpl
-fileannotate = fileannotate.tmpl
-filediff = filediff.tmpl
-filelog = filelog.tmpl
-fileline = '
-  <div style="font-family:monospace" class="parity{parity}">
-    <pre><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</pre>
-  </div>'
-annotateline = '
-  <tr class="parity{parity}">
-    <td class="linenr">
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
-    </td>
-    <td class="lineno">
-      <a href="#{lineid}" id="{lineid}">{linenumber}</a>
-    </td>
-    <td class="source">{line|escape}</td>
-  </tr>'
-difflineplus = '<span style="color:#008800;"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineminus = '<span style="color:#cc0000;"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineat = '<span style="color:#990099;"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-diffline = '<span><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-changelogparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-    </td>
-  </tr>'
-changesetbranch = '<dt>branch</dt><dd>{name}</dd>'
-changesetparent = '
-  <dt>parent {rev}</dt>
-  <dd><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
-filerevbranch = '<dt>branch</dt><dd>{name}</dd>'
-filerevparent = '
-  <dt>parent {rev}</dt>
-  <dd>
-    <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-      {rename%filerename}{node|short}
-    </a>
-  </dd>'
-filerename = '{file|escape}@'
-filelogrename = '| <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">base</a>'
-fileannotateparent = '
-  <dt>parent {rev}</dt>
-  <dd>
-    <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-      {rename%filerename}{node|short}
-    </a>
-  </dd>'
-changelogchild = '
-  <dt>child {rev}:</dt>
-  <dd><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
-changesetchild = '
-  <dt>child {rev}</dt>
-  <dd><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
-filerevchild = '
-  <dt>child {rev}</dt>
-  <dd>
-    <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
-  </dd>'
-fileannotatechild = '
-  <dt>child {rev}</dt>
-  <dd>
-    <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
-  </dd>'
-tags = tags.tmpl
-tagentry = '
-  <tr class="parity{parity}">
-    <td class="nowrap">{date|age} ago</td>
-    <td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{tag|escape}</a></td>
-    <td class="nowrap">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-      <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
-      <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-branches = branches.tmpl
-branchentry = '
-  <tr class="parity{parity}">
-    <td class="nowrap">{date|age} ago</td>
-    <td><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-    <td class="{status}">{branch|escape}</td>
-    <td class="nowrap">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-      <a href="{url}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
-      <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-diffblock = '<pre>{lines}</pre>'
-filediffparent = '
-  <dt>parent {rev}</dt>
-  <dd><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
-filelogparent = '
-  <tr>
-    <td align="right">parent {rev}:&nbsp;</td>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filediffchild = '
-  <dt>child {rev}</dt>
-  <dd><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
-filelogchild = '
-  <tr>
-    <td align="right">child {rev}:&nbsp;</td>
-    <td><a href="{url}file{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-shortlog = shortlog.tmpl
-tagtag = '<span class="tagtag" title="{name}">{name}</span> '
-branchtag = '<span class="branchtag" title="{name}">{name}</span> '
-inbranchtag = '<span class="inbranchtag" title="{name}">{name}</span> '
-shortlogentry = '
-  <tr class="parity{parity}">
-    <td class="nowrap">{date|age} ago</td>
-    <td>{author|person}</td>
-    <td>
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        {desc|strip|firstline|escape|nonempty}
-        <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span>
-      </a>
-    </td>
-    <td class="nowrap">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
-      <a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-    </td>
-  </tr>'
-filelogentry = '
-  <tr class="parity{parity}">
-    <td class="nowrap">{date|age} ago</td>
-    <td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a></td>
-    <td class="nowrap">
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
-      {rename%filelogrename}
-    </td>
-  </tr>'
-archiveentry = '<li><a href="{url}archive/{node|short}{extension}">{type|escape}</a></li>'
-indexentry = '
-  <tr class="parity{parity}">
-    <td><a href="{url}{sessionvars%urlparameter}">{name|escape}</a></td>
-    <td>{description}</td>
-    <td>{contact|obfuscate}</td>
-    <td>{lastchange|age} ago</td>
-    <td class="indexlinks">{archives%indexarchiveentry}</td>
-    <td>
-      <div class="rss_logo">
-        <a href="{url}rss-log">RSS</a>
-        <a href="{url}atom-log">Atom</a>
-      </div>
-    </td>
-  </tr>\n'
-indexarchiveentry = '<a href="{url}archive/{node|short}{extension}">{type|escape}</a> '
-index = index.tmpl
-urlparameter = '{separator}{name}={value|urlescape}'
-hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
-graph = graph.tmpl
--- a/sys/src/cmd/hg/templates/monoblue/notfound.tmpl
+++ /dev/null
@@ -1,35 +1,0 @@
-{header}
-    <title>{repo|escape}: Mercurial repository not found</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / Not found: {repo|escape}</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li class="current">summary</li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}</li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">Not Found</h2>
-    <p class="normal">The specified repository "{repo|escape}" is unknown, sorry.</p>
-    <p class="normal">Please go back to the <a href="{url}">main repository list page</a>.</p>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/search.tmpl
+++ /dev/null
@@ -1,34 +1,0 @@
-{header}
-    <title>{repo|escape}: Search</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / search</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" value="{query|escape}" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">searching for {query|escape}</h2>
-    {entries}
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/shortlog.tmpl
+++ /dev/null
@@ -1,41 +1,0 @@
-{header}
-    <title>{repo|escape}: shortlog</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / shortlog</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li class="current">shortlog</li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}</li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">shortlog</h2>
-
-    <table>
-{entries%shortlogentry}
-    </table>
-
-    <div class="page-path">
-{changenav%navshortentry}
-    </div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/summary.tmpl
+++ /dev/null
@@ -1,66 +1,0 @@
-{header}
-    <title>{repo|escape}: Summary</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / summary</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li class="current">summary</li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}log{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">Mercurial Repository Overview</h2>
-    <dl class="overview">
-        <dt>name</dt>
-        <dd>{repo|escape}</dd>
-        <dt>description</dt>
-        <dd>{desc}</dd>
-        <dt>owner</dt>
-        <dd>{owner|obfuscate}</dd>
-        <dt>last change</dt>
-        <dd>{lastchange|rfc822date}</dd>
-    </dl>
-
-    <h2><a href="{url}shortlog{sessionvars%urlparameter}">Changes</a></h2>
-    <table>
-{shortlog}
-        <tr class="light">
-            <td colspan="4"><a class="list" href="{url}shortlog{sessionvars%urlparameter}">...</a></td>
-        </tr>
-    </table>
-
-    <h2><a href="{url}tags{sessionvars%urlparameter}">Tags</a></h2>
-    <table>
-{tags}
-        <tr class="light">
-            <td colspan="3"><a class="list" href="{url}tags{sessionvars%urlparameter}">...</a></td>
-        </tr>
-    </table>
-
-    <h2 class="no-link">Branches</h2>
-    <table>
-    {branches%branchentry}
-        <tr class="light">
-          <td colspan="4"><a class="list"  href="#">...</a></td>
-        </tr>
-    </table>
-{footer}
--- a/sys/src/cmd/hg/templates/monoblue/tags.tmpl
+++ /dev/null
@@ -1,36 +1,0 @@
-{header}
-    <title>{repo|escape}: Tags</title>
-    <link rel="alternate" type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}"/>
-    <link rel="alternate" type="application/rss+xml" href="{url}rss-log" title="RSS feed for {repo|escape}"/>
-</head>
-
-<body>
-<div id="container">
-    <div class="page-header">
-        <h1><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / Tags</h1>
-
-        <form action="{url}log">
-            {sessionvars%hiddenformentry}
-            <dl class="search">
-                <dt><label>Search: </label></dt>
-                <dd><input type="text" name="rev" /></dd>
-            </dl>
-        </form>
-
-        <ul class="page-nav">
-            <li><a href="{url}summary{sessionvars%urlparameter}">summary</a></li>
-            <li><a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a></li>
-            <li><a href="{url}changelog{sessionvars%urlparameter}">changelog</a></li>
-            <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-            <li class="current">tags</li>
-            <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-            <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a></li>
-        </ul>
-    </div>
-
-    <h2 class="no-link no-border">tags</h2>
-    <table cellspacing="0">
-{entries%tagentry}
-    </table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/branches.tmpl
+++ /dev/null
@@ -1,45 +1,0 @@
-{header}
-<title>{repo|escape}: branches</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-tags" title="Atom feed for {repo|escape}: branches" />
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-tags" title="RSS feed for {repo|escape}: branches" />
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li class="active">branches</li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>branches</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<table class="bigtable">
-<tr>
- <th>branch</th>
- <th>node</th>
-</tr>
-{entries%branchentry}
-</table>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/changeset.tmpl
+++ /dev/null
@@ -1,71 +1,0 @@
-{header}
-<title>{repo|escape}: {node|short}</title>
-</head>
-<body>
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
- <li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
- <li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
- <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
- <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
- <li class="active">changeset</li>
- <li><a href="{url}raw-rev/{node|short}{sessionvars%urlparameter}">raw</a></li>
- <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-<ul>
- {archives%archiveentry}
-</ul>
-</div>
-
-<div class="main">
-
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>changeset {rev}:{node|short} {changesetbranch%changelogbranchname} {changesettag}</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="description">{desc|strip|escape|addbreaks|nonempty}</div>
-
-<table id="changesetEntry">
-<tr>
- <th class="author">author</th>
- <td class="author">{author|obfuscate}</td>
-</tr>
-<tr>
- <th class="date">date</th>
- <td class="date">{date|date} ({date|age} ago)</td></tr>
-<tr>
- <th class="author">parents</th>
- <td class="author">{parent%changesetparent}</td>
-</tr>
-<tr>
- <th class="author">children</th>
- <td class="author">{child%changesetchild}</td>
-</tr>
-<tr>
- <th class="files">files</th>
- <td class="files">{files}</td>
-</tr>
-</table>
-
-<div class="overflow">
-<div class="sourcefirst">   line diff</div>
-
-{diff}
-</div>
-
-</div>
-</div>
-{footer}
--- a/sys/src/cmd/hg/templates/paper/error.tmpl
+++ /dev/null
@@ -1,43 +1,0 @@
-{header}
-<title>{repo|escape}: error</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-</div>
-
-<div class="main">
-
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>error</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30"></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="description">
-<p>
-An error occurred while processing your request:
-</p>
-<p>
-{error|escape}
-</p>
-</div>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/fileannotate.tmpl
+++ /dev/null
@@ -1,77 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape} annotate</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-<ul>
-<li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
-<li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
-<li class="active">annotate</li>
-<li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
-<li><a href="{url}raw-annotate/{node|short}/{file|urlescape}">raw</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>annotate {file|escape} @ {rev}:{node|short}</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="description">{desc|strip|escape|addbreaks|nonempty}</div>
-
-<table id="changesetEntry">
-<tr>
- <th class="author">author</th>
- <td class="author">{author|obfuscate}</td>
-</tr>
-<tr>
- <th class="date">date</th>
- <td class="date">{date|date} ({date|age} ago)</td>
-</tr>
-<tr>
- <th class="author">parents</th>
- <td class="author">{parent%filerevparent}</td>
-</tr>
-<tr>
- <th class="author">children</th>
- <td class="author">{child%filerevchild}</td>
-</tr>
-{changesettag}
-</table>
-
-<div class="overflow">
-<table class="bigtable">
-<tr>
- <th class="annotate">rev</th>
- <th class="line">&nbsp;&nbsp;line source</th>
-</tr>
-{annotate%annotateline}
-</table>
-</div>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/filediff.tmpl
+++ /dev/null
@@ -1,72 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape} diff</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-<ul>
-<li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
-<li class="active">diff</li>
-<li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
-<li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
-<li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>diff {file|escape} @ {rev}:{node|short}</h3>
-
-<form class="search" action="{url}log">
-<p>{sessionvars%hiddenformentry}</p>
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="description">{desc|strip|escape|addbreaks|nonempty}</div>
-
-<table id="changesetEntry">
-<tr>
- <th>author</th>
- <td>{author|obfuscate}</td>
-</tr>
-<tr>
- <th>date</th>
- <td>{date|date} ({date|age} ago)</td>
-</tr>
-<tr>
- <th>parents</th>
- <td>{parent%filerevparent}</td>
-</tr>
-<tr>
- <th>children</th>
- <td>{child%filerevchild}</td>
-</tr>
-{changesettag}
-</table>
-
-<div class="overflow">
-<div class="sourcefirst">   line diff</div>
-
-{diff}
-</div>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/filelog.tmpl
+++ /dev/null
@@ -1,60 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape} history</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log/tip/{file|urlescape}" title="Atom feed for {repo|escape}:{file}" />
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log/tip/{file|urlescape}" title="RSS feed for {repo|escape}:{file}" />
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-<ul>
-<li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
-<li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
-<li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
-<li class="active">file log</li>
-<li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>log {file|escape}</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="navigate">{nav%filenaventry}</div>
-
-<table class="bigtable">
- <tr>
-  <th class="age">age</th>
-  <th class="author">author</th>
-  <th class="description">description</th>
- </tr>
-{entries%filelogentry}
-</table>
-
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/filelogentry.tmpl
+++ /dev/null
@@ -1,5 +1,0 @@
- <tr class="parity{parity}">
-  <td class="age">{date|age}</td>
-  <td class="author">{author|person}</td>
-  <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}</td>
- </tr>
--- a/sys/src/cmd/hg/templates/paper/filerevision.tmpl
+++ /dev/null
@@ -1,72 +1,0 @@
-{header}
-<title>{repo|escape}: {node|short} {file|escape}</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-<ul>
-<li class="active">file</li>
-<li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
-<li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
-<li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
-<li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>view {file|escape} @ {rev}:{node|short}</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="description">{desc|strip|escape|addbreaks|nonempty}</div>
-
-<table id="changesetEntry">
-<tr>
- <th class="author">author</th>
- <td class="author">{author|obfuscate}</td>
-</tr>
-<tr>
- <th class="date">date</th>
- <td class="date">{date|date} ({date|age} ago)</td>
-</tr>
-<tr>
- <th class="author">parents</th>
- <td class="author">{parent%filerevparent}</td>
-</tr>
-<tr>
- <th class="author">children</th>
- <td class="author">{child%filerevchild}</td>
-</tr>
-{changesettag}
-</table>
-
-<div class="overflow">
-<div class="sourcefirst"> line source</div>
-{text%fileline}
-<div class="sourcelast"></div>
-</div>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/footer.tmpl
+++ /dev/null
@@ -1,4 +1,0 @@
-{motd}
-
-</body>
-</html>
--- a/sys/src/cmd/hg/templates/paper/graph.tmpl
+++ /dev/null
@@ -1,132 +1,0 @@
-{header}
-<title>{repo|escape}: revision graph</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}: log" />
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}: log" />
-<!--[if IE]><script type="text/javascript" src="{staticurl}excanvas.js"></script><![endif]-->
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
-<li class="active">graph</li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>graph</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="navigate">
-<a href="{url}graph/{rev}{lessvars%urlparameter}">less</a>
-<a href="{url}graph/{rev}{morevars%urlparameter}">more</a>
-| rev {rev}: {changenav%navgraphentry}
-</div>
-
-<noscript><p>The revision graph only works with JavaScript-enabled browsers.</p></noscript>
-
-<div id="wrapper">
-<ul id="nodebgs"></ul>
-<canvas id="graph" width="224" height="{canvasheight}"></canvas>
-<ul id="graphnodes"></ul>
-</div>
-
-<script type="text/javascript" src="{staticurl}graph.js"></script>
-<script type="text/javascript">
-<!-- hide script content
-
-var data = {jsdata|json};
-var graph = new Graph();
-graph.scale({bg_height});
-
-graph.edge = function(x0, y0, x1, y1, color) {
-	
-	this.setColor(color, 0.0, 0.65);
-	this.ctx.beginPath();
-	this.ctx.moveTo(x0, y0);
-	this.ctx.lineTo(x1, y1);
-	this.ctx.stroke();
-	
-}
-
-var revlink = '<li style="_STYLE"><span class="desc">';
-revlink += '<a href="{url}rev/_NODEID{sessionvars%urlparameter}" title="_NODEID">_DESC</a>';
-revlink += '</span>_TAGS<span class="info">_DATE ago, by _USER</span></li>';
-
-graph.vertex = function(x, y, color, parity, cur) {
-	
-	this.ctx.beginPath();
-	color = this.setColor(color, 0.25, 0.75);
-	this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
-	this.ctx.fill();
-	
-	var bg = '<li class="bg parity' + parity + '"></li>';
-	var left = (this.columns + 1) * this.bg_height;
-	var nstyle = 'padding-left: ' + left + 'px;';
-	var item = revlink.replace(/_STYLE/, nstyle);
-	item = item.replace(/_PARITY/, 'parity' + parity);
-	item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_DESC/, cur[3]);
-	item = item.replace(/_USER/, cur[4]);
-	item = item.replace(/_DATE/, cur[5]);
-
-	var tagspan = '';
-	if (cur[7].length || (cur[6][0] != 'default' || cur[6][1])) {
-		tagspan = '<span class="logtags">';
-		if (cur[6][1]) {
-			tagspan += '<span class="branchhead" title="' + cur[6][0] + '">';
-			tagspan += cur[6][0] + '</span> ';
-		} else if (!cur[6][1] && cur[6][0] != 'default') {
-			tagspan += '<span class="branchname" title="' + cur[6][0] + '">';
-			tagspan += cur[6][0] + '</span> ';
-		}
-		if (cur[7].length) {
-			for (var t in cur[7]) {
-				var tag = cur[7][t];
-				tagspan += '<span class="tag">' + tag + '</span> ';
-			}
-		}
-		tagspan += '</span>';
-	}
-	
-	item = item.replace(/_TAGS/, tagspan);
-	return [bg, item];
-	
-}
-
-graph.render(data);
-
-// stop hiding script -->
-</script>
-
-<div class="navigate">
-<a href="{url}graph/{rev}{lessvars%urlparameter}">less</a>
-<a href="{url}graph/{rev}{morevars%urlparameter}">more</a>
-| rev {rev}: {changenav%navgraphentry}
-</div>
-
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/header.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-<head>
-<link rel="icon" href="{staticurl}hgicon.png" type="image/png" />
-<meta name="robots" content="index, nofollow" />
-<link rel="stylesheet" href="{staticurl}style-paper.css" type="text/css" />
--- a/sys/src/cmd/hg/templates/paper/index.tmpl
+++ /dev/null
@@ -1,26 +1,0 @@
-{header}
-<title>Mercurial repositories index</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
-</div>
-<div class="main">
-<h2>Mercurial Repositories</h2>
-
-<table class="bigtable">
-    <tr>
-        <th><a href="?sort={sort_name}">Name</a></th>
-        <th><a href="?sort={sort_description}">Description</a></th>
-        <th><a href="?sort={sort_contact}">Contact</a></th>
-        <th><a href="?sort={sort_lastchange}">Last change</a></th>
-        <th>&nbsp;</th>
-    </tr>
-    {entries%indexentry}
-</table>
-</div>
-</div>
-{footer}
--- a/sys/src/cmd/hg/templates/paper/manifest.tmpl
+++ /dev/null
@@ -1,54 +1,0 @@
-{header}
-<title>{repo|escape}: {node|short} {path|escape}</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li class="active">browse</li>
-</ul>
-<ul>
-{archives%archiveentry}
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>directory {path|escape} @ {rev}:{node|short} {tags%changelogtag}</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<table class="bigtable">
-<tr>
-  <th class="name">name</th>
-  <th class="size">size</th>
-  <th class="permissions">permissions</th>
-</tr>
-<tr class="fileline parity{upparity}">
-  <td class="name"><a href="{url}file/{node|short}{up|urlescape}{sessionvars%urlparameter}">[up]</a></td>
-  <td class="size"></td>
-  <td class="permissions">drwxr-xr-x</td>
-</tr>
-{dentries%direntry}
-{fentries%fileentry}
-</table>
-</div>
-</div>
-{footer}
--- a/sys/src/cmd/hg/templates/paper/map
+++ /dev/null
@@ -1,191 +1,0 @@
-default = 'shortlog'
-
-mimetype = 'text/html; charset={encoding}'
-header = header.tmpl
-footer = footer.tmpl
-search = search.tmpl
-
-changelog = shortlog.tmpl
-shortlog = shortlog.tmpl
-shortlogentry = shortlogentry.tmpl
-graph = graph.tmpl
-
-naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navgraphentry = '<a href="{url}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
-filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenodelink = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenolink = '{file|escape} '
-fileellipses = '...'
-changelogentry = shortlogentry.tmpl
-searchentry = shortlogentry.tmpl
-changeset = changeset.tmpl
-manifest = manifest.tmpl
-
-direntry = '
-  <tr class="fileline parity{parity}">
-    <td class="name">
-      <a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">
-        <img src="{staticurl}coal-folder.png" alt="dir."/> {basename|escape}/
-      </a>
-      <a href="{url}file/{node|short}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
-        {emptydirs|escape}
-      </a>
-    </td>
-    <td class="size"></td>
-    <td class="permissions">drwxr-xr-x</td>
-  </tr>'
-
-fileentry = '
-  <tr class="fileline parity{parity}">
-    <td class="filename">
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        <img src="{staticurl}coal-file.png" alt="file"/> {basename|escape}
-      </a>
-    </td>
-    <td class="size">{size}</td>
-    <td class="permissions">{permissions|permissions}</td>
-  </tr>'
-
-filerevision = filerevision.tmpl
-fileannotate = fileannotate.tmpl
-filediff = filediff.tmpl
-filelog = filelog.tmpl
-fileline = '
-  <div class="parity{parity} source"><a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</div>'
-filelogentry = filelogentry.tmpl
-
-annotateline = '
-  <tr class="parity{parity}">
-    <td class="annotate">
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
-    </td>
-    <td class="source"><a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</td>
-  </tr>'
-
-diffblock = '<div class="source bottomline parity{parity}"><pre>{lines}</pre></div>'
-difflineplus = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="plusline">{line|escape}</span>'
-difflineminus = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="minusline">{line|escape}</span>'
-difflineat = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="atline">{line|escape}</span>'
-diffline = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}'
-
-changelogparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-
-changesetparent = '<a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
-
-filerevparent = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
-filerevchild = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
-
-filerename = '{file|escape}@'
-filelogrename = '
-  <tr>
-    <th>base:</th>
-    <td>
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {file|escape}@{node|short}
-      </a>
-    </td>
-  </tr>'
-fileannotateparent = '
-  <tr>
-    <td class="metatag">parent:</td>
-    <td>
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-changesetchild = ' <a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
-changelogchild = '
-  <tr>
-    <th class="child">child</th>
-    <td class="child">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-fileannotatechild = '
-  <tr>
-    <td class="metatag">child:</td>
-    <td>
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-tags = tags.tmpl
-tagentry = '
-  <tr class="tagEntry parity{parity}">
-    <td>
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">
-        {tag|escape}
-      </a>
-    </td>
-    <td class="node">
-      {node|short}
-    </td>
-  </tr>'
-branches = branches.tmpl
-branchentry = '
-  <tr class="tagEntry parity{parity}">
-    <td>
-      <a href="{url}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">
-        {branch|escape}
-      </a>
-    </td>
-    <td class="node">
-      {node|short}
-    </td>
-  </tr>'
-changelogtag = '<span class="tag">{name|escape}</span> '
-changesettag = '<span class="tag">{tag|escape}</span> '
-changelogbranchhead = '<span class="branchhead">{name|escape}</span> '
-changelogbranchname = '<span class="branchname">{name|escape}</span> ' 
-
-filediffparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filelogparent = '
-  <tr>
-    <th>parent {rev}:</th>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filediffchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-  </td>
-  </tr>'
-filelogchild = '
-  <tr>
-    <th>child {rev}:</th>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-
-indexentry = '
-  <tr class="parity{parity}">
-    <td><a href="{url}{sessionvars%urlparameter}">{name|escape}</a></td>
-    <td>{description}</td>
-    <td>{contact|obfuscate}</td>
-    <td class="age">{lastchange|age} ago</td>
-    <td class="indexlinks">{archives%indexarchiveentry}</td>
-  </tr>\n'
-indexarchiveentry = '<a href="{url}archive/{node|short}{extension|urlescape}">&nbsp;&darr;{type|escape}</a>'
-index = index.tmpl
-archiveentry = '
-  <li>
-    <a href="{url}archive/{node|short}{extension|urlescape}">{type|escape}</a>
-  </li>'
-notfound = notfound.tmpl
-error = error.tmpl
-urlparameter = '{separator}{name}={value|urlescape}'
-hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
--- a/sys/src/cmd/hg/templates/paper/notfound.tmpl
+++ /dev/null
@@ -1,12 +1,0 @@
-{header}
-<title>Mercurial repository not found</title>
-</head>
-<body>
-
-<h2>Mercurial repository not found</h2>
-
-The specified repository "{repo|escape}" is unknown, sorry.
-
-Please go back to the <a href="{url}">main repository list page</a>.
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/search.tmpl
+++ /dev/null
@@ -1,43 +1,0 @@
-{header}
-<title>{repo|escape}: searching for {query|escape}</title>
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
-</div>
-<ul>
-<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>searching for '{query|escape}'</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30"></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<table class="bigtable">
- <tr>
-  <th class="age">age</th>
-  <th class="author">author</th>
-  <th class="description">description</th>
- </tr>
-{entries}
-</table>
-
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/shortlog.tmpl
+++ /dev/null
@@ -1,57 +1,0 @@
-{header}
-<title>{repo|escape}: log</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}" />
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}" />
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li class="active">log</li>
-<li><a href="{url}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
-<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-<ul>
-<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
-<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
-</ul>
-<ul>
-{archives%archiveentry}
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>log</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<div class="navigate">rev {rev}: {changenav%navshortentry}</div>
-
-<table class="bigtable">
- <tr>
-  <th class="age">age</th>
-  <th class="author">author</th>
-  <th class="description">description</th>
- </tr>
-{entries%shortlogentry}
-</table>
-
-<div class="navigate">rev {rev}: {changenav%navshortentry}</div>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/paper/shortlogentry.tmpl
+++ /dev/null
@@ -1,5 +1,0 @@
- <tr class="parity{parity}">
-  <td class="age">{date|age}</td>
-  <td class="author">{author|person}</td>
-  <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}</td>
- </tr>
--- a/sys/src/cmd/hg/templates/paper/tags.tmpl
+++ /dev/null
@@ -1,45 +1,0 @@
-{header}
-<title>{repo|escape}: tags</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-tags" title="Atom feed for {repo|escape}: tags" />
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-tags" title="RSS feed for {repo|escape}: tags" />
-</head>
-<body>
-
-<div class="container">
-<div class="menu">
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" alt="mercurial" /></a>
-</div>
-<ul>
-<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
-<li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li>
-<li class="active">tags</li>
-<li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
-</ul>
-</div>
-
-<div class="main">
-<h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
-<h3>tags</h3>
-
-<form class="search" action="{url}log">
-{sessionvars%hiddenformentry}
-<p><input name="rev" id="search1" type="text" size="30" /></p>
-<div id="hint">find changesets by author, revision,
-files, or words in the commit message</div>
-</form>
-
-<table class="bigtable">
-<tr>
- <th>tag</th>
- <th>node</th>
-</tr>
-{entries%tagentry}
-</table>
-</div>
-</div>
-
-{footer}
--- a/sys/src/cmd/hg/templates/raw/changeset.tmpl
+++ /dev/null
@@ -1,9 +1,0 @@
-{header}
-# HG changeset patch
-# User {author}
-# Date {date|hgdate}
-# Node ID {node}
-{parent%changesetparent}
-{desc}
-
-{diff}
--- a/sys/src/cmd/hg/templates/raw/error.tmpl
+++ /dev/null
@@ -1,2 +1,0 @@
-{header}
-error: {error}
--- a/sys/src/cmd/hg/templates/raw/fileannotate.tmpl
+++ /dev/null
@@ -1,5 +1,0 @@
-{header}
-{annotate%annotateline}
-{footer}
-
-
--- a/sys/src/cmd/hg/templates/raw/filediff.tmpl
+++ /dev/null
@@ -1,5 +1,0 @@
-{header}
-{diff}
-{footer}
-
-
--- a/sys/src/cmd/hg/templates/raw/index.tmpl
+++ /dev/null
@@ -1,2 +1,0 @@
-{header}
-{entries%indexentry}
--- a/sys/src/cmd/hg/templates/raw/manifest.tmpl
+++ /dev/null
@@ -1,3 +1,0 @@
-{header}
-{dentries%direntry}{fentries%fileentry}
-{footer}
--- a/sys/src/cmd/hg/templates/raw/map
+++ /dev/null
@@ -1,23 +1,0 @@
-mimetype = 'text/plain; charset={encoding}'
-header = ''
-footer = ''
-changeset = changeset.tmpl
-difflineplus = '{line}'
-difflineminus = '{line}'
-difflineat = '{line}'
-diffline = '{line}'
-changesetparent = '# Parent  {node}'
-changesetchild = '# Child   {node}'
-filenodelink = ''
-fileline = '{line}'
-diffblock = '{lines}'
-filediff = filediff.tmpl
-fileannotate = fileannotate.tmpl
-annotateline = '{author|user}@{rev}: {line}'
-manifest = manifest.tmpl
-direntry = 'drwxr-xr-x {basename}\n'
-fileentry = '{permissions|permissions} {size} {basename}\n'
-index = index.tmpl
-notfound = notfound.tmpl
-error = error.tmpl
-indexentry = '{url}\n'
--- a/sys/src/cmd/hg/templates/raw/notfound.tmpl
+++ /dev/null
@@ -1,2 +1,0 @@
-{header}
-error: repository {repo} not found
--- a/sys/src/cmd/hg/templates/rss/changelog.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-{header}
-    <title>{repo|escape} Changelog</title>
-    <description>{repo|escape} Changelog</description>
-    {entries%changelogentry}
-  </channel>
-</rss>
\ No newline at end of file
--- a/sys/src/cmd/hg/templates/rss/changelogentry.tmpl
+++ /dev/null
@@ -1,7 +1,0 @@
-<item>
-    <title>{desc|strip|firstline|strip|escape}</title>
-    <guid isPermaLink="true">{urlbase}{url}rev/{node|short}</guid>
-    <description><![CDATA[{desc|strip|escape|addbreaks|nonempty}]]></description>
-    <author>{author|obfuscate}</author>
-    <pubDate>{date|rfc822date}</pubDate>
-</item>
--- a/sys/src/cmd/hg/templates/rss/error.tmpl
+++ /dev/null
@@ -1,10 +1,0 @@
-{header}
-    <title>Error</title>
-    <description>Error</description>
-    <item>
-      <title>Error</title>
-      <description>{error|escape}</description>
-      <guid>http://mercurial.selenic.com/#error</guid>
-    </item>
-  </channel>
-</rss>
--- a/sys/src/cmd/hg/templates/rss/filelog.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-{header}
-    <title>{repo|escape}: {file|escape} history</title>
-    <description>{file|escape} revision history</description>
-    {entries%filelogentry}
-  </channel>
-</rss>
--- a/sys/src/cmd/hg/templates/rss/filelogentry.tmpl
+++ /dev/null
@@ -1,7 +1,0 @@
-<item>
-    <title>{desc|strip|firstline|strip|escape}</title>
-    <link>{urlbase}{url}log{{node|short}}/{file|urlescape}</link>
-    <description><![CDATA[{desc|strip|escape|addbreaks|nonempty}]]></description>
-    <author>{author|obfuscate}</author>
-    <pubDate>{date|rfc822date}</pubDate>
-</item>
--- a/sys/src/cmd/hg/templates/rss/header.tmpl
+++ /dev/null
@@ -1,5 +1,0 @@
-<?xml version="1.0" encoding="{encoding}"?>
-<rss version="2.0">
-  <channel>
-    <link>{urlbase}{url}</link>
-    <language>en-us</language>
--- a/sys/src/cmd/hg/templates/rss/map
+++ /dev/null
@@ -1,10 +1,0 @@
-default = 'changelog'
-mimetype = 'text/xml; charset={encoding}'
-header = header.tmpl
-changelog = changelog.tmpl
-changelogentry = changelogentry.tmpl
-filelog = filelog.tmpl
-filelogentry = filelogentry.tmpl
-tags = tags.tmpl
-tagentry = tagentry.tmpl
-error = error.tmpl
--- a/sys/src/cmd/hg/templates/rss/tagentry.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-<item>
-    <title>{tag|escape}</title>
-    <link>{urlbase}{url}rev/{node|short}</link>
-    <description><![CDATA[{tag|strip|escape|addbreaks}]]></description>
-    <pubDate>{date|rfc822date}</pubDate>
-</item>
--- a/sys/src/cmd/hg/templates/rss/tags.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-{header}
-    <title>{repo|escape}: tags </title>
-    <description>{repo|escape} tag history</description>
-    {entriesnotip%tagentry}
-  </channel>
-</rss>
--- a/sys/src/cmd/hg/templates/spartan/branches.tmpl
+++ /dev/null
@@ -1,26 +1,0 @@
-{header}
-<title>{repo|escape}: branches</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-branches" title="Atom feed for {repo|escape}: branches">
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-branches" title="RSS feed for {repo|escape}: branches">
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}file/{node|short}/{sessionvars%urlparameter}">files</a>
-<a type="application/rss+xml" href="{url}rss-branches">rss</a>
-<a type="application/atom+xml" href="{url}atom-branches">atom</a>
-</div>
-
-<h2>branches:</h2>
-
-<ul id="tagEntries">
-{entries%branchentry}
-</ul>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/changelog.tmpl
+++ /dev/null
@@ -1,43 +1,0 @@
-{header}
-<title>{repo|escape}: changelog</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}">
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}">
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-{archives%archiveentry}
-<a type="application/rss+xml" href="{url}rss-log">rss</a>
-<a type="application/atom+xml" href="{url}atom-log" title="Atom feed for {repo|escape}">atom</a>
-</div>
-
-<h2>changelog for {repo|escape}</h2>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<p>
-<label for="search1">search:</label>
-<input name="rev" id="search1" type="text" size="30">
-navigate: <small class="navigate">{changenav%naventry}</small>
-</p>
-</form>
-
-{entries%changelogentry}
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<p>
-<label for="search2">search:</label>
-<input name="rev" id="search2" type="text" size="30">
-navigate: <small class="navigate">{changenav%naventry}</small>
-</p>
-</form>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/changelogentry.tmpl
+++ /dev/null
@@ -1,25 +1,0 @@
-<table class="logEntry parity{parity}">
- <tr>
-  <th class="age">{date|age} ago:</th>
-  <th class="firstline">{desc|strip|firstline|escape|nonempty}</th>
- </tr>
- <tr>
-  <th class="revision">changeset {rev}:</th>
-  <td class="node"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
- </tr>
- {parent%changelogparent}
- {child%changelogchild}
- {changelogtag}
- <tr>
-  <th class="author">author:</th>
-  <td class="author">{author|obfuscate}</td>
- </tr>
- <tr>
-  <th class="date">date:</th>
-  <td class="date">{date|date}</td>
- </tr>
- <tr>
-  <th class="files"><a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>:</th>
-  <td class="files">{files}</td>
- </tr>
-</table>
--- a/sys/src/cmd/hg/templates/spartan/changeset.tmpl
+++ /dev/null
@@ -1,51 +1,0 @@
-{header}
-<title>{repo|escape}: changeset {node|short}</title>
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-<a href="{url}raw-rev/{node|short}">raw</a>
-{archives%archiveentry}
-</div>
-
-<h2>changeset: {desc|strip|escape|firstline|nonempty}</h2>
-
-<table id="changesetEntry">
-<tr>
- <th class="changeset">changeset {rev}:</th>
- <td class="changeset"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-</tr>
-{parent%changesetparent}
-{child%changesetchild}
-{changesettag}
-<tr>
- <th class="author">author:</th>
- <td class="author">{author|obfuscate}</td>
-</tr>
-<tr>
- <th class="date">date:</th>
- <td class="date">{date|date} ({date|age} ago)</td>
-</tr>
-<tr>
- <th class="files">files:</th>
- <td class="files">{files}</td>
-</tr>
-<tr>
- <th class="description">description:</th>
- <td class="description">{desc|strip|escape|addbreaks|nonempty}</td>
-</tr>
-</table>
-
-<div id="changesetDiff">
-{diff}
-</div>
-
-{footer}
-
-
--- a/sys/src/cmd/hg/templates/spartan/error.tmpl
+++ /dev/null
@@ -1,15 +1,0 @@
-{header}
-<title>Mercurial Error</title>
-</head>
-<body>
-
-<h2>Mercurial Error</h2>
-
-<p>
-An error occurred while processing your request:
-</p>
-<p>
-{error|escape}
-</p>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/fileannotate.tmpl
+++ /dev/null
@@ -1,48 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape} annotate</title>
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a>
-<a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a>
-<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a>
-<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-<a href="{url}raw-annotate/{node|short}/{file|urlescape}">raw</a>
-</div>
-
-<h2>Annotate {file|escape}</h2>
-
-<table>
-<tr>
- <td class="metatag">changeset {rev}:</td>
- <td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
-{parent%fileannotateparent}
-{child%fileannotatechild}
-<tr>
- <td class="metatag">author:</td>
- <td>{author|obfuscate}</td></tr>
-<tr>
- <td class="metatag">date:</td>
- <td>{date|date} ({date|age} ago)</td>
-</tr>
-<tr>
- <td class="metatag">permissions:</td>
- <td>{permissions|permissions}</td>
-</tr>
-<tr>
-  <td class="metatag">description:</td>
-  <td>{desc|strip|escape|addbreaks|nonempty}</td>
-</tr>
-</table>
-
-<table cellspacing="0" cellpadding="0">
-{annotate%annotateline}
-</table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/filediff.tmpl
+++ /dev/null
@@ -1,36 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape} diff</title>
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a>
-<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a>
-<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
-<a href="{url}raw-diff/{node|short}/{file|urlescape}">raw</a>
-</div>
-
-<h2>{file|escape}</h2>
-
-<table id="filediffEntry">
-<tr>
- <th class="revision">revision {rev}:</th>
- <td class="revision"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-</tr>
-{parent%filediffparent}
-{child%filediffchild}
-</table>
-
-<div id="fileDiff">
-{diff}
-</div>
-
-{footer}
-
-
--- a/sys/src/cmd/hg/templates/spartan/filelog.tmpl
+++ /dev/null
@@ -1,28 +1,0 @@
-{header}
-<title>{repo|escape}: {file|escape} history</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log/tip/{file|urlescape}" title="Atom feed for {repo|escape}:{file}">
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log/tip/{file|urlescape}" title="RSS feed for {repo|escape}:{file}">
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a>
-<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
-<a type="application/rss+xml" href="{url}rss-log/tip/{file|urlescape}">rss</a>
-<a type="application/atom+xml" href="{url}atom-log/tip/{file|urlescape}" title="Atom feed for {repo|escape}:{file}">atom</a>
-</div>
-
-<h2>{file|escape} revision history</h2>
-
-<p>navigate: <small class="navigate">{nav%filenaventry}</small></p>
-
-{entries%filelogentry}
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/filelogentry.tmpl
+++ /dev/null
@@ -1,25 +1,0 @@
-<table class="logEntry parity{parity}">
- <tr>
-  <th class="age">{date|age} ago:</th>
-  <th class="firstline"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a></th>
- </tr>
- <tr>
-  <th class="revision">revision {filerev}:</td>
-  <td class="node">
-   <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
-   <a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">(diff)</a>
-   <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">(annotate)</a>
-  </td>
- </tr>
- {rename%filelogrename}
- <tr>
-  <th class="author">author:</th>
-  <td class="author">{author|obfuscate}</td>
- </tr>
- <tr>
-  <th class="date">date:</th>
-  <td class="date">{date|date}</td>
- </tr>
-</table>
-
-
--- a/sys/src/cmd/hg/templates/spartan/filerevision.tmpl
+++ /dev/null
@@ -1,46 +1,0 @@
-{header}
-<title>{repo|escape}:{file|escape}</title>
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a>
-<a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a>
-<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
-<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
-<a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a>
-</div>
-
-<h2>{file|escape}</h2>
-
-<table>
-<tr>
- <td class="metatag">changeset {rev}:</td>
- <td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
-{parent%filerevparent}
-{child%filerevchild}
-<tr>
- <td class="metatag">author:</td>
- <td>{author|obfuscate}</td></tr>
-<tr>
- <td class="metatag">date:</td>
- <td>{date|date} ({date|age} ago)</td></tr>
-<tr>
- <td class="metatag">permissions:</td>
- <td>{permissions|permissions}</td></tr>
-<tr>
-  <td class="metatag">description:</td>
-  <td>{desc|strip|escape|addbreaks|nonempty}</td>
-</tr>
-</table>
-
-<pre>
-{text%fileline}
-</pre>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/footer.tmpl
+++ /dev/null
@@ -1,8 +1,0 @@
-{motd}
-<div class="logo">
-<a href="http://mercurial.selenic.com/">
-<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
-</div>
-
-</body>
-</html>
--- a/sys/src/cmd/hg/templates/spartan/graph.tmpl
+++ /dev/null
@@ -1,96 +1,0 @@
-{header}
-<title>{repo|escape}: graph</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-tags" title="Atom feed for {repo|escape}: tags">
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-tags" title="RSS feed for {repo|escape}: tags">
-<!--[if IE]><script type="text/javascript" src="{staticurl}excanvas.js"></script><![endif]-->
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}/{sessionvars%urlparameter}">files</a>
-</div>
-
-<h2>graph</h2>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<p>
-<label for="search1">search:</label>
-<input name="rev" id="search1" type="text" size="30">
-navigate: <small class="navigate">{changenav%navgraphentry}</small>
-</p>
-</form>
-
-<noscript>The revision graph only works with JavaScript-enabled browsers.</noscript>
-
-<div id="wrapper">
-<ul id="nodebgs"></ul>
-<canvas id="graph" width="224" height="{canvasheight}"></canvas>
-<ul id="graphnodes"></ul>
-</div>
-
-<script type="text/javascript" src="{staticurl}graph.js"></script>
-<script type="text/javascript">
-<!-- hide script content
-
-var data = {jsdata|json};
-var graph = new Graph();
-graph.scale({bg_height});
-
-graph.edge = function(x0, y0, x1, y1, color) {
-	
-	this.setColor(color, 0.0, 0.65);
-	this.ctx.beginPath();
-	this.ctx.moveTo(x0, y0);
-	this.ctx.lineTo(x1, y1);
-	this.ctx.stroke();
-	
-}
-
-var revlink = '<li style="_STYLE"><span class="desc">';
-revlink += '<a href="{url}rev/_NODEID{sessionvars%urlparameter}" title="_NODEID">_DESC</a>';
-revlink += '</span><span class="info">_DATE ago, by _USER</span></li>';
-
-graph.vertex = function(x, y, color, parity, cur) {
-	
-	this.ctx.beginPath();
-	color = this.setColor(color, 0.25, 0.75);
-	this.ctx.arc(x, y, radius, 0, Math.PI * 2, true);
-	this.ctx.fill();
-	
-	var bg = '<li class="bg parity' + parity + '"></li>';
-	var left = (this.columns + 1) * this.bg_height;
-	var nstyle = 'padding-left: ' + left + 'px;';
-	var item = revlink.replace(/_STYLE/, nstyle);
-	item = item.replace(/_PARITY/, 'parity' + parity);
-	item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_NODEID/, cur[0]);
-	item = item.replace(/_DESC/, cur[3]);
-	item = item.replace(/_USER/, cur[4]);
-	item = item.replace(/_DATE/, cur[5]);
-	
-	return [bg, item];
-	
-}
-
-graph.render(data);
-
-// stop hiding script -->
-</script>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<p>
-<label for="search1">search:</label>
-<input name="rev" id="search1" type="text" size="30">
-navigate: <small class="navigate">{changenav%navgraphentry}</small>
-</p>
-</form>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/header.tmpl
+++ /dev/null
@@ -1,6 +1,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
-<head>
-<link rel="icon" href="{staticurl}hgicon.png" type="image/png">
-<meta name="robots" content="index, nofollow" />
-<link rel="stylesheet" href="{staticurl}style.css" type="text/css" />
--- a/sys/src/cmd/hg/templates/spartan/index.tmpl
+++ /dev/null
@@ -1,19 +1,0 @@
-{header}
-<title>Mercurial repositories index</title>
-</head>
-<body>
-
-<h2>Mercurial Repositories</h2>
-
-<table>
-    <tr>
-        <td><a href="?sort={sort_name}">Name</a></td>
-        <td><a href="?sort={sort_description}">Description</a></td>
-        <td><a href="?sort={sort_contact}">Contact</a></td>
-        <td><a href="?sort={sort_lastchange}">Last change</a></td>
-        <td>&nbsp;</td>
-    </tr>
-    {entries%indexentry}
-</table>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/manifest.tmpl
+++ /dev/null
@@ -1,28 +1,0 @@
-{header}
-<title>{repo|escape}: files for changeset {node|short}</title>
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog/{rev}{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a>
-{archives%archiveentry}
-</div>
-
-<h2>files for changeset {node|short}: {path|escape}</h2>
-
-<table cellpadding="0" cellspacing="0">
-<tr class="parity{upparity}">
-  <td><tt>drwxr-xr-x</tt>&nbsp;
-  <td>&nbsp;
-  <td>&nbsp;
-  <td><a href="{url}file/{node|short}{up|urlescape}{sessionvars%urlparameter}">[up]</a>
-</tr>
-{dentries%direntry}
-{fentries%fileentry}
-</table>
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/map
+++ /dev/null
@@ -1,178 +1,0 @@
-default = 'shortlog'
-mimetype = 'text/html; charset={encoding}'
-header = header.tmpl
-footer = footer.tmpl
-search = search.tmpl
-changelog = changelog.tmpl
-shortlog = shortlog.tmpl
-shortlogentry = shortlogentry.tmpl
-graph = graph.tmpl
-naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navgraphentry = '<a href="{url}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
-filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenodelink = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenolink = '{file|escape} '
-fileellipses = '...'
-changelogentry = changelogentry.tmpl
-searchentry = changelogentry.tmpl
-changeset = changeset.tmpl
-manifest = manifest.tmpl
-
-direntry = '
-  <tr class="parity{parity}">
-    <td><tt>drwxr-xr-x</tt>&nbsp;
-    <td>&nbsp;
-    <td>&nbsp;
-    <td>
-      <a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}/</a>
-      <a href="{url}file/{node|short}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
-        {emptydirs|urlescape}
-      </a>'
-
-fileentry = '
-  <tr class="parity{parity}">
-    <td><tt>{permissions|permissions}</tt>&nbsp;
-    <td align=right><tt class="date">{date|isodate}</tt>&nbsp;
-    <td align=right><tt>{size}</tt>&nbsp;
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>'
-
-filerevision = filerevision.tmpl
-fileannotate = fileannotate.tmpl
-filediff = filediff.tmpl
-filelog = filelog.tmpl
-fileline = '<div class="parity{parity}"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>&nbsp;{line|escape}</div>'
-filelogentry = filelogentry.tmpl
-
-# The &nbsp; ensures that all table cells have content (even if there
-# is an empty line in the annotated file), which in turn ensures that
-# all table rows have equal height.
-annotateline = '
-  <tr class="parity{parity}">
-    <td class="annotate">
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
-    </td>
-    <td>
-      <a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>
-    </td>
-    <td><pre>&nbsp;{line|escape}</pre></td>
-  </tr>'
-difflineplus = '<span class="plusline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
-difflineminus = '<span class="minusline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
-difflineat = '<span class="atline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
-diffline = '<a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}'
-changelogparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent">
-      <a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-    </td>
-  </tr>'
-changesetparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filerevparent = '
-  <tr>
-    <td class="metatag">parent:</td>
-    <td>
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-filerename = '{file|escape}@'
-filelogrename = '
-  <tr>
-    <th>base:</th>
-    <td>
-      <a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {file|escape}@{node|short}
-      </a>
-    </td>
-  </tr>'
-fileannotateparent = '
-  <tr>
-    <td class="metatag">parent:</td>
-    <td>
-      <a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-changesetchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-changelogchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filerevchild = '
-  <tr>
-    <td class="metatag">child:</td>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-fileannotatechild = '
-  <tr>
-    <td class="metatag">child:</td>
-    <td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-tags = tags.tmpl
-tagentry = '
-  <li class="tagEntry parity{parity}">
-    <tt class="node">{node}</tt>
-    <a href="{url}rev/{node|short}{sessionvars%urlparameter}">{tag|escape}</a>
-  </li>'
-branches = branches.tmpl
-branchentry = '
-  <li class="tagEntry parity{parity}">
-    <tt class="node">{node}</tt>
-    <a href="{url}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">{branch|escape}</a>
-  </li>'
-diffblock = '<pre class="parity{parity}">{lines}</pre>'
-changelogtag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
-changesettag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
-filediffparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filelogparent = '
-  <tr>
-    <th>parent {rev}:</th>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filediffchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filelogchild = '
-  <tr>
-    <th>child {rev}:</th>
-    <td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-indexentry = '
-  <tr class="parity{parity}">
-    <td><a href="{url}{sessionvars%urlparameter}">{name|escape}</a></td>
-    <td>{description}</td>
-    <td>{contact|obfuscate}</td>
-    <td class="age">{lastchange|age} ago</td>
-    <td class="indexlinks">
-      <a href="{url}rss-log">RSS</a>
-      <a href="{url}atom-log">Atom</a>
-      {archives%archiveentry}
-    </td>
-  </tr>'
-index = index.tmpl
-archiveentry = '<a href="{url}archive/{node|short}{extension|urlescape}">{type|escape}</a> '
-notfound = notfound.tmpl
-error = error.tmpl
-urlparameter = '{separator}{name}={value|urlescape}'
-hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
--- a/sys/src/cmd/hg/templates/spartan/notfound.tmpl
+++ /dev/null
@@ -1,12 +1,0 @@
-{header}
-<title>Mercurial repository not found</title>
-</head>
-<body>
-
-<h2>Mercurial repository not found</h2>
-
-The specified repository "{repo|escape}" is unknown, sorry.
-
-Please go back to the <a href="{url}">main repository list page</a>.
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/search.tmpl
+++ /dev/null
@@ -1,36 +1,0 @@
-{header}
-<title>{repo|escape}: searching for {query|escape}</title>
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}{sessionvars%urlparameter}">files</a>
-{archives%archiveentry}
-</div>
-
-<h2>searching for {query|escape}</h2>
-
-<form>
-{sessionvars%hiddenformentry}
-<p>
-search:
-<input name="rev" type="text" width="30" value="{query|escape}">
-</p>
-</form>
-
-{entries}
-
-<form>
-{sessionvars%hiddenformentry}
-<p>
-search:
-<input name="rev" type="text" width="30" value="{query|escape}">
-</p>
-</form>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/shortlog.tmpl
+++ /dev/null
@@ -1,43 +1,0 @@
-{header}
-<title>{repo|escape}: shortlog</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-log" title="Atom feed for {repo|escape}">
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-log" title="RSS feed for {repo|escape}">
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log/{rev}{sessionvars%urlparameter}">changelog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}/{sessionvars%urlparameter}">files</a>
-{archives%archiveentry}
-<a type="application/rss+xml" href="{url}rss-log">rss</a>
-<a type="application/rss+xml" href="{url}atom-log" title="Atom feed for {repo|escape}">atom</a>
-</div>
-
-<h2>shortlog for {repo|escape}</h2>
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<p>
-<label for="search1">search:</label>
-<input name="rev" id="search1" type="text" size="30">
-navigate: <small class="navigate">{changenav%navshortentry}</small>
-</p>
-</form>
-
-{entries%shortlogentry}
-
-<form action="{url}log">
-{sessionvars%hiddenformentry}
-<p>
-<label for="search2">search:</label>
-<input name="rev" id="search2" type="text" size="30">
-navigate: <small class="navigate">{changenav%navshortentry}</small>
-</p>
-</form>
-
-{footer}
--- a/sys/src/cmd/hg/templates/spartan/shortlogentry.tmpl
+++ /dev/null
@@ -1,7 +1,0 @@
-<table class="slogEntry parity{parity}">
- <tr>
-  <td class="age">{date|age}</td>
-  <td class="author">{author|person}</td>
-  <td class="node"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a></td>
- </tr>
-</table>
--- a/sys/src/cmd/hg/templates/spartan/tags.tmpl
+++ /dev/null
@@ -1,26 +1,0 @@
-{header}
-<title>{repo|escape}: tags</title>
-<link rel="alternate" type="application/atom+xml"
-   href="{url}atom-tags" title="Atom feed for {repo|escape}: tags">
-<link rel="alternate" type="application/rss+xml"
-   href="{url}rss-tags" title="RSS feed for {repo|escape}: tags">
-</head>
-<body>
-
-<div class="buttons">
-<a href="{url}log{sessionvars%urlparameter}">changelog</a>
-<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a>
-<a href="{url}graph{sessionvars%urlparameter}">graph</a>
-<a href="{url}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url}file/{node|short}/{sessionvars%urlparameter}">files</a>
-<a type="application/rss+xml" href="{url}rss-tags">rss</a>
-<a type="application/atom+xml" href="{url}atom-tags">atom</a>
-</div>
-
-<h2>tags:</h2>
-
-<ul id="tagEntries">
-{entries%tagentry}
-</ul>
-
-{footer}
binary files a/sys/src/cmd/hg/templates/static/background.png /dev/null differ
binary files a/sys/src/cmd/hg/templates/static/coal-file.png /dev/null differ
binary files a/sys/src/cmd/hg/templates/static/coal-folder.png /dev/null differ
--- a/sys/src/cmd/hg/templates/static/excanvas.js
+++ /dev/null
@@ -1,19 +1,0 @@
-if(!window.CanvasRenderingContext2D){(function(){var I=Math,i=I.round,L=I.sin,M=I.cos,m=10,A=m/2,Q={init:function(a){var b=a||document;if(/MSIE/.test(navigator.userAgent)&&!window.opera){var c=this;b.attachEvent("onreadystatechange",function(){c.r(b)})}},r:function(a){if(a.readyState=="complete"){if(!a.namespaces["s"]){a.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml")}var b=a.createStyleSheet();b.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}";
-var c=a.getElementsByTagName("canvas");for(var d=0;d<c.length;d++){if(!c[d].getContext){this.initElement(c[d])}}}},q:function(a){var b=a.outerHTML,c=a.ownerDocument.createElement(b);if(b.slice(-2)!="/>"){var d="/"+a.tagName,e;while((e=a.nextSibling)&&e.tagName!=d){e.removeNode()}if(e){e.removeNode()}}a.parentNode.replaceChild(c,a);return c},initElement:function(a){a=this.q(a);a.getContext=function(){if(this.l){return this.l}return this.l=new K(this)};a.attachEvent("onpropertychange",V);a.attachEvent("onresize",
-W);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+"px"}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+"px"}else{a.height=a.clientHeight}return a}};function V(a){var b=a.srcElement;switch(a.propertyName){case "width":b.style.width=b.attributes.width.nodeValue+"px";b.getContext().clearRect();break;case "height":b.style.height=b.attributes.height.nodeValue+"px";b.getContext().clearRect();break}}function W(a){var b=a.srcElement;
-if(b.firstChild){b.firstChild.style.width=b.clientWidth+"px";b.firstChild.style.height=b.clientHeight+"px"}}Q.init();var R=[];for(var E=0;E<16;E++){for(var F=0;F<16;F++){R[E*16+F]=E.toString(16)+F.toString(16)}}function J(){return[[1,0,0],[0,1,0],[0,0,1]]}function G(a,b){var c=J();for(var d=0;d<3;d++){for(var e=0;e<3;e++){var g=0;for(var h=0;h<3;h++){g+=a[d][h]*b[h][e]}c[d][e]=g}}return c}function N(a,b){b.fillStyle=a.fillStyle;b.lineCap=a.lineCap;b.lineJoin=a.lineJoin;b.lineWidth=a.lineWidth;b.miterLimit=
-a.miterLimit;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.shadowOffsetX=a.shadowOffsetX;b.shadowOffsetY=a.shadowOffsetY;b.strokeStyle=a.strokeStyle;b.d=a.d;b.e=a.e}function O(a){var b,c=1;a=String(a);if(a.substring(0,3)=="rgb"){var d=a.indexOf("(",3),e=a.indexOf(")",d+1),g=a.substring(d+1,e).split(",");b="#";for(var h=0;h<3;h++){b+=R[Number(g[h])]}if(g.length==4&&a.substr(3,1)=="a"){c=g[3]}}else{b=a}return[b,c]}function S(a){switch(a){case "butt":return"flat";case "round":return"round";
-case "square":default:return"square"}}function K(a){this.a=J();this.m=[];this.k=[];this.c=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=m*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement("div");b.style.width=a.clientWidth+"px";b.style.height=a.clientHeight+"px";b.style.overflow="hidden";b.style.position="absolute";a.appendChild(b);this.j=b;this.d=1;this.e=1}var j=K.prototype;j.clearRect=function(){this.j.innerHTML=
-"";this.c=[]};j.beginPath=function(){this.c=[]};j.moveTo=function(a,b){this.c.push({type:"moveTo",x:a,y:b});this.f=a;this.g=b};j.lineTo=function(a,b){this.c.push({type:"lineTo",x:a,y:b});this.f=a;this.g=b};j.bezierCurveTo=function(a,b,c,d,e,g){this.c.push({type:"bezierCurveTo",cp1x:a,cp1y:b,cp2x:c,cp2y:d,x:e,y:g});this.f=e;this.g=g};j.quadraticCurveTo=function(a,b,c,d){var e=this.f+0.6666666666666666*(a-this.f),g=this.g+0.6666666666666666*(b-this.g),h=e+(c-this.f)/3,l=g+(d-this.g)/3;this.bezierCurveTo(e,
-g,h,l,c,d)};j.arc=function(a,b,c,d,e,g){c*=m;var h=g?"at":"wa",l=a+M(d)*c-A,n=b+L(d)*c-A,o=a+M(e)*c-A,f=b+L(e)*c-A;if(l==o&&!g){l+=0.125}this.c.push({type:h,x:a,y:b,radius:c,xStart:l,yStart:n,xEnd:o,yEnd:f})};j.rect=function(a,b,c,d){this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath()};j.strokeRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.stroke()};j.fillRect=function(a,
-b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill()};j.createLinearGradient=function(a,b,c,d){var e=new H("gradient");return e};j.createRadialGradient=function(a,b,c,d,e,g){var h=new H("gradientradial");h.n=c;h.o=g;h.i.x=a;h.i.y=b;return h};j.drawImage=function(a,b){var c,d,e,g,h,l,n,o,f=a.runtimeStyle.width,k=a.runtimeStyle.height;a.runtimeStyle.width="auto";a.runtimeStyle.height="auto";var q=a.width,r=a.height;a.runtimeStyle.width=
-f;a.runtimeStyle.height=k;if(arguments.length==3){c=arguments[1];d=arguments[2];h=(l=0);n=(e=q);o=(g=r)}else if(arguments.length==5){c=arguments[1];d=arguments[2];e=arguments[3];g=arguments[4];h=(l=0);n=q;o=r}else if(arguments.length==9){h=arguments[1];l=arguments[2];n=arguments[3];o=arguments[4];c=arguments[5];d=arguments[6];e=arguments[7];g=arguments[8]}else{throw"Invalid number of arguments";}var s=this.b(c,d),t=[],v=10,w=10;t.push(" <g_vml_:group",' coordsize="',m*v,",",m*w,'"',' coordorigin="0,0"',
-' style="width:',v,";height:",w,";position:absolute;");if(this.a[0][0]!=1||this.a[0][1]){var x=[];x.push("M11='",this.a[0][0],"',","M12='",this.a[1][0],"',","M21='",this.a[0][1],"',","M22='",this.a[1][1],"',","Dx='",i(s.x/m),"',","Dy='",i(s.y/m),"'");var p=s,y=this.b(c+e,d),z=this.b(c,d+g),B=this.b(c+e,d+g);p.x=Math.max(p.x,y.x,z.x,B.x);p.y=Math.max(p.y,y.y,z.y,B.y);t.push("padding:0 ",i(p.x/m),"px ",i(p.y/m),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",x.join(""),", sizingmethod='clip');")}else{t.push("top:",
-i(s.y/m),"px;left:",i(s.x/m),"px;")}t.push(' ">','<g_vml_:image src="',a.src,'"',' style="width:',m*e,";"," height:",m*g,';"',' cropleft="',h/q,'"',' croptop="',l/r,'"',' cropright="',(q-h-n)/q,'"',' cropbottom="',(r-l-o)/r,'"'," />","</g_vml_:group>");this.j.insertAdjacentHTML("BeforeEnd",t.join(""))};j.stroke=function(a){var b=[],c=O(a?this.fillStyle:this.strokeStyle),d=c[0],e=c[1]*this.globalAlpha,g=10,h=10;b.push("<g_vml_:shape",' fillcolor="',d,'"',' filled="',Boolean(a),'"',' style="position:absolute;width:',
-g,";height:",h,';"',' coordorigin="0 0" coordsize="',m*g," ",m*h,'"',' stroked="',!a,'"',' strokeweight="',this.lineWidth,'"',' strokecolor="',d,'"',' path="');var l={x:null,y:null},n={x:null,y:null};for(var o=0;o<this.c.length;o++){var f=this.c[o];if(f.type=="moveTo"){b.push(" m ");var k=this.b(f.x,f.y);b.push(i(k.x),",",i(k.y))}else if(f.type=="lineTo"){b.push(" l ");var k=this.b(f.x,f.y);b.push(i(k.x),",",i(k.y))}else if(f.type=="close"){b.push(" x ")}else if(f.type=="bezierCurveTo"){b.push(" c ");
-var k=this.b(f.x,f.y),q=this.b(f.cp1x,f.cp1y),r=this.b(f.cp2x,f.cp2y);b.push(i(q.x),",",i(q.y),",",i(r.x),",",i(r.y),",",i(k.x),",",i(k.y))}else if(f.type=="at"||f.type=="wa"){b.push(" ",f.type," ");var k=this.b(f.x,f.y),s=this.b(f.xStart,f.yStart),t=this.b(f.xEnd,f.yEnd);b.push(i(k.x-this.d*f.radius),",",i(k.y-this.e*f.radius)," ",i(k.x+this.d*f.radius),",",i(k.y+this.e*f.radius)," ",i(s.x),",",i(s.y)," ",i(t.x),",",i(t.y))}if(k){if(l.x==null||k.x<l.x){l.x=k.x}if(n.x==null||k.x>n.x){n.x=k.x}if(l.y==
-null||k.y<l.y){l.y=k.y}if(n.y==null||k.y>n.y){n.y=k.y}}}b.push(' ">');if(typeof this.fillStyle=="object"){var v={x:"50%",y:"50%"},w=n.x-l.x,x=n.y-l.y,p=w>x?w:x;v.x=i(this.fillStyle.i.x/w*100+50)+"%";v.y=i(this.fillStyle.i.y/x*100+50)+"%";var y=[];if(this.fillStyle.p=="gradientradial"){var z=this.fillStyle.n/p*100,B=this.fillStyle.o/p*100-z}else{var z=0,B=100}var C={offset:null,color:null},D={offset:null,color:null};this.fillStyle.h.sort(function(T,U){return T.offset-U.offset});for(var o=0;o<this.fillStyle.h.length;o++){var u=
-this.fillStyle.h[o];y.push(u.offset*B+z,"% ",u.color,",");if(u.offset>C.offset||C.offset==null){C.offset=u.offset;C.color=u.color}if(u.offset<D.offset||D.offset==null){D.offset=u.offset;D.color=u.color}}y.pop();b.push("<g_vml_:fill",' color="',D.color,'"',' color2="',C.color,'"',' type="',this.fillStyle.p,'"',' focusposition="',v.x,", ",v.y,'"',' colors="',y.join(""),'"',' opacity="',e,'" />')}else if(a){b.push('<g_vml_:fill color="',d,'" opacity="',e,'" />')}else{b.push("<g_vml_:stroke",' opacity="',
-e,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',S(this.lineCap),'"',' weight="',this.lineWidth,'px"',' color="',d,'" />')}b.push("</g_vml_:shape>");this.j.insertAdjacentHTML("beforeEnd",b.join(""));this.c=[]};j.fill=function(){this.stroke(true)};j.closePath=function(){this.c.push({type:"close"})};j.b=function(a,b){return{x:m*(a*this.a[0][0]+b*this.a[1][0]+this.a[2][0])-A,y:m*(a*this.a[0][1]+b*this.a[1][1]+this.a[2][1])-A}};j.save=function(){var a={};N(this,a);
-this.k.push(a);this.m.push(this.a);this.a=G(J(),this.a)};j.restore=function(){N(this.k.pop(),this);this.a=this.m.pop()};j.translate=function(a,b){var c=[[1,0,0],[0,1,0],[a,b,1]];this.a=G(c,this.a)};j.rotate=function(a){var b=M(a),c=L(a),d=[[b,c,0],[-c,b,0],[0,0,1]];this.a=G(d,this.a)};j.scale=function(a,b){this.d*=a;this.e*=b;var c=[[a,0,0],[0,b,0],[0,0,1]];this.a=G(c,this.a)};j.clip=function(){};j.arcTo=function(){};j.createPattern=function(){return new P};function H(a){this.p=a;this.n=0;this.o=
-0;this.h=[];this.i={x:0,y:0}}H.prototype.addColorStop=function(a,b){b=O(b);this.h.push({offset:1-a,color:b})};function P(){}G_vmlCanvasManager=Q;CanvasRenderingContext2D=K;CanvasGradient=H;CanvasPattern=P})()};
--- a/sys/src/cmd/hg/templates/static/graph.js
+++ /dev/null
@@ -1,137 +1,0 @@
-// branch_renderer.js - Rendering of branch DAGs on the client side
-//
-// Copyright 2008 Dirkjan Ochtman <dirkjan AT ochtman DOT nl>
-// Copyright 2006 Alexander Schremmer <alex AT alexanderweb DOT de>
-//
-// derived from code written by Scott James Remnant <scott@ubuntu.com>
-// Copyright 2005 Canonical Ltd.
-//
-// This software may be used and distributed according to the terms
-// of the GNU General Public License, incorporated herein by reference.
-
-var colors = [
-	[ 1.0, 0.0, 0.0 ],
-	[ 1.0, 1.0, 0.0 ],
-	[ 0.0, 1.0, 0.0 ],
-	[ 0.0, 1.0, 1.0 ],
-	[ 0.0, 0.0, 1.0 ],
-	[ 1.0, 0.0, 1.0 ]
-];
-
-function Graph() {
-	
-	this.canvas = document.getElementById('graph');
-	if (navigator.userAgent.indexOf('MSIE') >= 0) this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
-	this.ctx = this.canvas.getContext('2d');
-	this.ctx.strokeStyle = 'rgb(0, 0, 0)';
-	this.ctx.fillStyle = 'rgb(0, 0, 0)';
-	this.cur = [0, 0];
-	this.line_width = 3;
-	this.bg = [0, 4];
-	this.cell = [2, 0];
-	this.columns = 0;
-	this.revlink = '';
-	
-	this.scale = function(height) {
-		this.bg_height = height;
-		this.box_size = Math.floor(this.bg_height / 1.2);
-		this.cell_height = this.box_size;
-	}
-	
-	function colorPart(num) {
-		num *= 255
-		num = num < 0 ? 0 : num;
-		num = num > 255 ? 255 : num;
-		var digits = Math.round(num).toString(16);
-		if (num < 16) {
-			return '0' + digits;
-		} else {
-			return digits;
-		}
-	}
-
-	this.setColor = function(color, bg, fg) {
-		
-		// Set the colour.
-		//
-		// Picks a distinct colour based on an internal wheel; the bg
-		// parameter provides the value that should be assigned to the 'zero'
-		// colours and the fg parameter provides the multiplier that should be
-		// applied to the foreground colours.
-		
-		color %= colors.length;
-		var red = (colors[color][0] * fg) || bg;
-		var green = (colors[color][1] * fg) || bg;
-		var blue = (colors[color][2] * fg) || bg;
-		red = Math.round(red * 255);
-		green = Math.round(green * 255);
-		blue = Math.round(blue * 255);
-		var s = 'rgb(' + red + ', ' + green + ', ' + blue + ')';
-		this.ctx.strokeStyle = s;
-		this.ctx.fillStyle = s;
-		return s;
-		
-	}
-
-	this.render = function(data) {
-		
-		var backgrounds = '';
-		var nodedata = '';
-		
-		for (var i in data) {
-			
-			var parity = i % 2;
-			this.cell[1] += this.bg_height;
-			this.bg[1] += this.bg_height;
-			
-			var cur = data[i];
-			var node = cur[1];
-			var edges = cur[2];
-			var fold = false;
-			
-			for (var j in edges) {
-				
-				line = edges[j];
-				start = line[0];
-				end = line[1];
-				color = line[2];
-
-				if (end > this.columns || start > this.columns) {
-					this.columns += 1;
-				}
-				
-				if (start == this.columns && start > end) {
-					var fold = true;
-				}
-				
-				x0 = this.cell[0] + this.box_size * start + this.box_size / 2;
-				y0 = this.bg[1] - this.bg_height / 2;
-				x1 = this.cell[0] + this.box_size * end + this.box_size / 2;
-				y1 = this.bg[1] + this.bg_height / 2;
-				
-				this.edge(x0, y0, x1, y1, color);
-				
-			}
-			
-			// Draw the revision node in the right column
-			
-			column = node[0]
-			color = node[1]
-			
-			radius = this.box_size / 8;
-			x = this.cell[0] + this.box_size * column + this.box_size / 2;
-			y = this.bg[1] - this.bg_height / 2;
-			var add = this.vertex(x, y, color, parity, cur);
-			backgrounds += add[0];
-			nodedata += add[1];
-			
-			if (fold) this.columns -= 1;
-			
-		}
-		
-		document.getElementById('nodebgs').innerHTML += backgrounds;
-		document.getElementById('graphnodes').innerHTML += nodedata;
-		
-	}
-
-}
binary files a/sys/src/cmd/hg/templates/static/hgicon.png /dev/null differ
binary files a/sys/src/cmd/hg/templates/static/hglogo.png /dev/null differ
--- a/sys/src/cmd/hg/templates/static/style-coal.css
+++ /dev/null
@@ -1,265 +1,0 @@
-body {
-  margin: 0;
-  padding: 0;
-  background: black url(background.png) repeat-x;
-  font-family: sans-serif;
-}
-
-.container {
-  padding-right: 150px;
-}
-
-.main {
-  position: relative;
-  background: white;
-  padding: 2em;
-  border-right: 15px solid black;
-  border-bottom: 15px solid black;
-}
-
-#.main {
-  width: 98%;
-}
-
-.overflow {
-  width: 100%;
-  overflow: auto;
-}
-
-.menu {
-  background: #999;
-  padding: 10px;
-  width: 75px;
-  margin: 0;
-  font-size: 80%;
-  text-align: left;
-  position: fixed;
-  top: 27px;
-  left: auto;
-  right: 27px;
-}
-
-#.menu {
-  position: absolute !important;
-  top:expression(eval(document.body.scrollTop + 27));
-}
-
-.menu ul {
-  list-style: none;
-  padding: 0;
-  margin: 10px 0 0 0;
-}
-
-.menu li {
-  margin-bottom: 3px;
-  padding: 2px 4px;
-  background: white;
-  color: black;
-  font-weight: normal;
-}
-
-.menu li.active {
-  background: black;
-  color: white;
-}
-
-.menu img {
-  width: 75px;
-  height: 90px;
-  border: 0;
-}
-
-.menu a { color: black; display: block; }
-
-.search {
-  position: absolute;
-  top: .7em;
-  right: 2em;
-}
-
-form.search div#hint {
-  display: none;
-  position: absolute;
-  top: 40px;
-  right: 0px;
-  width: 190px;
-  padding: 5px;
-  background: #ffc;
-  font-size: 70%;
-  border: 1px solid yellow;
-  -moz-border-radius: 5px; /* this works only in camino/firefox */
-  -webkit-border-radius: 5px; /* this is just for Safari */
-}
-
-form.search:hover div#hint { display: block; }
-
-a { text-decoration:none; }
-.age { white-space:nowrap; }
-.date { white-space:nowrap; }
-.indexlinks { white-space:nowrap; }
-.parity0 { background-color: #f0f0f0; }
-.parity1 { background-color: white; }
-.plusline { color: green; }
-.minusline { color: #dc143c; } /* crimson */
-.atline { color: purple; }
-
-.navigate {
-  text-align: right;
-  font-size: 60%;
-  margin: 1em 0;
-}
-
-.tag {
-  color: #999;
-  font-size: 70%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-.branchhead {
-  color: #000;
-  font-size: 80%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-ul#graphnodes .branchhead {
-  font-size: 75%;
-}
-
-.branchname {
-  color: #000;
-  font-size: 60%; 
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-h3 .branchname {
-  font-size: 80%;
-}
-
-/* Common */
-pre { margin: 0; }
-
-h2 { font-size: 120%; border-bottom: 1px solid #999; }
-h2 a { color: #000; }
-h3 {
-  margin-top: -.7em;
-  font-size: 100%;
-}
-
-/* log and tags tables */
-.bigtable {
-  border-bottom: 1px solid #999;
-  border-collapse: collapse;
-  font-size: 90%;
-  width: 100%;
-  font-weight: normal;
-  text-align: left;
-}
-
-.bigtable td {
-  vertical-align: top;
-}
-
-.bigtable th {
-  padding: 1px 4px;
-  border-bottom: 1px solid #999;
-}
-.bigtable tr { border: none; }
-.bigtable .age { width: 6em; }
-.bigtable .author { width: 12em; }
-.bigtable .description { }
-.bigtable .node { width: 5em; font-family: monospace;}
-.bigtable .lineno { width: 2em; text-align: right;}
-.bigtable .lineno a { color: #999; font-size: smaller; font-family: monospace;}
-.bigtable .permissions { width: 8em; text-align: left;}
-.bigtable .size { width: 5em; text-align: right; }
-.bigtable .annotate { text-align: right; }
-.bigtable td.annotate { font-size: smaller; }
-.bigtable td.source { font-size: inherit; }
-
-.source, .sourcefirst, .sourcelast {
-  font-family: monospace;
-  white-space: pre;
-  padding: 1px 4px;
-  font-size: 90%;
-}
-.sourcefirst { border-bottom: 1px solid #999; font-weight: bold; }
-.sourcelast { border-top: 1px solid #999; }
-.source a { color: #999; font-size: smaller; font-family: monospace;}
-.bottomline { border-bottom: 1px solid #999; }
-
-.fileline { font-family: monospace; }
-.fileline img { border: 0; }
-
-.tagEntry .closed { color: #99f; }
-
-/* Changeset entry */
-#changesetEntry {
-  border-collapse: collapse;
-  font-size: 90%;
-  width: 100%;
-  margin-bottom: 1em;
-}
-
-#changesetEntry th {
-  padding: 1px 4px;
-  width: 4em;
-  text-align: right;
-  font-weight: normal;
-  color: #999;
-  margin-right: .5em;
-  vertical-align: top;
-}
-
-div.description {
-  border-left: 3px solid #999;
-  margin: 1em 0 1em 0;
-  padding: .3em;
-}
-
-/* Graph */
-div#wrapper {
-	position: relative;
-	border-top: 1px solid black;
-	border-bottom: 1px solid black;
-	margin: 0;
-	padding: 0;
-}
-
-canvas {
-	position: absolute;
-	z-index: 5;
-	top: -0.7em;
-	margin: 0;
-}
-
-ul#graphnodes {
-	position: absolute;
-	z-index: 10;
-	top: -1.0em;
-	list-style: none inside none;
-	padding: 0;
-}
-
-ul#nodebgs {
-	list-style: none inside none;
-	padding: 0;
-	margin: 0;
-	top: -0.7em;
-}
-
-ul#graphnodes li, ul#nodebgs li {
-	height: 39px;
-}
-
-ul#graphnodes li .info {
-	display: block;
-	font-size: 70%;
-	position: relative;
-	top: -3px;
-}
--- a/sys/src/cmd/hg/templates/static/style-gitweb.css
+++ /dev/null
@@ -1,123 +1,0 @@
-body { font-family: sans-serif; font-size: 12px; margin:0px; border:solid #d9d8d1; border-width:1px; margin:10px; }
-a { color:#0000cc; }
-a:hover, a:visited, a:active { color:#880000; }
-div.page_header { height:25px; padding:8px; font-size:18px; font-weight:bold; background-color:#d9d8d1; }
-div.page_header a:visited { color:#0000cc; }
-div.page_header a:hover { color:#880000; }
-div.page_nav { padding:8px; }
-div.page_nav a:visited { color:#0000cc; }
-div.page_path { padding:8px; border:solid #d9d8d1; border-width:0px 0px 1px}
-div.page_footer { padding:4px 8px; background-color: #d9d8d1; }
-div.page_footer_text { float:left; color:#555555; font-style:italic; }
-div.page_body { padding:8px; }
-div.title, a.title {
-	display:block; padding:6px 8px;
-	font-weight:bold; background-color:#edece6; text-decoration:none; color:#000000;
-}
-a.title:hover { background-color: #d9d8d1; }
-div.title_text { padding:6px 0px; border: solid #d9d8d1; border-width:0px 0px 1px; }
-div.log_body { padding:8px 8px 8px 150px; }
-.age { white-space:nowrap; }
-span.age { position:relative; float:left; width:142px; font-style:italic; }
-div.log_link {
-	padding:0px 8px;
-	font-size:10px; font-family:sans-serif; font-style:normal;
-	position:relative; float:left; width:136px;
-}
-div.list_head { padding:6px 8px 4px; border:solid #d9d8d1; border-width:1px 0px 0px; font-style:italic; }
-a.list { text-decoration:none; color:#000000; }
-a.list:hover { text-decoration:underline; color:#880000; }
-table { padding:8px 4px; }
-th { padding:2px 5px; font-size:12px; text-align:left; }
-tr.light:hover, .parity0:hover { background-color:#edece6; }
-tr.dark, .parity1 { background-color:#f6f6f0; }
-tr.dark:hover, .parity1:hover { background-color:#edece6; }
-td { padding:2px 5px; font-size:12px; vertical-align:top; }
-td.link { padding:2px 5px; font-family:sans-serif; font-size:10px; }
-td.indexlinks { white-space: nowrap; }
-td.indexlinks a {
-  padding: 2px 5px; line-height: 10px;
-  border: 1px solid;
-  color: #ffffff; background-color: #7777bb;
-  border-color: #aaaadd #333366 #333366 #aaaadd;
-  font-weight: bold;  text-align: center; text-decoration: none;
-  font-size: 10px;
-}
-td.indexlinks a:hover { background-color: #6666aa; }
-div.pre { font-family:monospace; font-size:12px; white-space:pre; }
-div.diff_info { font-family:monospace; color:#000099; background-color:#edece6; font-style:italic; }
-div.index_include { border:solid #d9d8d1; border-width:0px 0px 1px; padding:12px 8px; }
-div.search { margin:4px 8px; position:absolute; top:56px; right:12px }
-.linenr { color:#999999; text-decoration:none }
-div.rss_logo { float: right; white-space: nowrap; }
-div.rss_logo a {
-	padding:3px 6px; line-height:10px;
-	border:1px solid; border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
-	color:#ffffff; background-color:#ff6600;
-	font-weight:bold; font-family:sans-serif; font-size:10px;
-	text-align:center; text-decoration:none;
-}
-div.rss_logo a:hover { background-color:#ee5500; }
-pre { margin: 0; }
-span.logtags span {
-	padding: 0px 4px;
-	font-size: 10px;
-	font-weight: normal;
-	border: 1px solid;
-	background-color: #ffaaff;
-	border-color: #ffccff #ff00ee #ff00ee #ffccff;
-}
-span.logtags span.tagtag {
-	background-color: #ffffaa;
-	border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
-}
-span.logtags span.branchtag {
-	background-color: #aaffaa;
-	border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
-}
-span.logtags span.inbranchtag {
-	background-color: #d5dde6;
-	border-color: #e3ecf4 #9398f4 #9398f4 #e3ecf4;
-}
-
-/* Graph */
-div#wrapper {
-	position: relative;
-	margin: 0;
-	padding: 0;
-	margin-top: 3px;
-}
-
-canvas {
-	position: absolute;
-	z-index: 5;
-	top: -0.9em;
-	margin: 0;
-}
-
-ul#nodebgs {
-	list-style: none inside none;
-	padding: 0;
-	margin: 0;
-	top: -0.7em;
-}
-
-ul#graphnodes li, ul#nodebgs li {
-	height: 39px;
-}
-
-ul#graphnodes {
-	position: absolute;
-	z-index: 10;
-	top: -0.8em;
-	list-style: none inside none;
-	padding: 0;
-}
-
-ul#graphnodes li .info {
-	display: block;
-	font-size: 100%;
-	position: relative;
-	top: -3px;
-	font-style: italic;
-}
--- a/sys/src/cmd/hg/templates/static/style-monoblue.css
+++ /dev/null
@@ -1,472 +1,0 @@
-/*** Initial Settings ***/
-* {
-  margin: 0;
-  padding: 0;
-  font-weight: normal;
-  font-style: normal;
-}
-
-html {
-  font-size: 100%;
-  font-family: sans-serif;
-}
-
-body {
-  font-size: 77%;
-  margin: 15px 50px;
-  background: #4B4B4C;
-}
-
-a {
-  color:#0000cc;
-  text-decoration: none;
-}
-/*** end of Initial Settings ***/
-
-
-/** common settings **/
-div#container {
-  background: #FFFFFF;
-  position: relative;
-  color: #666;
-}
-
-div.page-header {
-  padding: 50px 20px 0;
-  background: #006699 top left repeat-x;
-  position: relative;
-}
-  div.page-header h1 {
-    margin: 10px 0 30px;
-    font-size: 1.8em;
-    font-weight: bold;
-    font-family: osaka,'MS P Gothic', Georgia, serif;
-    letter-spacing: 1px;
-    color: #DDD;
-  }
-  div.page-header h1 a {
-    font-weight: bold;
-    color: #FFF;
-  }
-  div.page-header a {
-    text-decoration: none;
-  }
-
-  div.page-header form {
-    position: absolute;
-    margin-bottom: 2px;
-    bottom: 0;
-    right: 20px;
-  }
-  div.page-header form label {
-    color: #DDD;
-  }
-  div.page-header form input {
-    padding: 2px;
-    border: solid 1px #DDD;
-  }
-  div.page-header form dl {
-    overflow: hidden;
-  }
-  div.page-header form dl dt {
-    font-size: 1.2em;
-  }
-  div.page-header form dl dt,
-  div.page-header form dl dd {
-    margin: 0 0 0 5px;
-    float: left;
-    height: 24px;
-    line-height: 20px;
-  }
-
-  ul.page-nav {
-    margin: 10px 0 0 0;
-    list-style-type: none;
-    overflow: hidden;
-    width: 800px;
-  }
-    ul.page-nav li {
-      margin: 0 2px 0 0;
-      float: left;
-      width: 80px;
-      height: 24px;
-      font-size: 1.1em;
-      line-height: 24px;
-      text-align: center;
-    }
-    ul.page-nav li.current {
-      background: #FFF;
-    }
-    ul.page-nav li a {
-      height: 24px;
-      color: #666;
-      background: #DDD;
-      display: block;
-      text-decoration: none;
-    }
-    ul.page-nav li a:hover {
-      color:#333;
-      background: #FFF;
-    }
-
-ul.submenu {
-  margin: 10px 0 -10px 20px;
-  list-style-type: none;
-}
-ul.submenu li {
-  margin: 0 10px 0 0;
-  font-size: 1.2em;
-  display: inline;
-}
-
-h2 {
-  margin: 20px 0 10px;
-  height: 30px;
-  line-height: 30px;
-  text-indent: 20px;
-  background: #FFF;
-  font-size: 1.2em;
-  border-top: dotted 1px #D5E1E6;
-  font-weight: bold;
-}
-h2.no-link {
-  color:#006699;
-}
-h2.no-border {
-  color: #FFF;
-  background: #006699;
-  border: 0;
-}
-h2 a {
-  font-weight:bold;
-  color:#006699;
-}
-
-div.page-path {
-  text-align: right;
-  padding: 20px 30px 10px 0;
-  border:solid #d9d8d1;
-  border-width:0px 0px 1px;
-  font-size: 1.2em;
-}
-
-div.page-footer {
-  margin: 50px 0 0;
-  position: relative;
-}
-  div.page-footer p {
-    position: relative;
-    left: 20px;
-    bottom: 5px;
-    font-size: 1.2em;
-  }
-
-  ul.rss-logo {
-    position: absolute;
-    top: -10px;
-    right: 20px;
-    height: 20px;
-    list-style-type: none;
-  }
-  ul.rss-logo li {
-    display: inline;
-  }
-  ul.rss-logo li a {
-    padding: 3px 6px;
-    line-height: 10px;
-    border:1px solid;
-    border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
-    color:#ffffff;
-    background-color:#ff6600;
-    font-weight:bold;
-    font-family:sans-serif;
-    font-size:10px;
-    text-align:center;
-    text-decoration:none;
-  }
-  div.rss-logo li a:hover {
-    background-color:#ee5500;
-  }
-
-p.normal {
-  margin: 20px 0 20px 30px;
-  font-size: 1.2em;
-}
-
-table {
-  margin: 10px 0 0 20px;
-  width: 95%;
-  border-collapse: collapse;
-}
-table tr td {
-  font-size: 1.1em;
-}
-table tr td.nowrap {
-  white-space: nowrap;
-}
-/*
-table tr.parity0:hover,
-table tr.parity1:hover {
-  background: #D5E1E6;
-}
-*/
-table tr.parity0 {
-  background: #F1F6F7;
-}
-table tr.parity1 {
-  background: #FFFFFF;
-}
-table tr td {
-  padding: 5px 5px;
-}
-table.annotated tr td {
-  padding: 0px 5px;
-}
-
-span.logtags span {
-  padding: 2px 6px;
-  font-weight: normal;
-  font-size: 11px;
-  border: 1px solid;
-  background-color: #ffaaff;
-  border-color: #ffccff #ff00ee #ff00ee #ffccff;
-}
-span.logtags span.tagtag {
-  background-color: #ffffaa;
-  border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
-}
-span.logtags span.branchtag {
-  background-color: #aaffaa;
-  border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
-}
-span.logtags span.inbranchtag {
-  background-color: #d5dde6;
-  border-color: #e3ecf4 #9398f4 #9398f4 #e3ecf4;
-}
-
-div.diff pre {
-  margin: 10px 0 0 0;
-}
-div.diff pre span {
-  font-family: monospace;
-  white-space: pre;
-  font-size: 1.2em;
-  padding: 3px 0;
-}
-td.source {
-  white-space: pre;
-  font-family: monospace;
-  margin: 10px 30px 0;
-  font-size: 1.2em;
-  font-family: monospace;
-}
-  div.source div.parity0,
-  div.source div.parity1 {
-    padding: 1px;
-    font-size: 1.2em;
-  }
-  div.source div.parity0 {
-    background: #F1F6F7;
-  }
-  div.source div.parity1 {
-    background: #FFFFFF;
-  }
-div.parity0:hover,
-div.parity1:hover {
-  background: #D5E1E6;
-}
-.linenr {
-  color: #999;
-  text-align: right;
-}
-.lineno {
-  text-align: right;
-}
-.lineno a {
-  color: #999;
-}
-td.linenr {
-  width: 60px;
-}
-
-div#powered-by {
-  position: absolute;
-  width: 75px;
-  top: 15px;
-  right: 20px;
-  font-size: 1.2em;
-}
-div#powered-by a {
-  color: #EEE;
-  text-decoration: none;
-}
-div#powered-by a:hover {
-  text-decoration: underline;
-}
-/*
-div#monoblue-corner-top-left {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) top left no-repeat !important;
-  background: none;
-}
-div#monoblue-corner-top-right {
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) top right no-repeat !important;
-  background: none;
-}
-div#monoblue-corner-bottom-left {
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) bottom left no-repeat !important;
-  background: none;
-}
-div#monoblue-corner-bottom-right {
-  position: absolute;
-  bottom: 0;
-  right: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) bottom right no-repeat !important;
-  background: none;
-}
-*/
-/** end of common settings **/
-
-/** summary **/
-dl.overview {
-  margin: 0 0 0 30px;
-  font-size: 1.1em;
-  overflow: hidden;
-}
-  dl.overview dt,
-  dl.overview dd {
-    margin: 5px 0;
-    float: left;
-  }
-  dl.overview dt {
-    clear: left;
-    font-weight: bold;
-    width: 150px;
-  }
-/** end of summary **/
-
-/** chagelog **/
-h3.changelog {
-  margin: 20px 0 5px 30px;
-  padding: 0 0 2px;
-  font-size: 1.4em;
-  border-bottom: dotted 1px #D5E1E6;
-}
-ul.changelog-entry {
-  margin: 0 0 10px 30px;
-  list-style-type: none;
-  position: relative;
-}
-ul.changelog-entry li span.revdate {
-  font-size: 1.1em;
-}
-ul.changelog-entry li.age {
-  position: absolute;
-  top: -25px;
-  right: 10px;
-  font-size: 1.4em;
-  color: #CCC;
-  font-weight: bold;
-  font-style: italic;
-}
-ul.changelog-entry li span.name {
-  font-size: 1.2em;
-  font-weight: bold;
-}
-ul.changelog-entry li.description {
-  margin: 10px 0 0;
-  font-size: 1.1em;
-}
-/** end of changelog **/
-
-/** file **/
-p.files {
-  margin: 0 0 0 20px;
-  font-size: 2.0em;
-  font-weight: bold;
-}
-/** end of file **/
-
-/** changeset **/
-h3.changeset {
-  margin: 20px 0 5px 20px;
-  padding: 0 0 2px;
-  font-size: 1.6em;
-  border-bottom: dotted 1px #D5E1E6;
-}
-p.changeset-age {
-  position: relative;
-}
-p.changeset-age span {
-  position: absolute;
-  top: -25px;
-  right: 10px;
-  font-size: 1.4em;
-  color: #CCC;
-  font-weight: bold;
-  font-style: italic;
-}
-p.description {
-  margin: 10px 30px 0 30px;
-  padding: 10px;
-  border: solid 1px #CCC;
-  font-size: 1.2em;
-}
-/** end of changeset **/
-
-/** canvas **/
-div#wrapper {
-	position: relative;
-    font-size: 1.2em;
-}
-
-canvas {
-	position: absolute;
-	z-index: 5;
-	top: -0.7em;
-}
-
-ul#nodebgs li.parity0 {
-    background: #F1F6F7;
-}
-
-ul#nodebgs li.parity1 {
-    background: #FFFFFF;
-}
-
-ul#graphnodes {
-	position: absolute;
-	z-index: 10;
-	top: 7px;
-	list-style: none inside none;
-}
-
-ul#nodebgs {
-	list-style: none inside none;
-}
-
-ul#graphnodes li, ul#nodebgs li {
-	height: 39px;
-}
-
-ul#graphnodes li .info {
-	display: block;
-	position: relative;
-}
-/** end of canvas **/
--- a/sys/src/cmd/hg/templates/static/style-paper.css
+++ /dev/null
@@ -1,254 +1,0 @@
-body {
-  margin: 0;
-  padding: 0;
-  background: white;
-  font-family: sans-serif;
-}
-
-.container {
-  padding-left: 115px;
-}
-
-.main {
-  position: relative;
-  background: white;
-  padding: 2em 2em 2em 0;
-}
-
-#.main {
-  width: 98%;
-}
-
-.overflow {
-  width: 100%;
-  overflow: auto;
-}
-
-.menu {
-  width: 90px;
-  margin: 0;
-  font-size: 80%;
-  text-align: left;
-  position: absolute;
-  top: 20px;
-  left: 20px;
-  right: auto;
-}
-
-.menu ul {
-  list-style: none;
-  padding: 0;
-  margin: 10px 0 0 0;
-  border-left: 2px solid #999;
-}
-
-.menu li {
-  margin-bottom: 3px;
-  padding: 2px 4px;
-  background: white;
-  color: black;
-  font-weight: normal;
-}
-
-.menu li.active {
-  font-weight: bold;
-}
-
-.menu img {
-  width: 75px;
-  height: 90px;
-  border: 0;
-}
-
-.menu a { color: black; display: block; }
-
-.search {
-  position: absolute;
-  top: .7em;
-  right: 2em;
-}
-
-form.search div#hint {
-  display: none;
-  position: absolute;
-  top: 40px;
-  right: 0px;
-  width: 190px;
-  padding: 5px;
-  background: #ffc;
-  font-size: 70%;
-  border: 1px solid yellow;
-  -moz-border-radius: 5px; /* this works only in camino/firefox */
-  -webkit-border-radius: 5px; /* this is just for Safari */
-}
-
-form.search:hover div#hint { display: block; }
-
-a { text-decoration:none; }
-.age { white-space:nowrap; }
-.date { white-space:nowrap; }
-.indexlinks { white-space:nowrap; }
-.parity0 { background-color: #f0f0f0; }
-.parity1 { background-color: white; }
-.plusline { color: green; }
-.minusline { color: #dc143c; } /* crimson */
-.atline { color: purple; }
-
-.navigate {
-  text-align: right;
-  font-size: 60%;
-  margin: 1em 0;
-}
-
-.tag {
-  color: #999;
-  font-size: 70%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-.branchhead {
-  color: #000;
-  font-size: 80%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-ul#graphnodes .branchhead {
-  font-size: 75%;
-}
-
-.branchname {
-  color: #000;
-  font-size: 60%; 
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-h3 .branchname {
-  font-size: 80%;
-}
-
-/* Common */
-pre { margin: 0; }
-
-h2 { font-size: 120%; border-bottom: 1px solid #999; }
-h2 a { color: #000; }
-h3 {
-  margin-top: -.7em;
-  font-size: 100%;
-}
-
-/* log and tags tables */
-.bigtable {
-  border-bottom: 1px solid #999;
-  border-collapse: collapse;
-  font-size: 90%;
-  width: 100%;
-  font-weight: normal;
-  text-align: left;
-}
-
-.bigtable td {
-  vertical-align: top;
-}
-
-.bigtable th {
-  padding: 1px 4px;
-  border-bottom: 1px solid #999;
-}
-.bigtable tr { border: none; }
-.bigtable .age { width: 6em; }
-.bigtable .author { width: 12em; }
-.bigtable .description { }
-.bigtable .node { width: 5em; font-family: monospace;}
-.bigtable .permissions { width: 8em; text-align: left;}
-.bigtable .size { width: 5em; text-align: right; }
-.bigtable .annotate { text-align: right; }
-.bigtable td.annotate { font-size: smaller; }
-.bigtable td.source { font-size: inherit; }
-
-.source, .sourcefirst, .sourcelast {
-  font-family: monospace;
-  white-space: pre;
-  padding: 1px 4px;
-  font-size: 90%;
-}
-.sourcefirst { border-bottom: 1px solid #999; font-weight: bold; }
-.sourcelast { border-top: 1px solid #999; }
-.source a { color: #999; font-size: smaller; font-family: monospace;}
-.bottomline { border-bottom: 1px solid #999; }
-
-.fileline { font-family: monospace; }
-.fileline img { border: 0; }
-
-.tagEntry .closed { color: #99f; }
-
-/* Changeset entry */
-#changesetEntry {
-  border-collapse: collapse;
-  font-size: 90%;
-  width: 100%;
-  margin-bottom: 1em;
-}
-
-#changesetEntry th {
-  padding: 1px 4px;
-  width: 4em;
-  text-align: right;
-  font-weight: normal;
-  color: #999;
-  margin-right: .5em;
-  vertical-align: top;
-}
-
-div.description {
-  border-left: 2px solid #999;
-  margin: 1em 0 1em 0;
-  padding: .3em;
-}
-
-/* Graph */
-div#wrapper {
-	position: relative;
-	border-top: 1px solid black;
-	border-bottom: 1px solid black;
-	margin: 0;
-	padding: 0;
-}
-
-canvas {
-	position: absolute;
-	z-index: 5;
-	top: -0.7em;
-	margin: 0;
-}
-
-ul#graphnodes {
-	position: absolute;
-	z-index: 10;
-	top: -1.0em;
-	list-style: none inside none;
-	padding: 0;
-}
-
-ul#nodebgs {
-	list-style: none inside none;
-	padding: 0;
-	margin: 0;
-	top: -0.7em;
-}
-
-ul#graphnodes li, ul#nodebgs li {
-	height: 39px;
-}
-
-ul#graphnodes li .info {
-	display: block;
-	font-size: 70%;
-	position: relative;
-	top: -3px;
-}
--- a/sys/src/cmd/hg/templates/static/style.css
+++ /dev/null
@@ -1,105 +1,0 @@
-a { text-decoration:none; }
-.age { white-space:nowrap; }
-.date { white-space:nowrap; }
-.indexlinks { white-space:nowrap; }
-.parity0 { background-color: #ddd; }
-.parity1 { background-color: #eee; }
-.lineno { width: 60px; color: #aaa; font-size: smaller;
-          text-align: right; }
-.plusline { color: green; }
-.minusline { color: red; }
-.atline { color: purple; }
-.annotate { font-size: smaller; text-align: right; padding-right: 1em; }
-.buttons a {
-  background-color: #666;
-  padding: 2pt;
-  color: white;
-  font-family: sans;
-  font-weight: bold;
-}
-.navigate a {
-  background-color: #ccc;
-  padding: 2pt;
-  font-family: sans;
-  color: black;
-}
-
-.metatag {
-  background-color: #888;
-  color: white;
-  text-align: right;
-}
-
-/* Common */
-pre { margin: 0; }
-
-.logo {
-  float: right;
-  clear: right;
-}
-
-/* Changelog/Filelog entries */
-.logEntry { width: 100%; }
-.logEntry .age { width: 15%; }
-.logEntry th { font-weight: normal; text-align: right; vertical-align: top; }
-.logEntry th.age, .logEntry th.firstline { font-weight: bold; }
-.logEntry th.firstline { text-align: left; width: inherit; }
-
-/* Shortlog entries */
-.slogEntry { width: 100%; }
-.slogEntry .age { width: 8em; }
-.slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
-.slogEntry td.author { width: 15em; }
-
-/* Tag entries */
-#tagEntries { list-style: none; margin: 0; padding: 0; }
-#tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
-
-/* Changeset entry */
-#changesetEntry { }
-#changesetEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
-#changesetEntry th.files, #changesetEntry th.description { vertical-align: top; }
-
-/* File diff view */
-#filediffEntry { }
-#filediffEntry th { font-weight: normal; background-color: #888; color: #fff; text-align: right; }
-
-/* Graph */
-div#wrapper {
-	position: relative;
-	margin: 0;
-	padding: 0;
-}
-
-canvas {
-	position: absolute;
-	z-index: 5;
-	top: -0.6em;
-	margin: 0;
-}
-
-ul#nodebgs {
-	list-style: none inside none;
-	padding: 0;
-	margin: 0;
-	top: -0.7em;
-}
-
-ul#graphnodes li, ul#nodebgs li {
-	height: 39px;
-}
-
-ul#graphnodes {
-	position: absolute;
-	z-index: 10;
-	top: -0.85em;
-	list-style: none inside none;
-	padding: 0;
-}
-
-ul#graphnodes li .info {
-	display: block;
-	font-size: 70%;
-	position: relative;
-	top: -1px;
-}